summaryrefslogtreecommitdiff
path: root/src/drivers/Wayland
diff options
context:
space:
mode:
Diffstat (limited to 'src/drivers/Wayland')
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H34
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx60
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H62
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx486
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H72
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx310
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H40
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx185
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.H193
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx2204
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.H185
-rw-r--r--src/drivers/Wayland/Fl_Wayland_Window_Driver.cxx2191
-rw-r--r--src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx741
-rw-r--r--src/drivers/Wayland/fl_wayland_platform_init.cxx157
14 files changed, 0 insertions, 6920 deletions
diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H
deleted file mode 100644
index e10a801ce..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.H
+++ /dev/null
@@ -1,34 +0,0 @@
-//
-// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2022 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
-//
-
-#ifndef FL_WAYLAND_COPY_SURFACE_DRIVER_H
-#define FL_WAYLAND_COPY_SURFACE_DRIVER_H
-
-#include <FL/Fl_Copy_Surface.H>
-#include <FL/Fl_Image_Surface.H>
-
-class Fl_Wayland_Copy_Surface_Driver : public Fl_Copy_Surface_Driver {
- friend class Fl_Copy_Surface_Driver;
- Fl_Image_Surface *img_surf;
-protected:
- Fl_Wayland_Copy_Surface_Driver(int w, int h);
- ~Fl_Wayland_Copy_Surface_Driver();
- void set_current() FL_OVERRIDE;
- void translate(int x, int y) FL_OVERRIDE;
- void untranslate() FL_OVERRIDE;
-};
-
-#endif // FL_WAYLAND_COPY_SURFACE_DRIVER_H
diff --git a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
deleted file mode 100644
index 043114781..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
+++ /dev/null
@@ -1,60 +0,0 @@
-//
-// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2023 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_Wayland_Copy_Surface_Driver.H"
-#include <FL/Fl_Image_Surface.H>
-#include "Fl_Wayland_Graphics_Driver.H"
-#include "Fl_Wayland_Screen_Driver.H"
-#include "Fl_Wayland_Window_Driver.H"
-
-
-Fl_Wayland_Copy_Surface_Driver::Fl_Wayland_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) {
- float os_scale = Fl_Graphics_Driver::default_driver().scale();
- int d = 1;
- if (Fl::first_window()) {
- d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale();
- }
- img_surf = new Fl_Image_Surface(int(w * os_scale) * d, int(h * os_scale) * d);
- driver(img_surf->driver());
- driver()->scale(d * os_scale);
-}
-
-
-Fl_Wayland_Copy_Surface_Driver::~Fl_Wayland_Copy_Surface_Driver() {
- Fl_RGB_Image *rgb = img_surf->image();
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- scr_driver->copy_image(rgb->array, rgb->data_w(), rgb->data_h());
- delete rgb;
- delete img_surf;
- driver(NULL);
-}
-
-
-void Fl_Wayland_Copy_Surface_Driver::set_current() {
- Fl_Surface_Device::set_current();
- Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver();
- if (!dr->cr()) dr->set_cairo((cairo_t*)img_surf->offscreen());
-}
-
-
-void Fl_Wayland_Copy_Surface_Driver::translate(int x, int y) {
- ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y);
-}
-
-
-void Fl_Wayland_Copy_Surface_Driver::untranslate() {
- ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate();
-}
diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H
deleted file mode 100644
index ad67c01bf..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.H
+++ /dev/null
@@ -1,62 +0,0 @@
-//
-// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2021-2023 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
-//
-
-#ifndef FL_WAYLAND_GL_WINDOW_DRIVER_H
-#define FL_WAYLAND_GL_WINDOW_DRIVER_H
-
-#include <config.h>
-#if HAVE_GL
-#include "../../Fl_Gl_Window_Driver.H"
-#include <wayland-egl.h>
-#include <EGL/egl.h>
-#include <FL/gl.h>
-
-
-class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver {
- friend Fl_Gl_Window_Driver* Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *);
- friend class Fl_Wayland_Gl_Plugin;
-private:
- static EGLDisplay egl_display;
- struct wl_egl_window *egl_window;
- EGLSurface egl_surface;
- bool need_swap;
- Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win);
- float pixels_per_unit() FL_OVERRIDE;
- void make_current_before() FL_OVERRIDE;
- int mode_(int m, const int *a) FL_OVERRIDE;
- void swap_buffers() FL_OVERRIDE;
- void resize(int is_a_resize, int w, int h) FL_OVERRIDE;
- char swap_type() FL_OVERRIDE;
- void swap_interval(int) FL_OVERRIDE;
- int swap_interval() const FL_OVERRIDE;
- Fl_Gl_Choice *find(int m, const int *alistp) FL_OVERRIDE;
- GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g) FL_OVERRIDE;
- void set_gl_context(Fl_Window* w, GLContext context) FL_OVERRIDE;
- void delete_gl_context(GLContext) FL_OVERRIDE;
- void make_overlay_current() FL_OVERRIDE;
- void redraw_overlay() FL_OVERRIDE;
- void gl_start() FL_OVERRIDE;
- void gl_visual(Fl_Gl_Choice *c) FL_OVERRIDE;
- void init();
- void* GetProcAddress(const char *procName) FL_OVERRIDE;
-public:
- static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time);
- //virtual bool need_scissor() { return true; } // CONTROL_LEAKING_SUB_GL_WINDOWS
- //void apply_scissor(); // CONTROL_LEAKING_SUB_GL_WINDOWS
-};
-
-#endif // HAVE_GL
-#endif // FL_WAYLAND_GL_WINDOW_DRIVER_H
diff --git a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx
deleted file mode 100644
index d20b941b7..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx
+++ /dev/null
@@ -1,486 +0,0 @@
-//
-// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2021-2023 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 <config.h>
-#if HAVE_GL
-#include <FL/platform.H>
-#include <FL/Fl_Image_Surface.H>
-#include "../../Fl_Gl_Choice.H"
-#include "Fl_Wayland_Window_Driver.H"
-#include "Fl_Wayland_Graphics_Driver.H"
-#include "Fl_Wayland_Gl_Window_Driver.H"
-#include "../Posix/Fl_Posix_System_Driver.H"
-#ifdef FLTK_USE_X11
-# include "../X11/Fl_X11_Gl_Window_Driver.H"
-#endif
-#include <wayland-egl.h>
-#include <EGL/egl.h>
-#include <FL/gl.h>
-
-/* Implementation notes about OpenGL drawing on the Wayland platform
-
-* After eglCreateWindowSurface() with attributes {EGL_RENDER_BUFFER, EGL_SINGLE_BUFFER, EGL_NONE},
-eglQueryContext() reports that EGL_RENDER_BUFFER equals EGL_BACK_BUFFER.
-This experiment suggests that the platform only supports double-buffer drawing.
-Consequently, FL_DOUBLE is enforced in all Fl_Gl_Window::mode_ values under Wayland.
-
-* Commented out code marked with CONTROL_LEAKING_SUB_GL_WINDOWS aims to prevent
- sub GL windows from leaking out from their parent by making leaking parts fully transparent.
- This code is commented out because it requires the FL_ALPHA flag to be on
- which not all client applications do.
-*/
-
-// Describes crap needed to create a GLContext.
-class Fl_Wayland_Gl_Choice : public Fl_Gl_Choice {
- friend class Fl_Wayland_Gl_Window_Driver;
-private:
- EGLConfig egl_conf;
-public:
- Fl_Wayland_Gl_Choice(int m, const int *alistp, Fl_Gl_Choice *n) : Fl_Gl_Choice(m, alistp, n) {
- egl_conf = 0;
- }
-};
-
-
-struct gl_start_support { // to support use of gl_start / gl_finish
- struct wl_surface *surface;
- struct wl_subsurface *subsurface;
- struct wl_egl_window *egl_window;
- EGLSurface egl_surface;
-};
-
-
-static EGLConfig wld_egl_conf = NULL;
-static EGLint swap_interval_ = 1;
-static EGLint max_swap_interval = 1000;
-static EGLint min_swap_interval = 0;
-
-
-EGLDisplay Fl_Wayland_Gl_Window_Driver::egl_display = EGL_NO_DISPLAY;
-
-
-Fl_Wayland_Gl_Window_Driver::Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win) :
- Fl_Gl_Window_Driver(win) {
- if (egl_display == EGL_NO_DISPLAY) init();
- egl_window = NULL;
- egl_surface = NULL;
- need_swap = false;
-}
-
-
-Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w)
-{
-#ifdef FLTK_USE_X11
- if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_X11_Gl_Window_Driver(w);
-#endif
- return new Fl_Wayland_Gl_Window_Driver(w);
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::init() {
- EGLint major, minor;
-
- if (!fl_wl_display()) fl_open_display();
- egl_display = eglGetDisplay((EGLNativeDisplayType) fl_wl_display());
- if (egl_display == EGL_NO_DISPLAY) {
- Fl::fatal("Can't create egl display\n");
- }
-
- if (eglInitialize(egl_display, &major, &minor) != EGL_TRUE) {
- Fl::fatal("Can't initialise egl display\n");
- }
- //printf("EGL major: %d, minor %d\n", major, minor);
- //eglGetConfigs(egl_display, NULL, 0, &configs_count);
- //printf("EGL has %d configs\n", configs_count);
- eglBindAPI(EGL_OPENGL_API);
-}
-
-
-Fl_Gl_Choice *Fl_Wayland_Gl_Window_Driver::find(int m, const int *alistp)
-{
- m |= FL_DOUBLE;
- //if (pWindow->parent()) m |= FL_ALPHA; // CONTROL_LEAKING_SUB_GL_WINDOWS
- Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)Fl_Gl_Window_Driver::find_begin(
- m, alistp);
- if (g) return g;
-
- EGLint n;
- EGLint config_attribs[] = {
- EGL_SURFACE_TYPE, EGL_WINDOW_BIT,
- EGL_RED_SIZE, 8,
- EGL_GREEN_SIZE, 8,
- EGL_BLUE_SIZE, 8,
- EGL_RENDERABLE_TYPE, EGL_OPENGL_BIT,
- EGL_DEPTH_SIZE, 0, // set at 11
- EGL_SAMPLE_BUFFERS, 0, // set at 13
- EGL_STENCIL_SIZE, 0, // set at 15
- EGL_ALPHA_SIZE, 0, // set at 17
- EGL_NONE
- };
-
- if (m & FL_DEPTH32)
- config_attribs[11] = 32; // request at least 32 bits
- else if (m & FL_DEPTH)
- config_attribs[11] = 1; // accept any size
-
- if (m & FL_MULTISAMPLE) config_attribs[13] = 1;
- if (m & FL_STENCIL) config_attribs[15] = 1;
- if (m & FL_ALPHA) config_attribs[17] = (m & FL_RGB8) ? 8 : 1;
-
- g = new Fl_Wayland_Gl_Choice(m, alistp, first);
- eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n);
- if (n == 0 && (m & FL_MULTISAMPLE)) {
- config_attribs[13] = 0;
- eglChooseConfig(egl_display, config_attribs, &(g->egl_conf), 1, &n);
- }
- if (n == 0) {
- Fl::fatal("failed to choose an EGL config\n");
- }
-
- eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MAX_SWAP_INTERVAL, &max_swap_interval);
- eglGetConfigAttrib(egl_display, g->egl_conf, EGL_MIN_SWAP_INTERVAL, &min_swap_interval);
-
- first = g;
- return g;
-}
-
-
-GLContext Fl_Wayland_Gl_Window_Driver::create_gl_context(Fl_Window* window,
- const Fl_Gl_Choice* g) {
- GLContext shared_ctx = 0;
- if (context_list && nContext) shared_ctx = context_list[0];
-
- static const EGLint context_attribs[] = { EGL_CONTEXT_CLIENT_VERSION, 2, EGL_NONE };
- GLContext ctx = (GLContext)eglCreateContext(egl_display,
- ((Fl_Wayland_Gl_Choice*)g)->egl_conf,
- (shared_ctx ? (EGLContext)shared_ctx : EGL_NO_CONTEXT),
- context_attribs);
-//fprintf(stderr, "eglCreateContext=%p shared_ctx=%p\n", ctx, shared_ctx);
- if (ctx) {
- add_context(ctx);
- /* CONTROL_LEAKING_SUB_GL_WINDOWS
- if (egl_surface) {
- eglMakeCurrent(egl_display, egl_surface, egl_surface, (EGLContext)ctx);
- glClearColor(0., 0., 0., 1.); // set opaque black as starting background color
- apply_scissor();
- }*/
- }
- return ctx;
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) {
- struct wld_window *win = fl_wl_xid(w);
- if (!win) return;
- Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(w);
- EGLSurface target_egl_surface = NULL;
- if (egl_surface) target_egl_surface = egl_surface;
- else if (dr->gl_start_support_) target_egl_surface = dr->gl_start_support_->egl_surface;
- if (!target_egl_surface) { // useful for gl_start()
- dr->gl_start_support_ = new struct gl_start_support;
- float s = Fl::screen_scale(w->screen_num());
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- // the GL scene will be a transparent subsurface above the cairo-drawn surface
- dr->gl_start_support_->surface =
- wl_compositor_create_surface(scr_driver->wl_compositor);
- dr->gl_start_support_->subsurface = wl_subcompositor_get_subsurface(
- scr_driver->wl_subcompositor, dr->gl_start_support_->surface, win->wl_surface);
- wl_subsurface_set_position(dr->gl_start_support_->subsurface, w->x() * s, w->y() * s);
- wl_subsurface_place_above(dr->gl_start_support_->subsurface, win->wl_surface);
- dr->gl_start_support_->egl_window = wl_egl_window_create(
- dr->gl_start_support_->surface, w->w() * s, w->h() * s);
- target_egl_surface = dr->gl_start_support_->egl_surface = eglCreateWindowSurface(
- egl_display, wld_egl_conf, dr->gl_start_support_->egl_window, NULL);
- }
- GLContext current_context = eglGetCurrentContext();
- if (context != current_context || w != cached_window) {
- cached_window = w;
- if (eglMakeCurrent(egl_display, target_egl_surface, target_egl_surface,
- (EGLContext)context)) {
-//fprintf(stderr, "EGLContext %p made current\n", context);
- } else {
- Fl::error("eglMakeCurrent() failed\n");
- }
- }
- if (!(mode() & FL_ALPHA)) { // useful at least for Linux on MacBook hardware
- GLfloat vals[4];
- glGetFloatv(GL_COLOR_CLEAR_VALUE, vals);
- if (vals[3] == 0.) glClearColor(vals[0], vals[1], vals[2], 1.);
- }
-}
-
-/* CONTROL_LEAKING_SUB_GL_WINDOWS
-void Fl_Wayland_Gl_Window_Driver::apply_scissor() {
- cairo_rectangle_int_t *extents = Fl_Wayland_Window_Driver::driver(pWindow)->subRect();
- if (extents) {
- glDisable(GL_SCISSOR_TEST);
- GLdouble vals[4];
- glGetDoublev(GL_COLOR_CLEAR_VALUE, vals);
- glClearColor(0., 0., 0., 0.);
- glClear(GL_COLOR_BUFFER_BIT);
- glClearColor(vals[0], vals[1], vals[2], vals[3]);
- float s = pWindow->pixels_per_unit();
- glScissor(s*extents->x, s*extents->y, s*extents->width, s*extents->height);
-//printf("apply_scissor %dx%d %dx%d\n",extents->x, extents->y, extents->width, extents->height);
- glEnable(GL_SCISSOR_TEST);
- }
-}*/
-
-
-void Fl_Wayland_Gl_Window_Driver::delete_gl_context(GLContext context) {
- GLContext current_context = eglGetCurrentContext();
- if (current_context == context) {
- cached_window = 0;
- }
- if (current_context == (EGLContext)context) {
- eglMakeCurrent(egl_display, EGL_NO_SURFACE, EGL_NO_SURFACE, EGL_NO_CONTEXT);
- }
- eglDestroyContext(egl_display, (EGLContext)context);
- eglDestroySurface(egl_display, egl_surface);
- egl_surface = NULL;
- wl_egl_window_destroy(egl_window);
- egl_window = NULL;
- del_context(context);
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::make_overlay_current() {
- glDrawBuffer(GL_FRONT);
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::redraw_overlay() {
- pWindow->redraw();
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::make_current_before() {
- if (!egl_window) {
- struct wld_window *win = fl_wl_xid(pWindow);
- struct wl_surface *surface = win->wl_surface;
- int W = pWindow->pixel_w();
- int H = pWindow->pixel_h();
- int scale = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale();
- egl_window = wl_egl_window_create(surface, (W/scale)*scale, (H/scale)*scale);
- if (egl_window == EGL_NO_SURFACE) {
- Fl::fatal("Can't create egl window with wl_egl_window_create()\n");
- }
- Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)this->g();
- egl_surface = eglCreateWindowSurface(egl_display, g->egl_conf, egl_window, NULL);
- wl_surface_set_buffer_scale(surface, scale);
- if (mode() & FL_ALPHA) wl_surface_set_opaque_region(surface, NULL);
- // Tested apps: shape, glpuzzle, cube, fractals, gl_overlay, fullscreen, unittests,
- // OpenGL3-glut-test, OpenGL3test.
- // Tested wayland compositors: mutter, kde-plasma, weston, sway on FreeBSD.
- if (pWindow->parent()) win = fl_wl_xid(pWindow->top_window());
- while (wl_list_empty(&win->outputs)) wl_display_dispatch(fl_wl_display());
- }
-}
-
-
-float Fl_Wayland_Gl_Window_Driver::pixels_per_unit()
-{
- int ns = pWindow->screen_num();
- int wld_scale = (pWindow->shown() ?
- Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale() : 1);
- return wld_scale * Fl::screen_driver()->scale(ns);
-}
-
-
-int Fl_Wayland_Gl_Window_Driver::mode_(int m, const int *a) {
- mode(m | FL_DOUBLE);
- return 1;
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
- Fl_Wayland_Gl_Window_Driver *gl_dr = (Fl_Wayland_Gl_Window_Driver *)data;
- wl_callback_destroy(cb);
- struct wld_window *window = fl_wl_xid(gl_dr->pWindow);
- window->frame_cb = NULL;
- if (gl_dr->need_swap) {
- eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, gl_dr->egl_surface);
- gl_dr->need_swap = false;
- }
-}
-
-
-static const struct wl_callback_listener surface_frame_listener = {
- .done = Fl_Wayland_Gl_Window_Driver::surface_frame_done,
-};
-
-
-void Fl_Wayland_Gl_Window_Driver::swap_buffers() {
- if (overlay()) {
- static bool overlay_buffer = true;
- int wo = pWindow->pixel_w(), ho = pWindow->pixel_h();
- GLint matrixmode;
- GLfloat pos[4];
- glGetIntegerv(GL_MATRIX_MODE, &matrixmode);
- glGetFloatv(GL_CURRENT_RASTER_POSITION, pos); // save original glRasterPos
- glMatrixMode(GL_PROJECTION); // save proj/model matrices
- glPushMatrix();
- glLoadIdentity();
- glMatrixMode(GL_MODELVIEW);
- glPushMatrix();
- glLoadIdentity();
- glScalef(2.0f/wo, 2.0f/ho, 1.0f);
- glTranslatef(-wo/2.0f, -ho/2.0f, 0.0f); // set transform so 0,0 is bottom/left of window
- glRasterPos2i(0,0); // set glRasterPos to bottom left corner
- {
- // Emulate overlay by doing copypixels
- glReadBuffer(overlay_buffer?GL_BACK:GL_FRONT);
- glDrawBuffer(overlay_buffer?GL_FRONT:GL_BACK);
- overlay_buffer = ! overlay_buffer;
- glCopyPixels(0, 0, wo, ho, GL_COLOR);
- }
- glPopMatrix(); // GL_MODELVIEW // restore model/proj matrices
- glMatrixMode(GL_PROJECTION);
- glPopMatrix();
- glMatrixMode(matrixmode);
- glRasterPos3f(pos[0], pos[1], pos[2]); // restore original glRasterPos
- if (!overlay_buffer) return; // don't call eglSwapBuffers until overlay has been drawn
- }
-
- if (egl_surface) {
- Fl_Window *parent = pWindow->parent() ? pWindow->window() : NULL;
- struct wld_window *parent_xid = parent ? fl_wl_xid(parent) : NULL;
- if (parent_xid) { // issue #967
- struct wld_window *xid = fl_wl_xid(pWindow);
- if (xid->frame_cb) {
- need_swap = true;
- return;
- }
- if (!parent_xid->frame_cb) {
- xid->frame_cb = wl_surface_frame(xid->wl_surface);
- wl_callback_add_listener(xid->frame_cb, &surface_frame_listener, this);
- }
- }
- eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, egl_surface);
- need_swap = false;
- }
-}
-
-
-class Fl_Wayland_Gl_Plugin : public Fl_Wayland_Plugin {
-public:
- Fl_Wayland_Gl_Plugin() : Fl_Wayland_Plugin(name()) { }
- const char *name() FL_OVERRIDE { return "gl.wayland.fltk.org"; }
- void do_swap(Fl_Window *w) FL_OVERRIDE {
- Fl_Gl_Window_Driver *gldr = Fl_Gl_Window_Driver::driver(w->as_gl_window());
- if (gldr->overlay() == w) gldr->swap_buffers();
- }
- void invalidate(Fl_Window *w) FL_OVERRIDE {
- w->as_gl_window()->valid(0);
- }
- void terminate() FL_OVERRIDE {
- if (Fl_Wayland_Gl_Window_Driver::egl_display != EGL_NO_DISPLAY) {
- eglTerminate(Fl_Wayland_Gl_Window_Driver::egl_display);
- }
- }
- void destroy(struct gl_start_support *gl_start_support_) FL_OVERRIDE {
- eglDestroySurface(Fl_Wayland_Gl_Window_Driver::egl_display,
- gl_start_support_->egl_surface);
- wl_egl_window_destroy(gl_start_support_->egl_window);
- wl_subsurface_destroy(gl_start_support_->subsurface);
- wl_surface_destroy(gl_start_support_->surface);
- delete gl_start_support_;
- }
-};
-
-
-static Fl_Wayland_Gl_Plugin Gl_Overlay_Plugin;
-
-
-/* CONTROL_LEAKING_SUB_GL_WINDOWS
-static void delayed_scissor(Fl_Wayland_Gl_Window_Driver *dr) {
- dr->apply_scissor();
-}*/
-
-
-void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) {
- if (!egl_window) return;
- float f = Fl::screen_scale(pWindow->screen_num());
- int s = Fl_Wayland_Window_Driver::driver(pWindow)->wld_scale();
- W = int(W * f) * s; // W, H must be multiples of int s
- H = int(H * f) * s;
- int W2, H2;
- wl_egl_window_get_attached_size(egl_window, &W2, &H2);
- if (W2 != W || H2 != H) {
- struct wld_window *xid = fl_wl_xid(pWindow);
- if (xid->kind == Fl_Wayland_Window_Driver::DECORATED && !xid->frame_cb) {
- xid->frame_cb = wl_surface_frame(xid->wl_surface);
- wl_callback_add_listener(xid->frame_cb,
- Fl_Wayland_Graphics_Driver::p_surface_frame_listener, xid);
- }
- wl_egl_window_resize(egl_window, W, H, 0, 0);
- wl_surface_set_buffer_scale(xid->wl_surface, s);
- }
- /* CONTROL_LEAKING_SUB_GL_WINDOWS
- if (Fl_Wayland_Window_Driver::driver(pWindow)->subRect()) {
- pWindow->redraw();
- Fl::add_timeout(0.01, (Fl_Timeout_Handler)delayed_scissor, this);
- }*/
-}
-
-
-char Fl_Wayland_Gl_Window_Driver::swap_type() {
- return copy;
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::gl_visual(Fl_Gl_Choice *c) {
- Fl_Gl_Window_Driver::gl_visual(c);
- wld_egl_conf = ((Fl_Wayland_Gl_Choice*)c)->egl_conf;
-}
-
-
-void Fl_Wayland_Gl_Window_Driver::gl_start() {
- float f = Fl::screen_scale(Fl_Window::current()->screen_num());
- int W = Fl_Window::current()->w() * f;
- int H = Fl_Window::current()->h() * f;
- int W2, H2;
- Fl_Wayland_Window_Driver *dr = Fl_Wayland_Window_Driver::driver(Fl_Window::current());
- wl_egl_window_get_attached_size(dr->gl_start_support_->egl_window, &W2, &H2);
- if (W2 != W || H2 != H) {
- wl_egl_window_resize(dr->gl_start_support_->egl_window, W, H, 0, 0);
- }
- glClearColor(0., 0., 0., 0.);
- glClear(GL_COLOR_BUFFER_BIT);
-}
-
-void Fl_Wayland_Gl_Window_Driver::swap_interval(int interval) {
- if (interval < min_swap_interval) interval = min_swap_interval;
- if (interval > max_swap_interval) interval = max_swap_interval;
- if (egl_display && eglSwapInterval(egl_display, interval))
- swap_interval_ = interval;
- // printf("swap_interval_=%d\n",swap_interval_);
-}
-
-
-int Fl_Wayland_Gl_Window_Driver::swap_interval() const {
- return swap_interval_;
-}
-
-
-void* Fl_Wayland_Gl_Window_Driver::GetProcAddress(const char *procName) {
- return Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, procName);
-}
-
-
-FL_EXPORT EGLContext fl_wl_glcontext(GLContext rc) { return (EGLContext)rc; }
-
-#endif // HAVE_GL
diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H
deleted file mode 100644
index ac8786a47..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H
+++ /dev/null
@@ -1,72 +0,0 @@
-//
-// Definition of class Fl_Wayland_Graphics_Driver.
-//
-// Copyright 2021-2023 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
-//
-
-/**
- \file Fl_Wayland_Graphics_Driver.H
- \brief Definition of Wayland graphics driver.
- */
-
-#ifndef FL_WAYLAND_GRAPHICS_DRIVER_H
-#define FL_WAYLAND_GRAPHICS_DRIVER_H
-
-#include "../Cairo/Fl_Cairo_Graphics_Driver.H"
-#include <stdint.h> // for uint32_t
-#include <wayland-client.h> // for wl_list
-
-
-class Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver {
-public:
- struct draw_buffer {
- unsigned char *buffer;
- cairo_t *cairo_;
- size_t data_size; // of wl_buffer and buffer
- int stride;
- int width;
- };
- struct wld_buffer {
- struct draw_buffer draw_buffer;
- struct wl_list link; // links all buffers from the same wl_shm_pool
- struct wl_buffer *wl_buffer;
- void *data;
- struct wl_shm_pool *shm_pool;
- bool draw_buffer_needs_commit;
- bool in_use; // true while being committed
- bool released; // true after buffer_release() was called
- };
- struct wld_shm_pool_data { // one record attached to each wl_shm_pool object
- char *pool_memory; // start of mmap'ed memory encapsulated by the wl_shm_pool
- size_t pool_size; // size of encapsulated memory
- struct wl_list buffers; // to list of fl_wld_buffer's from this pool
- };
- static const uint32_t wld_format;
- static struct wl_shm_pool *current_pool;
- static FL_EXPORT const struct wl_callback_listener *p_surface_frame_listener;
- void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc,
- int srcx, int srcy) FL_OVERRIDE;
- void cache_size(Fl_Image *img, int &width, int &height) FL_OVERRIDE;
- static struct wld_buffer *create_wld_buffer(int width, int height, bool with_shm = true);
- static void create_shm_buffer(wld_buffer *buffer);
- static void buffer_release(struct wld_window *window);
- static void buffer_commit(struct wld_window *window, cairo_region_t *r = NULL);
- static void cairo_init(struct draw_buffer *buffer, int width, int height, int stride,
- cairo_format_t format);
- // used by class Fl_Wayland_Gl_Window_Driver
- static FL_EXPORT struct draw_buffer *offscreen_buffer(Fl_Offscreen);
- static const cairo_user_data_key_t key;
- static Fl_Image_Surface *custom_offscreen(int w, int h, struct wld_buffer **buffer);
-};
-
-#endif // FL_WAYLAND_GRAPHICS_DRIVER_H
diff --git a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx
deleted file mode 100644
index 5c9539a8c..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx
+++ /dev/null
@@ -1,310 +0,0 @@
-//
-// Implementation of the Wayland graphics driver.
-//
-// Copyright 2021-2023 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_Wayland_Graphics_Driver.H"
-#include "Fl_Wayland_Screen_Driver.H"
-#include "Fl_Wayland_Window_Driver.H"
-#include <FL/Fl_Image_Surface.H>
-#include <sys/mman.h>
-#include <unistd.h> // for close()
-#include <errno.h>
-#include <string.h> // for strerror()
-#include <cairo/cairo.h>
-
-extern "C" {
-# include "../../../libdecor/src/os-compatibility.h" // for libdecor_os_create_anonymous_file()
-}
-
-// used by create_shm_buffer and do_buffer_release
-struct wl_shm_pool *Fl_Wayland_Graphics_Driver::current_pool = NULL;
-
-
-static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *);
-
-
-static void buffer_release_listener(void *user_data, struct wl_buffer *wl_buffer)
-{
- struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer =
- (struct Fl_Wayland_Graphics_Driver::wld_buffer*)user_data;
- buffer->in_use = false;
- if (buffer->released) do_buffer_release(buffer);
-}
-
-
-static const struct wl_buffer_listener buffer_listener = {
- buffer_release_listener
-};
-
-
-void Fl_Wayland_Graphics_Driver::create_shm_buffer(Fl_Wayland_Graphics_Driver::wld_buffer *buffer) {
- int width = buffer->draw_buffer.width;
- int stride = buffer->draw_buffer.stride;
- int height = buffer->draw_buffer.data_size / stride;
- const size_t default_pool_size = 10000000; // larger pools are possible if needed
- int chunk_offset = 0; // offset to start of available memory in pool
- struct wld_shm_pool_data *pool_data = current_pool ? // data record attached to current pool
- (struct wld_shm_pool_data *)wl_shm_pool_get_user_data(current_pool) : NULL;
- size_t pool_size = current_pool ? pool_data->pool_size : default_pool_size; // current pool size
- if (current_pool && !wl_list_empty(&pool_data->buffers)) {
- // last wld_buffer created from current pool
- struct wld_buffer *record = wl_container_of(pool_data->buffers.next, record, link);
- chunk_offset = ((char*)record->data - pool_data->pool_memory) +
- record->draw_buffer.data_size;
- }
- if (!current_pool || chunk_offset + buffer->draw_buffer.data_size > pool_size) {
- // if true, a new pool is needed
- if (current_pool && wl_list_empty(&pool_data->buffers)) {
- wl_shm_pool_destroy(current_pool);
- /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size);
-// printf("create_shm_buffer munmap(%p)->%d\n", pool_data->pool_memory, err);
- free(pool_data);
- }
- chunk_offset = 0;
- pool_size = default_pool_size;
- if (buffer->draw_buffer.data_size > pool_size)
- pool_size = 2 * buffer->draw_buffer.data_size; // a larger pool is needed
- int fd = libdecor_os_create_anonymous_file(pool_size);
- if (fd < 0) {
- Fl::fatal("libdecor_os_create_anonymous_file failed: %s\n", strerror(errno));
- }
- pool_data = (struct wld_shm_pool_data*)calloc(1, sizeof(struct wld_shm_pool_data));
- pool_data->pool_memory = (char*)mmap(NULL, pool_size, PROT_READ | PROT_WRITE,
- MAP_SHARED, fd, 0);
- if (pool_data->pool_memory == MAP_FAILED) {
- close(fd);
- Fl::fatal("mmap failed: %s\n", strerror(errno));
- }
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- current_pool = wl_shm_create_pool(scr_driver->wl_shm, fd, (int32_t)pool_size);
- close(fd); // does not prevent the mmap'ed memory from being used
- //printf("wl_shm_create_pool %p size=%lu\n",pool_data->pool_memory , pool_size);
- pool_data->pool_size = pool_size;
- wl_list_init(&pool_data->buffers);
- wl_shm_pool_set_user_data(current_pool, pool_data);
- }
- buffer->wl_buffer = wl_shm_pool_create_buffer(current_pool, chunk_offset,
- width, height, stride, wld_format);
- wl_buffer_add_listener(buffer->wl_buffer, &buffer_listener, buffer);
- // add this buffer to head of list of current pool's buffers
- wl_list_insert(&pool_data->buffers, &buffer->link);
- buffer->shm_pool = current_pool;
- buffer->data = (void*)(pool_data->pool_memory + chunk_offset);
-//fprintf(stderr, "last=%p chunk_offset=%d ", pool_data->buffers.next, chunk_offset);
-//fprintf(stderr, "create_shm_buffer: %dx%d = %d\n", width, height, size);
-}
-
-
-struct Fl_Wayland_Graphics_Driver::wld_buffer *
- Fl_Wayland_Graphics_Driver::create_wld_buffer(int width, int height, bool with_shm) {
- struct wld_buffer *buffer = (struct wld_buffer*)calloc(1, sizeof(struct wld_buffer));
- int stride = cairo_format_stride_for_width(cairo_format, width);
- cairo_init(&buffer->draw_buffer, width, height, stride, cairo_format);
- buffer->draw_buffer_needs_commit = true;
- if (with_shm) create_shm_buffer(buffer);
- return buffer;
-}
-
-
-// used to support both normal and progressive drawing and for top-level GL windows
-static void surface_frame_done(void *data, struct wl_callback *cb, uint32_t time) {
- struct wld_window *window = (struct wld_window *)data;
- wl_callback_destroy(cb);
- window->frame_cb = NULL;
- if (window->buffer && window->buffer->draw_buffer_needs_commit) {
- Fl_Wayland_Graphics_Driver::buffer_commit(window);
- }
-}
-
-
-static const struct wl_callback_listener surface_frame_listener = {
- .done = surface_frame_done,
-};
-
-
-const struct wl_callback_listener *Fl_Wayland_Graphics_Driver::p_surface_frame_listener =
- &surface_frame_listener;
-
-
-// copy pixels in region r from the Cairo surface to the Wayland buffer
-static void copy_region(struct wld_window *window, cairo_region_t *r) {
- struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer = window->buffer;
- float f = Fl::screen_scale(window->fl_win->screen_num());
- int d = Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale();
- int count = cairo_region_num_rectangles(r);
- cairo_rectangle_int_t rect;
- for (int i = 0; i < count; i++) {
- cairo_region_get_rectangle(r, i, &rect);
- int left = d * int(rect.x * f);
- int top = d * int(rect.y * f);
- int right = d * ceil((rect.x + rect.width) * f);
- if (right > d * int(window->fl_win->w() * f)) right = d * int(window->fl_win->w() * f);
- int width = right - left;
- int bottom = d * ceil((rect.y + rect.height) * f);
- if (bottom > d * int(window->fl_win->h() * f)) bottom = d * int(window->fl_win->h() * f);
- int height = bottom - top;
- int offset = top * buffer->draw_buffer.stride + 4 * left;
- int W4 = 4 * width;
- for (int l = 0; l < height; l++) {
- if (offset + W4 >= (int)buffer->draw_buffer.data_size) {
- W4 = buffer->draw_buffer.data_size - offset;
- if (W4 <= 0) break;
- }
- memcpy((uchar*)buffer->data + offset, buffer->draw_buffer.buffer + offset, W4);
- offset += buffer->draw_buffer.stride;
- }
- wl_surface_damage_buffer(window->wl_surface, left, top, width, height);
- }
-}
-
-
-void Fl_Wayland_Graphics_Driver::buffer_commit(struct wld_window *window, cairo_region_t *r)
-{
- if (!window->buffer->wl_buffer) create_shm_buffer(window->buffer);
- cairo_surface_t *surf = cairo_get_target(window->buffer->draw_buffer.cairo_);
- cairo_surface_flush(surf);
- if (r) copy_region(window, r);
- else {
- memcpy(window->buffer->data, window->buffer->draw_buffer.buffer,
- window->buffer->draw_buffer.data_size);
- wl_surface_damage_buffer(window->wl_surface, 0, 0, 1000000, 1000000);
- }
- window->buffer->in_use = true;
- wl_surface_attach(window->wl_surface, window->buffer->wl_buffer, 0, 0);
- wl_surface_set_buffer_scale( window->wl_surface,
- Fl_Wayland_Window_Driver::driver(window->fl_win)->wld_scale() );
- if (!window->covered) { // see issue #878
- window->frame_cb = wl_surface_frame(window->wl_surface);
- wl_callback_add_listener(window->frame_cb, p_surface_frame_listener, window);
- }
- wl_surface_commit(window->wl_surface);
- window->buffer->draw_buffer_needs_commit = false;
-}
-
-
-void Fl_Wayland_Graphics_Driver::cairo_init(struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer,
- int width, int height, int stride,
- cairo_format_t format) {
- buffer->data_size = stride * height;
- buffer->stride = stride;
- buffer->buffer = new uchar[buffer->data_size];
- buffer->width = width;
- cairo_surface_t *surf = cairo_image_surface_create_for_data(buffer->buffer, format,
- width, height, stride);
- if (cairo_surface_status(surf) != CAIRO_STATUS_SUCCESS) {
- Fl::fatal("Can't create Cairo surface with cairo_image_surface_create_for_data()\n");
- return;
- }
- buffer->cairo_ = cairo_create(surf);
- cairo_status_t err;
- if ((err = cairo_status(buffer->cairo_)) != CAIRO_STATUS_SUCCESS) {
- Fl::fatal("Cairo error during cairo_create() %s\n", cairo_status_to_string(err));
- return;
- }
- cairo_surface_destroy(surf);
- memset(buffer->buffer, 0, buffer->data_size); // useful for transparent windows
- cairo_set_source_rgba(buffer->cairo_, .0, .0, .0, 1.0); // Black default color
- cairo_save(buffer->cairo_);
-}
-
-
-// runs when buffer->in_use is false and buffer->released is true
-static void do_buffer_release(struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer) {
- struct wl_shm_pool *my_pool = buffer->shm_pool;
- if (buffer->wl_buffer) {
- struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data =
- (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*)
- wl_shm_pool_get_user_data(my_pool);
- wl_buffer_destroy(buffer->wl_buffer);
- // remove wld_buffer from list of pool's buffers
- wl_list_remove(&buffer->link);
- if (wl_list_empty(&pool_data->buffers) && my_pool != Fl_Wayland_Graphics_Driver::current_pool) {
- // all buffers from pool are gone
- wl_shm_pool_destroy(my_pool);
- /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size);
- //printf("do_buffer_release munmap(%p)->%d\n", pool_data->pool_memory, err);
- free(pool_data);
- }
- }
- free(buffer);
-}
-
-
-void Fl_Wayland_Graphics_Driver::buffer_release(struct wld_window *window)
-{
- if (window->buffer && !window->buffer->released) {
- window->buffer->released = true;
- if (window->frame_cb) { wl_callback_destroy(window->frame_cb); window->frame_cb = NULL; }
- delete[] window->buffer->draw_buffer.buffer;
- window->buffer->draw_buffer.buffer = NULL;
- cairo_destroy(window->buffer->draw_buffer.cairo_);
- if (!window->buffer->in_use) do_buffer_release(window->buffer);
- window->buffer = NULL;
- }
-}
-
-
-// this refers to the same memory layout for pixel data as does CAIRO_FORMAT_ARGB32
-const uint32_t Fl_Wayland_Graphics_Driver::wld_format = WL_SHM_FORMAT_ARGB8888;
-
-
-void Fl_Wayland_Graphics_Driver::copy_offscreen(int x, int y, int w, int h,
- Fl_Offscreen src, int srcx, int srcy) {
- // draw portion srcx,srcy,w,h of osrc to position x,y (top-left) of
- // the graphics driver's surface
- cairo_matrix_t matrix;
- cairo_get_matrix(cairo_, &matrix);
- double s = matrix.xx;
- cairo_save(cairo_);
- cairo_rectangle(cairo_, x - 0.5, y - 0.5, w, h);
- cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_NONE);
- cairo_clip(cairo_);
- cairo_set_antialias(cairo_, CAIRO_ANTIALIAS_DEFAULT);
- cairo_surface_t *surf = cairo_get_target((cairo_t *)src);
- cairo_pattern_t *pat = cairo_pattern_create_for_surface(surf);
- cairo_set_source(cairo_, pat);
- cairo_matrix_init_scale(&matrix, s, s);
- cairo_matrix_translate(&matrix, -(x - srcx), -(y - srcy));
- cairo_pattern_set_matrix(pat, &matrix);
- cairo_paint(cairo_);
- cairo_pattern_destroy(pat);
- cairo_restore(cairo_);
- surface_needs_commit();
-}
-
-
-const cairo_user_data_key_t Fl_Wayland_Graphics_Driver::key = {};
-
-
-struct Fl_Wayland_Graphics_Driver::draw_buffer*
-Fl_Wayland_Graphics_Driver::offscreen_buffer(Fl_Offscreen offscreen) {
- return (struct draw_buffer*)cairo_get_user_data((cairo_t*)offscreen, &key);
-}
-
-
-Fl_Image_Surface *Fl_Wayland_Graphics_Driver::custom_offscreen(int w, int h,
- struct Fl_Wayland_Graphics_Driver::wld_buffer **p_off) {
- struct wld_buffer *off = create_wld_buffer(w, h);
- *p_off = off;
- cairo_set_user_data(off->draw_buffer.cairo_, &key, &off->draw_buffer, NULL);
- return new Fl_Image_Surface(w, h, 0, (Fl_Offscreen)off->draw_buffer.cairo_);
-}
-
-
-void Fl_Wayland_Graphics_Driver::cache_size(Fl_Image *img, int &width, int &height) {
- Fl_Graphics_Driver::cache_size(img, width, height);
- width *= wld_scale;
- height *= wld_scale;
-}
diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H
deleted file mode 100644
index ae32ac3df..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.H
+++ /dev/null
@@ -1,40 +0,0 @@
-//
-// Draw-to-image code for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2022 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
-//
-
-#ifndef FL_WAYLAND_IMAGE_SURFACE_DRIVER_H
-#define FL_WAYLAND_IMAGE_SURFACE_DRIVER_H
-
-#include <FL/Fl_Image_Surface.H>
-
-class Fl_Wayland_Image_Surface_Driver : public Fl_Image_Surface_Driver {
- void end_current() FL_OVERRIDE;
- struct wld_window *pre_window;
-public:
- Fl_Wayland_Image_Surface_Driver(int w, int h, int high_res, Fl_Offscreen off);
- ~Fl_Wayland_Image_Surface_Driver();
- void mask(const Fl_RGB_Image *) FL_OVERRIDE;
- struct shape_data_type {
- double scale;
- cairo_pattern_t *mask_pattern_;
- cairo_t *bg_cr;
- } *shape_data_;
- void set_current() FL_OVERRIDE;
- void translate(int x, int y) FL_OVERRIDE;
- void untranslate() FL_OVERRIDE;
- Fl_RGB_Image *image() FL_OVERRIDE;
-};
-
-#endif // FL_WAYLAND_IMAGE_SURFACE_DRIVER_H
diff --git a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx
deleted file mode 100644
index ec9c56cb7..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-// Draw-to-image code for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 1998-2023 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_Graphics_Driver.H"
-#include "Fl_Wayland_Window_Driver.H"
-#include "Fl_Wayland_Image_Surface_Driver.H"
-
-
-Fl_Wayland_Image_Surface_Driver::Fl_Wayland_Image_Surface_Driver(int w, int h,
- int high_res, Fl_Offscreen off) : Fl_Image_Surface_Driver(w, h, high_res, off) {
- shape_data_ = NULL;
- float s = 1;
- int d = 1;
- if (!off) {
- fl_open_display();
- if (Fl::first_window()) {
- d = Fl_Wayland_Window_Driver::driver(Fl::first_window())->wld_scale();
- }
- s = Fl_Graphics_Driver::default_driver().scale();
- if (d*s != 1 && high_res) {
- w = int(w * s) * d;
- h = int(h * s) * d;
- }
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
- (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1,
- sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer));
- Fl_Wayland_Graphics_Driver::cairo_init(off_, w, h,
- cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, w), CAIRO_FORMAT_RGB24);
- offscreen = (Fl_Offscreen)off_->cairo_;
- cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL);
- if (d*s != 1 && high_res) cairo_scale((cairo_t*)offscreen, d*s, d*s);
- }
- driver(new Fl_Wayland_Graphics_Driver());
- if (d*s != 1 && high_res) driver()->scale(d*s);
-}
-
-
-Fl_Wayland_Image_Surface_Driver::~Fl_Wayland_Image_Surface_Driver() {
- if (shape_data_) {
- cairo_surface_t *surf;
- cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
- unsigned char *bits = cairo_image_surface_get_data(surf);
- cairo_pattern_destroy(shape_data_->mask_pattern_);
- delete[] bits;
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
- Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr);
- delete[] off_->buffer;
- free(off_);
- cairo_destroy(shape_data_->bg_cr);
- free(shape_data_);
- }
- if (offscreen && !external_offscreen) {
- struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer =
- Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
- cairo_destroy((cairo_t *)offscreen);
- delete[] buffer->buffer;
- free(buffer);
- }
- delete driver();
-}
-
-
-void Fl_Wayland_Image_Surface_Driver::set_current() {
- Fl_Surface_Device::set_current();
- Fl_Cairo_Graphics_Driver *dr = (Fl_Cairo_Graphics_Driver*)driver();
- if (!dr->cr()) dr->set_cairo((cairo_t*)offscreen);
- pre_window = Fl_Wayland_Window_Driver::wld_window;
- Fl_Wayland_Window_Driver::wld_window = NULL;
- fl_window = 0;
-}
-
-
-void Fl_Wayland_Image_Surface_Driver::end_current() {
- cairo_surface_t *surf = cairo_get_target((cairo_t*)offscreen);
- cairo_surface_flush(surf);
- Fl_Wayland_Window_Driver::wld_window = pre_window;
- fl_window = (Window)pre_window;
- Fl_Surface_Device::end_current();
-}
-
-
-void Fl_Wayland_Image_Surface_Driver::translate(int x, int y) {
- ((Fl_Wayland_Graphics_Driver*)driver())->ps_translate(x, y);
-}
-
-
-void Fl_Wayland_Image_Surface_Driver::untranslate() {
- ((Fl_Wayland_Graphics_Driver*)driver())->ps_untranslate();
-}
-
-
-Fl_RGB_Image* Fl_Wayland_Image_Surface_Driver::image() {
- if (shape_data_ && shape_data_->mask_pattern_) {
- // draw above the secondary offscreen the main offscreen masked by mask_pattern_
- cairo_t *c = ((Fl_Cairo_Graphics_Driver*)driver())->cr();
- cairo_pattern_t *paint_pattern = cairo_pattern_create_for_surface(cairo_get_target(c));
- cairo_set_source(shape_data_->bg_cr, paint_pattern);
- cairo_mask(shape_data_->bg_cr, shape_data_->mask_pattern_);
- cairo_pattern_destroy(paint_pattern);
- // copy secondary offscreen to the main offscreen
- cairo_pattern_t *pat = cairo_pattern_create_for_surface(cairo_get_target(shape_data_->bg_cr));
- cairo_scale(c, shape_data_->scale, shape_data_->scale);
- cairo_set_source(c, pat),
- cairo_paint(c);
- cairo_pattern_destroy(pat);
- // delete secondary offscreen
- cairo_surface_t *surf;
- cairo_pattern_get_surface(shape_data_->mask_pattern_, &surf);
- unsigned char *bits = cairo_image_surface_get_data(surf);
- cairo_pattern_destroy(shape_data_->mask_pattern_);
- delete[] bits;
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
- Fl_Wayland_Graphics_Driver::offscreen_buffer((Fl_Offscreen)shape_data_->bg_cr);
- delete[] off_->buffer;
- free(off_);
- cairo_destroy(shape_data_->bg_cr);
- free(shape_data_);
- shape_data_ = NULL;
- }
-
- // Convert depth-4 image in draw_buffer to a depth-3 image while exchanging R and B colors
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf =
- Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
- int height = int(off_buf->data_size / off_buf->stride);
- uchar *rgb = new uchar[off_buf->width * height * 3];
- uchar *p = rgb;
- uchar *q;
- for (int j = 0; j < height; j++) {
- q = off_buf->buffer + j*off_buf->stride;
- for (int i = 0; i < off_buf->width; i++) { // exchange R and B colors, transmit G
- *p = *(q+2);
- *(p+1) = *(q+1);
- *(p+2) = *q;
- p += 3; q += 4;
- }
- }
- Fl_RGB_Image *image = new Fl_RGB_Image(rgb, off_buf->width, height, 3);
- image->alloc_array = 1;
- return image;
-}
-
-
-void Fl_Wayland_Image_Surface_Driver::mask(const Fl_RGB_Image *mask) {
- bool using_copy = false;
- shape_data_ = (struct shape_data_type*)calloc(1, sizeof(struct shape_data_type));
- int W, H;
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_buf =
- Fl_Wayland_Graphics_Driver::offscreen_buffer(offscreen);
- W = off_buf->width;
- H = (int)(off_buf->data_size / off_buf->stride);
- if (W != mask->data_w() || H != mask->data_h()) {
- Fl_RGB_Image *copy = (Fl_RGB_Image*)mask->copy(W, H);
- mask = copy;
- using_copy = true;
- }
- shape_data_->mask_pattern_ = Fl_Cairo_Graphics_Driver::calc_cairo_mask(mask);
- //duplicate current offscreen content to new cairo_t* shape_data_->bg_cr
- int width, height;
- printable_rect(&width, &height);
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off_ =
- (struct Fl_Wayland_Graphics_Driver::draw_buffer*)calloc(1,
- sizeof(struct Fl_Wayland_Graphics_Driver::draw_buffer));
- Fl_Wayland_Graphics_Driver::cairo_init(off_, W, H,
- cairo_format_stride_for_width(CAIRO_FORMAT_RGB24, W),
- CAIRO_FORMAT_RGB24);
- cairo_set_user_data(off_->cairo_, &Fl_Wayland_Graphics_Driver::key, off_, NULL);
- shape_data_->bg_cr = off_->cairo_;
- memcpy(off_->buffer, off_buf->buffer, off_buf->data_size);
- shape_data_->scale = double(width) / W;
- if (using_copy) delete mask;
-}
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
deleted file mode 100644
index 83efd79a3..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.H
+++ /dev/null
@@ -1,193 +0,0 @@
-//
-// Definition of the Wayland Screen interface
-// for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2010-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
-//
-
-/**
- \file Fl_Wayland_Screen_Driver.H
- \brief Definition of Wayland Screen interface
- */
-
-#ifndef FL_WAYLAND_SCREEN_DRIVER_H
-#define FL_WAYLAND_SCREEN_DRIVER_H
-
-#include <config.h>
-#include "../Unix/Fl_Unix_Screen_Driver.H"
-#include <wayland-client.h>
-
-class Fl_Window;
-
-class Fl_Wayland_Screen_Driver : public Fl_Unix_Screen_Driver
-{
-private:
- static int insertion_point_x;
- static int insertion_point_y;
- static int insertion_point_width;
- static int insertion_point_height;
- static bool insertion_point_location_is_valid;
-public:
-// type definitions
- typedef enum {unspecified, MUTTER, WESTON, KWIN, OWL, WAYFIRE} compositor_name;
- struct seat {
- struct wl_seat *wl_seat;
- struct wl_pointer *wl_pointer;
- struct wl_keyboard *wl_keyboard;
- uint32_t keyboard_enter_serial;
- struct wl_surface *keyboard_surface;
- struct wl_list pointer_outputs;
- struct wl_cursor_theme *cursor_theme;
- struct wl_cursor *default_cursor;
- struct wl_surface *cursor_surface;
- struct wl_surface *pointer_focus;
- int pointer_scale;
- uint32_t serial;
- uint32_t pointer_enter_serial;
- struct wl_data_device_manager *data_device_manager;
- struct wl_data_device *data_device;
- struct wl_data_source *data_source;
- struct xkb_state *xkb_state;
- struct xkb_context *xkb_context;
- struct xkb_keymap *xkb_keymap;
- struct xkb_compose_state *xkb_compose_state;
- char *name;
- struct zwp_text_input_v3 *text_input;
- struct gtk_shell1 *gtk_shell;
- };
- struct output { // one record for each screen
- uint32_t id;
- int x, y; // logical position of screen
- int pixel_width; // in pixels
- int pixel_height; // in pixels
- int width; // in pixels, account for fractional scaling
- int height; // in pixels, account for fractional scaling
- float dpi;
- struct wl_output *wl_output;
- int wld_scale; // Wayland scale factor
- float gui_scale; // FLTK scale factor
- bool done;
- struct wl_list link;
- };
- enum cursor_shapes {arrow = 0, wait, insert, hand, help, cross, move,
- north, south, west, east, north_south, west_east, south_west, south_east, north_east, north_west, nesw, nwse};
- static const int cursor_count = nwse + 1; // nber of elements of 'enum cursor_shapes'
-
-// static member variables
- static FL_EXPORT struct wl_display *wl_display;
- static const struct wl_data_device_listener *p_data_device_listener;
- // next length of marked text after current marked text will have been replaced
- static int next_marked_length;
- static compositor_name compositor; // identifies the used Wayland compositor
-
-// static member functions
- static void insertion_point_location(int x, int y, int height);
- static bool insertion_point_location(int *px, int *py, int *pwidth, int *pheight);
- static bool own_output(struct wl_output *output);
- static void do_set_cursor(struct Fl_Wayland_Screen_Driver::seat *,
- struct wl_cursor *wl_cursor = NULL, Fl_Cursor c = FL_CURSOR_NONE);
-// member variables
- struct wl_cursor *xc_cursor[cursor_count]; // one for each element of enum cursor_shapes
- struct wl_registry *wl_registry;
- struct wl_compositor *wl_compositor;
- struct wl_subcompositor *wl_subcompositor;
- struct wl_shm *wl_shm;
- struct seat *seat;
- struct wl_list outputs; // linked list of struct output records for all screens in system
- struct libdecor *libdecor_context;
- struct xdg_wm_base *xdg_wm_base;
- struct zwp_text_input_manager_v3 *text_input_base;
-#if HAVE_XDG_DIALOG
- struct xdg_wm_dialog_v1 *xdg_wm_dialog;
-#endif
-#if HAVE_CURSOR_SHAPE
- struct wp_cursor_shape_manager_v1 *wp_cursor_shape_manager;
- struct wp_cursor_shape_device_v1 *wp_cursor_shape_device;
-#endif
-
-// constructor
- Fl_Wayland_Screen_Driver();
-
-// overridden functions from parent class Fl_Screen_Driver
- APP_SCALING_CAPABILITY rescalable() FL_OVERRIDE { return PER_SCREEN_APP_SCALING; }
- float scale(int n) FL_OVERRIDE;
- void scale(int n, float f) FL_OVERRIDE;
- // --- screen configuration
- void init() FL_OVERRIDE;
- int x() FL_OVERRIDE;
- int y() FL_OVERRIDE;
- int w() FL_OVERRIDE;
- int h() FL_OVERRIDE;
- void screen_xywh(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE;
- void screen_dpi(float &h, float &v, int n=0) FL_OVERRIDE;
- void screen_work_area(int &X, int &Y, int &W, int &H, int n) FL_OVERRIDE;
- // --- audible output
- void beep(int type) FL_OVERRIDE;
- // --- global events
- void flush() FL_OVERRIDE;
- void grab(Fl_Window* win) FL_OVERRIDE;
- // --- global colors
- void get_system_colors() FL_OVERRIDE;
- // this one is in fl_wayland_clipboard_dnd.cxx
- int dnd(int unused) FL_OVERRIDE;
- int compose(int &del) FL_OVERRIDE;
- void compose_reset() FL_OVERRIDE;
- Fl_RGB_Image *read_win_rectangle(int X, int Y, int w, int h, Fl_Window *win,
- bool may_capture_subwins, bool *did_capture_subwins) FL_OVERRIDE;
- int get_mouse(int &x, int &y) FL_OVERRIDE;
- void open_display_platform() FL_OVERRIDE;
- void close_display() FL_OVERRIDE;
- void display(const char *d) FL_OVERRIDE;
- // --- compute dimensions of an Fl_Offscreen
- void offscreen_size(Fl_Offscreen o, int &width, int &height) FL_OVERRIDE;
- int has_marked_text() const FL_OVERRIDE;
- // --- clipboard operations
- // this one is in fl_wayland_clipboard_dnd.cxx
- void copy(const char *stuff, int len, int clipboard, const char *type) FL_OVERRIDE;
- // this one is in fl_wayland_clipboard_dnd.cxx
- void paste(Fl_Widget &receiver, int clipboard, const char *type) FL_OVERRIDE;
- // this one is in fl_wayland_clipboard_dnd.cxx
- int clipboard_contains(const char *type) FL_OVERRIDE;
- void set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) FL_OVERRIDE;
- void reset_spot() FL_OVERRIDE;
- void *control_maximize_button(void *data) FL_OVERRIDE;
- int event_key(int k) FL_OVERRIDE;
- int get_key(int k) FL_OVERRIDE;
- void enable_im() FL_OVERRIDE;
- void disable_im() FL_OVERRIDE;
- bool screen_boundaries_known() FL_OVERRIDE { return false; }
- float base_scale(int numscreen) FL_OVERRIDE;
-
- // overridden functions from parent class Fl_Unix_Screen_Driver
- int poll_or_select_with_delay(double time_to_wait) FL_OVERRIDE;
- int poll_or_select() FL_OVERRIDE;
-
-// Wayland-specific member functions
- void screen_count_set(int count) {num_screens = count;}
- int screen_count_get() {return num_screens;}
- void reset_cursor();
- // this one is in fl_wayland_clipboard_dnd.cxx
- void copy_image(const unsigned char* data, int W, int H);
- void init_workarea();
- void set_cursor();
- struct wl_cursor *default_cursor();
- void default_cursor(struct wl_cursor *cursor);
- struct wl_cursor *cache_cursor(const char *cursor_name);
- uint32_t get_serial();
- struct wl_seat *get_wl_seat();
- char *get_seat_name();
- struct xkb_keymap *get_xkb_keymap();
-};
-
-
-#endif // FL_WAYLAND_SCREEN_DRIVER_H
diff --git a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx b/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
deleted file mode 100644
index 9199f3a5f..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
+++ /dev/null
@@ -1,2204 +0,0 @@
-//
-// Implementation of Wayland Screen interface
-//
-// 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_Wayland_Screen_Driver.H"
-#include "Fl_Wayland_Window_Driver.H"
-#include "Fl_Wayland_Graphics_Driver.H"
-#include "../../Fl_Scalable_Graphics_Driver.H"
-#include <wayland-cursor.h>
-#include "../../../libdecor/build/fl_libdecor.h"
-#include "xdg-shell-client-protocol.h"
-#include "../Posix/Fl_Posix_System_Driver.H"
-#include <FL/Fl.H>
-#include <FL/Fl_Image_Surface.H>
-#include <FL/platform.H>
-#include <FL/fl_ask.H>
-#include <FL/filename.H>
-#include <vector>
-#include "../../print_button.h"
-#include <dlfcn.h>
-#include <linux/input.h>
-#include <stdlib.h>
-#include <xkbcommon/xkbcommon.h>
-#include <xkbcommon/xkbcommon-compose.h>
-#include "text-input-client-protocol.h"
-#include "gtk-shell-client-protocol.h"
-#if HAVE_XDG_DIALOG
-# include "xdg-dialog-client-protocol.h"
-#endif
-#if HAVE_CURSOR_SHAPE
-# include "cursor-shape-client-protocol.h"
-#endif
-#include <assert.h>
-#include <sys/mman.h>
-#include <poll.h>
-#include <errno.h>
-#include <string.h> // for strerror()
-#include <map>
-extern "C" {
- bool libdecor_get_cursor_settings(char **theme, int *size);
- bool fl_is_surface_from_GTK_titlebar (struct wl_surface *surface, struct libdecor_frame *frame,
- bool *using_GTK);
-}
-
-// set this to 1 for keyboard debug output, 0 for no debug output
-#define DEBUG_KEYBOARD 0
-
-#define fl_max(a,b) ((a) > (b) ? (a) : (b))
-#define fl_min(a,b) ((a) < (b) ? (a) : (b))
-
-struct pointer_output {
- Fl_Wayland_Screen_Driver::output* output;
- struct wl_list link;
-};
-
-/* Implementation note:
-
-- About CSD and SSD :
- * Mutter and Weston use CSD (client-side decoration) which means that libdecor.so draws all window
- titlebars and responds to resize, minimization and maximization events.
- * KWin uses SSD (server-side decoration) which means the OS draws titlebars according to its own rules
- and triggers resize, minimization and maximization events.
-
-- Function registry_handle_global() runs within fl_open_display() and sets public static variable
- Fl_Wayland_Screen_Driver::compositor to either Fl_Wayland_Screen_Driver::MUTTER, ::WESTON, or ::KWIN.
-
-- Specific operations for WESTON:
- * When a libdecor-framed window is minimized under Weston, the frame remains on display. To avoid
- that, function libdecor_frame_set_minimized() is modified so it turns off the frame's visibility, with
- function libdecor_frame_set_visibility(), when the window is minimized. That's implemented in file
- libdecor/build/fl_libdecor.c. The modified libdecor_frame_set_minimized() function, part of libdecor.so,
- needs access to variable Fl_Wayland_Screen_Driver::compositor, part of libfltk.a. This is achieved
- calling FLTK function fl_libdecor_using_weston() which returns whether the running compositor
- is Weston. This Weston bug has been corrected in Weston version 10. Thus, this special processing
- is not performed when Weston version is ≥ 10.
-
-- Support of Fl_Window::border(int) :
- FLTK uses libdecor_frame_set_visibility() to show or hide a toplevel window's frame. This doesn't work
- with KWin which uses Server-Side Decoration. In that case, FLTK hides and re-shows the window to toggle
- between presence and absence of a window's frame.
-*/
-
-
-static std::vector<int> key_vector; // used by Fl_Wayland_Screen_Driver::event_key()
-static struct wl_surface *gtk_shell_surface = NULL;
-
-Fl_Wayland_Screen_Driver::compositor_name Fl_Wayland_Screen_Driver::compositor =
- Fl_Wayland_Screen_Driver::unspecified;
-
-
-extern "C" {
- bool fl_libdecor_using_weston(void) {
- return Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON;
- }
-}
-
-
-static void xdg_wm_base_ping(void *data, struct xdg_wm_base *xdg_wm_base, uint32_t serial)
-{
- xdg_wm_base_pong(xdg_wm_base, serial);
-}
-
-
-static const struct xdg_wm_base_listener xdg_wm_base_listener = {
- .ping = xdg_wm_base_ping,
-};
-
-
-// these are set by Fl::args() and override any system colors: from Fl_get_system_colors.cxx
-extern const char *fl_fg;
-extern const char *fl_bg;
-extern const char *fl_bg2;
-// end of extern additions workaround
-
-
-void Fl_Wayland_Screen_Driver::do_set_cursor(
- struct Fl_Wayland_Screen_Driver::seat *seat, struct wl_cursor *wl_cursor, Fl_Cursor cursor) {
- /*
- wl_cursor: when non-NULL means a custom cursor;
- when NULL:
- - with "Cursor shape" protocol, cursor is meaningful if != FL_CURSOR_NONE;
- - with old-school cursors, seat->default_cursor gives the desired cursor.
- cursor: used with "Cursor shape" protocol for enumerated cursor shape, otherwise equal to FL_CURSOR_NONE
- */
- struct wl_cursor_image *image;
- struct wl_buffer *buffer;
- const int scale = seat->pointer_scale;
-
-#if HAVE_CURSOR_SHAPE
- static std::map<int, int> cursor_shape_map = {
- {FL_CURSOR_DEFAULT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT },
- {FL_CURSOR_ARROW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_DEFAULT },
- {FL_CURSOR_CROSS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_CROSSHAIR },
- {FL_CURSOR_WAIT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_WAIT },
- {FL_CURSOR_INSERT, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_TEXT },
- {FL_CURSOR_HAND, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_GRAB },
- {FL_CURSOR_HELP, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_HELP },
- {FL_CURSOR_MOVE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_MOVE },
- {FL_CURSOR_N, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_N_RESIZE },
- {FL_CURSOR_E, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_E_RESIZE },
- {FL_CURSOR_W, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_W_RESIZE },
- {FL_CURSOR_S, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_S_RESIZE },
- {FL_CURSOR_NS, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NS_RESIZE },
- {FL_CURSOR_WE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_EW_RESIZE },
- {FL_CURSOR_SW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SW_RESIZE },
- {FL_CURSOR_SE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_SE_RESIZE },
- {FL_CURSOR_NE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NE_RESIZE },
- {FL_CURSOR_NW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NW_RESIZE },
- {FL_CURSOR_NESW, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NESW_RESIZE },
- {FL_CURSOR_NWSE, WP_CURSOR_SHAPE_DEVICE_V1_SHAPE_NWSE_RESIZE }
- };
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (scr_driver->wp_cursor_shape_device && !wl_cursor) {
- if (cursor != FL_CURSOR_NONE) wp_cursor_shape_device_v1_set_shape(
- scr_driver->wp_cursor_shape_device, seat->pointer_enter_serial, cursor_shape_map[cursor]);
- return;
- }
-#endif
-
- if ((!seat->cursor_theme && !wl_cursor) || !seat->wl_pointer)
- return;
-
- if (!wl_cursor) wl_cursor = seat->default_cursor;
- image = wl_cursor->images[0];
- buffer = wl_cursor_image_get_buffer(image);
- wl_pointer_set_cursor(seat->wl_pointer, seat->pointer_enter_serial,
- seat->cursor_surface,
- image->hotspot_x / scale,
- image->hotspot_y / scale);
- wl_surface_attach(seat->cursor_surface, buffer, 0, 0);
- wl_surface_set_buffer_scale(seat->cursor_surface, scale);
- wl_surface_damage_buffer(seat->cursor_surface, 0, 0,
- image->width, image->height);
- wl_surface_commit(seat->cursor_surface);
-}
-
-
-static uint32_t ptime;
-static uint32_t wld_event_time;
-static int px, py;
-
-
-static void set_event_xy(Fl_Window *win) {
- // turn off is_click if enough time or mouse movement has passed:
- if (abs(Fl::e_x_root-px)+abs(Fl::e_y_root-py) > 3 ||
- wld_event_time >= ptime+1000) {
- Fl::e_is_click = 0;
-//fprintf(stderr, "Fl::e_is_click = 0\n");
- }
-}
-
-
-// if this is same event as last && is_click, increment click count:
-static inline void checkdouble() {
- if (Fl::e_is_click == Fl::e_keysym) {
- Fl::e_clicks++;
-//fprintf(stderr, "Fl::e_clicks = %d\n", Fl::e_clicks);
- } else {
- Fl::e_clicks = 0;
- Fl::e_is_click = Fl::e_keysym;
-//fprintf(stderr, "Fl::e_is_click = %d\n", Fl::e_is_click);
- }
- px = Fl::e_x_root;
- py = Fl::e_y_root;
- ptime = wld_event_time;
-}
-
-
-struct wl_display *Fl_Wayland_Screen_Driver::wl_display = NULL;
-
-
-static Fl_Window *event_coords_from_surface(struct wl_surface *surface,
- wl_fixed_t surface_x, wl_fixed_t surface_y) {
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
- if (!win) return NULL;
- int delta_x = 0, delta_y = 0;
- while (win->parent()) {
- delta_x += win->x();
- delta_y += win->y();
- win = win->window();
- }
- float f = Fl::screen_scale(win->screen_num());
- Fl::e_x = wl_fixed_to_int(surface_x) / f + delta_x;
- Fl::e_x_root = Fl::e_x + win->x();
- Fl::e_y = wl_fixed_to_int(surface_y) / f + delta_y;
- int *poffset = Fl_Window_Driver::menu_offset_y(win);
- if (poffset) Fl::e_y -= *poffset;
- Fl::e_y_root = Fl::e_y + win->y();
- return win;
-}
-
-static Fl_Window *need_leave = NULL;
-
-static void pointer_enter(void *data, struct wl_pointer *wl_pointer, uint32_t serial,
- struct wl_surface *surface, wl_fixed_t surface_x, wl_fixed_t surface_y) {
- struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
- Fl_Window *win = event_coords_from_surface(surface, surface_x, surface_y);
- static bool using_GTK = seat->gtk_shell &&
- (gtk_shell1_get_version(seat->gtk_shell) >= GTK_SURFACE1_TITLEBAR_GESTURE_SINCE_VERSION);
- if (!win && using_GTK) {
- // check whether surface is the headerbar of a GTK-decorated window
- Fl_X *xp = Fl_X::first;
- while (xp && using_GTK) { // all mapped windows
- struct wld_window *xid = (struct wld_window*)xp->xid;
- if (xid->kind == Fl_Wayland_Window_Driver::DECORATED &&
- fl_is_surface_from_GTK_titlebar(surface, xid->frame, &using_GTK)) {
- gtk_shell_surface = surface;
- break;
- }
- xp = xp->next;
- }
- }
- if (!win) return;
- //fprintf(stderr, "pointer_enter window=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface));
- seat->pointer_focus = surface;
- // use custom cursor if present
- struct wl_cursor *cursor =
- fl_wl_xid(win)->custom_cursor ? fl_wl_xid(win)->custom_cursor->wl_cursor : NULL;
- seat->serial = serial;
- seat->pointer_enter_serial = serial;
- Fl_Wayland_Screen_Driver::do_set_cursor(seat, cursor, Fl_Wayland_Window_Driver::driver(win)->standard_cursor());
- set_event_xy(win);
- need_leave = NULL;
- win = Fl_Wayland_Window_Driver::surface_to_window(surface);
- // Caution: with an Fl_Tooltip this call can hide the window being entered (#1317)
- if (!win->parent()) Fl::handle(FL_ENTER, win);
-}
-
-
-static void pointer_leave(void *data, struct wl_pointer *wl_pointer,
- uint32_t serial, struct wl_surface *surface) {
- struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
- if (seat->pointer_focus == surface) seat->pointer_focus = NULL;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
- gtk_shell_surface = NULL;
- if (win) {
- //fprintf(stderr, "pointer_leave window=%p [%s]\n", win, (win->parent()?"sub":"top"));
- set_event_xy(win);
- need_leave = win->top_window(); // we leave a sub or toplevel window
- wl_display_roundtrip(fl_wl_display()); // pointer_enter to other win, if applicable, will run
- if (need_leave) { // we really left the sub-or-top win and did not enter another
- extern Fl_Window *fl_xmousewin;
- fl_xmousewin = 0;
- Fl::handle(FL_LEAVE, need_leave);
- }
- }
-}
-
-
-static void pointer_motion(void *data, struct wl_pointer *wl_pointer,
- uint32_t time, wl_fixed_t surface_x, wl_fixed_t surface_y) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- Fl_Window *win = event_coords_from_surface(seat->pointer_focus, surface_x, surface_y);
- if (!win) return;
- if (Fl::grab() && !Fl::grab()->menu_window() && Fl::grab() != win) {
- // If there's an active, non-menu grab() and the pointer is in a window other than
- // the grab(), make e_x_root too large to be in any window
- Fl::e_x_root = 1000000;
- }
- else if (Fl_Window_Driver::menu_parent(NULL) && // any kind of menu is active now, and
- !win->menu_window() && // we enter a non-menu window
- win != Fl_Window_Driver::menu_parent(NULL) // that's not the window below the menu
- ) {
- Fl::e_x_root = 1000000; // make it too large to be in any window
- }
-//fprintf(stderr, "FL_MOVE on win=%p to x:%dx%d root:%dx%d\n", win, Fl::e_x, Fl::e_y, Fl::e_x_root, Fl::e_y_root);
- wld_event_time = time;
- set_event_xy(win);
- Fl::handle(FL_MOVE, win);
-}
-
-
-//#include <FL/names.h>
-static void pointer_button(void *data,
- struct wl_pointer *wl_pointer,
- uint32_t serial,
- uint32_t time,
- uint32_t button,
- uint32_t state)
-{
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- if (gtk_shell_surface && state == WL_POINTER_BUTTON_STATE_PRESSED &&
- button == BTN_MIDDLE) {
- struct gtk_surface1 *gtk_surface = gtk_shell1_get_gtk_surface(seat->gtk_shell,gtk_shell_surface);
- gtk_surface1_titlebar_gesture(gtk_surface, serial, seat->wl_seat,
- GTK_SURFACE1_GESTURE_MIDDLE_CLICK);
- gtk_surface1_release(gtk_surface); // very necessary
- return;
- }
- seat->serial = serial;
- int event = 0;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus);
- if (!win) return;
- win = win->top_window();
- wld_event_time = time;
- int b = 0;
- // Fl::e_state &= ~FL_BUTTONS; // DO NOT reset the mouse button state!
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- if (button == BTN_LEFT) { Fl::e_state |= FL_BUTTON1; b = 1; }
- else if (button == BTN_RIGHT) { Fl::e_state |= FL_BUTTON3; b = 3; }
- else if (button == BTN_MIDDLE) { Fl::e_state |= FL_BUTTON2; b = 2; }
- else if (button == BTN_BACK) { Fl::e_state |= FL_BUTTON4; b = 4; } // ?
- else if (button == BTN_SIDE) { Fl::e_state |= FL_BUTTON4; b = 4; } // OK: Debian 12
- else if (button == BTN_FORWARD) { Fl::e_state |= FL_BUTTON5; b = 5; } // ?
- else if (button == BTN_EXTRA) { Fl::e_state |= FL_BUTTON5; b = 5; } // OK: Debian 12
- } else { // must be WL_POINTER_BUTTON_STATE_RELEASED
- if (button == BTN_LEFT) { Fl::e_state &= ~FL_BUTTON1; b = 1; }
- else if (button == BTN_RIGHT) { Fl::e_state &= ~FL_BUTTON3; b = 3; }
- else if (button == BTN_MIDDLE) { Fl::e_state &= ~FL_BUTTON2; b = 2; }
- else if (button == BTN_BACK) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // ?
- else if (button == BTN_SIDE) { Fl::e_state &= ~FL_BUTTON4; b = 4; } // OK: Debian 12
- else if (button == BTN_FORWARD) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // ?
- else if (button == BTN_EXTRA) { Fl::e_state &= ~FL_BUTTON5; b = 5; } // OK: Debian 12
- }
- Fl::e_keysym = FL_Button + b;
- Fl::e_dx = Fl::e_dy = 0;
-
- set_event_xy(win);
- if (state == WL_POINTER_BUTTON_STATE_PRESSED) {
- event = FL_PUSH;
- checkdouble();
- } else if (state == WL_POINTER_BUTTON_STATE_RELEASED) {
- event = FL_RELEASE;
- }
- // fprintf(stderr, "%s %s\n", fl_eventnames[event], win->label() ? win->label():"[]");
- Fl::handle(event, win);
-}
-
-
-static void pointer_axis(void *data, struct wl_pointer *wl_pointer,
- uint32_t time, uint32_t axis, wl_fixed_t value) {
- struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus);
- if (!win) return;
- wld_event_time = time;
- int delta = wl_fixed_to_int(value);
- if (abs(delta) >= 10) delta /= 10;
- // fprintf(stderr, "FL_MOUSEWHEEL: %c delta=%d\n", axis==WL_POINTER_AXIS_HORIZONTAL_SCROLL?'H':'V', delta);
- // allow both horizontal and vertical movements to be processed by the widget
- if (axis == WL_POINTER_AXIS_HORIZONTAL_SCROLL) {
- if (Fl::event_shift()) { // shift key pressed: send vertical mousewheel event
- Fl::e_dx = 0;
- Fl::e_dy = delta;
- } else { // shift key not pressed (normal behavior): send horizontal mousewheel event
- Fl::e_dx = delta;
- Fl::e_dy = 0;
- }
- Fl::handle(FL_MOUSEWHEEL, win->top_window());
- }
- if (axis == WL_POINTER_AXIS_VERTICAL_SCROLL) {
- if (Fl::event_shift()) { // shift key pressed: send horizontal mousewheel event
- Fl::e_dx = delta;
- Fl::e_dy = 0;
- } else {// shift key not pressed (normal behavior): send vertical mousewheel event
- Fl::e_dx = 0;
- Fl::e_dy = delta;
- }
- Fl::handle(FL_MOUSEWHEEL, win->top_window());
- }
-}
-
-
-static struct wl_pointer_listener pointer_listener = {
- pointer_enter,
- pointer_leave,
- pointer_motion,
- pointer_button,
- pointer_axis
-};
-
-
-static const char *proxy_tag = "FLTK for Wayland";
-
-
-bool Fl_Wayland_Screen_Driver::own_output(struct wl_output *output)
-{
- return wl_proxy_get_tag((struct wl_proxy *)output) == &proxy_tag;
-}
-
-
-static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat);
-
-
-static void try_update_cursor(struct Fl_Wayland_Screen_Driver::seat *seat) {
- if (wl_list_empty(&seat->pointer_outputs)) return;
- struct pointer_output *pointer_output;
- int scale = 1;
-
- wl_list_for_each(pointer_output, &seat->pointer_outputs, link) {
- scale = fl_max(scale, pointer_output->output->wld_scale);
- }
-
- if (scale != seat->pointer_scale) {
- seat->pointer_scale = scale;
- init_cursors(seat);
- Fl_Wayland_Screen_Driver::do_set_cursor(seat);
- }
-}
-
-
-static void output_scale(void *data, struct wl_output *wl_output, int32_t factor);
-
-
-static void cursor_surface_enter(void *data,
- struct wl_surface *wl_surface, struct wl_output *wl_output) {
- // Runs when the seat's cursor_surface enters a display
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- struct pointer_output *pointer_output;
-
- if (!Fl_Wayland_Screen_Driver::own_output(wl_output))
- return;
-
- pointer_output = (struct pointer_output *)calloc(1, sizeof(struct pointer_output));
- pointer_output->output =
- (Fl_Wayland_Screen_Driver::output *)wl_output_get_user_data(wl_output);
-//fprintf(stderr, "cursor_surface_enter: wl_output_get_user_data(%p)=%p\n", wl_output, pointer_output->output);
- wl_list_insert(&seat->pointer_outputs, &pointer_output->link);
- try_update_cursor(seat);
- Fl_Wayland_Screen_Driver::output *output =
- (Fl_Wayland_Screen_Driver::output*)wl_output_get_user_data(wl_output);
- output_scale(output, wl_output, output->wld_scale); // rescale custom cursors
- // maintain custom or standard window cursor
- Fl_Window *win = Fl::first_window();
- if (win) {
- Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win);
- struct wld_window *xid = fl_wl_xid(win);
- if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor);
- else if (driver->cursor_default()) driver->set_cursor(driver->cursor_default());
- else win->cursor(driver->standard_cursor());
- }
-}
-
-
-static void cursor_surface_leave(void *data, struct wl_surface *wl_surface,
- struct wl_output *wl_output) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- struct pointer_output *pointer_output, *tmp;
- wl_list_for_each_safe(pointer_output, tmp, &seat->pointer_outputs, link) {
- if (pointer_output->output->wl_output == wl_output) {
- wl_list_remove(&pointer_output->link);
- free(pointer_output);
- }
- }
- try_update_cursor(seat);
- // maintain custom window cursor
- Fl_Window *win = Fl::first_window();
- if (win) {
- struct wld_window *xid = fl_wl_xid(win);
- if (xid->custom_cursor) Fl_Wayland_Screen_Driver::do_set_cursor(seat, xid->custom_cursor->wl_cursor);
- }
-}
-
-
-static struct wl_surface_listener cursor_surface_listener = {
- cursor_surface_enter,
- cursor_surface_leave,
-};
-
-
-static void init_cursors(struct Fl_Wayland_Screen_Driver::seat *seat) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (!seat->cursor_surface) {
- seat->cursor_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
- wl_surface_add_listener(seat->cursor_surface, &cursor_surface_listener, seat);
- }
-#if HAVE_CURSOR_SHAPE
- if (scr_driver->wp_cursor_shape_manager) return;
-#endif
-
- char *name;
- int size;
- struct wl_cursor_theme *theme;
-
- if (!libdecor_get_cursor_settings(&name, &size)) {
- name = NULL;
- size = 24;
- }
- size *= seat->pointer_scale;
- theme = wl_cursor_theme_load(name, size, scr_driver->wl_shm);
- free(name);
- if (theme != NULL) {
- if (seat->cursor_theme) {
- // caution to destroy theme because Fl_Wayland_Window_Driver::set_cursor(Fl_Cursor) caches used cursors
- scr_driver->reset_cursor();
- wl_cursor_theme_destroy(seat->cursor_theme);
- }
- seat->cursor_theme = theme;
- }
- if (seat->cursor_theme) {
- seat->default_cursor = scr_driver->xc_cursor[Fl_Wayland_Screen_Driver::arrow] =
- wl_cursor_theme_get_cursor(seat->cursor_theme, "left_ptr");
- }
-}
-
-
-static void wl_keyboard_keymap(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t format, int32_t fd, uint32_t size) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- assert(format == WL_KEYBOARD_KEYMAP_FORMAT_XKB_V1);
-
- char *map_shm = (char*)mmap(NULL, size, PROT_READ,
- wl_keyboard_get_version(wl_keyboard) >= 7 ? MAP_PRIVATE : MAP_SHARED, fd, 0);
- assert(map_shm != MAP_FAILED);
-
- struct xkb_keymap *xkb_keymap = xkb_keymap_new_from_string(seat->xkb_context, map_shm,
- XKB_KEYMAP_FORMAT_TEXT_V1, XKB_KEYMAP_COMPILE_NO_FLAGS);
- munmap(map_shm, size);
- close(fd);
- if (xkb_keymap) {
- struct xkb_state *xkb_state = xkb_state_new(xkb_keymap);
- xkb_keymap_unref(seat->xkb_keymap);
- if (seat->xkb_state) xkb_state_unref(seat->xkb_state);
- seat->xkb_keymap = xkb_keymap;
- seat->xkb_state = xkb_state;
- }
-}
-
-
-static int search_int_vector(std::vector<int>& v, int val) {
- for (unsigned pos = 0; pos < v.size(); pos++) {
- if (v[pos] == val) return pos;
- }
- return -1;
-}
-
-
-static void remove_int_vector(std::vector<int>& v, int val) {
- int pos = search_int_vector(v, val);
- if (pos < 0) return;
- v.erase(v.begin()+pos);
-}
-
-
-static int process_wld_key(struct xkb_state *xkb_state, uint32_t key,
- uint32_t *p_keycode, xkb_keysym_t *p_sym) {
- uint32_t keycode = key + 8;
- xkb_keysym_t sym = xkb_state_key_get_one_sym(xkb_state, keycode);
- if (sym == 0xfe20) sym = FL_Tab;
- if (sym == 0xffeb) sym = FL_Meta_L; // repair value libxkb gives for FL_Meta_L
- if (sym == 0xffec) sym = FL_Meta_R; // repair value libxkb gives for FL_Meta_R
- if (sym >= 'A' && sym <= 'Z') sym += 32; // replace uppercase by lowercase letter
- int for_key_vector = sym; // for support of Fl::event_key(int)
- // special processing for number keys == keycodes 10-19 :
- if (keycode >= 10 && keycode <= 18) {
- for_key_vector = '1' + (keycode - 10);
- } else if (keycode == 19) {
- for_key_vector = '0';
- }
- if (p_keycode) *p_keycode = keycode;
- if (p_sym) *p_sym = sym;
- return for_key_vector;
-}
-
-
-static uint32_t last_keydown_serial = 0; // serial of last keydown event
-
-
-static void wl_keyboard_enter(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t serial, struct wl_surface *surface, struct wl_array *keys) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
-//fprintf(stderr, "keyboard enter fl_win=%p; keys pressed are: ", Fl_Wayland_Window_Driver::surface_to_window(surface));
- key_vector.clear();
- // Replace wl_array_for_each(p, keys) rejected by C++
- for (uint32_t *p = (uint32_t *)(keys)->data;
- (const char *) p < ((const char *) (keys)->data + (keys)->size);
- (p)++) {
- int for_key_vector = process_wld_key(seat->xkb_state, *p, NULL, NULL);
-//fprintf(stderr, "%d ", for_key_vector);
- if (search_int_vector(key_vector, for_key_vector) < 0) {
- key_vector.push_back(for_key_vector);
- }
- }
-//fprintf(stderr, "\n");
- seat->keyboard_surface = surface;
- seat->keyboard_enter_serial = serial;
- last_keydown_serial = 0;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
- if (win) {
- Fl::handle(FL_FOCUS, win);
- fl_wl_find(fl_wl_xid(win));
- }
-}
-
-
-struct key_repeat_data_t {
- uint32_t serial;
- Fl_Window *window;
-};
-
-#define KEY_REPEAT_DELAY 0.5 // sec
-#define KEY_REPEAT_INTERVAL 0.05 // sec
-
-
-static void key_repeat_timer_cb(key_repeat_data_t *key_repeat_data) {
- if (last_keydown_serial == key_repeat_data->serial) {
- Fl::handle(FL_KEYDOWN, key_repeat_data->window);
- Fl::add_timeout(KEY_REPEAT_INTERVAL, (Fl_Timeout_Handler)key_repeat_timer_cb, key_repeat_data);
- }
- else delete key_repeat_data;
-}
-
-
-int Fl_Wayland_Screen_Driver::next_marked_length = 0;
-
-
-int Fl_Wayland_Screen_Driver::has_marked_text() const {
- return 1;
-}
-
-
-int Fl_Wayland_Screen_Driver::insertion_point_x = 0;
-int Fl_Wayland_Screen_Driver::insertion_point_y = 0;
-int Fl_Wayland_Screen_Driver::insertion_point_width = 0;
-int Fl_Wayland_Screen_Driver::insertion_point_height = 0;
-bool Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false;
-
-static int previous_cursor_x = 0, previous_cursor_y = 0, previous_cursor_h = 0;
-static uint32_t commit_serial = 0;
-static char *current_pre_edit = NULL;
-static char *pending_pre_edit = NULL;
-static char *pending_commit = NULL;
-
-
-static void send_commit(struct zwp_text_input_v3 *zwp_text_input_v3) {
- zwp_text_input_v3_commit(zwp_text_input_v3);
- commit_serial++;
-}
-
-
-// inform TIM about location of the insertion point, and memorize this info.
-void Fl_Wayland_Screen_Driver::insertion_point_location(int x, int y, int height) {
-//printf("insertion_point_location %dx%d\n",x,y);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (scr_driver->seat->text_input /*&& !current_pre_edit*/ &&
- (x != previous_cursor_x || y != previous_cursor_y || height != previous_cursor_h)) {
- previous_cursor_x = x;
- previous_cursor_y = y;
- previous_cursor_h = height;
- if (Fl::focus()) {
- Fl_Widget *focuswin = Fl::focus()->window();
- while (focuswin && focuswin->parent()) {
- x += focuswin->x(); y += focuswin->y();
- focuswin = focuswin->window();
- }
- }
- float s = fl_graphics_driver->scale();
- insertion_point_location_is_valid = true;
- insertion_point_x = s*x;
- insertion_point_y = s*(y-height);
- insertion_point_width = s*5;
- insertion_point_height = s*height;
- if (zwp_text_input_v3_get_user_data(scr_driver->seat->text_input) ) {
- zwp_text_input_v3_set_cursor_rectangle(scr_driver->seat->text_input,
- insertion_point_x, insertion_point_y,
- insertion_point_width, insertion_point_height);
- send_commit(scr_driver->seat->text_input);
- }
- }
-}
-
-
-// computes window coordinates & size of insertion point
-bool Fl_Wayland_Screen_Driver::insertion_point_location(int *px, int *py,
- int *pwidth, int *pheight) {
- // return true if the current coordinates and size of the insertion point are available
- if ( ! insertion_point_location_is_valid ) return false;
- *px = insertion_point_x;
- *py = insertion_point_y;
- *pwidth = insertion_point_width;
- *pheight = insertion_point_height;
- return true;
-}
-
-
-int Fl_Wayland_Screen_Driver::compose(int& del) {
- unsigned char ascii = (unsigned char)Fl::e_text[0];
- // letter+modifier key
- int condition = (Fl::e_state & (FL_ALT | FL_META | FL_CTRL)) && ascii < 128 ;
- // pressing modifier key
- // FL_Shift_L, FL_Shift_R, FL_Control_L, FL_Control_R, FL_Caps_Lock
- // FL_Meta_L, FL_Meta_R, FL_Alt_L, FL_Alt_R
- condition |= ((Fl::e_keysym >= FL_Shift_L && Fl::e_keysym <= FL_Alt_R) ||
- Fl::e_keysym == FL_Alt_Gr);
- // FL_Home FL_Left FL_Up FL_Right FL_Down FL_Page_Up FL_Page_Down FL_End
- // FL_Print FL_Insert FL_Menu FL_Help and more
- condition |= (Fl::e_keysym >= FL_Home && Fl::e_keysym <= FL_Num_Lock);
- condition |= (Fl::e_keysym >= FL_F && Fl::e_keysym <= FL_F_Last);
- condition |= Fl::e_keysym == FL_Tab || Fl::e_keysym == FL_Scroll_Lock || Fl::e_keysym == FL_Pause;
-//fprintf(stderr, "compose: condition=%d e_state=%x ascii=%d\n", condition, Fl::e_state, ascii);
- if (condition) { del = 0; return 0;}
-//fprintf(stderr, "compose: del=%d compose_state=%d next_marked_length=%d \n", del, Fl::compose_state, next_marked_length);
- del = Fl::compose_state;
- Fl::compose_state = next_marked_length;
- // no-underlined-text && (ascii non-printable || ascii == delete)
- if (ascii && (!Fl::compose_state) && (ascii <= 31 || ascii == 127)) { del = 0; return 0; }
- return 1;
-}
-
-
-void Fl_Wayland_Screen_Driver::compose_reset() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
- Fl::compose_state = 0;
- next_marked_length = 0;
- if (seat->xkb_compose_state) xkb_compose_state_reset(seat->xkb_compose_state);
-}
-
-
-struct dead_key_struct {
- xkb_keysym_t keysym; // the keysym obtained when hitting a dead key
- const char *marked_text; // the temporary text to display for that dead key
-};
-
-
-static dead_key_struct dead_keys[] = {
- {XKB_KEY_dead_grave, "`"},
- {XKB_KEY_dead_acute, "´"},
- {XKB_KEY_dead_circumflex, "^"},
- {XKB_KEY_dead_tilde, "~"},
- {XKB_KEY_dead_macron, "¯"},
- {XKB_KEY_dead_breve, "˘"},
- {XKB_KEY_dead_abovedot, "˙"},
- {XKB_KEY_dead_diaeresis, "¨"},
- {XKB_KEY_dead_abovering, "˚"},
- {XKB_KEY_dead_doubleacute, "˝"},
- {XKB_KEY_dead_caron, "ˇ"},
- {XKB_KEY_dead_cedilla, "¸"},
- {XKB_KEY_dead_ogonek, "˛"},
- {XKB_KEY_dead_iota, "ι"},
- {XKB_KEY_dead_doublegrave, " ̏"},
-};
-
-
-const int dead_key_count = sizeof(dead_keys)/sizeof(struct dead_key_struct);
-
-static void wl_keyboard_key(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t serial, uint32_t time, uint32_t key, uint32_t state) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- seat->serial = serial;
- static char buf[128];
- uint32_t keycode;
- xkb_keysym_t sym;
- int for_key_vector = process_wld_key(seat->xkb_state, key, &keycode, &sym);
-#if (DEBUG_KEYBOARD)
- xkb_keysym_get_name(sym, buf, sizeof(buf));
- const char *action = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? "press" : "release");
- fprintf(stderr, "wl_keyboard_key: key %s: sym: %-12s(%d) code:%u fl_win=%p, ",
- action, buf, sym, keycode,
- Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface));
-#endif
- xkb_state_key_get_utf8(seat->xkb_state, keycode, buf, sizeof(buf));
-#if (DEBUG_KEYBOARD)
- fprintf(stderr, "utf8: '%s' e_length=%d [%d]\n", buf, (int)strlen(buf), *buf);
-#endif
- Fl::e_keysym = Fl::e_original_keysym = for_key_vector;
- if (!(Fl::e_state & FL_NUM_LOCK) && sym >= XKB_KEY_KP_Home && sym <= XKB_KEY_KP_Delete) {
- // compute e_keysym and e_original_keysym for keypad number keys and '.|,' when NumLock is off
- static const int table[11] = {FL_Home /* 7 */, FL_Left /* 4 */, FL_Up /* 8 */,
- FL_Right /* 6 */, FL_Down /* 2 */, FL_Page_Up /* 9 */,
- FL_Page_Down /* 3 */, FL_End /* 1 */, 0xff0b /* 5 */,
- FL_Insert /* 0 */, FL_Delete /* .|, */};
- static const int table_original[11] = {0xffb7 /* 7 */, 0xffb4 /* 4 */, 0xffb8 /* 8 */,
- 0xffb6 /* 6 */, 0xffb2 /* 2 */, 0xffb9 /* 9 */,
- 0xffb3 /* 3 */, 0xffb1 /* 1 */, 0xffb5 /* 5 */,
- 0xffb0 /* 0 */, 0xffac /* .|, */};
- Fl::e_keysym = table[sym - XKB_KEY_KP_Home];
- Fl::e_original_keysym = table_original[sym - XKB_KEY_KP_Home];
- for_key_vector = Fl::e_original_keysym;
- }
-#if (DEBUG_KEYBOARD)
- fprintf(stderr, "wl_keyboard_key: e_keysym=%x e_original_keysym=%x\n", Fl::e_keysym, Fl::e_original_keysym);
-#endif
- if (state == WL_KEYBOARD_KEY_STATE_PRESSED) {
- if (search_int_vector(key_vector, for_key_vector) < 0) {
- key_vector.push_back(for_key_vector);
- }
- } else {
- last_keydown_serial = 0;
- remove_int_vector(key_vector, for_key_vector);
- }
- Fl::e_text = buf;
- Fl::e_length = (int)strlen(buf);
- // Process dead keys and compose sequences :
- enum xkb_compose_status status = XKB_COMPOSE_NOTHING;
- // This part is useful only if the compositor doesn't support protocol text-input-unstable-v3
- if (seat->xkb_compose_state && state == WL_KEYBOARD_KEY_STATE_PRESSED &&
- !(sym >= FL_Shift_L && sym <= FL_Alt_R) && sym != XKB_KEY_ISO_Level3_Shift) {
- xkb_compose_state_feed(seat->xkb_compose_state, sym);
- status = xkb_compose_state_get_status(seat->xkb_compose_state);
- if (status == XKB_COMPOSE_COMPOSING) {
- if (Fl::e_length == 0) { // dead keys produce e_length = 0
- int i;
- for (i = 0; i < dead_key_count; i++) {
- if (dead_keys[i].keysym == sym) break;
- }
- if (i < dead_key_count) strcpy(buf, dead_keys[i].marked_text);
- else buf[0] = 0;
- Fl::e_length = (int)strlen(buf);
- Fl::compose_state = 0;
- }
- Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length;
- } else if (status == XKB_COMPOSE_COMPOSED) {
- Fl::e_length = xkb_compose_state_get_utf8(seat->xkb_compose_state, buf, sizeof(buf));
- Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length;
- Fl_Wayland_Screen_Driver::next_marked_length = 0;
- } else if (status == XKB_COMPOSE_CANCELLED) {
- Fl::e_length = 0;
- Fl::compose_state = Fl_Wayland_Screen_Driver::next_marked_length;
- Fl_Wayland_Screen_Driver::next_marked_length = 0;
- }
-//fprintf(stderr, "xkb_compose_status=%d ctxt=%p state=%p l=%d[%s]\n", status, seat->xkb_context, seat->xkb_compose_state, Fl::e_length, buf);
- }
- // end of part used only without text-input-unstable-v3
-
- wld_event_time = time;
- int event = (state == WL_KEYBOARD_KEY_STATE_PRESSED ? FL_KEYDOWN : FL_KEYUP);
- // Send event to focus-containing top window as defined by FLTK,
- // otherwise send it to Wayland-defined focus window
- Fl_Window *win = ( Fl::focus() ? Fl::focus()->top_window() :
- Fl_Wayland_Window_Driver::surface_to_window(seat->keyboard_surface) );
- if (win) {
- set_event_xy(win);
- Fl::e_is_click = 0;
- Fl::handle(event, win);
- }
- if (event == FL_KEYDOWN && status == XKB_COMPOSE_NOTHING &&
- !(sym >= FL_Shift_L && sym <= FL_Alt_R)) {
- // Handling of key repeats :
- // Use serial argument rather than time to detect repeated keys because
- // serial value changes at each key up or down in all tested OS and compositors,
- // whereas time value changes in Ubuntu24.04 KDE/Plasma 5.27.11 and Ubuntu22.04 KDE/Plasma 5.24.7
- // but not in Debian-testing KDE/Plasma 5.27.10.
- // Unexplained difference in behaviors of KDE/Plasma compositor:
- // Consider KDE settings -> input -> keyboard -> when a key is held: repeat/do nothing.
- // This setting (repeat) has key-down wayland events repeated when key is held under Debian/KDE
- // but not under Ubuntu/KDE !
- key_repeat_data_t *key_repeat_data = new key_repeat_data_t;
- key_repeat_data->serial = serial;
- key_repeat_data->window = win;
- last_keydown_serial = serial;
- Fl::add_timeout(KEY_REPEAT_DELAY, (Fl_Timeout_Handler)key_repeat_timer_cb,
- key_repeat_data);
- }
-}
-
-
-static void wl_keyboard_leave(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t serial, struct wl_surface *surface) {
- struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
-//fprintf(stderr, "keyboard leave fl_win=%p\n", Fl_Wayland_Window_Driver::surface_to_window(surface));
- seat->keyboard_surface = NULL;
- last_keydown_serial = 0;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
- if (!win && Fl::focus()) win = Fl::focus()->top_window();
- if (win) Fl::handle(FL_UNFOCUS, win);
- key_vector.clear();
-}
-
-
-static void wl_keyboard_modifiers(void *data, struct wl_keyboard *wl_keyboard,
- uint32_t serial, uint32_t mods_depressed,
- uint32_t mods_latched, uint32_t mods_locked,
- uint32_t group) {
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- xkb_state_update_mask(seat->xkb_state, mods_depressed, mods_latched, mods_locked,
- 0, 0, group);
- Fl::e_state &= ~(FL_SHIFT+FL_CTRL+FL_ALT+FL_META+FL_CAPS_LOCK+FL_NUM_LOCK);
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_SHIFT,
- XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_SHIFT;
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CTRL,
- XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_CTRL;
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_ALT,
- XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_ALT;
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_LOGO,
- XKB_STATE_MODS_DEPRESSED)) Fl::e_state |= FL_META;
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_CAPS,
- XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_CAPS_LOCK;
- if (xkb_state_mod_name_is_active(seat->xkb_state, XKB_MOD_NAME_NUM,
- XKB_STATE_MODS_LOCKED)) Fl::e_state |= FL_NUM_LOCK;
-//fprintf(stderr, "mods_depressed=%u Fl::e_state=%X\n", mods_depressed, Fl::e_state);
-}
-
-
-static void wl_keyboard_repeat_info(void *data, struct wl_keyboard *wl_keyboard, int32_t rate, int32_t delay)
-{
- // wl_keyboard is version 3 under Debian, but that event isn't sent until version 4
-}
-
-
-static const struct wl_keyboard_listener wl_keyboard_listener = {
- .keymap = wl_keyboard_keymap,
- .enter = wl_keyboard_enter,
- .leave = wl_keyboard_leave,
- .key = wl_keyboard_key,
- .modifiers = wl_keyboard_modifiers,
- .repeat_info = wl_keyboard_repeat_info,
-};
-
-
-void text_input_enter(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
- struct wl_surface *surface) {
-//puts("text_input_enter");
- zwp_text_input_v3_set_user_data(zwp_text_input_v3, surface);
- zwp_text_input_v3_enable(zwp_text_input_v3);
- zwp_text_input_v3_set_content_type(zwp_text_input_v3, ZWP_TEXT_INPUT_V3_CONTENT_HINT_NONE, ZWP_TEXT_INPUT_V3_CONTENT_PURPOSE_NORMAL);
- int x, y, width, height;
- if (Fl_Wayland_Screen_Driver::insertion_point_location(&x, &y, &width, &height)) {
- zwp_text_input_v3_set_cursor_rectangle(zwp_text_input_v3, x, y, width, height);
- }
- send_commit(zwp_text_input_v3);
-}
-
-
-void text_input_leave(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
- struct wl_surface *surface) {
-//puts("text_input_leave");
- zwp_text_input_v3_disable(zwp_text_input_v3);
- zwp_text_input_v3_set_user_data(zwp_text_input_v3, NULL);
- send_commit(zwp_text_input_v3);
- free(pending_pre_edit); pending_pre_edit = NULL;
- free(current_pre_edit); current_pre_edit = NULL;
- free(pending_commit); pending_commit = NULL;
-}
-
-
-static void send_text_to_fltk(const char *text, bool is_marked, struct wl_surface *current_surface) {
-//printf("send_text_to_fltk(%s, %d)\n",text,is_marked);
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(current_surface);
- Fl::e_text = text ? (char*)text : (char*)"";
- Fl::e_length = text ? (int)strlen(text) : 0;
- Fl::e_keysym = 'a'; // fake a simple key
- set_event_xy(win);
- Fl::e_is_click = 0;
- if (is_marked) { // goes to widget as marked text
- Fl_Wayland_Screen_Driver::next_marked_length = Fl::e_length;
- Fl::handle(FL_KEYDOWN, win);
- } else if (text) {
- Fl_Wayland_Screen_Driver::next_marked_length = 0;
- Fl::handle(FL_KEYDOWN, win);
- Fl::compose_state = 0;
- } else {
- Fl_Wayland_Screen_Driver::next_marked_length = 0;
- Fl::handle(FL_KEYDOWN, win);
- }
-}
-
-
-void text_input_preedit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
- const char *text, int32_t cursor_begin, int32_t cursor_end) {
-//printf("text_input_preedit_string %s cursor_begin=%d cursor_end=%d\n",text, cursor_begin, cursor_end);
- free(pending_pre_edit);
- pending_pre_edit = text ? strdup(text) : NULL;
-}
-
-
-void text_input_commit_string(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
- const char *text) {
-//printf("text_input_commit_string %s\n",text);
- free(pending_commit);
- pending_commit = (text ? strdup(text) : NULL);
-}
-
-
-void text_input_delete_surrounding_text(void *data,
- struct zwp_text_input_v3 *zwp_text_input_v3,
- uint32_t before_length, uint32_t after_length) {
- fprintf(stderr, "delete_surrounding_text before=%d adfter=%d\n",
- before_length,after_length);
-}
-
-
-void text_input_done(void *data, struct zwp_text_input_v3 *zwp_text_input_v3,
- uint32_t serial) {
-//puts("text_input_done");
- struct wl_surface *current_surface = (struct wl_surface*)data;
- const bool bad_event = (serial != commit_serial);
- if ((pending_pre_edit == NULL && current_pre_edit == NULL) ||
- (pending_pre_edit && current_pre_edit && strcmp(pending_pre_edit, current_pre_edit) == 0)) {
- free(pending_pre_edit); pending_pre_edit = NULL;
- } else {
- free(current_pre_edit);
- current_pre_edit = pending_pre_edit;
- pending_pre_edit = NULL;
- if (current_pre_edit) {
- send_text_to_fltk(current_pre_edit, !bad_event, current_surface);
- } else {
- send_text_to_fltk(NULL, false, current_surface);
- }
- }
- if (pending_commit) {
- send_text_to_fltk(pending_commit, false, current_surface);
- free(pending_commit); pending_commit = NULL;
- }
-}
-
-
-static const struct zwp_text_input_v3_listener text_input_listener = {
- .enter = text_input_enter,
- .leave = text_input_leave,
- .preedit_string = text_input_preedit_string,
- .commit_string = text_input_commit_string,
- .delete_surrounding_text = text_input_delete_surrounding_text,
- .done = text_input_done,
-};
-
-
-void Fl_Wayland_Screen_Driver::enable_im() {
- if (text_input_base && !seat->text_input) {
- seat->text_input = zwp_text_input_manager_v3_get_text_input(text_input_base,
- seat->wl_seat);
- //printf("seat->text_input=%p\n",seat->text_input);
- zwp_text_input_v3_add_listener(seat->text_input, &text_input_listener, NULL);
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::disable_im() {
- if (seat->text_input) {
- zwp_text_input_v3_disable(seat->text_input);
- zwp_text_input_v3_commit(seat->text_input);
- zwp_text_input_v3_destroy(seat->text_input);
- seat->text_input = NULL;
- free(pending_pre_edit); pending_pre_edit = NULL;
- free(current_pre_edit); current_pre_edit = NULL;
- free(pending_commit); pending_commit = NULL;
- }
-}
-
-
-static void seat_capabilities(void *data, struct wl_seat *wl_seat, uint32_t capabilities)
-{
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- struct Fl_Wayland_Screen_Driver::seat *seat =
- (struct Fl_Wayland_Screen_Driver::seat*)data;
- if ((capabilities & WL_SEAT_CAPABILITY_POINTER) && !seat->wl_pointer) {
- seat->wl_pointer = wl_seat_get_pointer(wl_seat);
- wl_pointer_add_listener(seat->wl_pointer, &pointer_listener, seat);
- seat->pointer_scale = 1;
-#if HAVE_CURSOR_SHAPE
- if (scr_driver->wp_cursor_shape_manager) {
- scr_driver->wp_cursor_shape_device =
- wp_cursor_shape_manager_v1_get_pointer(scr_driver->wp_cursor_shape_manager, seat->wl_pointer);
- }
-#endif // HAVE_CURSOR_SHAPE
- init_cursors(seat);
- } else if (!(capabilities & WL_SEAT_CAPABILITY_POINTER) && seat->wl_pointer) {
- wl_pointer_release(seat->wl_pointer);
- seat->wl_pointer = NULL;
- }
-
- bool have_keyboard = seat->xkb_context && (capabilities & WL_SEAT_CAPABILITY_KEYBOARD);
- if (have_keyboard && seat->wl_keyboard == NULL) {
- seat->wl_keyboard = wl_seat_get_keyboard(wl_seat);
- wl_keyboard_add_listener(seat->wl_keyboard,
- &wl_keyboard_listener, seat);
-//fprintf(stderr, "wl_keyboard version=%d\n", wl_keyboard_get_version(seat->wl_keyboard));
-
- } else if (!have_keyboard && seat->wl_keyboard != NULL) {
- wl_keyboard_release(seat->wl_keyboard);
- seat->wl_keyboard = NULL;
- }
- scr_driver->enable_im();
-}
-
-
-static void seat_name(void *data, struct wl_seat *wl_seat, const char *name) {
- struct Fl_Wayland_Screen_Driver::seat *seat = (struct Fl_Wayland_Screen_Driver::seat*)data;
- seat->name = strdup(name);
-}
-
-
-static struct wl_seat_listener seat_listener = {
- seat_capabilities,
- seat_name
-};
-
-
-static void output_geometry(void *data,
- struct wl_output *wl_output,
- int32_t x,
- int32_t y,
- int32_t physical_width,
- int32_t physical_height,
- int32_t subpixel,
- const char *make,
- const char *model,
- int32_t transform)
-{
- //fprintf(stderr, "output_geometry: x=%d y=%d physical=%dx%d\n",x,y,physical_width,physical_height);
- Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
- output->x = int(x);
- output->y = int(y);
- output->dpi = 96; // to elaborate
-}
-
-
-static void output_mode(void *data, struct wl_output *wl_output, uint32_t flags,
- int32_t width, int32_t height, int32_t refresh)
-{
- Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
- output->pixel_width = int(width);
- output->pixel_height = int(height);
- output->width = output->pixel_width; // until further notice
- output->height = output->pixel_height;
-//fprintf(stderr, "output_mode: [%p]=%dx%d\n",output->wl_output,width,height);
-}
-
-
-static void output_done(void *data, struct wl_output *wl_output)
-{
- // Runs at startup and when desktop scale factor is changed or screen added
- Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
-//fprintf(stderr, "output_done output=%p\n",output);
- Fl_X *xp = Fl_X::first;
- while (xp) { // all mapped windows
- struct wld_window *win = (struct wld_window*)xp->xid;
- Fl_Window *W = win->fl_win;
- if (win->buffer || W->as_gl_window()) {
- if (W->as_gl_window()) {
- wl_surface_set_buffer_scale(win->wl_surface, output->wld_scale);
- Fl_Window_Driver::driver(W)->is_a_rescale(true);
- W->resize(W->x(), W->y(), W->w(), W->h());
- Fl_Window_Driver::driver(W)->is_a_rescale(false);
- } else {
- Fl_Wayland_Graphics_Driver::buffer_release(win);
- }
- W->redraw();
- Fl_Window_Driver::driver(W)->flush();
- }
- xp = xp->next;
- }
- output->done = true;
-
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (scr_driver->screen_count_get() > 0) { // true when output_done runs after initial screen dectection
- scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) );
- scr_driver->init_workarea();
- }
-}
-
-
-static void output_scale(void *data, struct wl_output *wl_output, int32_t factor) {
- Fl_Wayland_Screen_Driver::output *output = (Fl_Wayland_Screen_Driver::output*)data;
- output->wld_scale = factor;
-//fprintf(stderr,"output_scale: wl_output=%p factor=%d\n",wl_output, factor);
- // rescale cursors of windows that map here and have a custom cursor
- Fl_Window *win = Fl::first_window();
- while (win) {
- struct wld_window *xid = fl_wl_xid(win);
- struct Fl_Wayland_Window_Driver::surface_output *s_output;
- // get 1st screen where window appears
- s_output = wl_container_of(xid->outputs.next, s_output, link);
- if (xid->custom_cursor && output == s_output->output) {
- Fl_Wayland_Window_Driver *driver = Fl_Wayland_Window_Driver::driver(win);
- driver->set_cursor_4args(xid->custom_cursor->rgb,
- xid->custom_cursor->hotx, xid->custom_cursor->hoty, false);
- };
- win = Fl::next_window(win);
- }
-}
-
-
-static struct wl_output_listener output_listener = {
- output_geometry,
- output_mode,
- output_done,
- output_scale
-};
-
-
-struct pair_bool {
- bool found_gtk_shell;
- bool found_wf_shell;
-};
-
-
-// Notice: adding use of unstable protocol "XDG output" would allow FLTK to be notified
-// in real time of changes to the relative location of multiple displays;
-// with the present code, that information is received at startup only.
-static void registry_handle_global(void *user_data, struct wl_registry *wl_registry,
- uint32_t id, const char *interface, uint32_t version) {
-//fprintf(stderr, "interface=%s version=%u\n", interface, version);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (strcmp(interface, "wl_compositor") == 0) {
- if (version < 4) {
- Fl::fatal("wl_compositor version >= 4 required");
- }
- scr_driver->wl_compositor = (struct wl_compositor*)wl_registry_bind(wl_registry,
- id, &wl_compositor_interface, 4);
-
- } else if (strcmp(interface, "wl_subcompositor") == 0) {
- scr_driver->wl_subcompositor = (struct wl_subcompositor*)wl_registry_bind(wl_registry,
- id, &wl_subcompositor_interface, 1);
-
- } else if (strcmp(interface, "wl_shm") == 0) {
- scr_driver->wl_shm = (struct wl_shm*)wl_registry_bind(wl_registry,
- id, &wl_shm_interface, 1);
-
- } else if (strcmp(interface, "wl_seat") == 0) {
- if (version < 3) {
- Fl::fatal("%s version 3 required but only version %i is available\n",
- interface, version);
- }
- if (!scr_driver->seat) scr_driver->seat =
- (struct Fl_Wayland_Screen_Driver::seat*)calloc(1,
- sizeof(struct Fl_Wayland_Screen_Driver::seat));
-//fprintf(stderr, "registry_handle_global: seat=%p\n", scr_driver->seat);
- wl_list_init(&scr_driver->seat->pointer_outputs);
- scr_driver->seat->wl_seat = (wl_seat*)wl_registry_bind(wl_registry, id,
- &wl_seat_interface, 3);
- scr_driver->seat->xkb_context = xkb_context_new(XKB_CONTEXT_NO_FLAGS);
- if (scr_driver->seat->xkb_context) {
- const char *locale = getenv("LC_ALL");
- if (!locale || !*locale)
- locale = getenv("LC_CTYPE");
- if (!locale || !*locale)
- locale = getenv("LANG");
- if (!locale || !*locale)
- locale = "C";
- struct xkb_compose_table *table =
- xkb_compose_table_new_from_locale(scr_driver->seat->xkb_context, locale,
- XKB_COMPOSE_COMPILE_NO_FLAGS);
- if (table) {
- scr_driver->seat->xkb_compose_state =
- xkb_compose_state_new(table, XKB_COMPOSE_STATE_NO_FLAGS);
- }
- }
- wl_seat_add_listener(scr_driver->seat->wl_seat, &seat_listener, scr_driver->seat);
- if (scr_driver->seat->data_device_manager) {
- scr_driver->seat->data_device =
- wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager,
- scr_driver->seat->wl_seat);
- wl_data_device_add_listener(scr_driver->seat->data_device,
- Fl_Wayland_Screen_Driver::p_data_device_listener, NULL);
- }
-
- } else if (strcmp(interface, wl_data_device_manager_interface.name) == 0) {
- if (!scr_driver->seat) scr_driver->seat =
- (struct Fl_Wayland_Screen_Driver::seat*)calloc(1,
- sizeof(struct Fl_Wayland_Screen_Driver::seat));
- scr_driver->seat->data_device_manager =
- (struct wl_data_device_manager*)wl_registry_bind(wl_registry, id,
- &wl_data_device_manager_interface,
- fl_min(version, 3));
- if (scr_driver->seat->wl_seat) {
- scr_driver->seat->data_device =
- wl_data_device_manager_get_data_device(scr_driver->seat->data_device_manager,
- scr_driver->seat->wl_seat);
- wl_data_device_add_listener(scr_driver->seat->data_device,
- Fl_Wayland_Screen_Driver::p_data_device_listener, NULL);
- }
-//fprintf(stderr, "registry_handle_global: %s\n", interface);
-
- } else if (strcmp(interface, "wl_output") == 0) {
- if (version < 2) {
- Fl::fatal("%s version 2 required but only version %i is available\n",
- interface, version);
- }
- Fl_Wayland_Screen_Driver::output *output =
- (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output);
- output->id = id;
- output->wld_scale = 1;
-#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION
- const int used_version = WL_OUTPUT_RELEASE_SINCE_VERSION;
-#else
- const int used_version = 2;
-#endif
- output->wl_output = (struct wl_output*)wl_registry_bind(wl_registry,
- id, &wl_output_interface, fl_min(used_version, version));
- output->gui_scale = 1.f;
- wl_proxy_set_tag((struct wl_proxy *) output->wl_output, &proxy_tag);
- wl_output_add_listener(output->wl_output, &output_listener, output);
- // Put new screen in list of screens, but make sure it's not in list already
- // which may occur after having removed a screen.
- bool found = false;
- Fl_Wayland_Screen_Driver::output *elt;
- wl_list_for_each(elt, &scr_driver->outputs, link) {
- if (elt == output) found = true;
- }
- if (!found) { // add to end of the linked list of displays
- struct wl_list *e = &scr_driver->outputs;
- while (e->next != &scr_driver->outputs) e = e->next; // move e to end of linked list
- wl_list_insert(e, &output->link);
- }
-//fprintf(stderr, "wl_output: id=%d wl_output=%p \n", id, output->wl_output);
-
- } else if (strcmp(interface, xdg_wm_base_interface.name) == 0) {
-//fprintf(stderr, "registry_handle_global interface=%s\n", interface);
- scr_driver->xdg_wm_base = (struct xdg_wm_base *)wl_registry_bind(wl_registry, id,
- &xdg_wm_base_interface, 1);
- xdg_wm_base_add_listener(scr_driver->xdg_wm_base, &xdg_wm_base_listener, NULL);
- } else if (strstr(interface, "wf_shell_manager")) {
- ((pair_bool*)user_data)->found_wf_shell = true;
- } else if (strcmp(interface, "gtk_shell1") == 0) {
- ((pair_bool*)user_data)->found_gtk_shell = true;
- //fprintf(stderr, "Running the Mutter compositor\n");
- scr_driver->seat->gtk_shell = (struct gtk_shell1*)wl_registry_bind(wl_registry, id,
- &gtk_shell1_interface, version);
- } else if (strcmp(interface, "weston_desktop_shell") == 0) {
- Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::WESTON;
- //fprintf(stderr, "Running the Weston compositor\n");
- } else if (strcmp(interface, "org_kde_plasma_shell") == 0) {
- Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::KWIN;
- //fprintf(stderr, "Running the KWin compositor\n");
- } else if (strncmp(interface, "zowl_mach_ipc", 13) == 0) {
- Fl_Wayland_Screen_Driver::compositor = Fl_Wayland_Screen_Driver::OWL;
- //fprintf(stderr, "Running the Owl compositor\n");
- if (wl_list_length(&scr_driver->outputs) == 0) {
- Fl_Wayland_Screen_Driver::output *output =
- (Fl_Wayland_Screen_Driver::output*)calloc(1, sizeof *output);
- output->id = 1;
- output->wld_scale = 1;
- output->gui_scale = 1.f;
- output->width = 1440; output->height = 900;
- output->pixel_width = 1440; output->pixel_height = 900;
- output->done = true;
- wl_list_insert(&(scr_driver->outputs), &output->link);
- scr_driver->screen_count_set(1);
- }
- } else if (strcmp(interface, zwp_text_input_manager_v3_interface.name) == 0) {
- scr_driver->text_input_base = (struct zwp_text_input_manager_v3 *)
- wl_registry_bind(wl_registry, id, &zwp_text_input_manager_v3_interface, 1);
-//printf("scr_driver->text_input_base=%p version=%d\n",scr_driver->text_input_base,version);
-#if HAVE_XDG_DIALOG
- } else if (strcmp(interface, xdg_wm_dialog_v1_interface.name) == 0) {
- scr_driver->xdg_wm_dialog = (struct xdg_wm_dialog_v1 *)
- wl_registry_bind(wl_registry, id, &xdg_wm_dialog_v1_interface, 1);
-#endif // HAVE_XDG_DIALOG
-#if HAVE_CURSOR_SHAPE
- } else if (strcmp(interface, wp_cursor_shape_manager_v1_interface.name) == 0) {
- scr_driver->wp_cursor_shape_manager = (struct wp_cursor_shape_manager_v1 *)
- wl_registry_bind(wl_registry, id, &wp_cursor_shape_manager_v1_interface, 1);
-#endif // HAVE_CURSOR_SHAPE
- }
-}
-
-
-static void registry_handle_global_remove(void *data, struct wl_registry *registry, uint32_t name) {
- Fl_Wayland_Screen_Driver::output *output;
-//fprintf(stderr, "registry_handle_global_remove data=%p id=%u\n", data, name);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- bool has_removed_screen = false;
- wl_list_for_each(output, &(scr_driver->outputs), link) { // all screens
- if (output->id == name) { // the screen being removed
- wl_list_remove(&output->link);
- wl_output_destroy(output->wl_output);
- free(output);
- has_removed_screen = true;
- break;
- }
- }
- if (has_removed_screen) {
- scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) );
- scr_driver->init_workarea();
- }
-}
-
-
-static const struct wl_registry_listener registry_listener = {
- registry_handle_global,
- registry_handle_global_remove
-};
-
-
-static void wayland_socket_callback(int fd, struct wl_display *display)
-{
- if (wl_display_prepare_read(display) == -1) {
- wl_display_dispatch_pending(display);
- return;
- }
- wl_display_flush(display);
- struct pollfd fds = (struct pollfd) { fd, POLLIN, 0 };
- if (poll(&fds, 1, 0) <= 0) {
- wl_display_cancel_read(display);
- return;
- }
- if (fds.revents & (POLLERR | POLLHUP)) {
- wl_display_cancel_read(display);
- goto fatal;
- }
- if (wl_display_read_events(display) == -1)
- goto fatal;
- if (wl_display_dispatch_pending(display) == -1)
- goto fatal;
- return;
-fatal:
- if (wl_display_get_error(display) == EPROTO) {
- const struct wl_interface *interface;
- int code = wl_display_get_protocol_error(display, &interface, NULL);
- Fl::fatal("Fatal error %d in Wayland protocol: %s",
- code, (interface ? interface->name : "unknown") );
- } else {
- Fl::fatal("Fatal error while communicating with Wayland server: %s",
- strerror(errno));
- }
-}
-
-
-Fl_Wayland_Screen_Driver::Fl_Wayland_Screen_Driver() : Fl_Unix_Screen_Driver() {
- libdecor_context = NULL;
- seat = NULL;
- text_input_base = NULL;
- reset_cursor();
- wl_registry = NULL;
-#if HAVE_XDG_DIALOG
- xdg_wm_dialog = NULL;
-#endif
-#if HAVE_CURSOR_SHAPE
- wp_cursor_shape_manager = NULL;
- wp_cursor_shape_device = NULL;
-#endif
-}
-
-
-static void sync_done(void *data, struct wl_callback *cb, uint32_t time) {
- // runs after all calls to registry_handle_global()
- *(struct wl_callback **)data = NULL;
- wl_callback_destroy(cb);
- // keep processing until output_done() has run for each screen
- 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) { // each screen of the system
- while (!output->done) wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
- }
- // Now all screens have been initialized
- scr_driver->screen_count_set( wl_list_length(&(scr_driver->outputs)) );
- struct pair_bool *pair = (struct pair_bool*)wl_registry_get_user_data(scr_driver->wl_registry);
- if (pair->found_gtk_shell || pair->found_wf_shell) {
- Fl_Wayland_Screen_Driver::compositor = (pair->found_wf_shell ?
- Fl_Wayland_Screen_Driver::WAYFIRE : Fl_Wayland_Screen_Driver::MUTTER);
- }
- if (scr_driver->seat) {
-#if HAVE_CURSOR_SHAPE
- if (!scr_driver->wp_cursor_shape_manager)
-#endif
- try_update_cursor(scr_driver->seat);
- }
- if (Fl_Wayland_Screen_Driver::compositor != Fl_Wayland_Screen_Driver::OWL) scr_driver->init_workarea();
-}
-
-
-static const struct wl_callback_listener sync_listener = {
- sync_done
-};
-
-
-static void do_atexit() {
- if (Fl_Wayland_Screen_Driver::wl_display) {
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::open_display_platform() {
- static bool beenHereDoneThat = false;
- if (beenHereDoneThat)
- return;
-
- beenHereDoneThat = true;
-
- if (!wl_display) {
- wl_display = wl_display_connect(NULL);
- if (!wl_display) {
- Fl::fatal("No Wayland connection\n");
- }
- }
- //puts("Using Wayland backend");
- wl_list_init(&outputs);
-
- wl_registry = wl_display_get_registry(wl_display);
- struct pair_bool pair = {false, false};
- wl_registry_add_listener(wl_registry, &registry_listener, &pair);
- struct wl_callback *registry_cb = wl_display_sync(wl_display);
- wl_callback_add_listener(registry_cb, &sync_listener, &registry_cb);
- while (registry_cb) wl_display_dispatch(wl_display);
- Fl::add_fd(wl_display_get_fd(wl_display), FL_READ, (Fl_FD_Handler)wayland_socket_callback,
- wl_display);
- fl_create_print_window();
- /* This is useful to avoid crash of the Wayland compositor after
- FLTK apps terminate in certain situations:
- - gnome-shell version < 44 (e.g. version 42.9)
- - focus set to "follow-mouse"
- See issue #821 for details.
- */
- atexit(do_atexit);
-}
-
-
-void Fl_Wayland_Screen_Driver::close_display() {
- if (!Fl_Wayland_Screen_Driver::wl_display) return;
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- if (text_input_base) {
- disable_im();
- zwp_text_input_manager_v3_destroy(text_input_base);
- text_input_base = NULL;
- }
- while (wl_list_length(&outputs) > 0) {
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- wl_list_remove(&output->link);
- screen_count_set( wl_list_length(&outputs) );
- if (output->wl_output) {
-#ifdef WL_OUTPUT_RELEASE_SINCE_VERSION
- if (wl_output_get_version(output->wl_output) >= WL_OUTPUT_RELEASE_SINCE_VERSION)
- wl_output_release(output->wl_output);
- else
-#endif
- wl_output_destroy(output->wl_output);
- }
- free(output);
- break;
- }
- }
- wl_subcompositor_destroy(wl_subcompositor); wl_subcompositor = NULL;
- wl_surface_destroy(seat->cursor_surface); seat->cursor_surface = NULL;
- if (seat->cursor_theme) {
- wl_cursor_theme_destroy(seat->cursor_theme);
- seat->cursor_theme = NULL;
- }
- wl_compositor_destroy(wl_compositor); wl_compositor = NULL;
- // wl_shm-related data
- if (Fl_Wayland_Graphics_Driver::current_pool) {
- struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data *pool_data =
- (struct Fl_Wayland_Graphics_Driver::wld_shm_pool_data*)
- wl_shm_pool_get_user_data(Fl_Wayland_Graphics_Driver::current_pool);
- wl_shm_pool_destroy(Fl_Wayland_Graphics_Driver::current_pool);
- Fl_Wayland_Graphics_Driver::current_pool = NULL;
- /*int err = */munmap(pool_data->pool_memory, pool_data->pool_size);
- //printf("close_display munmap(%p)->%d\n", pool_data->pool_memory, err);
- free(pool_data);
- }
- wl_shm_destroy(wl_shm); wl_shm = NULL;
- if (seat->wl_keyboard) {
- if (seat->xkb_state) {
- xkb_state_unref(seat->xkb_state);
- seat->xkb_state = NULL;
- }
- if (seat->xkb_keymap) {
- xkb_keymap_unref(seat->xkb_keymap);
- seat->xkb_keymap = NULL;
- }
- wl_keyboard_destroy(seat->wl_keyboard);
- seat->wl_keyboard = NULL;
- }
- wl_pointer_destroy(seat->wl_pointer); seat->wl_pointer = NULL;
- if (seat->xkb_compose_state) {
- xkb_compose_state_unref(seat->xkb_compose_state);
- seat->xkb_compose_state = NULL;
- }
- if (seat->xkb_context) {
- xkb_context_unref(seat->xkb_context);
- seat->xkb_context = NULL;
- }
- if (seat->data_source) {
- wl_data_source_destroy(seat->data_source);
- seat->data_source = NULL;
- }
- wl_data_device_destroy(seat->data_device); seat->data_device = NULL;
- wl_data_device_manager_destroy(seat->data_device_manager);
- seat->data_device_manager = NULL;
- wl_seat_destroy(seat->wl_seat); seat->wl_seat = NULL;
- if (seat->name) free(seat->name);
- free(seat); seat = NULL;
- if (libdecor_context) {
- libdecor_unref(libdecor_context);
- libdecor_context = NULL;
- }
- xdg_wm_base_destroy(xdg_wm_base); xdg_wm_base = NULL;
- Fl_Wayland_Plugin *plugin = Fl_Wayland_Window_Driver::gl_plugin();
- if (plugin) plugin->terminate();
-#if HAVE_XDG_DIALOG
- if (xdg_wm_dialog) {
- xdg_wm_dialog_v1_destroy(xdg_wm_dialog);
- xdg_wm_dialog = NULL;
- }
-#endif // HAVE_XDG_DIALOG
-#if HAVE_CURSOR_SHAPE
- if (wp_cursor_shape_device ) {
- wp_cursor_shape_device_v1_destroy(wp_cursor_shape_device);
- wp_cursor_shape_device = NULL;
- }
- if (wp_cursor_shape_manager ) {
- wp_cursor_shape_manager_v1_destroy(wp_cursor_shape_manager);
- wp_cursor_shape_manager = NULL;
- }
-#endif // HAVE_CURSOR_SHAPE
-
- Fl::remove_fd(wl_display_get_fd(Fl_Wayland_Screen_Driver::wl_display));
- wl_registry_destroy(wl_registry); wl_registry = NULL;
- wl_display_disconnect(Fl_Wayland_Screen_Driver::wl_display);
- Fl_Wayland_Screen_Driver::wl_display = NULL;
- delete Fl_Display_Device::display_device()->driver();
- delete Fl_Display_Device::display_device();
- delete Fl::system_driver();
- delete this;
-}
-
-
-struct configure_s { int W, H; uint32_t state; };
-
-static void xdg_toplevel_configure(void *v, struct xdg_toplevel *xdg_toplevel,
- int32_t width, int32_t height, struct wl_array *states)
-{
- struct configure_s *data = (struct configure_s*)v;
- data->W = width;
- data->H = height;
- data->state = (width && height && states ? *(uint32_t *)(states->data) : 0);
-}
-
-static const struct xdg_toplevel_listener xdg_toplevel_listener = {
- .configure = xdg_toplevel_configure,
-};
-
-
-static bool compute_full_and_maximized_areas(Fl_Wayland_Screen_Driver::output *output,
- int& Wfullscreen, int& Hfullscreen,
- int& Wworkarea, int& Hworkarea) {
- if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::unspecified) {
- Wfullscreen = 0;
- return false;
- }
- bool found_workarea = false;
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- struct wl_surface *wl_surface = wl_compositor_create_surface(scr_driver->wl_compositor);
- wl_surface_set_opaque_region(wl_surface, NULL);
- struct xdg_surface *xdg_surface = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface);
- struct xdg_toplevel *xdg_toplevel = xdg_surface_get_toplevel(xdg_surface);
- struct configure_s data = {0, 0, 0};
- xdg_toplevel_add_listener(xdg_toplevel, &xdg_toplevel_listener, &data);
- xdg_toplevel_set_fullscreen(xdg_toplevel, output->wl_output);
- wl_surface_commit(wl_surface); // necessary under KWin
- while (data.state != XDG_TOPLEVEL_STATE_FULLSCREEN)
- wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
- Wfullscreen = data.W;
- Hfullscreen = data.H;
- if (Wfullscreen && Hfullscreen && wl_list_length(&scr_driver->outputs) == 1) {
- struct wl_surface *wl_surface2 = wl_compositor_create_surface(scr_driver->wl_compositor);
- struct xdg_surface *xdg_surface2 = xdg_wm_base_get_xdg_surface(scr_driver->xdg_wm_base, wl_surface2);
- struct xdg_toplevel *xdg_toplevel2 = xdg_surface_get_toplevel(xdg_surface2);
- struct configure_s data2 = {0, 0, 0};
- xdg_toplevel_add_listener(xdg_toplevel2, &xdg_toplevel_listener, &data2);
- xdg_toplevel_set_parent(xdg_toplevel2, xdg_toplevel);
- xdg_toplevel_set_maximized(xdg_toplevel2);
- wl_surface_commit(wl_surface2); // necessary under KWin
- while (data2.state != XDG_TOPLEVEL_STATE_MAXIMIZED)
- wl_display_dispatch(Fl_Wayland_Screen_Driver::wl_display);
- Wworkarea = data2.W;
- Hworkarea = data2.H;
- xdg_toplevel_destroy(xdg_toplevel2);
- xdg_surface_destroy(xdg_surface2);
- wl_surface_destroy(wl_surface2);
- if (Wworkarea == Wfullscreen && Hworkarea < Hfullscreen && Hworkarea > Hfullscreen - 80)
- found_workarea = true;
- if (Hworkarea == Hfullscreen && Wworkarea < Wfullscreen && Wworkarea > Wfullscreen - 80)
- found_workarea = true;
- } else {
- Wworkarea = Wfullscreen;
- Hworkarea = Hfullscreen;
- }
- xdg_toplevel_destroy(xdg_toplevel);
- xdg_surface_destroy(xdg_surface);
- wl_surface_destroy(wl_surface);
- /*int fractional_scale = int(100 * (output->pixel_width / float(Wfullscreen)));
- printf("fullscreen=%dx%d workarea=%dx%d fractional_scale=%d%% wld_s=%d\n",
- Wfullscreen,Hfullscreen,Wworkarea,Hworkarea,fractional_scale,output->wld_scale);*/
- return found_workarea;
-}
-
-static int workarea_xywh[4] = { -1, -1, -1, -1 };
-
-
-/* Implementation note about computing work area and about handling fractional scaling.
-
- FLTK computes 2 pairs of (WxH) values for each display:
- 1) (pixel_width x pixel_height) gives the size in pixel of a display. It's unchanged by
- any scaling applied by the compositor; it's assigned by function output_mode().
- 2) (width x height) gives the size in pixels of a buffer that would fully cover the display.
- When the active scaling is non-fractional, these equations hold:
- pixel_width = width = wld_scale * configured-width-of-fullscreen-window
- pixel_height = height = wld_scale * configured-height-of-fullscreen-window
-
- When fractional scaling is active, buffers received from client are scaled down
- by the compositor and mapped to screen. These equations hold:
- pixel_width < width = wld_scale * configured-width-of-fullscreen-window
- pixel_height < height = wld_scale * configured-height-of-fullscreen-window
-
- One way for a client to discover that fractional scaling is active on a given display
- is to ask for a fullscreen window on that display, get its configured size and compare
- it to that display's pixel size. That's what function compute_full_and_maximized_areas() does.
-
- One way for a client to discover the work area size of a display is to get the configured size
- of a maximized window on that display. FLTK didn't find a way to control in general
- on what display the compositor puts a maximized window. Therefore, FLTK computes an exact
- work area size only when the system contains a single display. We create first a fullscreen
- window on the display and then we create a maximized window made a child of the
- fullscreen one and record its configured size. That's also done by function
- compute_full_and_maximized_areas().
- */
-
-void Fl_Wayland_Screen_Driver::init_workarea()
-{
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display); // important after screen removal
- bool need_init_workarea = true;
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- int Wfullscreen, Hfullscreen, Wworkarea, Hworkarea;
- bool found_workarea = compute_full_and_maximized_areas(output, Wfullscreen, Hfullscreen, Wworkarea, Hworkarea);
- if (Wfullscreen && Hfullscreen) { // skip sway which puts 0 there
- output->width = Wfullscreen * output->wld_scale; // pixels
- output->height = Hfullscreen * output->wld_scale; // pixels
- if (found_workarea) {
- workarea_xywh[0] = output->x; // pixels
- workarea_xywh[1] = output->y; // pixels
- workarea_xywh[2] = Wworkarea * output->wld_scale; // pixels
- workarea_xywh[3] = Hworkarea * output->wld_scale; // pixels
- need_init_workarea = false;
- }
- }
- }
- if (need_init_workarea) {
- screen_xywh(workarea_xywh[0], workarea_xywh[1], workarea_xywh[2], workarea_xywh[3], 0);
- }
- Fl::handle(FL_SCREEN_CONFIGURATION_CHANGED, NULL);
-}
-
-
-int Fl_Wayland_Screen_Driver::x() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- break;
- }
- return workarea_xywh[0] / (output->gui_scale * output->wld_scale);
-}
-
-
-int Fl_Wayland_Screen_Driver::y() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- break;
- }
- return workarea_xywh[1] / (output->gui_scale * output->wld_scale);
-}
-
-
-int Fl_Wayland_Screen_Driver::w() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- break;
- }
- return workarea_xywh[2] / (output->gui_scale * output->wld_scale);
-}
-
-
-int Fl_Wayland_Screen_Driver::h() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
- Fl_Wayland_Screen_Driver::output *output;
- wl_list_for_each(output, &outputs, link) {
- break;
- }
- return workarea_xywh[3] / (output->gui_scale * output->wld_scale);
-}
-
-
-void Fl_Wayland_Screen_Driver::init() {
- if (!Fl_Wayland_Screen_Driver::wl_registry) open_display();
-}
-
-
-void Fl_Wayland_Screen_Driver::screen_work_area(int &X, int &Y, int &W, int &H, int n)
-{
- if (num_screens < 0) init();
- if (n < 0 || n >= num_screens) n = 0;
- if (n == 0) { // for the main screen, these return the work area
- X = Fl::x();
- Y = Fl::y();
- W = Fl::w();
- H = Fl::h();
- } else { // for other screens, work area is full screen,
- screen_xywh(X, Y, W, H, n);
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::screen_xywh(int &X, int &Y, int &W, int &H, int n)
-{
- if (num_screens < 0) init();
-
- if ((n < 0) || (n >= num_screens))
- n = 0;
-
- if (num_screens > 0) {
- Fl_Wayland_Screen_Driver::output *output;
- int i = 0;
- wl_list_for_each(output, &outputs, link) {
- if (i++ == n) { // n'th screen of the system
- float s = output->gui_scale * output->wld_scale;
- X = output->x / s;
- Y = output->y / s;
- W = output->width / s;
- H = output->height / s;
- break;
- }
- }
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::screen_dpi(float &h, float &v, int n)
-{
- if (num_screens < 0) init();
- h = v = 0.0f;
-
- if (n >= 0 && n < num_screens) {
- Fl_Wayland_Screen_Driver::output *output;
- int i = 0;
- wl_list_for_each(output, &outputs, link) {
- if (i++ == n) { // n'th screen of the system
- h = output->dpi;
- v = output->dpi;
- break;
- }
- }
- }
-}
-
-
-// Implements fl_beep(). See documentation in src/fl_ask.cxx.
-void Fl_Wayland_Screen_Driver::beep(int type)
-{
- fprintf(stderr, "\007");
-}
-
-
-void Fl_Wayland_Screen_Driver::flush()
-{
- if (Fl_Wayland_Screen_Driver::wl_display) {
- wl_display_flush(Fl_Wayland_Screen_Driver::wl_display);
- }
-}
-
-
-extern void fl_fix_focus(); // in Fl.cxx
-
-
-void Fl_Wayland_Screen_Driver::grab(Fl_Window* win)
-{
- if (win) {
- if (!Fl::grab()) {
- }
- Fl::grab_ = win; // FIXME: Fl::grab_ "should be private", but we need
- // a way to *set* the variable from the driver!
- } else {
- if (Fl::grab()) {
- // We must keep the grab in the non-EWMH fullscreen case
- Fl::grab_ = 0; // FIXME: Fl::grab_ "should be private", but we need
- // a way to *set* the variable from the driver!
- fl_fix_focus();
- }
- }
-}
-
-
-static void set_selection_color(uchar r, uchar g, uchar b)
-{
- Fl::set_color(FL_SELECTION_COLOR,r,g,b);
-}
-
-
-static void getsyscolor(const char *key1, const char* key2, const char *arg,
- const char *defarg, void (*func)(uchar,uchar,uchar)) {
- uchar r, g, b;
- if (!arg) arg = defarg;
- if (!Fl::screen_driver()->parse_color(arg, r, g, b))
- Fl::error("Unknown color: %s", arg);
- else
- func(r, g, b);
-}
-
-
-void Fl_Wayland_Screen_Driver::get_system_colors()
-{
- open_display();
- const char* key1 = 0;
- if (Fl::first_window()) key1 = Fl::first_window()->xclass();
- if (!key1) key1 = "fltk";
- if (!bg2_set)
- getsyscolor("Text","background", fl_bg2, "#ffffff", Fl::background2);
- if (!fg_set)
- getsyscolor(key1, "foreground", fl_fg, "#000000", Fl::foreground);
- if (!bg_set)
- getsyscolor(key1, "background", fl_bg, "#c0c0c0", Fl::background);
- getsyscolor("Text", "selectBackground", 0, "#000080", set_selection_color);
-}
-
-
-Fl_RGB_Image *Fl_Wayland_Screen_Driver::read_win_rectangle(int X, int Y, int w, int h,
- Fl_Window *win,
- bool ignore, bool *p_ignore) {
- struct wld_window* xid = win ? fl_wl_xid(win) : NULL;
- if (win && (!xid || !xid->buffer)) return NULL;
- struct Fl_Wayland_Graphics_Driver::draw_buffer *buffer;
- if (win) buffer = &xid->buffer->draw_buffer;
- else {
- Fl_Image_Surface_Driver *dr = (Fl_Image_Surface_Driver*)Fl_Surface_Device::surface();
- buffer = Fl_Wayland_Graphics_Driver::offscreen_buffer(
- dr->image_surface()->offscreen());
- }
- float s = win ?
- Fl_Wayland_Window_Driver::driver(win)->wld_scale() * scale(win->screen_num()) :
- Fl_Surface_Device::surface()->driver()->scale();
- int Xs, Ys, ws, hs;
- if (s == 1) {
- Xs = X; Ys = Y; ws = w; hs = h;
- } else {
- Xs = Fl_Scalable_Graphics_Driver::floor(X, s);
- Ys = Fl_Scalable_Graphics_Driver::floor(Y, s);
- ws = Fl_Scalable_Graphics_Driver::floor(X+w, s) - Xs;
- hs = Fl_Scalable_Graphics_Driver::floor(Y+h, s) - Ys;
- }
- if (ws == 0 || hs == 0) return NULL;
- uchar *data = new uchar[ws * hs * 3];
- uchar *p = data, *q;
- for (int j = 0; j < hs; j++) {
- q = buffer->buffer + (j+Ys) * buffer->stride + 4 * Xs;
- for (int i = 0; i < ws; i++) {
- *p++ = *(q+2); // R
- *p++ = *(q+1); // G
- *p++ = *q; // B
- q += 4;
- }
- }
- Fl_RGB_Image *rgb = new Fl_RGB_Image(data, ws, hs, 3);
- rgb->alloc_array = 1;
- return rgb;
-}
-
-
-void Fl_Wayland_Screen_Driver::offscreen_size(Fl_Offscreen off_, int &width, int &height)
-{
- struct Fl_Wayland_Graphics_Driver::draw_buffer *off = Fl_Wayland_Graphics_Driver::offscreen_buffer(off_);
- width = off->width;
- height = off->data_size / off->stride;
-}
-
-
-float Fl_Wayland_Screen_Driver::scale(int n) {
- Fl_Wayland_Screen_Driver::output *output;
- int i = 0;
- wl_list_for_each(output, &outputs, link) {
- if (i++ == n) break;
- }
- return output->gui_scale;
-}
-
-
-void Fl_Wayland_Screen_Driver::scale(int n, float f) {
- Fl_Wayland_Screen_Driver::output *output;
- int i = 0;
- wl_list_for_each(output, &outputs, link) {
- if (i++ == n) {
- output->gui_scale = f;
- return;
- }
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::set_cursor() {
- do_set_cursor(seat);
-}
-
-
-struct wl_cursor *Fl_Wayland_Screen_Driver::default_cursor() {
- return seat->default_cursor;
-}
-
-
-void Fl_Wayland_Screen_Driver::default_cursor(struct wl_cursor *cursor) {
- seat->default_cursor = cursor;
- do_set_cursor(seat);
-}
-
-
-struct wl_cursor *Fl_Wayland_Screen_Driver::cache_cursor(const char *cursor_name) {
- return wl_cursor_theme_get_cursor(seat->cursor_theme, cursor_name);
-}
-
-
-void Fl_Wayland_Screen_Driver::reset_cursor() {
- for (int i = 0; i < cursor_count; i++) xc_cursor[i] = NULL;
-}
-
-
-uint32_t Fl_Wayland_Screen_Driver::get_serial() {
- return seat->serial;
-}
-
-
-struct wl_seat*Fl_Wayland_Screen_Driver::get_wl_seat() {
- return seat->wl_seat;
-}
-
-
-char *Fl_Wayland_Screen_Driver::get_seat_name() {
- return seat->name;
-}
-
-
-struct xkb_keymap *Fl_Wayland_Screen_Driver::get_xkb_keymap() {
- return seat->xkb_keymap;
-}
-
-
-int Fl_Wayland_Screen_Driver::get_mouse(int &xx, int &yy) {
- open_display();
- xx = Fl::e_x_root; yy = Fl::e_y_root;
- if (!seat->pointer_focus) return 0;
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(seat->pointer_focus);
- if (!win) return 0;
- int snum = Fl_Window_Driver::driver(win)->screen_num();
-//printf("get_mouse(%dx%d)->%d\n", xx, yy, snum);
- return snum;
-}
-
-
-void Fl_Wayland_Screen_Driver::set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win) {
- Fl_Wayland_Screen_Driver::insertion_point_location(x, y, height);
-}
-
-
-void Fl_Wayland_Screen_Driver::reset_spot() {
- Fl::compose_state = 0;
- Fl_Wayland_Screen_Driver::next_marked_length = 0;
- Fl_Wayland_Screen_Driver::insertion_point_location_is_valid = false;
-}
-
-
-void Fl_Wayland_Screen_Driver::display(const char *d)
-{
- if (d && !wl_registry) { // if display was opened, it's too late
- if (wl_display) {
- // only the wl_display_connect() call was done, redo it because the target
- // Wayland compositor may be different
- wl_display_disconnect(wl_display);
- }
- wl_display = wl_display_connect(d);
- if (!wl_display) {
- fprintf(stderr, "Error: '%s' is not an active Wayland socket\n", d);
- exit(1);
- }
- }
-}
-
-
-void *Fl_Wayland_Screen_Driver::control_maximize_button(void *data) {
- // The code below aims at removing the calling window's fullscreen button
- // while dialog runs. Unfortunately, it doesn't work with some X11 window managers
- // (e.g., KDE, xfce) because the button goes away but doesn't come back,
- // so we move this code to a virtual member function.
- // Noticeably, this code works OK under Wayland.
- struct win_dims {
- Fl_Widget_Tracker *tracker;
- int minw, minh, maxw, maxh;
- struct win_dims *next;
- };
-
- if (!data) { // this call turns each decorated window's maximize button off
- struct win_dims *first_dim = NULL;
- // consider all bordered, top-level FLTK windows
- Fl_Window *win = Fl::first_window();
- while (win) {
- if (!win->parent() && win->border() &&
- !( ((struct wld_window*)Fl_X::flx(win)->xid)->state &
- LIBDECOR_WINDOW_STATE_MAXIMIZED) ) {
- win_dims *dim = new win_dims;
- dim->tracker = new Fl_Widget_Tracker(win);
- win->get_size_range(&dim->minw, &dim->minh, &dim->maxw, &dim->maxh, NULL, NULL, NULL);
- //make win un-resizable
- win->size_range(win->w(), win->h(), win->w(), win->h());
- dim->next = first_dim;
- first_dim = dim;
- }
- win = Fl::next_window(win);
- }
- return first_dim;
- } else { // this call returns each decorated window's maximize button to its previous state
- win_dims *first_dim = (win_dims *)data;
- while (first_dim) {
- win_dims *dim = first_dim;
- //give back win its resizing parameters
- if (dim->tracker->exists()) {
- Fl_Window *win = (Fl_Window*)dim->tracker->widget();
- win->size_range(dim->minw, dim->minh, dim->maxw, dim->maxh);
- }
- first_dim = dim->next;
- delete dim->tracker;
- delete dim;
- }
- return NULL;
- }
-}
-
-
-int Fl_Wayland_Screen_Driver::poll_or_select_with_delay(double time_to_wait) {
- if (wl_display_dispatch_pending(wl_display) > 0) return 1;
- return Fl_Unix_Screen_Driver::poll_or_select_with_delay(time_to_wait);
-}
-
-
-// like Fl_Wayland_Screen_Driver::poll_or_select_with_delay(0.0) except no callbacks are done:
-int Fl_Wayland_Screen_Driver::poll_or_select() {
- int ret = wl_display_prepare_read(wl_display);
- if (ret == 0) wl_display_cancel_read(wl_display);
- else return 1;
- return Fl_Unix_Screen_Driver::poll_or_select();
-}
-
-
-int Fl_Wayland_Screen_Driver::event_key(int k) {
- if (k >= 'A' && k <= 'Z') k += 32;
- return (search_int_vector(key_vector, k) >= 0);
-}
-
-
-int Fl_Wayland_Screen_Driver::get_key(int k) {
- return event_key(k);
-}
-
-
-float Fl_Wayland_Screen_Driver::base_scale(int numscreen) {
- const char *p;
- float factor = 1;
- if ((p = fl_getenv("FLTK_SCALING_FACTOR"))) {
- sscanf(p, "%f", &factor);
- }
- return factor;
-}
-
-
-struct wl_display *fl_wl_display() {
- return Fl_Wayland_Screen_Driver::wl_display;
-}
diff --git a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H b/src/drivers/Wayland/Fl_Wayland_Window_Driver.H
deleted file mode 100644
index c5c1bee50..000000000
--- a/src/drivers/Wayland/Fl_Wayland_Window_Driver.H
+++ /dev/null
@@ -1,185 +0,0 @@
-//
-// Definition of Wayland window driver for the Fast Light Tool Kit (FLTK).
-//
-// Copyright 2010-2025 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
-//
-
-/**
- \file Fl_Wayland_Window_Driver.H
- \brief Definition of Wayland window driver.
- */
-
-#ifndef FL_WAYLAND_WINDOW_DRIVER_H
-#define FL_WAYLAND_WINDOW_DRIVER_H
-
-#include <config.h>
-#include "../../Fl_Window_Driver.H"
-#include <FL/Fl_Plugin.H>
-#include "Fl_Wayland_Screen_Driver.H"
-#include "Fl_Wayland_Graphics_Driver.H"
-
-
-/*
- Move everything here that manages the native window interface.
-
- There is one window driver for each Fl_Window. Window drivers manage window
- actions such as resizing, events, decoration, fullscreen modes, etc. . All
- drawing and rendering is managed by the Surface device and the associated
- graphics driver.
-
- - window specific event handling
- - window types and styles, depth, etc.
- - decorations
- */
-
-typedef struct _cairo_pattern cairo_pattern_t;
-typedef struct _cairo_rectangle_int cairo_rectangle_int_t;
-class Fl_Wayland_Plugin;
-
-
-class Fl_Wayland_Window_Driver : public Fl_Window_Driver
-{
- friend class Fl_Wayland_Gl_Window_Driver;
-private:
- struct shape_data_type {
- int lw_; ///< width of shape image
- int lh_; ///< height of shape image
- Fl_Image* shape_; ///< shape image
- cairo_pattern_t *mask_pattern_;
- } *shape_data_;
- bool can_expand_outside_parent_; // specially to allow window docking (#987)
- cairo_rectangle_int_t *subRect_; // makes sure subwindow remains inside its parent window
- static bool in_flush_; // useful for progressive window drawing
- Fl_Cursor standard_cursor_; // window's standard custom kind
- struct gl_start_support *gl_start_support_; // for support of gl_start/gl_finish
- bool is_popup_window_;
-public:
- inline Fl_Cursor standard_cursor() { return standard_cursor_; }
- bool in_handle_configure; // distinguish OS and user window resize
-
- struct surface_output { // for linked list of displays where a surface maps
- struct Fl_Wayland_Screen_Driver::output *output;
- struct wl_list link;
- };
- struct custom_cursor {
- struct wl_cursor *wl_cursor;
- const Fl_RGB_Image *rgb;
- int hotx, hoty;
- };
- static void delete_cursor(struct custom_cursor *custom, bool delete_rgb = true);
- void decorated_win_size(int &w, int &h);
- void shape_bitmap_(Fl_Image* b);
- void shape_alpha_(Fl_Image* img, int offset) override;
- FL_EXPORT int wld_scale(); // used by class Fl_Wayland_Gl_Window_Driver
- cairo_rectangle_int_t *subRect() { return subRect_; } // getter
- void subRect(cairo_rectangle_int_t *r); // setter
- void checkSubwindowFrame();
- enum kind {DECORATED, SUBWINDOW, POPUP, UNFRAMED};
- struct xdg_toplevel *xdg_toplevel();
- Fl_Wayland_Window_Driver(Fl_Window*);
- virtual ~Fl_Wayland_Window_Driver();
- static struct wld_window *wld_window;
- static Fl_Window *surface_to_window(struct wl_surface *);
-
- static inline Fl_Wayland_Window_Driver* driver(const Fl_Window *w) {
- return (Fl_Wayland_Window_Driver*)Fl_Window_Driver::driver(w);
- }
- static Fl_Wayland_Plugin *gl_plugin();
-
- // --- window data
- int decorated_w() override;
- int decorated_h() override;
- const Fl_Image* shape() override;
-
- // --- window management
- void makeWindow() override;
- void take_focus() override;
- void flush() override;
- void flush_overlay() override;
- void draw_end() override;
- void make_current() override;
- void show() override;
- void resize(int X,int Y,int W,int H) override;
- void label(const char *name, const char *mininame) override;
- void hide() override;
- void map() override;
- void unmap() override;
- void fullscreen_on() override;
- void fullscreen_off(int X, int Y, int W, int H) override;
- void maximize() override;
- void un_maximize() override;
- void use_border() override;
- void size_range() override;
- void iconize() override;
- void decoration_sizes(int *top, int *left, int *right, int *bottom) override;
- // --- window cursor stuff
- int set_cursor(Fl_Cursor) override;
- int set_cursor(const Fl_RGB_Image*, int, int) override;
- int set_cursor_4args(const Fl_RGB_Image*, int, int, bool);
-
- void shape(const Fl_Image* img) override;
- void capture_titlebar_and_borders(Fl_RGB_Image*& top, Fl_RGB_Image*& left,
- Fl_RGB_Image*& bottom, Fl_RGB_Image*& right) override;
- int 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) override;
- void wait_for_expose() override;
- // menu-related stuff
- void reposition_menu_window(int x, int y) override;
- void menu_window_area(int &X, int &Y, int &W, int &H, int nscreen = -1) override;
- static bool new_popup; // to support tall menu buttons
- bool process_menu_or_tooltip(struct wld_window *);
- static Fl_Window *previous_floatingtitle; // to support floating menuwindow w/ title
- void allow_expand_outside_parent() override { can_expand_outside_parent_ = true; }
-};
-
-
-struct wld_window {
- Fl_Window *fl_win;
- struct wl_list outputs; // linked list of displays where part or whole of window maps
- struct wl_surface *wl_surface;
- struct wl_callback *frame_cb;
- struct Fl_Wayland_Graphics_Driver::wld_buffer *buffer;
- struct xdg_surface *xdg_surface;
- union { // for each value of kind
- struct libdecor_frame *frame;
- struct wl_subsurface *subsurface;
- struct xdg_popup *xdg_popup;
- struct xdg_toplevel *xdg_toplevel;
- };
- // non-null when using custom cursor
- struct Fl_Wayland_Window_Driver::custom_cursor *custom_cursor;
-#if HAVE_XDG_DIALOG
- struct xdg_dialog_v1 *xdg_dialog;
-#endif
- enum Fl_Wayland_Window_Driver::kind kind;
- int configured_width;
- int configured_height;
- int floating_width;
- int floating_height;
- int state;
- bool covered; // specially for Mutter and issue #878
-};
-
-
-class Fl_Wayland_Plugin : public Fl_Plugin {
-public:
- Fl_Wayland_Plugin(const char *pluginName) : Fl_Plugin(klass(), pluginName) { }
- virtual const char *klass() { return "wayland.fltk.org"; }
- virtual const char *name() = 0;
- virtual void do_swap(Fl_Window*) = 0;
- virtual void invalidate(Fl_Window*) = 0;
- virtual void terminate() = 0;
- virtual void destroy(struct gl_start_support *) = 0;
-};
-
-#endif // FL_WAYLAND_WINDOW_DRIVER_H
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();
-}
diff --git a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx b/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx
deleted file mode 100644
index 12c525c46..000000000
--- a/src/drivers/Wayland/fl_wayland_clipboard_dnd.cxx
+++ /dev/null
@@ -1,741 +0,0 @@
-//
-// Wayland-specific code for clipboard and drag-n-drop support.
-//
-// 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
-//
-
-#if !defined(FL_DOXYGEN)
-
-# include <FL/Fl.H>
-# include <FL/platform.H>
-# include <FL/Fl_Window.H>
-# include <FL/Fl_Shared_Image.H>
-# include <FL/Fl_Image_Surface.H>
-# include "Fl_Wayland_Screen_Driver.H"
-# include "Fl_Wayland_Window_Driver.H"
-# include "../Unix/Fl_Unix_System_Driver.H"
-# include "Fl_Wayland_Graphics_Driver.H"
-# include "../../flstring.h" // includes <string.h>
-
-# include <errno.h>
-# include <stdio.h>
-# include <stdlib.h>
-# include <map>
-
-
-////////////////////////////////////////////////////////////////
-// Code used for copy and paste and DnD into the program:
-
-static char *fl_selection_buffer[2];
-static int fl_selection_length[2];
-static const char * fl_selection_type[2];
-static int fl_selection_buffer_length[2];
-static char fl_i_own_selection[2] = {0,0};
-static struct wl_data_offer *fl_selection_offer = NULL;
-// The MIME type Wayland uses for text-containing clipboard:
-static const char wld_plain_text_clipboard[] = "text/plain;charset=utf-8";
-
-
-int Fl_Wayland_Screen_Driver::clipboard_contains(const char *type)
-{
- return fl_selection_type[1] == type;
-}
-
-
-struct data_source_write_struct {
- size_t rest;
- char *from;
-};
-
-void write_data_source_cb(FL_SOCKET fd, data_source_write_struct *data) {
- while (data->rest) {
- ssize_t n = write(fd, data->from, data->rest);
- if (n == -1) {
- if (errno == EAGAIN) return;
- Fl::error("write_data_source_cb: error while writing clipboard data\n");
- break;
- }
- data->from += n;
- data->rest -= n;
- }
- Fl::remove_fd(fd, FL_WRITE);
- delete data;
- close(fd);
-}
-
-
-static void data_source_handle_send(void *data, struct wl_data_source *source,
- const char *mime_type, int fd) {
- fl_intptr_t rank = (fl_intptr_t)data;
-//fprintf(stderr, "data_source_handle_send: %s fd=%d l=%d\n", mime_type, fd, fl_selection_length[1]);
- if (((!strcmp(mime_type, wld_plain_text_clipboard) || !strcmp(mime_type, "text/plain")) &&
- fl_selection_type[rank] == Fl::clipboard_plain_text)
- ||
- (!strcmp(mime_type, "image/bmp") && fl_selection_type[rank] == Fl::clipboard_image) ) {
- data_source_write_struct *write_data = new data_source_write_struct;
- write_data->rest = fl_selection_length[rank];
- write_data->from = fl_selection_buffer[rank];
- Fl::add_fd(fd, FL_WRITE, (Fl_FD_Handler)write_data_source_cb, write_data);
- } else {
- //Fl::error("Destination client requested unsupported MIME type: %s\n", mime_type);
- close(fd);
- }
-}
-
-
-static Fl_Window *fl_dnd_target_window = 0;
-static wl_surface *fl_dnd_target_surface = 0;
-static bool doing_dnd = false; // true when DnD is in action
-static wl_surface *dnd_icon = NULL; // non null when DnD uses text as cursor
-static wl_cursor* save_cursor = NULL; // non null when DnD uses "dnd-copy" cursor
-
-
-static void data_source_handle_cancelled(void *data, struct wl_data_source *source) {
- // An application has replaced the clipboard contents or DnD finished
- wl_data_source_destroy(source);
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
- if (scr_driver->seat->data_source == source) scr_driver->seat->data_source = NULL;
- doing_dnd = false;
- if (dnd_icon) {
- struct Fl_Wayland_Graphics_Driver::wld_buffer *off =
- (struct Fl_Wayland_Graphics_Driver::wld_buffer *)
- wl_surface_get_user_data(dnd_icon);
- struct wld_window fake_window;
- memset(&fake_window, 0, sizeof(fake_window));
- fake_window.buffer = off;
- Fl_Wayland_Graphics_Driver::buffer_release(&fake_window);
- wl_surface_destroy(dnd_icon);
- dnd_icon = NULL;
- }
- fl_i_own_selection[1] = 0;
- if (data == 0) { // at end of DnD
- if (save_cursor) {
- scr_driver->default_cursor(save_cursor);
- scr_driver->set_cursor();
- save_cursor = NULL;
- }
- if (fl_dnd_target_window) {
- Fl::handle(FL_RELEASE, fl_dnd_target_window);
- fl_dnd_target_window = 0;
- }
- Fl::pushed(0);
- }
-}
-
-
-static void data_source_handle_target(void *data, struct wl_data_source *source, const char *mime_type) {
- if (!Fl::pushed()) {
- data_source_handle_cancelled(data, source);
- return;
- }
- if (mime_type != NULL) {
- //printf("Destination would accept MIME type if dropped: %s\n", mime_type);
- } else {
- //printf("Destination would reject if dropped\n");
- }
-}
-
-
-static uint32_t last_dnd_action = WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
-
-
-static void data_source_handle_action(void *data, struct wl_data_source *source,
- uint32_t dnd_action) {
- last_dnd_action = dnd_action;
- switch (dnd_action) {
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
- //printf("Destination would perform a copy action if dropped\n");
- break;
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
- //printf("Destination would reject the drag if dropped\n");
- break;
- }
-}
-
-
-static void data_source_handle_dnd_drop_performed(void *data, struct wl_data_source *source) {
- //printf("Drop performed\n");
-}
-
-
-static void data_source_handle_dnd_finished(void *data, struct wl_data_source *source) {
- switch (last_dnd_action) {
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
- //printf("Destination has accepted the drop with a move action\n");
- break;
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
- //printf("Destination has accepted the drop with a copy action\n");
- break;
- }
-}
-
-
-static const struct wl_data_source_listener data_source_listener = {
- .target = data_source_handle_target,
- .send = data_source_handle_send,
- .cancelled = data_source_handle_cancelled,
- .dnd_drop_performed = data_source_handle_dnd_drop_performed,
- .dnd_finished = data_source_handle_dnd_finished,
- .action = data_source_handle_action,
-};
-
-
-static struct Fl_Wayland_Graphics_Driver::wld_buffer *offscreen_from_text(const char *text,
- int scale) {
- const char *p, *q;
- int width = 0, height, w2, ltext = strlen(text);
- fl_font(FL_HELVETICA, 10 * scale);
- p = text;
- int nl = 0;
- while(nl < 20 && (q=strchr(p, '\n')) != NULL) {
- nl++;
- w2 = int(fl_width(p, q - p));
- if (w2 > width) width = w2;
- p = q + 1;
- }
- if (nl < 20 && text[ ltext - 1] != '\n') {
- nl++;
- w2 = int(fl_width(p));
- if (w2 > width) width = w2;
- }
- if (width > 300*scale) width = 300*scale;
- height = nl * fl_height() + 3;
- width += 6;
- width = ceil(width/float(scale)) * scale; // these must be multiples of scale
- height = ceil(height/float(scale)) * scale;
- struct Fl_Wayland_Graphics_Driver::wld_buffer *off;
- Fl_Image_Surface *surf = Fl_Wayland_Graphics_Driver::custom_offscreen(
- width, height, &off);
- Fl_Surface_Device::push_current(surf);
- p = text;
- fl_font(FL_HELVETICA, 10 * scale);
- int y = fl_height();
- while (nl > 0) {
- q = strchr(p, '\n');
- if (q) {
- fl_draw(p, q - p, 3, y);
- } else {
- fl_draw(p, 3, y);
- break;
- }
- y += fl_height();
- p = q + 1;
- nl--;
- }
- Fl_Surface_Device::pop_current();
- delete surf;
- cairo_surface_flush( cairo_get_target(off->draw_buffer.cairo_) );
- memcpy(off->data, off->draw_buffer.buffer, off->draw_buffer.data_size);
- return off;
-}
-
-
-int Fl_Wayland_Screen_Driver::dnd(int use_selection) {
- Fl_Wayland_Screen_Driver *scr_driver = (Fl_Wayland_Screen_Driver*)Fl::screen_driver();
-
- struct wl_data_source *source =
- wl_data_device_manager_create_data_source(scr_driver->seat->data_device_manager);
- // we transmit the adequate value of index in fl_selection_buffer[index]
- wl_data_source_add_listener(source, &data_source_listener, (void*)0);
- wl_data_source_offer(source, wld_plain_text_clipboard);
- wl_data_source_set_actions(source, WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY);
- struct Fl_Wayland_Graphics_Driver::wld_buffer *off = NULL;
- int s = 1;
- if (use_selection) {
- // use the text as dragging icon
- Fl_Widget *current = Fl::pushed() ? Fl::pushed() : Fl::first_window();
- s = Fl_Wayland_Window_Driver::driver(current->top_window())->wld_scale();
- off = (struct Fl_Wayland_Graphics_Driver::wld_buffer *)offscreen_from_text(fl_selection_buffer[0], s);
- dnd_icon = wl_compositor_create_surface(scr_driver->wl_compositor);
- } else dnd_icon = NULL;
- doing_dnd = true;
- wl_data_device_start_drag(scr_driver->seat->data_device, source,
- scr_driver->seat->pointer_focus, dnd_icon,
- scr_driver->seat->serial);
- if (use_selection) {
- wl_surface_attach(dnd_icon, off->wl_buffer, 0, 0);
- wl_surface_set_buffer_scale(dnd_icon, s);
- wl_surface_damage(dnd_icon, 0, 0, 10000, 10000);
- wl_surface_commit(dnd_icon);
- wl_surface_set_user_data(dnd_icon, off);
- } else {
- static struct wl_cursor *dnd_cursor = scr_driver->cache_cursor("dnd-copy");
- if (dnd_cursor) {
- save_cursor = scr_driver->default_cursor();
- scr_driver->default_cursor(dnd_cursor);
- scr_driver->set_cursor();
- } else save_cursor = NULL;
- }
- return 1;
-}
-
-
-struct compare_utf8 { // used as key_comp member of following map object
- bool operator()(const char *a, const char *b) const { return strcmp(a, b) < 0; }
-};
-
-// map: for each clipboard mime-type FLTK has interest in, give FLTK clipboard type and priority.
-// A mime-type with higher priority for same FLTK clipboard type is preferred.
-typedef struct { const char * const fltk_type; int priority; } type_prio_struct;
-static std::map<const char * const, type_prio_struct, compare_utf8> clipboard_mimetypes_map {
-// mime-type FLTK-clipboard-type priority
- {"image/png", {Fl::clipboard_image, 1} },
- {"image/bmp", {Fl::clipboard_image, 2} },
- {"text/plain", {Fl::clipboard_plain_text, 1} },
- {"text/uri-list", {Fl::clipboard_plain_text, 2} },
- {"UTF8_STRING", {Fl::clipboard_plain_text, 3} },
- {wld_plain_text_clipboard, {Fl::clipboard_plain_text, 4} },
-};
-
-// map: for each FLTK-clipboard-type, give current preferred mime-type and priority
-typedef struct { const char *mime_type; int priority; } mime_prio_struct;
-static std::map<const char * const, mime_prio_struct> clipboard_kinds_map {
-// FLTK-clipboard-type current mime-type current highest priority
- {Fl::clipboard_image, {NULL, 0} },
- {Fl::clipboard_plain_text, {NULL, 0} },
-};
-
-
-static void data_offer_handle_offer(void *data, struct wl_data_offer *offer,
- const char *mime_type) {
- // runs when app becomes active once for each offered clipboard type
-//fprintf(stderr, "Clipboard offer=%p supports MIME type: %s\n", offer, mime_type);
- std::map<const char*const, type_prio_struct, compare_utf8>::iterator iter_mime =
- clipboard_mimetypes_map.find(mime_type);
- if (iter_mime == clipboard_mimetypes_map.end()) return; // FLTK doesn't handle this mime_type
- std::map<const char*const, mime_prio_struct>::iterator iter_kind =
- clipboard_kinds_map.find(iter_mime->second.fltk_type);
- if (iter_mime->second.priority > iter_kind->second.priority) { // found mime-type with higher priority
- iter_kind->second.priority = iter_mime->second.priority;
- iter_kind->second.mime_type = iter_mime->first;
- fl_selection_type[1] = iter_kind->first;
-//fprintf(stderr,"mime_type=%s priority=%d [%s]\n",iter_kind->second.mime_type, iter_kind->second.priority, fl_selection_type[1]);
- }
-}
-
-
-static void data_offer_handle_source_actions(void *data, struct wl_data_offer *offer,
- uint32_t actions) {
- if (actions & WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY) {
- //printf("Drag supports the copy action\n");
- }
-}
-
-
-static void data_offer_handle_action(void *data, struct wl_data_offer *offer,
- uint32_t dnd_action) {
- switch (dnd_action) {
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_MOVE:
- //printf("A move action would be performed if dropped\n");
- break;
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY:
- //printf("A copy action would be performed if dropped\n");
- break;
- case WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE:
- //printf("The drag would be rejected if dropped\n");
- break;
- }
-}
-
-
-static const struct wl_data_offer_listener data_offer_listener = {
- .offer = data_offer_handle_offer,
- .source_actions = data_offer_handle_source_actions,
- .action = data_offer_handle_action,
-};
-
-
-static void data_device_handle_data_offer(void *data, struct wl_data_device *data_device,
- struct wl_data_offer *offer) {
- // An application has created a new data source
-//fprintf(stderr, "data_device_handle_data_offer offer=%p\n", offer);
- fl_selection_type[1] = NULL;
- wl_data_offer_add_listener(offer, &data_offer_listener, NULL);
- // reset current best mime-type and priority
- std::map<const char*const, mime_prio_struct>::iterator iter = clipboard_kinds_map.begin();
- while (iter != clipboard_kinds_map.end()) {
- iter->second.mime_type = NULL;
- iter->second.priority = 0;
- iter++;
- }
-}
-
-
-static void data_device_handle_selection(void *data, struct wl_data_device *data_device,
- struct wl_data_offer *offer) {
- // An application has set the clipboard contents. W
-//fprintf(stderr, "data_device_handle_selection\n");
- if (fl_selection_offer) wl_data_offer_destroy(fl_selection_offer);
- fl_selection_offer = offer;
-//if (offer == NULL) fprintf(stderr, "Clipboard is empty\n");
-}
-
-
-// Gets from the system the clipboard or dnd text and puts it in fl_selection_buffer[1]
-// which is enlarged if necessary.
-static void get_clipboard_or_dragged_text(struct wl_data_offer *offer) {
- int fds[2];
- char *from;
- if (pipe(fds)) return;
- // preferred mime-type for the text clipboard type
- const char *type = clipboard_kinds_map[Fl::clipboard_plain_text].mime_type;
- wl_data_offer_receive(offer, type, fds[1]);
- close(fds[1]);
- wl_display_flush(Fl_Wayland_Screen_Driver::wl_display);
- // read in fl_selection_buffer
- char *to = fl_selection_buffer[1];
- ssize_t rest = fl_selection_buffer_length[1];
- while (rest) {
- ssize_t n = read(fds[0], to, rest);
- if (n <= 0) {
- close(fds[0]);
- fl_selection_length[1] = to - fl_selection_buffer[1];
- fl_selection_buffer[1][ fl_selection_length[1] ] = 0;
- goto way_out;
- }
- n = Fl_Screen_Driver::convert_crlf(to, n);
- to += n;
- rest -= n;
- }
- // compute size of unread clipboard data
- rest = fl_selection_buffer_length[1];
- while (true) {
- char buf[1000];
- ssize_t n = read(fds[0], buf, sizeof(buf));
- if (n <= 0) {
- close(fds[0]);
- break;
- }
- rest += n;
- }
-//fprintf(stderr, "get_clipboard_or_dragged_text: size=%ld\n", rest);
- // read full clipboard data
- if (pipe(fds)) goto way_out;
- wl_data_offer_receive(offer, type, fds[1]);
- close(fds[1]);
- wl_display_flush(Fl_Wayland_Screen_Driver::wl_display);
- if (rest+1 > fl_selection_buffer_length[1]) {
- delete[] fl_selection_buffer[1];
- fl_selection_buffer[1] = new char[rest+1000+1];
- fl_selection_buffer_length[1] = rest+1000;
- }
- from = fl_selection_buffer[1];
- while (rest > 0) {
- ssize_t n = read(fds[0], from, rest);
- if (n <= 0) break;
- n = Fl_Screen_Driver::convert_crlf(from, n);
- from += n;
- rest -= n;
- }
- close(fds[0]);
- fl_selection_length[1] = from - fl_selection_buffer[1];
- fl_selection_buffer[1][fl_selection_length[1]] = 0;
-way_out:
- if (strcmp(type, "text/uri-list") == 0) {
- fl_decode_uri(fl_selection_buffer[1]); // decode encoded bytes
- char *p = fl_selection_buffer[1];
- while (*p) { // remove prefixes
- if (strncmp(p, "file://", 7) == 0) {
- memmove(p, p+7, strlen(p+7)+1);
- }
- p = strchr(p, '\n');
- if (!p) break;
- if (*++p == 0) *(p-1) = 0; // remove last '\n'
- }
- fl_selection_length[1] = strlen(fl_selection_buffer[1]);
- }
- Fl::e_clipboard_type = Fl::clipboard_plain_text;
-}
-
-
-static struct wl_data_offer *current_drag_offer = NULL;
-static uint32_t fl_dnd_serial;
-
-
-static void data_device_handle_enter(void *data, struct wl_data_device *data_device,
- uint32_t serial, struct wl_surface *surface,
- wl_fixed_t x, wl_fixed_t y,
- struct wl_data_offer *offer) {
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(surface);
-//printf("Drag entered our surface %p(win=%p) at %dx%d\n", surface, win, wl_fixed_to_int(x), wl_fixed_to_int(y));
- if (win) {
- fl_dnd_target_surface = surface;
- float f = Fl::screen_scale(win->screen_num());
- Fl::e_x = wl_fixed_to_int(x) / f;
- Fl::e_y = wl_fixed_to_int(y) / f;
- while (win->parent()) {
- Fl::e_x += win->x();
- Fl::e_y += win->y();
- win = win->window();
- }
- fl_dnd_target_window = win;
- Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x();
- Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y();
- Fl::handle(FL_DND_ENTER, fl_dnd_target_window);
- current_drag_offer = offer;
- fl_dnd_serial = serial;
- } else fl_dnd_target_window = NULL; // we enter a non-FLTK window (titlebar, shade)
- uint32_t supported_actions = WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY;
- uint32_t preferred_action = supported_actions;
- wl_data_offer_set_actions(offer, supported_actions, preferred_action);
-}
-
-
-static void data_device_handle_motion(void *data, struct wl_data_device *data_device,
- uint32_t time, wl_fixed_t x, wl_fixed_t y) {
- if (!current_drag_offer) return;
-//printf("data_device_handle_motion fl_dnd_target_window=%p\n", fl_dnd_target_window);
- int ret = 0;
- if (fl_dnd_target_window) {
- float f = Fl::screen_scale(fl_dnd_target_window->screen_num());
- Fl_Window *win = Fl_Wayland_Window_Driver::surface_to_window(fl_dnd_target_surface);
- Fl::e_x = wl_fixed_to_int(x) / f;
- Fl::e_y = wl_fixed_to_int(y) / f;
- while (win->parent()) {
- Fl::e_x += win->x();
- Fl::e_y += win->y();
- win = win->window();
- }
- Fl::e_x_root = Fl::e_x + fl_dnd_target_window->x();
- Fl::e_y_root = Fl::e_y + fl_dnd_target_window->y();
- ret = Fl::handle(FL_DND_DRAG, fl_dnd_target_window);
- if (Fl::belowmouse()) Fl::belowmouse()->take_focus();
- }
- uint32_t supported_actions = ret && (Fl::pushed() || !doing_dnd) ?
- WL_DATA_DEVICE_MANAGER_DND_ACTION_COPY : WL_DATA_DEVICE_MANAGER_DND_ACTION_NONE;
- uint32_t preferred_action = supported_actions;
- wl_data_offer_set_actions(current_drag_offer, supported_actions, preferred_action);
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- if (ret && current_drag_offer) wl_data_offer_accept(current_drag_offer, fl_dnd_serial, "text/plain");
-}
-
-
-static void data_device_handle_leave(void *data, struct wl_data_device *data_device) {
- //printf("Drag left our surface\n");
- if (current_drag_offer) Fl::handle(FL_DND_LEAVE, fl_dnd_target_window);
-}
-
-
-static void data_device_handle_drop(void *data, struct wl_data_device *data_device) {
- if (!current_drag_offer) return;
- Fl::handle(FL_ENTER, fl_dnd_target_window); // useful to set the belowmouse widget
- int ret = Fl::handle(FL_DND_RELEASE, fl_dnd_target_window);
-//printf("data_device_handle_drop ret=%d doing_dnd=%d\n", ret, doing_dnd);
-
- if (!ret) {
- wl_data_offer_destroy(current_drag_offer);
- current_drag_offer = NULL;
- return;
- }
-
- if (doing_dnd) {
- Fl::e_text = fl_selection_buffer[0];
- Fl::e_length = fl_selection_length[0];
- } else {
- get_clipboard_or_dragged_text(current_drag_offer);
- Fl::e_text = fl_selection_buffer[1];
- Fl::e_length = fl_selection_length[1];
- }
- int old_event = Fl::e_number;
- Fl::belowmouse()->handle(Fl::e_number = FL_PASTE);
- Fl::e_number = old_event;
-
- wl_data_offer_finish(current_drag_offer);
- wl_data_offer_destroy(current_drag_offer);
- current_drag_offer = NULL;
-}
-
-
-static const struct wl_data_device_listener data_device_listener = {
- .data_offer = data_device_handle_data_offer,
- .enter = data_device_handle_enter,
- .leave = data_device_handle_leave,
- .motion = data_device_handle_motion,
- .drop = data_device_handle_drop,
- .selection = data_device_handle_selection,
-};
-
-
-const struct wl_data_device_listener *Fl_Wayland_Screen_Driver::p_data_device_listener =
- &data_device_listener;
-
-
-// Reads from the clipboard an image which can be in image/bmp or image/png MIME type.
-// Returns 0 if OK, != 0 if error.
-static int get_clipboard_image(struct wl_data_offer *offer) {
- int fds[2];
- if (pipe(fds)) return 1;
- // preferred mime-type for the image clipboard type
- const char *type = clipboard_kinds_map[Fl::clipboard_image].mime_type;
- wl_data_offer_receive(offer, type, fds[1]);
- close(fds[1]);
- wl_display_roundtrip(Fl_Wayland_Screen_Driver::wl_display);
- if (strcmp(type, "image/png") == 0) {
- char tmp_fname[21];
- Fl_Shared_Image *shared = 0;
- strcpy(tmp_fname, "/tmp/clipboardXXXXXX");
- int fd = mkstemp(tmp_fname);
- if (fd >= 0) {
- while (true) {
- char buf[10000];
- ssize_t n = read(fds[0], buf, sizeof(buf));
- if (n <= 0) break;
- n = write(fd, buf, n);
- }
- close(fd);
- shared = Fl_Shared_Image::get(tmp_fname);
- fl_unlink(tmp_fname);
- }
- close(fds[0]);
- if (!shared) return 1;
- int ld = shared->ld() ? shared->ld() : shared->w() * shared->d();
- uchar *rgb = new uchar[shared->w() * shared->h() * shared->d()];
- memcpy(rgb, shared->data()[0], ld * shared->h() );
- Fl_RGB_Image *image = new Fl_RGB_Image(rgb, shared->w(), shared->h(), shared->d(),
- shared->ld());
- shared->release();
- image->alloc_array = 1;
- Fl::e_clipboard_data = (void*)image;
- } else { // process image/bmp
- uchar buf[54];
- size_t rest = 1;
- char *bmp = NULL;
- ssize_t n = read(fds[0], buf, sizeof(buf)); // read size info of the BMP image
- if (n == sizeof(buf)) {
- int w, h; // size of the BMP image
- Fl_Unix_System_Driver::read_int(buf + 18, w);
- Fl_Unix_System_Driver::read_int(buf + 22, h);
- // the number of bytes per row of BMP image, rounded up to multiple of 4
- int R = ((3*w+3)/4) * 4;
- bmp = new char[R * h + 54];
- memcpy(bmp, buf, 54);
- char *from = bmp + 54;
- rest = R * h;
- while (rest) {
- ssize_t n = read(fds[0], from, rest);
- if (n <= 0) break;
- from += n;
- rest -= n;
- }
-//fprintf(stderr, "get_clipboard_image: image/bmp %dx%d rest=%lu\n", w,h,rest);
- }
- close(fds[0]);
- if (!rest) Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(bmp);
- delete[] bmp;
- if (rest) return 1;
- }
- Fl::e_clipboard_type = Fl::clipboard_image;
- return 0;
-}
-
-
-void Fl_Wayland_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) {
- if (clipboard != 1) return;
- if (fl_i_own_selection[1]) {
- // We already have it, do it quickly without compositor.
- if (type == Fl::clipboard_plain_text && fl_selection_type[1] == type) {
- Fl::e_text = fl_selection_buffer[1];
- Fl::e_length = fl_selection_length[1];
- if (!Fl::e_text) Fl::e_text = (char *)"";
- } else if (type == Fl::clipboard_image && fl_selection_type[1] == type) {
- Fl::e_clipboard_data = Fl_Unix_System_Driver::own_bmp_to_RGB(fl_selection_buffer[1]);
- Fl::e_clipboard_type = Fl::clipboard_image;
- } else return;
- receiver.handle(FL_PASTE);
- return;
- }
- // otherwise get the compositor to return it:
- if (!fl_selection_offer) return;
- if (type == Fl::clipboard_plain_text && clipboard_contains(Fl::clipboard_plain_text)) {
- get_clipboard_or_dragged_text(fl_selection_offer);
- Fl::e_text = fl_selection_buffer[1];
- Fl::e_length = fl_selection_length[1];
- receiver.handle(FL_PASTE);
- } else if (type == Fl::clipboard_image && clipboard_contains(Fl::clipboard_image)) {
- if (get_clipboard_image(fl_selection_offer)) return;
- struct wld_window * xid = fl_wl_xid(receiver.top_window());
- if (xid) {
- int s = Fl_Wayland_Window_Driver::driver(receiver.top_window())->wld_scale();
- if ( s > 1) {
- Fl_RGB_Image *rgb = (Fl_RGB_Image*)Fl::e_clipboard_data;
- rgb->scale(rgb->data_w() / s, rgb->data_h() / s);
- }
- }
- int done = receiver.handle(FL_PASTE);
- Fl::e_clipboard_type = "";
- if (done == 0) {
- delete (Fl_RGB_Image*)Fl::e_clipboard_data;
- Fl::e_clipboard_data = NULL;
- }
- }
-}
-
-
-void Fl_Wayland_Screen_Driver::copy(const char *stuff, int len, int clipboard,
- const char *type) {
- if (!stuff || len < 0) return;
-
- if (clipboard >= 2)
- clipboard = 1; // Only on X11 do multiple clipboards make sense.
-
- if (len+1 > fl_selection_buffer_length[clipboard]) {
- delete[] fl_selection_buffer[clipboard];
- fl_selection_buffer[clipboard] = new char[len+100];
- fl_selection_buffer_length[clipboard] = len+100;
- }
- memcpy(fl_selection_buffer[clipboard], stuff, len);
- fl_selection_buffer[clipboard][len] = 0; // needed for direct paste
- fl_selection_length[clipboard] = len;
- fl_i_own_selection[clipboard] = 1;
- fl_selection_type[clipboard] = Fl::clipboard_plain_text;
- if (clipboard == 1) {
- if (seat->data_source) wl_data_source_destroy(seat->data_source);
- seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager);
- // we transmit the adequate value of index in fl_selection_buffer[index]
- wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1);
- wl_data_source_offer(seat->data_source, wld_plain_text_clipboard);
- wl_data_device_set_selection(seat->data_device,
- seat->data_source,
- seat->keyboard_enter_serial);
-//fprintf(stderr, "wl_data_device_set_selection len=%d to %d\n", len, clipboard);
- }
-}
-
-
-// takes a raw RGB image and puts it in the copy/paste buffer
-void Fl_Wayland_Screen_Driver::copy_image(const unsigned char *data, int W, int H){
- if (!data || W <= 0 || H <= 0) return;
- delete[] fl_selection_buffer[1];
- fl_selection_buffer[1] =
- (char *)Fl_Unix_System_Driver::create_bmp(data,W,H,&fl_selection_length[1]);
- fl_selection_buffer_length[1] = fl_selection_length[1];
- fl_i_own_selection[1] = 1;
- fl_selection_type[1] = Fl::clipboard_image;
- if (seat->data_source) wl_data_source_destroy(seat->data_source);
- seat->data_source = wl_data_device_manager_create_data_source(seat->data_device_manager);
- // we transmit the adequate value of index in fl_selection_buffer[index]
- wl_data_source_add_listener(seat->data_source, &data_source_listener, (void*)1);
- wl_data_source_offer(seat->data_source, "image/bmp");
- wl_data_device_set_selection(seat->data_device, seat->data_source,
- seat->keyboard_enter_serial);
-//fprintf(stderr, "copy_image: len=%d\n", fl_selection_length[1]);
-}
-
-////////////////////////////////////////////////////////////////
-// Code for tracking clipboard changes:
-
-// is that possible with Wayland ?
-
-////////////////////////////////////////////////////////////////
-
-#endif // !defined(FL_DOXYGEN)
diff --git a/src/drivers/Wayland/fl_wayland_platform_init.cxx b/src/drivers/Wayland/fl_wayland_platform_init.cxx
deleted file mode 100644
index 4c4477740..000000000
--- a/src/drivers/Wayland/fl_wayland_platform_init.cxx
+++ /dev/null
@@ -1,157 +0,0 @@
-//
-// Wayland-specific code to initialize wayland support.
-//
-// Copyright 2022-2023 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/fl_config.h>
-#include "Fl_Wayland_Copy_Surface_Driver.H"
-#include "Fl_Wayland_Graphics_Driver.H"
-#include "Fl_Wayland_Screen_Driver.H"
-#include "../Unix/Fl_Unix_System_Driver.H"
-#include "Fl_Wayland_Window_Driver.H"
-#include "Fl_Wayland_Image_Surface_Driver.H"
-#include "../Base/Fl_Base_Pen_Events.H"
-#ifdef FLTK_USE_X11
-# include "../Xlib/Fl_Xlib_Copy_Surface_Driver.H"
-# include "../Cairo/Fl_X11_Cairo_Graphics_Driver.H"
-# include "../X11/Fl_X11_Screen_Driver.H"
-# include "../X11/Fl_X11_Window_Driver.H"
-# include "../Xlib/Fl_Xlib_Image_Surface_Driver.H"
-#endif
-#include <string.h>
-#include <stdlib.h>
-#include <stdio.h>
-
-
-#ifdef FLTK_USE_X11
-
-static bool attempt_wayland() {
- if (Fl_Wayland_Screen_Driver::wl_display) return true;
- static bool first = true;
- static bool disable_wl = false;
- if (first) { // get the value if it exists and cache it
- void *sym = Fl_Posix_System_Driver::dlopen_or_dlsym(NULL, "fl_disable_wayland");
- if (sym) {
- disable_wl = *(bool *)sym;
- // printf("fl_disable_wayland = %s\n", disable_wl ? "true" : "false");
- }
- first = false;
- }
- if (disable_wl)
- return false;
- const char *backend = ::getenv("FLTK_BACKEND");
- // fprintf(stderr, "FLTK_BACKEND='%s'\n", backend ? backend : "");
- if (backend && strcmp(backend, "x11") == 0) {
- return false;
- }
-
- if (backend && strcmp(backend, "wayland") == 0) {
- Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL);
- if (!Fl_Wayland_Screen_Driver::wl_display) {
- fprintf(stderr, "Error: no Wayland connection available, FLTK_BACKEND='wayland'\n");
- exit(1);
- }
- return true;
- }
-
- if (!backend) {
- // env var XDG_RUNTIME_DIR is required for Wayland
- const char *xdgrt = ::getenv("XDG_RUNTIME_DIR");
- if (xdgrt) {
- // is a Wayland connection available ?
- Fl_Wayland_Screen_Driver::wl_display = wl_display_connect(NULL);
- if (Fl_Wayland_Screen_Driver::wl_display) { // Yes, use Wayland drivers
- // puts("using wayland");
- return true;
- }
- }
- // no Wayland connection or environment variable XDG_RUNTIME_DIR not set,
- // falling back to X11
- return false;
- }
-
- fprintf(stderr, "Error: unexpected value of FLTK_BACKEND: '%s'\n", backend);
- exit(1);
- return false;
-}
-
-#endif // FLTK_USE_X11
-
-
-Fl_System_Driver *Fl_System_Driver::newSystemDriver() {
- return new Fl_Unix_System_Driver();
-}
-
-
-Fl_Graphics_Driver *Fl_Graphics_Driver::newMainGraphicsDriver() {
-#ifdef FLTK_USE_X11
- if (!attempt_wayland()) return new Fl_X11_Cairo_Graphics_Driver();
-#endif
- return new Fl_Wayland_Graphics_Driver();
-}
-
-
-Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h) {
-#ifdef FLTK_USE_X11
- if (!Fl_Wayland_Screen_Driver::wl_display) return new Fl_Xlib_Copy_Surface_Driver(w, h);
-#endif
- return new Fl_Wayland_Copy_Surface_Driver(w, h);
-}
-
-
-Fl_Screen_Driver *Fl_Screen_Driver::newScreenDriver() {
- if (!Fl_Screen_Driver::system_driver) Fl::system_driver();
-#ifdef FLTK_USE_X11
- if (attempt_wayland()) {
- return new Fl_Wayland_Screen_Driver();
- }
-
- Fl_X11_Screen_Driver *d = new Fl_X11_Screen_Driver();
- for (int i = 0; i < MAX_SCREENS; i++) d->screens[i].scale = 1;
- d->current_xft_dpi = 0.; // means the value of the Xft.dpi resource is still unknown
- return d;
-#else
- return new Fl_Wayland_Screen_Driver();
-#endif
-}
-
-
-Fl_Window_Driver *Fl_Window_Driver::newWindowDriver(Fl_Window *w)
-{
-#ifdef FLTK_USE_X11
- if (!attempt_wayland()) return new Fl_X11_Window_Driver(w);
-#endif
- return new Fl_Wayland_Window_Driver(w);
-}
-
-
-Fl_Image_Surface_Driver *Fl_Image_Surface_Driver::newImageSurfaceDriver(int w, int h, int high_res, Fl_Offscreen off)
-{
-#ifdef FLTK_USE_X11
- if (!attempt_wayland())
- return new Fl_Xlib_Image_Surface_Driver(w, h, high_res, off);
-#endif
- return new Fl_Wayland_Image_Surface_Driver(w, h, high_res, off);
-}
-
-#if defined(FLTK_HAVE_PEN_SUPPORT)
-
-namespace Fl {
-namespace Pen {
-Driver default_driver;
-Driver& driver = default_driver;
-} // namespace Pen
-} // namespace Fl
-
-#endif // FLTK_HAVE_PEN_SUPPORT