Add the Wayland platform to FLTK 1.4

This commit is contained in:
ManoloFLTK
2022-03-04 15:40:29 +01:00
parent a773fdc44b
commit 3718effc43
61 changed files with 18951 additions and 897 deletions

View File

@@ -1,4 +1,4 @@
Changes in FLTK 1.4.0 Released: ??? ?? 2021
Changes in FLTK 1.4.0 Released: ??? ?? 2022
General Information about this Release
@@ -17,6 +17,8 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2021
New Features and Extensions
- FLTK 1.4 introduces a new platform, Wayland, available for recent Unix
distributions. More information in README.Wayland.txt
- Windows platform: added support for using a manifest to set the
application's level of DPI awareness (issue #309).
- X11 platform: class Fl_Native_File_Chooser will run the KDE file dialog
@@ -121,6 +123,8 @@ Changes in FLTK 1.4.0 Released: ??? ?? 2021
New Configuration Options (ABI Version)
- Configure option --enable-wayland allows to build the FLTK library for
the new Wayland platform. The corresponding CMake option is OPTION_USE_WAYLAND.
- The new configure option --disable-gdiplus removes the possibility to draw
antialiased lines and curves on the Windows platform. The corresponding CMake
option is OPTION_USE_GDIPLUS.

View File

@@ -50,6 +50,24 @@ set (FL_ABI_VERSION ${OPTION_ABI_VERSION})
if (UNIX)
option (OPTION_CREATE_LINKS "create backwards compatibility links" OFF)
list (APPEND FLTK_LDLIBS -lm)
option (OPTION_USE_WAYLAND "use Wayland" OFF)
if (OPTION_USE_WAYLAND)
set (FLTK_USE_WAYLAND 1)
option (OPTION_USE_SYSTEM_LIBDECOR "use libdecor from the system" OFF)
unset (OPTION_USE_XRENDER CACHE)
unset (OPTION_USE_XINERAMA CACHE)
unset (OPTION_USE_XFT CACHE)
unset (OPTION_USE_XCURSOR CACHE)
unset (OPTION_USE_XFIXES CACHE)
unset (OPTION_USE_PANGO CACHE)
set (OPTION_USE_PANGO TRUE CACHE BOOL "use lib Pango")
if (OPTION_USE_SYSTEM_LIBDECOR)
pkg_check_modules(SYSTEM_LIBDECOR libdecor-0)
if (NOT SYSTEM_LIBDECOR_FOUND)
set (OPTION_USE_SYSTEM_LIBDECOR OFF)
endif (NOT SYSTEM_LIBDECOR_FOUND)
endif (OPTION_USE_SYSTEM_LIBDECOR)
endif (OPTION_USE_WAYLAND)
endif (UNIX)
if (WIN32)
@@ -72,7 +90,7 @@ endif (APPLE)
# find X11 libraries and headers
set (PATH_TO_XLIBS)
if ((NOT APPLE OR OPTION_APPLE_X11) AND NOT WIN32)
if ((NOT APPLE OR OPTION_APPLE_X11) AND NOT WIN32 AND NOT OPTION_USE_WAYLAND)
include (FindX11)
if (X11_FOUND)
set (FLTK_USE_X11 1)
@@ -82,7 +100,7 @@ if ((NOT APPLE OR OPTION_APPLE_X11) AND NOT WIN32)
endif (X11_Xext_FOUND)
get_filename_component (PATH_TO_XLIBS ${X11_X11_LIB} PATH)
endif (X11_FOUND)
endif ((NOT APPLE OR OPTION_APPLE_X11) AND NOT WIN32)
endif ((NOT APPLE OR OPTION_APPLE_X11) AND NOT WIN32 AND NOT OPTION_USE_WAYLAND)
if (OPTION_APPLE_X11)
if (NOT(${CMAKE_SYSTEM_VERSION} VERSION_LESS 17.0.0)) # a.k.a. macOS version ≥ 10.13
@@ -252,6 +270,8 @@ if (OPENGL_FOUND)
set (GLLIBS "-lglu32 -lopengl32")
elseif (APPLE AND NOT OPTION_APPLE_X11)
set (GLLIBS "-framework OpenGL")
elseif (OPTION_USE_WAYLAND)
set (GLLIBS "-lwayland-egl -lEGL -lGLU -lGL")
else ()
set (GLLIBS "-lGLU -lGL")
endif (WIN32)
@@ -481,7 +501,7 @@ if (X11_Xft_FOUND)
endif (X11_Xft_FOUND)
# test option compatibility: Pango requires Xft
if (OPTION_USE_PANGO)
if (OPTION_USE_PANGO AND NOT OPTION_USE_WAYLAND)
if (NOT X11_Xft_FOUND)
message (STATUS "Pango requires Xft but Xft library or headers could not be found.")
message (STATUS "Please install Xft development files and try again or disable OPTION_USE_PANGO.")
@@ -493,10 +513,10 @@ if (OPTION_USE_PANGO)
message (FATAL_ERROR "*** Aborting ***")
endif (NOT OPTION_USE_XFT)
endif (NOT X11_Xft_FOUND)
endif (OPTION_USE_PANGO)
endif (OPTION_USE_PANGO AND NOT OPTION_USE_WAYLAND)
#######################################################################
if (X11_Xft_FOUND AND OPTION_USE_PANGO)
if ((X11_Xft_FOUND OR OPTION_USE_WAYLAND) AND OPTION_USE_PANGO)
pkg_check_modules(PANGOXFT pangoxft)
pkg_check_modules(PANGOCAIRO pangocairo)
pkg_check_modules(CAIRO cairo)
@@ -553,7 +573,15 @@ if (X11_Xft_FOUND AND OPTION_USE_PANGO)
list (APPEND FLTK_LDLIBS -lpango-1.0 -lpangoxft-1.0 -lgobject-2.0)
endif (HAVE_LIB_PANGO AND HAVE_LIB_PANGOXFT AND HAVE_LIB_GOBJECT)
endif (PANGOXFT_FOUND AND PANGOCAIRO_FOUND AND CAIRO_FOUND)
endif (X11_Xft_FOUND AND OPTION_USE_PANGO)
endif ((X11_Xft_FOUND OR OPTION_USE_WAYLAND) AND OPTION_USE_PANGO)
if (OPTION_USE_WAYLAND AND NOT OPTION_USE_SYSTEM_LIBDECOR)
pkg_check_modules(GTK gtk+-3.0)
#set (GTK_FOUND 0) #use this to get cairo titlebars rather than GTK
if (GTK_FOUND)
include_directories (${GTK_INCLUDE_DIRS})
endif (GTK_FOUND)
endif (OPTION_USE_WAYLAND AND NOT OPTION_USE_SYSTEM_LIBDECOR)
if (OPTION_USE_XFT)
set (USE_XFT X11_Xft_FOUND)

View File

@@ -43,6 +43,11 @@ if (WIN32)
list (APPEND FLTK_LDLIBS -lole32 -luuid -lcomctl32 -lws2_32)
elseif (APPLE AND NOT OPTION_APPLE_X11)
list (APPEND FLTK_LDLIBS "-framework Cocoa")
elseif (OPTION_USE_WAYLAND)
list (APPEND FLTK_LDLIBS "-lwayland-cursor -lwayland-client -lxkbcommon -ldbus-1")
if (OPTION_USE_SYSTEM_LIBDECOR)
list (APPEND FLTK_LDLIBS "-ldecor-0")
endif (OPTION_USE_SYSTEM_LIBDECOR)
else ()
list (APPEND FLTK_LDLIBS -lm)
endif (WIN32)

View File

@@ -37,6 +37,8 @@ class Fl_Window;
# include "win32.H"
# elif defined(__APPLE__)
# include "mac.H"
# elif defined(FLTK_USE_WAYLAND)
# include "wayland.H"
# elif defined(FLTK_USE_X11)
# include "x11.H"
# endif // _WIN32

View File

@@ -1,5 +1,5 @@
/*
* Copyright 2016-2018 by Bill Spitzak and others.
* Copyright 2016-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
@@ -116,6 +116,17 @@ typedef struct HGLRC__ *GLContext;
struct dirent {char d_name[1];};
#endif
#elif defined(FLTK_USE_WAYLAND)
typedef struct fl_wld_buffer *Fl_Offscreen; /**< an offscreen drawing buffer */
typedef struct _cairo_pattern* Fl_Bitmask;
typedef struct flWaylandRegion* Fl_Region;
typedef int FL_SOCKET; /**< socket or file descriptor */
typedef void *EGLContext;
typedef EGLContext GLContext;
#include <sys/stat.h>
#include <sys/types.h>
#include <dirent.h>
#elif defined(FLTK_USE_X11)
typedef unsigned long Fl_Offscreen;

31
FL/wayland.H Executable file
View File

@@ -0,0 +1,31 @@
//
// Wayland platform header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 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_PLATFORM_H)
# error "Never use <FL/wayland.H> directly; include <FL/platform.H> instead."
#endif // !FL_PLATFORM_H
typedef struct wld_window *Window;
extern struct wl_display *fl_display;
struct flWaylandRegion {
int count;
struct _cairo_rectangle *rects;
}; // a region is the union of a series of rectangles
#include <stdint.h>
extern FL_EXPORT uint32_t fl_event_time;

141
README.Wayland.txt Normal file
View File

@@ -0,0 +1,141 @@
README.Wayland.txt - Wayland platform support for FLTK
------------------------------------------------------
CONTENTS
========
1 INTRODUCTION
2 WAYLAND SUPPORT FOR FLTK
2.1 Configuration
2.2 Known limitations
3 PLATFORM SPECIFIC NOTES
3.1 Debian and Derivatives (like Ubuntu)
1 INTRODUCTION
==============
Version 1.4 of the FLTK library introduces support of the public FLTK API on
the Wayland platform. It requires a Wayland-equipped OS which means Linux.
Pre-existing platform-independent source code for FLTK 1.3.x should build and
run unchanged with FLTK 1.4 and the Wayland platform.
The code has been tested on Debian and Ubuntu with 3 distinct Wayland compositors:
mutter (Debian's compositor), weston, and KDE.
CJK text-input methods, as well as dead and compose keys are supported.
2 WAYLAND SUPPORT FOR FLTK
==========================
It is possible to have your FLTK application do all its windowing and drawing
through the Wayland protocol on Linux systems. All graphics is done via Cairo or EGL.
All text-drawing is done via Pango.
2.1 Configuration
---------------
* Configure-based build can be performed as follows:
Once after "git clone", create the configure file :
autoconf -f
Prepare build with :
./configure --enable-wayland [--enable-shared]
Build with :
make
* CMake-based build can be performed as follows:
cmake -S <path-to-source> -B <path-to-build> -DCMAKE_BUILD_TYPE=Release -DOPTION_USE_WAYLAND=1
cd <path-to-build>; make
The FLTK wayland platform uses a library called libdecor which handles window decorations
(i.e., titlebars, shade). Libdecor is bundled in the FLTK source code and FLTK uses by default
this form of libdecor. Optionally, OPTION_USE_SYSTEM_LIBDECOR can be turned on to have FLTK
use the system's version of libdecor which is available on recent Linux distributions (e.g.,
Debian bookworm or more recent in packages libdecor-0-0 and libdecor-0-plugin-1-cairo).
2.2 Known limitations
-------------------------------
* A deliberate design trait of Wayland makes application windows ignorant of their exact
placement on screen. It's possible, though, to position a popup window relatively to another
window. This allows FLTK to properly position menu and tooltip windows. But Fl_Window::position()
has no effect on other top-level windows.
* With Wayland, there is no way to know if a window is currently minimized, nor is there any
way to programmatically unset minimization of a window. Consequently, Fl_Window::show() of
a minimized window has no effect.
* With GTK-style window titlebars, the minimum width of a window is currently set at 134 pixels.
* The library should support multi-display configurations in principle, but has not been
tested in that situation.
* Text input methods have been tested without any understanding of the writing systems,
so feedback on this subject would be helpful.
* While platform-independent source code prepared for FLTK 1.3 is expected to be compatible
with FLTK 1.4 and the Wayland platform, X11-specific code will not compile. In particular,
the common FLTK 1.3 construct :
#ifdef __APPLE__
*** macOS-specific code ***
#elif defined(_WIN32)
*** Windows-specific code ***
#else
*** X11-specific code ***
#endif
will choke at compile time because it exposes X11-specific code to the non-X11, Wayland
environment. This should be written instead :
#include <FL/fl_config.h>
#ifdef __APPLE__
*** macOS-specific code ***
#elif defined(_WIN32)
*** Windows-specific code ***
#elif defined(FLTK_USE_X11)
*** X11-specific code ***
#endif
Moreover, the new FLTK_USE_WAYLAND preprocessor variable is available to bracket
Wayland-specific source code.
3 PLATFORM SPECIFIC NOTES
=========================
The following are notes about building FLTK for the Wayland platform
on the various supported Linux distributions.
3.1 Debian and Derivatives (like Ubuntu)
----------------------------------------
Under Debian, the Wayland platform requires version 11 (a.k.a. Bullseye) or more recent.
Under Ubuntu, the Wayland platform is known to work with version 20.04 (focal fossa) or more recent.
These packages are necessary to build the FLTK library, in addition to those present
in a basic Debian/Ubuntu distribution :
- g++
- gdb
- make
- git
- autoconf
- libglu1-mesa-dev
- libpango1.0-dev
- libwayland-dev
- wayland-protocols
- libdbus-1-dev
- libxkbcommon-dev
- libgtk-3-dev <== with this, windows get a GTK-style titlebar
- libglew-dev <== necessary to use OpenGL version 3 or above
- cmake <== if you plan to build with CMake
- cmake-qt-gui <== if you plan to use the GUI of CMake
These further packages are necessary to run FLTK apps under the Gnome-Wayland desktop:
- gnome
- gnome-session-wayland
These packages allow to run FLTK apps under the KDE/Plasma-Wayland desktop:
- kde-plasma-desktop
- plasma-workspace-wayland

View File

@@ -1,7 +1,7 @@
//
// Main header file for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
// 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
@@ -30,6 +30,9 @@
# include <cairo-win32.h>
#elif defined(__APPLE_QUARTZ__) // macOS
# include <cairo-quartz.h>
#elif defined(FLTK_USE_WAYLAND)
# include "../src/drivers/Wayland/Fl_Wayland_Graphics_Driver.H"
# include "../src/drivers/Wayland/Fl_Wayland_Window_Driver.H"
#else
# error Cairo is not supported on this platform.
#endif
@@ -69,7 +72,13 @@ void Fl_Cairo_State::autolink(bool b) {
*/
cairo_t * Fl::cairo_make_current(Fl_Window* wi) {
if (!wi) return NULL; // Precondition
cairo_t * cairo_ctxt;
#if defined(FLTK_USE_WAYLAND)
Window xid = fl_xid(wi);
if (!xid->buffer) return NULL; // this may happen with GL windows
cairo_ctxt = xid->buffer->cairo_;
cairo_state_.cc(cairo_ctxt, false);
#else // FLTK_USE_WAYLAND
if (fl_gc==0) { // means remove current cc
Fl::cairo_cc(0); // destroy any previous cc
cairo_state_.window(0);
@@ -82,7 +91,6 @@ cairo_t * Fl::cairo_make_current(Fl_Window* wi) {
cairo_state_.window(wi);
cairo_t * cairo_ctxt;
#ifndef __APPLE__
float scale = Fl::screen_scale(wi->screen_num()); // get the screen scaling factor
#endif
@@ -95,9 +103,11 @@ cairo_t * Fl::cairo_make_current(Fl_Window* wi) {
#ifndef __APPLE__
cairo_scale(cairo_ctxt, scale, scale);
#endif
#endif // FLTK_USE_WAYLAND
return cairo_ctxt;
}
#if !defined(FLTK_USE_WAYLAND)
/*
Creates transparently a cairo_surface_t object.
gc is an HDC context in Windows, a CGContext* in Quartz, and
@@ -176,6 +186,9 @@ cairo_t * Fl::cairo_make_current(void *gc, int W, int H) {
cairo_surface_destroy(s);
return c;
}
#endif // !FLTK_USE_WAYLAND
#else
// just don't leave the libfltk_cairo lib empty to avoid warnings
#include <FL/Fl_Export.H>

View File

@@ -3,7 +3,7 @@ dnl the "configure" script is made from this by running GNU "autoconf"
dnl
dnl Configuration script for the Fast Light Tool Kit (FLTK).
dnl
dnl Copyright 1998-2021 by Bill Spitzak and others.
dnl Copyright 1998-2022 by Bill Spitzak and others.
dnl
dnl This library is free software. Distribution and use rights are outlined in
dnl the file "COPYING" which should have been included with this file. If this
@@ -110,6 +110,8 @@ AC_ARG_ENABLE([localzlib], AS_HELP_STRING([--enable-localzlib], [use local ZLIB
AC_ARG_ENABLE([pango], AS_HELP_STRING([--enable-pango], [turn on Pango support]))
AC_ARG_ENABLE([wayland], AS_HELP_STRING([--enable-wayland], [turn on Wayland support]))
AC_ARG_ENABLE([print], AS_HELP_STRING([--disable-print], [turn off print support (X11)]))
AS_IF([test x$enable_print = xno], [
AC_DEFINE([FL_NO_PRINT_SUPPORT], [Disable X11 print support?])
@@ -897,6 +899,7 @@ dnl Define OS-specific stuff...
HLINKS=
OSX_ONLY=:
THREADS=
LIBDECORDIR=""
AC_ARG_WITH([links], AS_HELP_STRING([--with-links], [make header links for common misspellings (default=no)]))
@@ -995,6 +998,64 @@ AS_CASE([$host_os_gui], [cygwin* | mingw*], [
THREADS="threads$EXEEXT"
])
AS_IF([test x$enable_wayland = xyes], [
dnl Prepare for Wayland...
AS_IF([test x$PKGCONFIG = x], [
dnl pkg-config is not available, issue warning and abort...
AC_MSG_WARN([--enable-wayland: please install pkg-config.])
AC_MSG_ERROR([Aborting.])
])
BUILD="WAYLAND"
AC_DEFINE([FLTK_USE_WAYLAND])
CFLAGS="$CFLAGS -DUSE_SYSTEM_LIBDECOR=0"
CXXFLAGS="$CXXFLAGS -DUSE_SYSTEM_LIBDECOR=0"
graphics="Wayland"
LIBS="$LIBS $($PKGCONFIG --libs wayland-cursor) $($PKGCONFIG --libs wayland-client) $($PKGCONFIG --libs xkbcommon)"
LIBS="$LIBS $($PKGCONFIG --libs dbus-1) -ldl"
CXXFLAGS="$CXXFLAGS -I../libdecor/src"
DSOFLAGS="$LIBS $DSOFLAGS"
enable_pango=yes
LIBDECORDIR="libdecor/build"
LDFLAGS="$LDFLAGS -rdynamic -no-pie"
AC_SEARCH_LIBS([dlopen], [dl])
AC_CHECK_HEADER([GL/gl.h], [AC_DEFINE([HAVE_GL])])
AC_CHECK_HEADER([GL/glu.h], [
AC_DEFINE([HAVE_GL_GLU_H])
GLLIBS="$($PKGCONFIG --libs wayland-egl) $($PKGCONFIG --libs egl) $($PKGCONFIG --libs glu) $GLLIBS"
])
dnl Check for GTK-3 ...
gtk_found=no
CFLAGS="$($PKGCONFIG --cflags gtk+-3.0) $CFLAGS"
AC_CHECK_HEADERS([gtk/gtk.h], [
CFLAGS="$CFLAGS -DHAVE_GTK"
LIBS="$LIBS $($PKGCONFIG --libs gtk+-3.0)"
gtk_found=yes
])
dnl Check for the Pango library ...
pango_found=no
CFLAGS="$($PKGCONFIG --cflags pangocairo) $CFLAGS"
CXXFLAGS="$($PKGCONFIG --cflags pangocairo) $CXXFLAGS"
LIBS="$LIBS $($PKGCONFIG --libs pangocairo)"
AC_CHECK_HEADERS([pango/pangocairo.h], [
AC_DEFINE([USE_PANGO])
AC_DEFINE([USE_XFT])
pango_found=yes
])
dnl Early abort if Pango could not be found
AS_IF([test x$pango_found != xyes], [
AC_MSG_NOTICE([--enable-wayland: Pango libs and/or headers could not be found.])
AC_MSG_ERROR([Aborting.])
])
], [
dnl Check for X11...
AC_PATH_XTRA
@@ -1016,7 +1077,7 @@ AS_CASE([$host_os_gui], [cygwin* | mingw*], [
AS_IF([test "x$x_includes" != x], [
ac_cpp="$ac_cpp -I$x_includes"
])
])
dnl Check for OpenGL unless disabled...
GLLIBS=
@@ -1217,6 +1278,8 @@ AC_SUBST([HLINKS])
AC_SUBST([OSX_ONLY])
AC_SUBST([THREADS])
AC_SUBST([LIBDECORDIR])
AC_SUBST([INSTALL_DESKTOP])
AC_SUBST([UNINSTALL_DESKTOP])
@@ -1344,17 +1407,21 @@ AS_IF([test -n "$GCC"], [
[AC_MSG_RESULT(no)])
CFLAGS="$OLDCFLAGS"
dnl Make sure that shared libraries don't have undefined references
# See if ld supports -no-undefined...
AC_MSG_CHECKING([if ld supports -no-undefined])
OLDLDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -Wl,-no-undefined"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[]], [[]])],
[DSOFLAGS="$DSOFLAGS -Wl,-no-undefined"
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
LDFLAGS="$OLDLDFLAGS"
AS_IF([test x$enable_wayland = xyes],[
DSOFLAGS="$DSOFLAGS -Wl,--allow-shlib-undefined"
] , [
dnl Make sure that shared libraries don't have undefined references
# See if ld supports -no-undefined...
AC_MSG_CHECKING([if ld supports -no-undefined])
OLDLDFLAGS="$LDFLAGS"
LDFLAGS="$LDFLAGS -Wl,-no-undefined"
AC_LINK_IFELSE(
[AC_LANG_PROGRAM([[]], [[]])],
[DSOFLAGS="$DSOFLAGS -Wl,-no-undefined"
AC_MSG_RESULT(yes)],
[AC_MSG_RESULT(no)])
LDFLAGS="$OLDLDFLAGS"
])
# See if ld supports -Bsymbolic-functions...
AC_MSG_CHECKING([if ld supports -Bsymbolic-functions])
@@ -1529,7 +1596,9 @@ AS_CASE([$host_os_gui], [cygwin* | mingw*], [
], [darwin*], [
graphics="Quartz"
], [*], [
graphics="X11"
AS_IF([test x$enable_wayland != xyes], [
graphics="X11"
])
AS_IF([test x$xft_found = xyes], [
graphics="$graphics + Xft"
])

View File

@@ -1,7 +1,7 @@
//
// Tiny OpenGL v3 + glut demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 by Bill Spitzak and others.
// 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
@@ -14,6 +14,7 @@
// https://www.fltk.org/bugs.php
//
#include <FL/Fl.H> // includes <FL/fl_config.h>
#if defined(__APPLE__)
# define GL_DO_NOT_WARN_IF_MULTI_GL_VERSION_HEADERS_INCLUDED 1
# include <OpenGL/gl3.h> // defines OpenGL 3.0+ functions
@@ -198,7 +199,10 @@ int main (int argc, char* argv[])
glutCreateWindow("Triangle Test");
#ifndef __APPLE__
GLenum err = glewInit(); // defines pters to functions of OpenGL V 1.2 and above
if (err) Fl::error("glewInit() failed returning %u", err);
#ifdef FLTK_USE_WAYLAND
if (err == GLEW_ERROR_NO_GLX_DISPLAY) err = GLEW_OK;
#endif
if (err != GLEW_OK) Fl::error("glewInit() failed returning %u", err);
fprintf(stderr, "Status: Using GLEW %s\n", glewGetString(GLEW_VERSION));
#endif
int gl_version_major;

View File

@@ -1,7 +1,7 @@
//
// Tiny OpenGL v3 demo program for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2018 by Bill Spitzak and others.
// 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
@@ -146,6 +146,11 @@ public:
make_current();
#ifndef __APPLE__
GLenum err = glewInit(); // defines pters to functions of OpenGL V 1.2 and above
# ifdef FLTK_USE_WAYLAND
// glewInit returns GLEW_ERROR_NO_GLX_DISPLAY with Wayland
// see https://github.com/nigels-com/glew/issues/273
if (err == GLEW_ERROR_NO_GLX_DISPLAY) err = GLEW_OK;
# endif
if (err) Fl::warning("glewInit() failed returning %u", err);
else add_output("Using GLEW %s\n", glewGetString(GLEW_VERSION));
#endif

View File

@@ -55,4 +55,14 @@
#cmakedefine FLTK_USE_X11 1
/*
* FLTK_USE_WAYLAND
*
* Do we use Wayland for the current platform?
*
*/
#cmakedefine FLTK_USE_WAYLAND 1
#endif /* _FL_fl_config_h_ */

View File

@@ -54,4 +54,14 @@
#undef FLTK_USE_X11
/*
* FLTK_USE_WAYLAND
*
* Do we use Wayland for the current platform?
*
*/
#undef FLTK_USE_WAYLAND
#endif /* _FL_fl_config_h_ */

19
libdecor/LICENSE Normal file
View File

@@ -0,0 +1,19 @@
MIT License
Permission is hereby granted, free of charge, to any person obtaining a copy
of this software and associated documentation files (the "Software"), to deal
in the Software without restriction, including without limitation the rights
to use, copy, modify, merge, publish, distribute, sublicense, and/or sell
copies of the Software, and to permit persons to whom the Software is
furnished to do so, subject to the following conditions:
The above copyright notice and this permission notice shall be included in all
copies or substantial portions of the Software.
THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR
IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY,
FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE
AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER
LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM,
OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
SOFTWARE.

86
libdecor/README.md Normal file
View File

@@ -0,0 +1,86 @@
# libdecor - A client-side decorations library for Wayland client
libdecor is a library that can help Wayland clients draw window
decorations for them. It aims to provide multiple backends that implements the
decoration drawing.
## Dependencies
Required:
- `meson` >= 0.47
- `ninja`
- `wayland-client` >= 1.18
- `wayland-protocols` >= 1.15
- `wayland-cursor`
- `cairo`
- `pangocairo`
Recommended:
- `dbus-1` (to query current cursor theme)
Optional
- `egl` (to build EGL example)
- `opengl`
- `xkbcommon` (to build cairo demo)
Install via apt:
`sudo apt install meson libwayland-dev wayland-protocols libpango1.0-dev libdbus-1-dev libegl-dev libopengl-dev libxkbcommon-dev`
Install via dnf:
`sudo dnf install meson wayland-devel wayland-protocols-devel pango-devel dbus-devel mesa-libEGL-devel libglvnd-devel libxkbcommon-devel`
Newer meson versions can be installed via pip: `pip3 install -U meson`.
## Build & Install
### Quick Start
To build and run the example program:
1. `meson build -Dinstall_demo=true && meson compile -C build`
2. `meson devenv -C build libdecor-demo`
### Release Builds
The library and default plugins can be built and installed via:
1. `meson build --buildtype release`
2. `meson install -C build`
where `build` is the build directory that will be created during this process.
This will install by default to `/usr/local/`. To change this set the `prefix` during built, e.g. `meson build --buildtype release -Dprefix=$HOME/.local/`.
Plugins will be installed into the same directory and from thereon will be selected automatically depending on their precedence. This behaviour can be overridden at runtime by setting the environment variable `LIBDECOR_PLUGIN_DIR` and pointing it to a directory with a valid plugin.
### Debug and Development Builds
During development and when debugging, it is recommended to enable the AddressSanitizer and increase the warning level:
1. `meson build -Dinstall_demo=true -Db_sanitize=address -Dwarning_level=3`
2. `meson compile -C build`
You may have to install `libasan6` (apt) or `libasan` (dnf). Otherwise linking will fail.
By default `libdecor` will look for plugins in the target directory of the installation. Therefore, when running the demos directly from the `build` directory, no plugins will be found and the fallback plugin without any decorations will be used.
On Meson 0.58.0 and above, this can be corrected using `devenv`, i.e., to run the demo:
`meson devenv -C build libdecor-demo`
On older Meson versions, the search path for plugins can be overridden by the environment variable `LIBDECOR_PLUGIN_DIR`. To use the `cairo` plugin, point to the plugin directory:
`export LIBDECOR_PLUGIN_DIR=build/src/plugins/cairo/`
and run the demo:
`./build/demo/libdecor-demo`.
### Code of Conduct
libdecor follows the Contributor Covenant, found at:
https://www.freedesktop.org/wiki/CodeOfConduct
Please conduct yourself in a respectful and civilised manner when interacting
with community members on mailing lists, IRC, or bug trackers. The community
represents the project as a whole, and abusive or bullying behaviour is not
tolerated by the project.

80
libdecor/build/Makefile Normal file
View File

@@ -0,0 +1,80 @@
#
# Library Makefile 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
#
include ../../makeinclude
CFLAGS_DECOR = -I. -I../.. -I../../src -I../src -fPIC -D_GNU_SOURCE -DUSE_SYSTEM_LIBDECOR=0
OBJECTS = fl_libdecor.o libdecor-cairo-blur.o fl_libdecor-plugins.o \
../../src/xdg-decoration-protocol.o ../../src/xdg-shell-protocol.o \
../../src/text-input-protocol.o cursor-settings.o os-compatibility.o
PROTOCOLS = /usr/share/wayland-protocols
all : demo egl
depend:
: echo "libdecor/build: make depend..."
fl_libdecor.o : fl_libdecor.c ../src/libdecor.c ../../src/xdg-shell-protocol.c ../../src/xdg-decoration-protocol.c ../../src/text-input-protocol.c
$(CC) $(CFLAGS) $(CFLAGS_DECOR) -c fl_libdecor.c -DLIBDECOR_PLUGIN_API_VERSION=1 -DLIBDECOR_PLUGIN_DIR=\"/usr/local/lib\"
fl_libdecor-plugins.o : fl_libdecor-plugins.c ../src/plugins/cairo/libdecor-cairo.c
$(CC) $(CFLAGS) $(CFLAGS_DECOR) -c fl_libdecor-plugins.c -DLIBDECOR_PLUGIN_API_VERSION=1 -DLIBDECOR_PLUGIN_DIR=\"/usr/local/lib\"
libdecor-cairo-blur.o : ../src/plugins/cairo/libdecor-cairo-blur.c
$(CC) $(CFLAGS_DECOR) -c ../src/plugins/cairo/libdecor-cairo-blur.c
os-compatibility.o : ../src/os-compatibility.c
$(CC) $(CFLAGS_DECOR) -c ../src/os-compatibility.c
cursor-settings.o : ../src/cursor-settings.c
$(CC) $(CFLAGS_DECOR) -c ../src/cursor-settings.c -DHAS_DBUS `pkg-config --cflags dbus-1`
../../src/xdg-shell-protocol.c :
wayland-scanner private-code $(PROTOCOLS)/stable/xdg-shell/xdg-shell.xml \
../../src/xdg-shell-protocol.c
wayland-scanner client-header $(PROTOCOLS)/stable/xdg-shell/xdg-shell.xml \
../../src/xdg-shell-client-protocol.h
../../src/xdg-decoration-protocol.c :
wayland-scanner private-code \
$(PROTOCOLS)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml \
../../src/xdg-decoration-protocol.c
wayland-scanner client-header \
$(PROTOCOLS)/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml \
../../src/xdg-decoration-client-protocol.h
../../src/text-input-protocol.c :
wayland-scanner private-code \
$(PROTOCOLS)/unstable/text-input/text-input-unstable-v3.xml \
../../src/text-input-protocol.c
wayland-scanner client-header \
$(PROTOCOLS)/unstable/text-input/text-input-unstable-v3.xml \
../../src/text-input-client-protocol.h
demo : ../demo/demo.c $(OBJECTS)
$(CC) -o demo ../demo/demo.c -D_GNU_SOURCE -I../.. -I../src -I. -I../../src $(OBJECTS) $(LDLIBS) -lm -rdynamic -no-pie -Wl,--defsym=fl_libdecor_using_weston=0
egl : ../demo/egl.c $(OBJECTS)
$(CC) -o egl ../demo/egl.c -D_GNU_SOURCE -I../.. -I../src -I. -I../../src $(OBJECTS) $(GLDLIBS) -lm -rdynamic -no-pie -Wl,--defsym=fl_libdecor_using_weston=0
install:
echo "Nothing to install"
uninstall:
clean:
$(RM) *.o ../../src/xdg-*.c ../../src/xdg-*.h ../../src/xdg-*.o ../../src/text-input-* demo egl

View File

@@ -0,0 +1,348 @@
//
// Interface with the libdecor library 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
//
/* Support of interactions between FLTK and libdecor plugins, either dynamically
loaded by dlopen() or built-in FLTK.
Under USE_SYSTEM_LIBDECOR, the plugin can only be dynamically loaded.
Under ! USE_SYSTEM_LIBDECOR, it can be dynamically loaded from a directory
given in environment variable LIBDECOR_PLUGIN_DIR, or the built-in one is used.
*/
#include <dlfcn.h>
#include <string.h>
#include "../src/libdecor.h"
#include "xdg-decoration-client-protocol.h"
#include <pango/pangocairo.h>
#if USE_SYSTEM_LIBDECOR
#include "../src/libdecor-plugin.h"
enum component {NONE};
enum decoration_type {DECORATION_TYPE_NONE};
struct buffer { // identical in libdecor-cairo.c and libdecor-gtk.c
struct wl_buffer *wl_buffer;
bool in_use;
bool is_detached;
void *data;
size_t data_size;
int width;
int height;
int scale;
int buffer_width;
int buffer_height;
};
#else // !USE_SYSTEM_LIBDECOR
const struct libdecor_plugin_description *fl_libdecor_plugin_description = NULL;
# ifdef HAVE_GTK
# include <gtk/gtk.h>
# include "../src/plugins/gtk/libdecor-gtk.c"
# else
# include "../src/plugins/cairo/libdecor-cairo.c"
# undef libdecor_frame_set_min_content_size
# endif // HAVE_GTK
#endif // USE_SYSTEM_LIBDECOR
#if USE_SYSTEM_LIBDECOR || HAVE_GTK
/* these definitions derive from libdecor/src/plugins/cairo/libdecor-cairo.c */
struct libdecor_plugin_cairo {
struct libdecor_plugin plugin;
struct wl_callback *globals_callback;
struct wl_callback *globals_callback_shm;
struct libdecor *context;
struct wl_registry *wl_registry;
struct wl_subcompositor *wl_subcompositor;
struct wl_compositor *wl_compositor;
struct wl_shm *wl_shm;
struct wl_callback *shm_callback;
bool has_argb;
struct wl_list visible_frame_list;
struct wl_list seat_list;
struct wl_list output_list;
char *cursor_theme_name;
int cursor_size;
PangoFontDescription *font;
};
enum composite_mode {
COMPOSITE_SERVER,
COMPOSITE_CLIENT,
};
struct border_component_cairo {
enum component type;
bool is_hidden;
bool opaque;
enum composite_mode composite_mode;
struct {
struct wl_surface *wl_surface;
struct wl_subsurface *wl_subsurface;
struct buffer *buffer;
struct wl_list output_list;
int scale;
} server;
struct {
cairo_surface_t *image;
struct border_component_cairo *parent_component;
} client;
struct wl_list child_components; /* border_component::link */
struct wl_list link; /* border_component::child_components */
};
struct libdecor_frame_cairo {
struct libdecor_frame frame;
struct libdecor_plugin_cairo *plugin_cairo;
int content_width;
int content_height;
enum decoration_type decoration_type;
enum libdecor_window_state window_state;
char *title;
enum libdecor_capabilities capabilities;
struct border_component_cairo *focus;
struct border_component_cairo *active;
struct border_component_cairo *grab;
bool shadow_showing;
struct border_component_cairo shadow;
struct {
bool is_showing;
struct border_component_cairo title;
struct border_component_cairo min;
struct border_component_cairo max;
struct border_component_cairo close;
} title_bar;
/* store pre-processed shadow tile */
cairo_surface_t *shadow_blur;
struct wl_list link;
};
#endif
#if USE_SYSTEM_LIBDECOR || !HAVE_GTK
/* Definitions derived from libdecor-gtk.c */
typedef struct _GtkWidget GtkWidget;
enum header_element { HDR_NONE };
typedef enum { GTK_STATE_FLAG_NORMAL = 0 } GtkStateFlags;
struct border_component_gtk {
enum component type;
struct wl_surface *wl_surface;
struct wl_subsurface *wl_subsurface;
struct buffer *buffer;
bool opaque;
struct wl_list output_list;
int scale;
struct wl_list child_components; /* border_component::link */
struct wl_list link; /* border_component::child_components */
};
struct header_element_data {
const char* name;
enum header_element type;
GtkWidget *widget;
GtkStateFlags state;
};
struct libdecor_frame_gtk {
struct libdecor_frame frame;
struct libdecor_plugin_gtk *plugin_gtk;
int content_width;
int content_height;
enum libdecor_window_state window_state;
enum decoration_type decoration_type;
char *title;
enum libdecor_capabilities capabilities;
struct border_component_gtk *active;
struct border_component_gtk *focus;
struct border_component_gtk *grab;
bool shadow_showing;
struct border_component_gtk shadow;
GtkWidget *window; /* offscreen window for rendering */
GtkWidget *header; /* header bar with widgets */
struct border_component_gtk headerbar;
struct header_element_data hdr_focus;
cairo_surface_t *shadow_blur;
struct wl_list link;
};
#endif // USE_SYSTEM_LIBDECOR || !HAVE_GTK
/* these definitions are copied from libdecor/src/libdecor.c */
struct libdecor_limits {
int min_width;
int min_height;
int max_width;
int max_height;
};
struct libdecor_frame_private {
int ref_count;
struct libdecor *context;
struct wl_surface *wl_surface;
struct libdecor_frame_interface *iface;
void *user_data;
struct xdg_surface *xdg_surface;
struct xdg_toplevel *xdg_toplevel;
struct zxdg_toplevel_decoration_v1 *toplevel_decoration;
bool pending_map;
struct {
char *app_id;
char *title;
struct libdecor_limits content_limits;
struct xdg_toplevel *parent;
} state;
struct libdecor_configuration *pending_configuration;
int content_width;
int content_height;
enum libdecor_window_state window_state;
enum zxdg_toplevel_decoration_v1_mode decoration_mode;
enum libdecor_capabilities capabilities;
struct libdecor_limits interactive_limits;
bool visible;
};
static unsigned char *gtk_titlebar_buffer(struct libdecor_frame *frame,
int *width, int *height, int *stride)
{
struct libdecor_frame_gtk *lfg = (struct libdecor_frame_gtk *)frame;
#if USE_SYSTEM_LIBDECOR || !HAVE_GTK
struct border_component_gtk *bc;
#else
struct border_component *bc;
#endif
bc = &lfg->headerbar;
struct buffer *buffer = bc->buffer;
*width = buffer->buffer_width;
*height = buffer->buffer_height;
*stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width);
return (unsigned char*)buffer->data;
}
static unsigned char *cairo_titlebar_buffer(struct libdecor_frame *frame,
int *width, int *height, int *stride)
{
struct libdecor_frame_cairo *lfc = (struct libdecor_frame_cairo *)frame;
#if USE_SYSTEM_LIBDECOR || HAVE_GTK
struct border_component_cairo *bc = &lfc->title_bar.title;
#else
struct border_component *bc = &lfc->title_bar.title;
#endif
struct buffer *buffer = bc->server.buffer;
*width = buffer->buffer_width;
*height = buffer->buffer_height;
*stride = cairo_format_stride_for_width(CAIRO_FORMAT_ARGB32, buffer->buffer_width);
return (unsigned char*)buffer->data;
}
/*
Although each plugin declares an exported global variable
LIBDECOR_EXPORT const struct libdecor_plugin_description libdecor_plugin_description;
these plugins are dlopen()'ed in libdecor.c without the RTLD_GLOBAL flag.
Consequently their symbols are not discovered by dlsym(RTLD_DEFAULT, "symbol-name").
Under USE_SYSTEM_LIBDECOR, we repeat the dlopen() for the same plugin
then dlsym() will report the address of libdecor_plugin_description.
Under !USE_SYSTEM_LIBDECOR, we compile fl_libdecor.c which modifies the dlopen()
to call dlsym(ld, "libdecor_plugin_description") just after the dlopen and memorizes
this address.
A plugin is loaded also if SSD.
KDE has its own size limit, similar to that of GDK plugin
*/
static const char *get_libdecor_plugin_description(struct libdecor_frame *frame) {
static const struct libdecor_plugin_description *plugin_description = NULL;
if (frame->priv->decoration_mode == ZXDG_TOPLEVEL_DECORATION_V1_MODE_SERVER_SIDE) {
return "Server-Side Decoration";
}
if (!plugin_description) {
#if USE_SYSTEM_LIBDECOR
char fname[PATH_MAX];
const char *dir = getenv("LIBDECOR_PLUGIN_DIR");
if (!dir) dir = LIBDECOR_PLUGIN_DIR;
sprintf(fname, "%s/libdecor-gtk.so", dir);
void *dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
if (!dl) {
sprintf(fname, "%s/libdecor-cairo.so", dir);
dl = dlopen(fname, RTLD_LAZY | RTLD_LOCAL);
}
if (dl) plugin_description = (const struct libdecor_plugin_description*)dlsym(dl, "libdecor_plugin_description");
#else
plugin_description = fl_libdecor_plugin_description;
extern const struct libdecor_plugin_description libdecor_plugin_description;
if (!plugin_description) plugin_description = &libdecor_plugin_description;
#endif
//if (plugin_description) puts(plugin_description->description);
}
return plugin_description ? plugin_description->description : NULL;
}
/*
FLTK-added utility function to give access to the pixel array representing
the titlebar of a window decorated by the cairo plugin of libdecor.
frame: a libdecor-defined pointer given by fl_xid(win)->frame (with Fl_Window *win);
*width, *height: returned assigned to the width and height in pixels of the titlebar;
*stride: returned assigned to the number of bytes per line of the pixel array;
return value: start of the pixel array, which is in BGRA order, or NULL.
*/
unsigned char *fl_libdecor_titlebar_buffer(struct libdecor_frame *frame,
int *width, int *height, int *stride)
{
static const char *my_plugin = NULL;
if (!my_plugin) my_plugin = get_libdecor_plugin_description(frame);
if (my_plugin && !strcmp(my_plugin, "GTK plugin")) {
return gtk_titlebar_buffer(frame, width, height, stride);
}
else if (my_plugin && !strcmp(my_plugin, "libdecor plugin using Cairo")) {
return cairo_titlebar_buffer(frame, width, height, stride);
}
return NULL;
}

View File

@@ -0,0 +1,127 @@
//
// Interface with the libdecor library 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
//
/* Improvements to libdecor.c without modifying libdecor.c itself */
#define libdecor_frame_set_minimized libdecor_frame_set_minimized_orig
#define libdecor_new libdecor_new_orig
#include <dlfcn.h>
static void *dlopen_corrected(const char *, int);
#define dlopen(A, B) dlopen_corrected(A, B)
#include "../src/libdecor.c"
#undef dlopen
#undef libdecor_frame_set_minimized
#undef libdecor_new
extern bool fl_libdecor_using_weston(void);
extern const struct libdecor_plugin_description *fl_libdecor_plugin_description;
//#include <stdio.h>
// we have a built-in plugin so don't need a fallback one
struct libdecor_plugin *libdecor_fallback_plugin_new(struct libdecor *context) {
return NULL;
}
// see get_libdecor_plugin_description() explaining why this is useful
static void *dlopen_corrected(const char *filename, int flags) {
static int best_priority = -1;
void *retval = dlopen(filename, flags);
if (retval) {
const struct libdecor_plugin_description *description =
(const struct libdecor_plugin_description*)dlsym(retval, "libdecor_plugin_description");
if (description && description->priorities->priority > best_priority) {
fl_libdecor_plugin_description = description;
best_priority = description->priorities->priority;
}
}
return retval;
}
LIBDECOR_EXPORT void libdecor_frame_set_minimized(struct libdecor_frame *frame)
{
static bool done = false;
static bool using_weston = false;
if (!done) {
typedef bool (*ext_f)(void);
volatile ext_f ext = fl_libdecor_using_weston;
done = true;
if (ext) using_weston = fl_libdecor_using_weston();
//fprintf(stderr, "fl_libdecor_using_weston=%p using_weston=%d\n", fl_libdecor_using_weston, using_weston);
if (using_weston) { // determine the version of the running Weston compositor
FILE *pipe = popen("weston --version", "r");
if (pipe) {
char line[50], *p;
int version = 0;
p = fgets(line, sizeof(line), pipe);
pclose(pipe);
if (p) p = strchr(line, ' ');
if (p) {
sscanf(p, "%d", &version);
// Weston version 10 has fixed the bug handled here
if (version >= 10) using_weston = false;
}
}
}
}
if (using_weston) libdecor_frame_set_visibility(frame, false);
libdecor_frame_set_minimized_orig(frame);
}
/*
By default, FLTK modifies libdecor's libdecor_new() function to determine the plugin as follows :
1) the directory pointed by environment variable LIBDECOR_PLUGIN_DIR or, in absence of this variable,
by -DLIBDECOR_PLUGIN_DIR=xxx at build time is searched for a libdecor plugin;
2) if this directory does not exist or contains no plugin, the built-in plugin is used.
* if FLTK was built with package libgtk-3-dev, the GTK plugin is used
* if FLTK was built without package libgtk-3-dev, the Cairo plugin is used
If FLTK was built with OPTION_USE_SYSTEM_LIBDECOR turned ON, the present modification
isn't compiled, so the plugin-searching algorithm of libdecor_new() in libdecor-0.so is used.
This corresponds to step 1) above and to use no titlebar is no plugin is found.
N.B.: only the system package is built with a meaningful value of -DLIBDECOR_PLUGIN_DIR=
so a plugin may be loaded that way only if FLTK was built with OPTION_USE_SYSTEM_LIBDECOR turned ON.
*/
LIBDECOR_EXPORT struct libdecor *libdecor_new(struct wl_display *wl_display, struct libdecor_interface *iface)
{
struct libdecor *context;
context = zalloc(sizeof *context);
context->ref_count = 1;
context->iface = iface;
context->wl_display = wl_display;
context->wl_registry = wl_display_get_registry(wl_display);
wl_registry_add_listener(context->wl_registry, &registry_listener, context);
context->init_callback = wl_display_sync(context->wl_display);
wl_callback_add_listener(context->init_callback, &init_wl_display_callback_listener, context);
wl_list_init(&context->frames);
// attempt to dynamically load a libdecor plugin with dlopen()
FILE *old_stderr = stderr;
stderr = fopen("/dev/null", "w+"); // avoid "Couldn't open plugin directory" messages
if (init_plugins(context) != 0) { // attempt to load plugin by dlopen()
// no plug-in was found by dlopen(), use built-in plugin instead
// defined in the source code of the built-in plugin: libdecor-cairo.c or libdecor-gtk.c
extern const struct libdecor_plugin_description libdecor_plugin_description;
context->plugin = libdecor_plugin_description.constructor(context);
}
fclose(stderr); // restore stderr as it was before
stderr = old_stderr;
wl_display_flush(wl_display);
return context;
}

1304
libdecor/demo/demo.c Normal file

File diff suppressed because it is too large Load Diff

355
libdecor/demo/egl.c Normal file
View File

@@ -0,0 +1,355 @@
/*
* Copyright © 2011 Benjamin Franzke
* Copyright © 2010 Intel Corporation
* Copyright © 2018 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#include <time.h>
#include <math.h>
#include <EGL/egl.h>
#include <wayland-client.h>
#include <wayland-egl.h>
#include <libdecor.h>
#include <GL/gl.h>
#include <utils.h>
static const size_t default_size = 200;
struct client {
struct wl_display *display;
struct wl_compositor *compositor;
EGLDisplay egl_display;
EGLContext egl_context;
};
struct window {
struct client *client;
struct wl_surface *surface;
struct libdecor_frame *frame;
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
int content_width;
int content_height;
int floating_width;
int floating_height;
bool open;
bool configured;
};
static void
frame_configure(struct libdecor_frame *frame,
struct libdecor_configuration *configuration,
void *user_data)
{
struct window *window = user_data;
struct libdecor_state *state;
int width, height;
if (!libdecor_configuration_get_content_size(configuration, frame,
&width, &height)) {
width = window->floating_width;
height = window->floating_height;
}
window->content_width = width;
window->content_height = height;
wl_egl_window_resize(window->egl_window,
window->content_width, window->content_height,
0, 0);
state = libdecor_state_new(width, height);
libdecor_frame_commit(frame, state, configuration);
libdecor_state_free(state);
/* store floating dimensions */
if (libdecor_frame_is_floating(window->frame)) {
window->floating_width = width;
window->floating_height = height;
}
window->configured = true;
}
static void
frame_close(struct libdecor_frame *frame,
void *user_data)
{
struct window *window = user_data;
window->open = false;
}
static void
frame_commit(struct libdecor_frame *frame,
void *user_data)
{
struct window *window = user_data;
eglSwapBuffers(window->client->display, window->egl_surface);
}
static struct libdecor_frame_interface frame_interface = {
frame_configure,
frame_close,
frame_commit,
};
static void
libdecor_error(struct libdecor *context,
enum libdecor_error error,
const char *message)
{
fprintf(stderr, "Caught error (%d): %s\n", error, message);
exit(EXIT_FAILURE);
}
static struct libdecor_interface libdecor_interface = {
libdecor_error,
};
static void
registry_global(void *data,
struct wl_registry *wl_registry,
uint32_t name,
const char *interface,
uint32_t version)
{
struct client *client = data;
if (strcmp(interface, wl_compositor_interface.name) == 0) {
client->compositor = wl_registry_bind(wl_registry, name,
&wl_compositor_interface, 1);
}
}
static void
registry_global_remove(void *data,
struct wl_registry *wl_registry,
uint32_t name)
{
}
static const struct wl_registry_listener registry_listener = {
registry_global,
registry_global_remove
};
static bool
setup(struct window *window)
{
static const 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_NONE
};
EGLint major, minor;
EGLint n;
EGLConfig config;
window->client->egl_display =
eglGetDisplay((EGLNativeDisplayType)window->client->display);
if (eglInitialize(window->client->egl_display, &major, &minor) == EGL_FALSE) {
fprintf(stderr, "Cannot initialise EGL!\n");
return false;
}
if (eglBindAPI(EGL_OPENGL_API) == EGL_FALSE) {
fprintf(stderr, "Cannot bind EGL API!\n");
return false;
}
if (eglChooseConfig(window->client->egl_display,
config_attribs,
&config, 1, &n) == EGL_FALSE) {
fprintf(stderr, "No matching EGL configurations!\n");
return false;
}
window->client->egl_context = eglCreateContext(window->client->egl_display,
config, EGL_NO_CONTEXT, NULL);
if (window->client->egl_context == EGL_NO_CONTEXT) {
fprintf(stderr, "No EGL context!\n");
return false;
}
window->surface = wl_compositor_create_surface(window->client->compositor);
window->egl_window = wl_egl_window_create(window->surface,
default_size, default_size);
window->egl_surface = eglCreateWindowSurface(
window->client->egl_display, config,
(EGLNativeWindowType)window->egl_window,
NULL);
eglMakeCurrent(window->client->egl_display, window->egl_surface,
window->egl_surface, window->client->egl_context);
return true;
}
static void
cleanup(struct window *window)
{
if (window->client->egl_display) {
eglMakeCurrent(window->client->egl_display, EGL_NO_SURFACE,
EGL_NO_SURFACE, EGL_NO_CONTEXT);
}
if (window->egl_surface) {
eglDestroySurface(window->client->egl_display, window->egl_surface);
}
if (window->egl_window) {
wl_egl_window_destroy(window->egl_window);
}
if (window->surface) {
wl_surface_destroy(window->surface);
}
if (window->client->egl_context) {
eglDestroyContext(window->client->egl_display, window->client->egl_context);
}
if (window->client->egl_display) {
eglTerminate(window->client->egl_display);
}
}
static float
hue_to_channel(const float *const hue, const int n)
{
/* convert hue to rgb channels with saturation and value equal to 1
* https://en.wikipedia.org/wiki/HSL_and_HSV#HSV_to_RGB_alternative
*/
const float k = fmod(n + ((*hue) * 3 / M_PI), 6);
return 1 - MAX(0, MIN(MIN(k, 4 - k), 1));
}
static void
hue_to_rgb(const float *const hue, float (*rgb)[3])
{
(*rgb)[0] = hue_to_channel(hue, 5);
(*rgb)[1] = hue_to_channel(hue, 3);
(*rgb)[2] = hue_to_channel(hue, 1);
}
static void
draw(struct window *window)
{
struct timespec tv;
double time;
/* change of colour hue (HSV space) in rad/sec */
static const float hue_change = (2 * M_PI) / 10;
float hue;
float rgb[3] = {0,0,0};
clock_gettime(CLOCK_REALTIME, &tv);
time = tv.tv_sec + tv.tv_nsec * 1e-9;
hue = fmod(time * hue_change, 2 * M_PI);
hue_to_rgb(&hue, &rgb);
glClearColor(rgb[0], rgb[1], rgb[2], 1);
glClear(GL_COLOR_BUFFER_BIT);
eglSwapBuffers(window->client->egl_display, window->egl_surface);
}
int
main(int argc, char *argv[])
{
struct wl_registry *wl_registry;
struct libdecor *context = NULL;
struct window *window;
struct client *client;
int ret = EXIT_SUCCESS;
client = calloc(1, sizeof(struct client));
client->display = wl_display_connect(NULL);
if (!client->display) {
fprintf(stderr, "No Wayland connection\n");
free(client);
return EXIT_FAILURE;
}
wl_registry = wl_display_get_registry(client->display);
wl_registry_add_listener(wl_registry, &registry_listener, client);
wl_display_roundtrip(client->display);
window = calloc(1, sizeof(struct window));
window->client = client;
window->open = true;
window->configured = false;
window->floating_width = window->floating_height = default_size;
if (!setup(window)) {
goto out;
}
context = libdecor_new(client->display, &libdecor_interface);
window->frame = libdecor_decorate(context, window->surface,
&frame_interface, window);
libdecor_frame_set_app_id(window->frame, "egl-demo");
libdecor_frame_set_title(window->frame, "EGL demo");
libdecor_frame_map(window->frame);
wl_display_roundtrip(client->display);
wl_display_roundtrip(client->display);
/* wait for the first configure event */
while (!window->configured) {
if (libdecor_dispatch(context, 0) < 0) {
ret = EXIT_FAILURE;
goto out;
}
}
while (window->open) {
if (libdecor_dispatch(context, 0) < 0) {
ret = EXIT_FAILURE;
goto out;
}
draw(window);
}
out:
if (context) {
libdecor_unref(context);
}
cleanup(window);
free(window);
free(client);
return ret;
}

View File

@@ -0,0 +1,136 @@
#include "cursor-settings.h"
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include "config.h"
#ifdef HAS_DBUS
#include <dbus/dbus.h>
static DBusMessage *
get_setting_sync(DBusConnection *const connection,
const char *key,
const char *value)
{
DBusError error;
dbus_bool_t success;
DBusMessage *message;
DBusMessage *reply;
dbus_error_init(&error);
message = dbus_message_new_method_call(
"org.freedesktop.portal.Desktop",
"/org/freedesktop/portal/desktop",
"org.freedesktop.portal.Settings",
"Read");
success = dbus_message_append_args(message,
DBUS_TYPE_STRING, &key,
DBUS_TYPE_STRING, &value,
DBUS_TYPE_INVALID);
if (!success)
return NULL;
reply = dbus_connection_send_with_reply_and_block(
connection,
message,
DBUS_TIMEOUT_USE_DEFAULT,
&error);
dbus_message_unref(message);
if (dbus_error_is_set(&error))
return NULL;
return reply;
}
static bool
parse_type(DBusMessage *const reply,
const int type,
void *value)
{
DBusMessageIter iter[3];
dbus_message_iter_init(reply, &iter[0]);
if (dbus_message_iter_get_arg_type(&iter[0]) != DBUS_TYPE_VARIANT)
return false;
dbus_message_iter_recurse(&iter[0], &iter[1]);
if (dbus_message_iter_get_arg_type(&iter[1]) != DBUS_TYPE_VARIANT)
return false;
dbus_message_iter_recurse(&iter[1], &iter[2]);
if (dbus_message_iter_get_arg_type(&iter[2]) != type)
return false;
dbus_message_iter_get_basic(&iter[2], value);
return true;
}
bool
libdecor_get_cursor_settings(char **theme, int *size)
{
static const char name[] = "org.gnome.desktop.interface";
static const char key_theme[] = "cursor-theme";
static const char key_size[] = "cursor-size";
DBusError error;
DBusConnection *connection;
DBusMessage *reply;
const char *value_theme = NULL;
dbus_error_init(&error);
connection = dbus_bus_get(DBUS_BUS_SESSION, &error);
if (dbus_error_is_set(&error))
return false;
reply = get_setting_sync(connection, name, key_theme);
if (!reply)
return false;
if (!parse_type(reply, DBUS_TYPE_STRING, &value_theme)) {
dbus_message_unref(reply);
return false;
}
*theme = strdup(value_theme);
dbus_message_unref(reply);
reply = get_setting_sync(connection, name, key_size);
if (!reply)
return false;
if (!parse_type(reply, DBUS_TYPE_INT32, size)) {
dbus_message_unref(reply);
return false;
}
dbus_message_unref(reply);
return true;
}
#else
bool
libdecor_get_cursor_settings(char **theme, int *size)
{
char *env_xtheme;
char *env_xsize;
env_xtheme = getenv("XCURSOR_THEME");
if (env_xtheme != NULL)
*theme = strdup(env_xtheme);
env_xsize = getenv("XCURSOR_SIZE");
if (env_xsize != NULL)
*size = atoi(env_xsize);
return env_xtheme != NULL && env_xsize != NULL;
}
#endif

View File

@@ -0,0 +1,6 @@
#pragma once
#include <stdbool.h>
bool
libdecor_get_cursor_settings(char **theme, int *size);

View File

@@ -0,0 +1,209 @@
/*
* Copyright © 2019 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "libdecor-fallback.h"
#include <poll.h>
#include <errno.h>
#include "utils.h"
struct libdecor_plugin_fallback {
struct libdecor_plugin plugin;
struct libdecor *context;
};
static void
libdecor_plugin_fallback_destroy(struct libdecor_plugin *plugin)
{
libdecor_plugin_release(plugin);
free(plugin);
}
static int
libdecor_plugin_fallback_get_fd(struct libdecor_plugin *plugin)
{
struct libdecor_plugin_fallback *plugin_fallback =
(struct libdecor_plugin_fallback *) plugin;
struct wl_display *wl_display =
libdecor_get_wl_display(plugin_fallback->context);
return wl_display_get_fd(wl_display);
}
static int
libdecor_plugin_fallback_dispatch(struct libdecor_plugin *plugin,
int timeout)
{
struct libdecor_plugin_fallback *plugin_fallback =
(struct libdecor_plugin_fallback *) plugin;
struct wl_display *wl_display =
libdecor_get_wl_display(plugin_fallback->context);
struct pollfd fds[1];
int ret;
int dispatch_count = 0;
while (wl_display_prepare_read(wl_display) != 0)
dispatch_count += wl_display_dispatch_pending(wl_display);
if (wl_display_flush(wl_display) < 0 &&
errno != EAGAIN) {
wl_display_cancel_read(wl_display);
return -errno;
}
fds[0] = (struct pollfd) { wl_display_get_fd(wl_display), POLLIN };
ret = poll(fds, ARRAY_SIZE (fds), timeout);
if (ret > 0) {
if (fds[0].revents & POLLIN) {
wl_display_read_events(wl_display);
dispatch_count += wl_display_dispatch_pending(wl_display);
return dispatch_count;
} else {
wl_display_cancel_read(wl_display);
return dispatch_count;
}
} else if (ret == 0) {
wl_display_cancel_read(wl_display);
return dispatch_count;
} else {
wl_display_cancel_read(wl_display);
return -errno;
}
}
static struct libdecor_frame *
libdecor_plugin_fallback_frame_new(struct libdecor_plugin *plugin)
{
struct libdecor_frame *frame;
frame = zalloc(sizeof *frame);
return frame;
}
static void
libdecor_plugin_fallback_frame_free(struct libdecor_plugin *plugin,
struct libdecor_frame *frame)
{
}
static void
libdecor_plugin_fallback_frame_commit(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
struct libdecor_configuration *configuration)
{
}
static void
libdecor_plugin_fallback_frame_property_changed(struct libdecor_plugin *plugin,
struct libdecor_frame *frame)
{
}
static void
libdecor_plugin_fallback_frame_translate_coordinate(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
int content_x,
int content_y,
int *frame_x,
int *frame_y)
{
*frame_x = content_x;
*frame_y = content_y;
}
static void
libdecor_plugin_fallback_frame_popup_grab(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name)
{
}
static void
libdecor_plugin_fallback_frame_popup_ungrab(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name)
{
}
static bool
libdecor_plugin_fallback_configuration_get_content_size(struct libdecor_plugin *plugin,
struct libdecor_configuration *configuration,
struct libdecor_frame *frame,
int *content_width,
int *content_height)
{
return libdecor_configuration_get_window_size(configuration,
content_width,
content_height);
}
static bool
libdecor_plugin_fallback_frame_get_window_size_for(
struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
int *window_width,
int *window_height)
{
*window_width = libdecor_state_get_content_width (state);
*window_height = libdecor_state_get_content_height (state);
return true;
}
static struct libdecor_plugin_interface fallback_plugin_iface = {
.destroy = libdecor_plugin_fallback_destroy,
.get_fd = libdecor_plugin_fallback_get_fd,
.dispatch = libdecor_plugin_fallback_dispatch,
.frame_new = libdecor_plugin_fallback_frame_new,
.frame_free = libdecor_plugin_fallback_frame_free,
.frame_commit = libdecor_plugin_fallback_frame_commit,
.frame_property_changed = libdecor_plugin_fallback_frame_property_changed,
.frame_translate_coordinate =
libdecor_plugin_fallback_frame_translate_coordinate,
.frame_popup_grab = libdecor_plugin_fallback_frame_popup_grab,
.frame_popup_ungrab = libdecor_plugin_fallback_frame_popup_ungrab,
.configuration_get_content_size = libdecor_plugin_fallback_configuration_get_content_size,
.frame_get_window_size_for = libdecor_plugin_fallback_frame_get_window_size_for,
};
struct libdecor_plugin *
libdecor_fallback_plugin_new(struct libdecor *context)
{
struct libdecor_plugin_fallback *plugin;
plugin = zalloc(sizeof *plugin);
libdecor_plugin_init(&plugin->plugin, context, &fallback_plugin_iface);
plugin->context = context;
libdecor_notify_plugin_ready(context);
return &plugin->plugin;
}

View File

@@ -0,0 +1,35 @@
/*
* Copyright © 2019 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef LIBDECOR_FALLBACK_H
#define LIBDECOR_FALLBACK_H
#include "libdecor.h"
#include "libdecor-plugin.h"
struct libdecor_plugin *
libdecor_fallback_plugin_new(struct libdecor *context);
#endif /* LIBDECOR_FALLBACK_H */

View File

@@ -0,0 +1,215 @@
/*
* Copyright © 2017-2018 Red Hat Inc.
* Copyright © 2018 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef LIBDECOR_PLUGIN_H
#define LIBDECOR_PLUGIN_H
#include "libdecor.h"
struct libdecor_frame_private;
struct libdecor_frame {
struct libdecor_frame_private *priv;
struct wl_list link;
};
struct libdecor_plugin_private;
struct libdecor_plugin {
struct libdecor_plugin_private *priv;
};
typedef struct libdecor_plugin * (* libdecor_plugin_constructor)(struct libdecor *context);
#define LIBDECOR_PLUGIN_PRIORITY_HIGH 1000
#define LIBDECOR_PLUGIN_PRIORITY_MEDIUM 100
#define LIBDECOR_PLUGIN_PRIORITY_LOW 0
struct libdecor_plugin_priority {
const char *desktop;
int priority;
};
enum libdecor_plugin_capabilities {
LIBDECOR_PLUGIN_CAPABILITY_BASE = 1 << 0,
};
struct libdecor_plugin_description {
/* API version the plugin is compatible with. */
int api_version;
/* Human readable string describing the plugin. */
char *description;
/* A plugin has a bitmask of capabilities. The plugin loader can use this
* to load a plugin with the right capabilities. */
enum libdecor_plugin_capabilities capabilities;
/*
* The priorities field points to a list of per desktop priorities.
* properties[i].desktop is matched against XDG_CURRENT_DESKTOP when
* determining what plugin to use. The last entry in the list MUST have
* the priorities[i].desktop pointer set to NULL as a default
* priority.
*/
const struct libdecor_plugin_priority *priorities;
/* Vfunc used for constructing a plugin instance. */
libdecor_plugin_constructor constructor;
};
struct libdecor_plugin_interface {
void (* destroy)(struct libdecor_plugin *plugin);
int (* get_fd)(struct libdecor_plugin *plugin);
int (* dispatch)(struct libdecor_plugin *plugin,
int timeout);
struct libdecor_frame * (* frame_new)(struct libdecor_plugin *plugin);
void (* frame_free)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame);
void (* frame_commit)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
struct libdecor_configuration *configuration);
void (*frame_property_changed)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame);
void (* frame_translate_coordinate)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
int content_x,
int content_y,
int *window_x,
int *window_y);
void (* frame_popup_grab)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name);
void (* frame_popup_ungrab)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name);
bool (* frame_get_window_size_for)(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
int *window_width,
int *window_height);
bool (* configuration_get_content_size)(struct libdecor_plugin *plugin,
struct libdecor_configuration *configuration,
struct libdecor_frame *frame,
int *content_width,
int *content_height);
/* Reserved */
void (* reserved0)(void);
void (* reserved1)(void);
void (* reserved2)(void);
void (* reserved3)(void);
void (* reserved4)(void);
void (* reserved5)(void);
void (* reserved6)(void);
void (* reserved7)(void);
void (* reserved8)(void);
void (* reserved9)(void);
};
struct wl_surface *
libdecor_frame_get_wl_surface(struct libdecor_frame *frame);
int
libdecor_frame_get_content_width(struct libdecor_frame *frame);
int
libdecor_frame_get_content_height(struct libdecor_frame *frame);
enum libdecor_window_state
libdecor_frame_get_window_state(struct libdecor_frame *frame);
void
libdecor_frame_set_window_geometry(struct libdecor_frame *frame,
int32_t x, int32_t y,
int32_t width, int32_t height);
enum libdecor_capabilities
libdecor_frame_get_capabilities(const struct libdecor_frame *frame);
void
libdecor_frame_dismiss_popup(struct libdecor_frame *frame,
const char *seat_name);
void
libdecor_frame_toplevel_commit(struct libdecor_frame *frame);
struct wl_display *
libdecor_get_wl_display(struct libdecor *context);
void
libdecor_notify_plugin_ready(struct libdecor *context);
void
libdecor_notify_plugin_error(struct libdecor *context,
enum libdecor_error error,
const char *__restrict fmt,
...);
int
libdecor_state_get_content_width (struct libdecor_state *state);
int
libdecor_state_get_content_height (struct libdecor_state *state);
enum libdecor_window_state
libdecor_state_get_window_state(struct libdecor_state *state);
bool
libdecor_configuration_get_window_size(struct libdecor_configuration *configuration,
int *width,
int *height);
int
libdecor_plugin_init(struct libdecor_plugin *plugin,
struct libdecor *context,
struct libdecor_plugin_interface *iface);
void
libdecor_plugin_release(struct libdecor_plugin *plugin);
/*
* Get the min content size as set before with libdecor_frame_set_min_content_size().
*/
void
libdecor_frame_get_min_content_size(struct libdecor_frame *frame,
int *pcontent_width,
int *pcontent_height);
/*
* Get the max content size as set before with libdecor_frame_set_max_content_size().
*/
void
libdecor_frame_get_max_content_size(struct libdecor_frame *frame,
int *pcontent_width,
int *pcontent_height);
#endif /* LIBDECOR_PLUGIN_H */

1664
libdecor/src/libdecor.c Normal file

File diff suppressed because it is too large Load Diff

521
libdecor/src/libdecor.h Normal file

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,181 @@
/*
* Copyright © 2012 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include <sys/types.h>
#include <unistd.h>
#include <fcntl.h>
#include <errno.h>
#include <string.h>
#include <stdlib.h>
#ifdef HAVE_MEMFD_CREATE
#include <sys/mman.h>
#endif
#include "os-compatibility.h"
#ifndef HAVE_MKOSTEMP
static int
set_cloexec_or_close(int fd)
{
long flags;
if (fd == -1)
return -1;
flags = fcntl(fd, F_GETFD);
if (flags == -1)
goto err;
if (fcntl(fd, F_SETFD, flags | FD_CLOEXEC) == -1)
goto err;
return fd;
err:
close(fd);
return -1;
}
#endif
static int
create_tmpfile_cloexec(char *tmpname)
{
int fd;
#ifdef HAVE_MKOSTEMP
fd = mkostemp(tmpname, O_CLOEXEC);
if (fd >= 0)
unlink(tmpname);
#else
fd = mkstemp(tmpname);
if (fd >= 0) {
fd = set_cloexec_or_close(fd);
unlink(tmpname);
}
#endif
return fd;
}
static int
os_resize_anonymous_file(int fd, off_t size)
{
#ifdef HAVE_POSIX_FALLOCATE
/*
* Filesystems that do support fallocate will return EINVAL or
* EOPNOTSUPP. In this case we need to fall back to ftruncate
*/
errno = posix_fallocate(fd, 0, size);
if (errno == 0)
return 0;
else if (errno != EINVAL && errno != EOPNOTSUPP)
return -1;
#endif
if (ftruncate(fd, size) < 0)
return -1;
return 0;
}
/*
* Create a new, unique, anonymous file of the given size, and
* return the file descriptor for it. The file descriptor is set
* CLOEXEC. The file is immediately suitable for mmap()'ing
* the given size at offset zero.
*
* The file should not have a permanent backing store like a disk,
* but may have if XDG_RUNTIME_DIR is not properly implemented in OS.
*
* The file name is deleted from the file system.
*
* The file is suitable for buffer sharing between processes by
* transmitting the file descriptor over Unix sockets using the
* SCM_RIGHTS methods.
*
* If the C library implements posix_fallocate(), it is used to
* guarantee that disk space is available for the file at the
* given size. If disk space is insufficient, errno is set to ENOSPC.
* If posix_fallocate() is not supported, program may receive
* SIGBUS on accessing mmap()'ed file contents instead.
*
* If the C library implements memfd_create(), it is used to create the
* file purely in memory, without any backing file name on the file
* system, and then sealing off the possibility of shrinking it. This
* can then be checked before accessing mmap()'ed file contents, to
* make sure SIGBUS can't happen. It also avoids requiring
* XDG_RUNTIME_DIR.
*/
int
os_create_anonymous_file(off_t size)
{
static const char template[] = "/libdecor-shared-XXXXXX";
const char *path;
char *name;
int fd;
#ifdef HAVE_MEMFD_CREATE
fd = memfd_create("libdecor", MFD_CLOEXEC | MFD_ALLOW_SEALING);
if (fd >= 0) {
/* We can add this seal before calling posix_fallocate(), as
* the file is currently zero-sized anyway.
*
* There is also no need to check for the return value, we
* couldn't do anything with it anyway.
*/
fcntl(fd, F_ADD_SEALS, F_SEAL_SHRINK | F_SEAL_SEAL);
} else
#endif
{
path = getenv("XDG_RUNTIME_DIR");
if (!path) {
errno = ENOENT;
return -1;
}
name = malloc(strlen(path) + sizeof(template));
if (!name)
return -1;
strcpy(name, path);
strcat(name, template);
fd = create_tmpfile_cloexec(name);
free(name);
if (fd < 0)
return -1;
}
if (os_resize_anonymous_file(fd, size) < 0) {
close(fd);
return -1;
}
return fd;
}

View File

@@ -0,0 +1,34 @@
/*
* Copyright © 2012 Collabora, Ltd.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef OS_COMPATIBILITY_H
#define OS_COMPATIBILITY_H
#include <sys/types.h>
int
os_create_anonymous_file(off_t size);
#endif /* OS_COMPATIBILITY_H */

View File

@@ -0,0 +1,255 @@
/*
* Copyright © 2008 Kristian Høgsberg
* Copyright © 2012 Intel Corporation
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
/*
* functions 'blur_surface' and 'render_shadow' from weston project:
* https://gitlab.freedesktop.org/wayland/weston/raw/master/shared/cairo-util.c
*/
#include "libdecor-cairo-blur.h"
#include <stdint.h>
#include <stdlib.h>
#include <math.h>
/**
* Compile-time computation of number of items in a hardcoded array.
*
* @param a the array being measured.
* @return the number of items hardcoded into the array.
*/
#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#endif
int
blur_surface(cairo_surface_t *surface, int margin)
{
int32_t width, height, stride, x, y, z, w;
uint8_t *src, *dst;
uint32_t *s, *d, a, p;
int i, j, k, size, half;
uint32_t kernel[71];
double f;
size = ARRAY_LENGTH(kernel);
width = cairo_image_surface_get_width(surface);
height = cairo_image_surface_get_height(surface);
stride = cairo_image_surface_get_stride(surface);
src = cairo_image_surface_get_data(surface);
dst = malloc(height * stride);
if (dst == NULL)
return -1;
half = size / 2;
a = 0;
for (i = 0; i < size; i++) {
f = (i - half);
kernel[i] = exp(- f * f / ARRAY_LENGTH(kernel)) * 10000;
a += kernel[i];
}
for (i = 0; i < height; i++) {
s = (uint32_t *) (src + i * stride);
d = (uint32_t *) (dst + i * stride);
for (j = 0; j < width; j++) {
if (margin < j && j < width - margin) {
d[j] = s[j];
continue;
}
x = 0;
y = 0;
z = 0;
w = 0;
for (k = 0; k < size; k++) {
if (j - half + k < 0 || j - half + k >= width)
continue;
p = s[j - half + k];
x += (p >> 24) * kernel[k];
y += ((p >> 16) & 0xff) * kernel[k];
z += ((p >> 8) & 0xff) * kernel[k];
w += (p & 0xff) * kernel[k];
}
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
}
}
for (i = 0; i < height; i++) {
s = (uint32_t *) (dst + i * stride);
d = (uint32_t *) (src + i * stride);
for (j = 0; j < width; j++) {
if (margin <= i && i < height - margin) {
d[j] = s[j];
continue;
}
x = 0;
y = 0;
z = 0;
w = 0;
for (k = 0; k < size; k++) {
if (i - half + k < 0 || i - half + k >= height)
continue;
s = (uint32_t *) (dst + (i - half + k) * stride);
p = s[j];
x += (p >> 24) * kernel[k];
y += ((p >> 16) & 0xff) * kernel[k];
z += ((p >> 8) & 0xff) * kernel[k];
w += (p & 0xff) * kernel[k];
}
d[j] = (x / a << 24) | (y / a << 16) | (z / a << 8) | w / a;
}
}
free(dst);
cairo_surface_mark_dirty(surface);
return 0;
}
void
render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height, int margin, int top_margin)
{
cairo_pattern_t *pattern;
cairo_matrix_t matrix;
int i, fx, fy, shadow_height, shadow_width;
cairo_set_source_rgba(cr, 0, 0, 0, 0.45);
cairo_set_operator(cr, CAIRO_OPERATOR_OVER);
pattern = cairo_pattern_create_for_surface (surface);
cairo_pattern_set_filter(pattern, CAIRO_FILTER_NEAREST);
for (i = 0; i < 4; i++) {
/* when fy is set, then we are working with lower corners,
* when fx is set, then we are working with right corners
*
* 00 ------- 01
* | |
* | |
* 10 ------- 11
*/
fx = i & 1;
fy = i >> 1;
cairo_matrix_init_translate(&matrix,
-x + fx * (128 - width),
-y + fy * (128 - height));
cairo_pattern_set_matrix(pattern, &matrix);
shadow_width = margin;
shadow_height = fy ? margin : top_margin;
/* if the shadows together are greater than the surface, we need
* to fix it - set the shadow size to the half of
* the size of surface. Also handle the case when the size is
* not divisible by 2. In that case we need one part of the
* shadow to be one pixel greater. !fy or !fx, respectively,
* will do the work.
*/
if (height < 2 * shadow_height)
shadow_height = (height + !fy) / 2;
if (width < 2 * shadow_width)
shadow_width = (width + !fx) / 2;
cairo_reset_clip(cr);
cairo_rectangle(cr,
x + fx * (width - shadow_width),
y + fy * (height - shadow_height),
shadow_width, shadow_height);
cairo_clip (cr);
cairo_mask(cr, pattern);
}
shadow_width = width - 2 * margin;
shadow_height = top_margin;
if (height < 2 * shadow_height)
shadow_height = height / 2;
if (shadow_width > 0 && shadow_height) {
/* Top stretch */
cairo_matrix_init_translate(&matrix, 60, 0);
cairo_matrix_scale(&matrix, 8.0 / width, 1);
cairo_matrix_translate(&matrix, -x - width / 2, -y);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_rectangle(cr, x + margin, y, shadow_width, shadow_height);
cairo_reset_clip(cr);
cairo_rectangle(cr,
x + margin, y,
shadow_width, shadow_height);
cairo_clip (cr);
cairo_mask(cr, pattern);
/* Bottom stretch */
cairo_matrix_translate(&matrix, 0, -height + 128);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_reset_clip(cr);
cairo_rectangle(cr, x + margin, y + height - margin,
shadow_width, margin);
cairo_clip (cr);
cairo_mask(cr, pattern);
}
shadow_width = margin;
if (width < 2 * shadow_width)
shadow_width = width / 2;
shadow_height = height - margin - top_margin;
/* if height is smaller than sum of margins,
* then the shadow is already done by the corners */
if (shadow_height > 0 && shadow_width) {
/* Left stretch */
cairo_matrix_init_translate(&matrix, 0, 60);
cairo_matrix_scale(&matrix, 1, 8.0 / height);
cairo_matrix_translate(&matrix, -x, -y - height / 2);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_reset_clip(cr);
cairo_rectangle(cr, x, y + top_margin,
shadow_width, shadow_height);
cairo_clip (cr);
cairo_mask(cr, pattern);
/* Right stretch */
cairo_matrix_translate(&matrix, -width + 128, 0);
cairo_pattern_set_matrix(pattern, &matrix);
cairo_rectangle(cr, x + width - shadow_width, y + top_margin,
shadow_width, shadow_height);
cairo_reset_clip(cr);
cairo_clip (cr);
cairo_mask(cr, pattern);
}
cairo_pattern_destroy(pattern);
cairo_reset_clip(cr);
}

View File

@@ -0,0 +1,10 @@
#pragma once
#include <cairo/cairo.h>
int
blur_surface(cairo_surface_t *surface, int margin);
void
render_shadow(cairo_t *cr, cairo_surface_t *surface,
int x, int y, int width, int height, int margin, int top_margin);

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,176 @@
/*
* Copyright © 2021 Jonas Ådahl
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#include "config.h"
#include "libdecor-plugin.h"
#include <errno.h>
#include <fcntl.h>
#include <poll.h>
#include <stdlib.h>
#include <wayland-cursor.h>
#include "utils.h"
struct libdecor_plugin_dummy {
struct libdecor_plugin plugin;
struct libdecor *context;
};
static void
libdecor_plugin_dummy_destroy(struct libdecor_plugin *plugin)
{
struct libdecor_plugin_dummy *plugin_dummy =
(struct libdecor_plugin_dummy *) plugin;
free(plugin_dummy);
}
static struct libdecor_frame *
libdecor_plugin_dummy_frame_new(struct libdecor_plugin *plugin)
{
struct libdecor_frame *frame;
frame = zalloc(sizeof *frame);
return frame;
}
static void
libdecor_plugin_dummy_frame_free(struct libdecor_plugin *plugin,
struct libdecor_frame *frame)
{
}
static void
libdecor_plugin_dummy_frame_commit(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
struct libdecor_configuration *configuration)
{
}
static void
libdecor_plugin_dummy_frame_property_changed(struct libdecor_plugin *plugin,
struct libdecor_frame *frame)
{
}
static void
libdecor_plugin_dummy_frame_translate_coordinate(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
int content_x,
int content_y,
int *frame_x,
int *frame_y)
{
*frame_x = content_x;
*frame_y = content_y;
}
static void
libdecor_plugin_dummy_frame_popup_grab(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name)
{
}
static void
libdecor_plugin_dummy_frame_popup_ungrab(struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
const char *seat_name)
{
}
static bool
libdecor_plugin_dummy_configuration_get_content_size(
struct libdecor_plugin *plugin,
struct libdecor_configuration *configuration,
struct libdecor_frame *frame,
int *content_width,
int *content_height)
{
return libdecor_configuration_get_window_size(configuration,
content_width,
content_height);
}
static bool
libdecor_plugin_dummy_frame_get_window_size_for(
struct libdecor_plugin *plugin,
struct libdecor_frame *frame,
struct libdecor_state *state,
int *window_width,
int *window_height)
{
*window_width = libdecor_state_get_content_width (state);
*window_height = libdecor_state_get_content_height (state);
return true;
}
static struct libdecor_plugin_interface dummy_plugin_iface = {
.destroy = libdecor_plugin_dummy_destroy,
.frame_new = libdecor_plugin_dummy_frame_new,
.frame_free = libdecor_plugin_dummy_frame_free,
.frame_commit = libdecor_plugin_dummy_frame_commit,
.frame_property_changed = libdecor_plugin_dummy_frame_property_changed,
.frame_translate_coordinate =
libdecor_plugin_dummy_frame_translate_coordinate,
.frame_popup_grab = libdecor_plugin_dummy_frame_popup_grab,
.frame_popup_ungrab = libdecor_plugin_dummy_frame_popup_ungrab,
.configuration_get_content_size =
libdecor_plugin_dummy_configuration_get_content_size,
.frame_get_window_size_for =
libdecor_plugin_dummy_frame_get_window_size_for,
};
static struct libdecor_plugin *
libdecor_plugin_new(struct libdecor *context)
{
struct libdecor_plugin_dummy *plugin_dummy;
plugin_dummy = zalloc(sizeof *plugin_dummy);
plugin_dummy->plugin.iface = &dummy_plugin_iface;
plugin_dummy->context = context;
libdecor_notify_plugin_ready(context);
return &plugin_dummy->plugin;
}
static struct libdecor_plugin_priority priorities[] = {
{ NULL, LIBDECOR_PLUGIN_PRIORITY_LOW }
};
LIBDECOR_EXPORT const struct libdecor_plugin_description
libdecor_plugin_description = {
.api_version = LIBDECOR_PLUGIN_API_VERSION,
.description = "dummy libdecor plugin",
.priorities = priorities,
.constructor = libdecor_plugin_new,
};

File diff suppressed because it is too large Load Diff

48
libdecor/src/utils.h Normal file
View File

@@ -0,0 +1,48 @@
/*
* Copyright © 2017 Red Hat Inc.
*
* Permission is hereby granted, free of charge, to any person obtaining
* a copy of this software and associated documentation files (the
* "Software"), to deal in the Software without restriction, including
* without limitation the rights to use, copy, modify, merge, publish,
* distribute, sublicense, and/or sell copies of the Software, and to
* permit persons to whom the Software is furnished to do so, subject to
* the following conditions:
*
* The above copyright notice and this permission notice (including the
* next paragraph) shall be included in all copies or substantial
* portions of the Software.
*
* THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND,
* EXPRESS OR IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF
* MERCHANTABILITY, FITNESS FOR A PARTICULAR PURPOSE AND
* NONINFRINGEMENT. IN NO EVENT SHALL THE AUTHORS OR COPYRIGHT HOLDERS
* BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER LIABILITY, WHETHER IN AN
* ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, OUT OF OR IN
* CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN THE
* SOFTWARE.
*/
#ifndef UTILS_H
#define UTILS_H
#include <stdlib.h>
#define MIN(a, b) (((a) < (b)) ? (a) : (b))
#define MAX(a, b) (((a) > (b)) ? (a) : (b))
#ifndef ARRAY_LENGTH
#define ARRAY_LENGTH(a) (sizeof (a) / sizeof (a)[0])
#endif
#ifndef ARRAY_SIZE
#define ARRAY_SIZE(a) (sizeof(a) / sizeof((a)[0]))
#endif
static inline void *
zalloc(size_t size)
{
return calloc(1, size);
}
#endif /* UTILS_H */

View File

@@ -1,7 +1,7 @@
#
# Make include file for the Fast Light Tool Kit (FLTK).
#
# Copyright 1998-2021 by Bill Spitzak and others.
# 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
@@ -24,7 +24,7 @@ FL_ABI_VERSION = @FL_ABI_VERSION@
FLTK_VERSION = @FLTK_VERSION@
# FLTK configuration options: BUILD = { WIN | OSX | X11 | XFT }
# FLTK configuration options: BUILD = { WIN | OSX | X11 | XFT | WAYLAND }
BUILD = @BUILD@
@@ -105,6 +105,9 @@ FLTKCAIROOPTION = @FLTKCAIROOPTION@
LINKSHARED = @DSOLINK@ @LINKSHARED@ $(IMAGELIBS) $(CAIROLIBS)
IMAGELIBS = -L../lib @IMAGELIBS@
# optional extra build step for libdecor:
LIBDECORDIR = @LIBDECORDIR@
# image libraries to build...
IMAGEDIRS = @JPEG@ @ZLIB@ @PNG@
CAIRODIR = @CAIRODIR@

View File

@@ -195,10 +195,11 @@ if (FLTK_USE_X11)
# X11 (including APPLE with X11)
set (DRIVER_FILES
drivers/Posix/Fl_Posix_System_Driver.cxx
drivers/Posix/Fl_Posix_Printer_Driver.cxx
drivers/X11/Fl_X11_Screen_Driver.cxx
drivers/X11/Fl_X11_Window_Driver.cxx
drivers/Posix/Fl_Posix_System_Driver.cxx
drivers/Unix/Fl_Unix_System_Driver.cxx
drivers/X11/Fl_X11_System_Driver.cxx
drivers/Xlib/Fl_Xlib_Graphics_Driver.cxx
drivers/Xlib/Fl_Xlib_Graphics_Driver_arci.cxx
@@ -241,6 +242,25 @@ if (FLTK_USE_X11)
drivers/Xlib/Fl_Font.H
)
elseif (OPTION_USE_WAYLAND)
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -I${CMAKE_CURRENT_BINARY_DIR}")
set (DRIVER_FILES
drivers/Posix/Fl_Posix_System_Driver.cxx
drivers/Posix/Fl_Posix_Printer_Driver.cxx
drivers/Wayland/Fl_Wayland_Screen_Driver.cxx
drivers/Wayland/Fl_Wayland_Window_Driver.cxx
drivers/Wayland/Fl_Wayland_System_Driver.cxx
drivers/Unix/Fl_Unix_System_Driver.cxx
drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx
drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx
drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx
drivers/Wayland/Fl_wayland.cxx
drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
Fl_Native_File_Chooser_FLTK.cxx
Fl_Native_File_Chooser_GTK.cxx
Fl_Native_File_Chooser_Kdialog.cxx
)
elseif (APPLE)
# Apple Quartz
@@ -353,6 +373,8 @@ set (GL_DRIVER_FILES
)
if (FLTK_USE_X11)
set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/X11/Fl_X11_Gl_Window_Driver.cxx)
elseif (OPTION_USE_WAYLAND)
set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx)
elseif (APPLE)
set (GL_DRIVER_FILES ${GL_DRIVER_FILES} drivers/Cocoa/Fl_Cocoa_Gl_Window_Driver.cxx)
elseif (WIN32)
@@ -410,6 +432,40 @@ if (FLTK_USE_X11)
endif (NOT USE_XFT)
endif (FLTK_USE_X11)
if (OPTION_USE_WAYLAND)
pkg_check_modules(DBUS dbus-1)
include_directories(${DBUS_INCLUDE_DIRS})
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_CURRENT_BINARY_DIR} -fPIC -D_GNU_SOURCE -DHAS_DBUS")
if (OPTION_USE_SYSTEM_LIBDECOR)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_SYSTEM_LIBDECOR")
get_filename_component(PATH_TO_SHARED_LIBS ${HAVE_LIB_PANGO} DIRECTORY)
set (LIBDECOR_PLUGIN_DIR "\\\"${PATH_TO_SHARED_LIBS}/libdecor/plugins-1\\\" " )
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DLIBDECOR_PLUGIN_DIR=${LIBDECOR_PLUGIN_DIR} ")
set (CMAKE_CXX_FLAGS "${CMAKE_CXX_FLAGS} -DUSE_SYSTEM_LIBDECOR")
else()
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -I${CMAKE_CURRENT_SOURCE_DIR}/../libdecor/src -DLIBDECOR_PLUGIN_API_VERSION=1 -DLIBDECOR_PLUGIN_DIR=\\\"/usr/local/lib\\\" ")
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DUSE_SYSTEM_LIBDECOR=0")
endif (OPTION_USE_SYSTEM_LIBDECOR)
if (GTK_FOUND)
set (CMAKE_C_FLAGS "${CMAKE_C_FLAGS} -DHAVE_GTK")
endif (GTK_FOUND)
list (APPEND CFILES
xutf8/keysym2Ucs.c
scandir_posix.c
../libdecor/src/cursor-settings.c
../libdecor/build/fl_libdecor-plugins.c
)
if (NOT OPTION_USE_SYSTEM_LIBDECOR)
list (APPEND CFILES
../libdecor/build/fl_libdecor.c
../libdecor/src/os-compatibility.c
../libdecor/src/plugins/cairo/libdecor-cairo-blur.c
)
endif (NOT OPTION_USE_SYSTEM_LIBDECOR)
endif (OPTION_USE_WAYLAND)
if (WIN32)
list (APPEND CFILES
scandir_win32.c
@@ -495,6 +551,52 @@ if (USE_XFT)
endif (LIB_fontconfig)
endif (USE_XFT)
if (OPTION_USE_WAYLAND)
add_custom_command(
OUTPUT xdg-shell-protocol.c xdg-shell-client-protocol.h
COMMAND wayland-scanner private-code /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml xdg-shell-protocol.c
COMMAND wayland-scanner client-header /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml xdg-shell-client-protocol.h
DEPENDS /usr/share/wayland-protocols/stable/xdg-shell/xdg-shell.xml
VERBATIM
)
list (APPEND STATIC_FILES "xdg-shell-protocol.c")
list (APPEND SHARED_FILES "xdg-shell-protocol.c")
if (NOT OPTION_USE_SYSTEM_LIBDECOR)
add_custom_command(
OUTPUT xdg-decoration-protocol.c xdg-decoration-client-protocol.h
COMMAND wayland-scanner private-code /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml xdg-decoration-protocol.c
COMMAND wayland-scanner client-header /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml xdg-decoration-client-protocol.h
DEPENDS /usr/share/wayland-protocols/unstable/xdg-decoration/xdg-decoration-unstable-v1.xml
VERBATIM
)
list (APPEND STATIC_FILES "xdg-decoration-protocol.c")
list (APPEND SHARED_FILES "xdg-decoration-protocol.c")
endif (NOT OPTION_USE_SYSTEM_LIBDECOR)
add_custom_command(
OUTPUT text-input-protocol.c text-input-client-protocol.h
COMMAND wayland-scanner private-code /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml text-input-protocol.c
COMMAND wayland-scanner client-header /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml text-input-client-protocol.h
DEPENDS /usr/share/wayland-protocols/unstable/text-input/text-input-unstable-v3.xml
VERBATIM
)
list (APPEND STATIC_FILES "text-input-protocol.c")
list (APPEND SHARED_FILES "text-input-protocol.c")
if (OPTION_USE_GL)
list (APPEND OPTIONAL_LIBS "-lwayland-egl -lEGL")
endif (OPTION_USE_GL)
if (OPTION_USE_SYSTEM_LIBDECOR)
list (APPEND OPTIONAL_LIBS "-ldecor-0")
endif (OPTION_USE_SYSTEM_LIBDECOR)
list (APPEND OPTIONAL_LIBS "-lwayland-cursor -lwayland-client -lxkbcommon -ldl -ldbus-1")
if (GTK_FOUND)
list (APPEND OPTIONAL_LIBS ${GTK_LDFLAGS} )
endif (GTK_FOUND)
if (NOT OPTION_BUILD_SHARED_LIBS)
list (APPEND OPTIONAL_LIBS "-no-pie")
endif (NOT OPTION_BUILD_SHARED_LIBS)
endif (OPTION_USE_WAYLAND)
#######################################################################
FL_ADD_LIBRARY (fltk STATIC "${STATIC_FILES}")

View File

@@ -22,6 +22,7 @@
#include <FL/Fl.H>
#include "Fl_System_Driver.H"
#include "Fl_Window_Driver.H"
#include <FL/Fl_Menu_Window.H>
#include <FL/Fl_Menu_.H>
#include <FL/fl_draw.H>
@@ -116,10 +117,13 @@ public:
// each vertical menu has one of these:
class menuwindow : public Fl_Menu_Window {
friend class Fl_Window_Driver;
friend class Fl_Menu_Item;
void draw();
void drawentry(const Fl_Menu_Item*, int i, int erase);
int handle_part1(int);
int handle_part2(int e, int ret);
static Fl_Window *parent_;
public:
menutitle* title;
int handle(int);
@@ -141,6 +145,12 @@ public:
int is_inside(int x, int y);
};
Fl_Window *menuwindow::parent_ = NULL;
Fl_Window *Fl_Window_Driver::menu_parent() {
return menuwindow::parent_;
}
extern char fl_draw_shortcut;
/**
@@ -293,7 +303,7 @@ menuwindow::menuwindow(const Fl_Menu_Item* m, int X, int Y, int Wp, int Hp,
int scr_x, scr_y, scr_w, scr_h;
int tx = X, ty = Y;
Fl::screen_work_area(scr_x, scr_y, scr_w, scr_h);
Fl_Window_Driver::driver(this)->menu_window_area(scr_x, scr_y, scr_w, scr_h);
if (!right_edge || right_edge > scr_x+scr_w) right_edge = scr_x+scr_w;
end();
@@ -439,14 +449,14 @@ void menuwindow::autoscroll(int n) {
int Y = y()+Fl::box_dx(box())+2+n*itemheight;
int xx, ww;
Fl::screen_work_area(xx, scr_y, ww, scr_h);
Fl_Window_Driver::driver(this)->menu_window_area(xx, scr_y, ww, scr_h);
if (Y <= scr_y) Y = scr_y-Y+10;
else {
Y = Y+itemheight-scr_h-scr_y;
if (Y < 0) return;
Y = -Y-10;
}
Fl_Menu_Window::position(x(), y()+Y);
Fl_Window_Driver::driver(this)->reposition_menu_window(x(), y()+Y);
// y(y()+Y); // don't wait for response from X
}
@@ -885,6 +895,7 @@ const Fl_Menu_Item* Fl_Menu_Item::pulldown(
button = pbutton;
if (pbutton && pbutton->window()) {
menuwindow::parent_ = pbutton->top_window();
for (Fl_Window* w = pbutton->window(); w; w = w->window()) {
X += w->x();
Y += w->y();
@@ -892,6 +903,7 @@ const Fl_Menu_Item* Fl_Menu_Item::pulldown(
} else {
X += Fl::event_x_root()-Fl::event_x();
Y += Fl::event_y_root()-Fl::event_y();
menuwindow::parent_ = Fl::first_window();
}
menuwindow mw(this, X, Y, W, H, initial_item, title, menubar);
Fl::grab(mw);
@@ -991,7 +1003,7 @@ const Fl_Menu_Item* Fl_Menu_Item::pulldown(
int dy = n->y()-nY;
int dx = n->x()-nX;
int waX, waY, waW, waH;
Fl::screen_work_area(waX, waY, waW, waH, X, Y);
Fl_Window_Driver::driver(n)->menu_window_area(waX, waY, waW, waH, Fl::screen_num(X, Y));
for (int menu = 0; menu <= pp.menu_number; menu++) {
menuwindow* tt = pp.p[menu];
int nx = tt->x()+dx; if (nx < waX) {nx = waX; dx = -tt->x() + waX;}
@@ -1030,6 +1042,7 @@ const Fl_Menu_Item* Fl_Menu_Item::pulldown(
while (pp.nummenus>1) delete pp.p[--pp.nummenus];
mw.hide();
Fl::grab(0);
menuwindow::parent_ = NULL;
return m;
}

View File

@@ -772,7 +772,7 @@ int Fl_GTK_Native_File_Chooser_Driver::fl_gtk_chooser_wrapper()
Fl_Event_Dispatch old_dispatch = Fl::event_dispatch();
// prevent FLTK from processing any event
Fl::event_dispatch(fnfc_dispatch);
void *control = ((Fl_Unix_System_Driver*)Fl::system_driver())->control_maximize_button(NULL);
gint response_id = GTK_RESPONSE_NONE;
fl_g_signal_connect_data(gtkw_ptr, "response", G_CALLBACK(run_response_handler), &response_id, NULL, (GConnectFlags) 0);
while (response_id == GTK_RESPONSE_NONE) { // loop that shows the GTK dialog window
@@ -836,6 +836,7 @@ int Fl_GTK_Native_File_Chooser_Driver::fl_gtk_chooser_wrapper()
while (fl_gtk_events_pending ()) fl_gtk_main_iteration ();
Fl::event_dispatch(old_dispatch);
if (control) ((Fl_Unix_System_Driver*)Fl::system_driver())->control_maximize_button(control);
return result;
} // fl_gtk_chooser_wrapper

View File

@@ -18,6 +18,7 @@
#include <FL/Fl_Native_File_Chooser.H>
#include "Fl_Native_File_Chooser_Kdialog.H"
#include "Fl_Window_Driver.H"
#include "drivers/Unix/Fl_Unix_System_Driver.H"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
@@ -129,12 +130,14 @@ int Fl_Kdialog_Native_File_Chooser_Driver::show() {
Fl_Event_Dispatch old_dispatch = Fl::event_dispatch();
// prevent FLTK from processing any event
Fl::event_dispatch(fnfc_dispatch);
void *control = ((Fl_Unix_System_Driver*)Fl::system_driver())->control_maximize_button(NULL);
// run event loop until pipe finishes
while (data.fd >= 0) Fl::wait();
Fl::remove_fd(fileno(pipe));
pclose(pipe);
// return to previous event processing by FLTK
Fl::event_dispatch(old_dispatch);
if (control) ((Fl_Unix_System_Driver*)Fl::system_driver())->control_maximize_button(control);
if (data.all_files) {
// process text received from pipe
if (data.all_files[strlen(data.all_files)-1] == '\n') data.all_files[strlen(data.all_files)-1] = 0;

View File

@@ -184,6 +184,12 @@ public:
int /*dest_x*/, int /*dest_y*/,
void (*)(void*, int,int,int,int), void*) { return 0; }
static inline Fl_Window_Driver* driver(const Fl_Window *win) {return win->pWindowDriver;}
// --- support for menu windows
// the default implementation of next 2 members is most probably enough
virtual void reposition_menu_window(int x, int y);
virtual void menu_window_area(int &X, int &Y, int &W, int &H, int nscreen = -1);
static Fl_Window *menu_parent();
};
#endif // FL_WINDOW_DRIVER_H

View File

@@ -26,6 +26,7 @@
#include <FL/fl_draw.H>
#include <FL/Fl.H>
#include <FL/platform.H>
#include "Fl_Screen_Driver.H"
extern void fl_throw_focus(Fl_Widget *o);
@@ -247,6 +248,17 @@ void Fl_Window_Driver::resize_after_scale_change(int ns, float old_f, float new_
is_a_rescale_ = false;
}
void Fl_Window_Driver::reposition_menu_window(int x, int y) {
if (y != pWindow->y() || x != pWindow->x()) pWindow->Fl_Widget::position(x, y);
}
void Fl_Window_Driver::menu_window_area(int &X, int &Y, int &W, int &H, int nscreen) {
int mx, my;
Fl_Screen_Driver *scr_driver = Fl::screen_driver();
if (nscreen < 0) nscreen = scr_driver->get_mouse(mx, my);
scr_driver->screen_work_area(X, Y, W, H, nscreen);
}
/**
\}
\endcond

View File

@@ -78,155 +78,16 @@ static bool have_xfixes = false;
# include <X11/extensions/Xrender.h>
# endif
# if USE_POLL
# include <poll.h>
# else
# define POLLIN 1
# endif /* USE_POLL */
extern Fl_Widget *fl_selection_requestor;
static void open_display_i(Display *d); // open display (internal)
////////////////////////////////////////////////////////////////
// Hack to speed up bg box drawing - aka "boxcheat":
// If the boxtype of a window is a filled rectangle, we can make the
// redisplay *look* faster by using X's background pixel erasing.
// This is done by setting a flag when the window is shown for the first time.
// Note to FLTK devs:
// This can cause unexpected behavior, for instance if the box() or
// color() of a window is changed after show(), and it does presumably not
// have much effect on current systems (compared to 1998).
// It is also fragile WRT checking the box type if any other scheme than
// the default scheme is loaded.
// Hence this is disabled since FLTK 1.4.0 (AlbrechtS Feb 02, 2022)
// Note to FLTK users:
// You may define ENABLE_BOXCHEAT to use it anyway but please tell the
// FLTK devs why you believe that you need it. Should we re-enable it?
#ifdef ENABLE_BOXCHEAT
static int fl_background_pixel = -1;
static inline int can_boxcheat(Fl_Boxtype b) {
return (b == 1 || ((b & 2) && b <= 15));
}
#endif // (ENABLE_BOXCHEAT)
////////////////////////////////////////////////////////////////
// interface to poll/select call:
# if USE_POLL
# include <poll.h>
static pollfd *pollfds = 0;
# else
# if HAVE_SYS_SELECT_H
# include <sys/select.h>
# endif /* HAVE_SYS_SELECT_H */
// The following #define is only needed for HP-UX 9.x and earlier:
//#define select(a,b,c,d,e) select((a),(int *)(b),(int *)(c),(int *)(d),(e))
static fd_set fdsets[3];
static int maxfd;
# define POLLIN 1
# define POLLOUT 4
# define POLLERR 8
# endif /* USE_POLL */
static int nfds = 0;
static int fd_array_size = 0;
struct FD {
# if !USE_POLL
int fd;
short events;
# endif
void (*cb)(int, void*);
void* arg;
};
static FD *fd = 0;
void Fl_X11_System_Driver::add_fd(int n, int events, void (*cb)(int, void*), void *v) {
remove_fd(n,events);
int i = nfds++;
if (i >= fd_array_size) {
FD *temp;
fd_array_size = 2*fd_array_size+1;
if (!fd) temp = (FD*)malloc(fd_array_size*sizeof(FD));
else temp = (FD*)realloc(fd, fd_array_size*sizeof(FD));
if (!temp) return;
fd = temp;
# if USE_POLL
pollfd *tpoll;
if (!pollfds) tpoll = (pollfd*)malloc(fd_array_size*sizeof(pollfd));
else tpoll = (pollfd*)realloc(pollfds, fd_array_size*sizeof(pollfd));
if (!tpoll) return;
pollfds = tpoll;
# endif
}
fd[i].cb = cb;
fd[i].arg = v;
# if USE_POLL
pollfds[i].fd = n;
pollfds[i].events = events;
# else
fd[i].fd = n;
fd[i].events = events;
if (events & POLLIN) FD_SET(n, &fdsets[0]);
if (events & POLLOUT) FD_SET(n, &fdsets[1]);
if (events & POLLERR) FD_SET(n, &fdsets[2]);
if (n > maxfd) maxfd = n;
# endif
}
void Fl_X11_System_Driver::add_fd(int n, void (*cb)(int, void*), void* v) {
add_fd(n, POLLIN, cb, v);
}
void Fl_X11_System_Driver::remove_fd(int n, int events) {
int i,j;
# if !USE_POLL
maxfd = -1; // recalculate maxfd on the fly
# endif
for (i=j=0; i<nfds; i++) {
# if USE_POLL
if (pollfds[i].fd == n) {
int e = pollfds[i].events & ~events;
if (!e) continue; // if no events left, delete this fd
pollfds[j].events = e;
}
# else
if (fd[i].fd == n) {
int e = fd[i].events & ~events;
if (!e) continue; // if no events left, delete this fd
fd[i].events = e;
}
if (fd[i].fd > maxfd) maxfd = fd[i].fd;
# endif
// move it down in the array if necessary:
if (j<i) {
fd[j] = fd[i];
# if USE_POLL
pollfds[j] = pollfds[i];
# endif
}
j++;
}
nfds = j;
# if !USE_POLL
if (events & POLLIN) FD_CLR(n, &fdsets[0]);
if (events & POLLOUT) FD_CLR(n, &fdsets[1]);
if (events & POLLERR) FD_CLR(n, &fdsets[2]);
# endif
}
void Fl_X11_System_Driver::remove_fd(int n) {
remove_fd(n, -1);
}
extern int fl_send_system_handlers(void *e);
@@ -255,10 +116,6 @@ static void do_queued_events() {
#endif
}
// these pointers are set by the Fl::lock() function:
static void nothing() {}
void (*fl_lock_function)() = nothing;
void (*fl_unlock_function)() = nothing;
// This is never called with time_to_wait < 0.0:
// It should return negative on error, 0 if nothing happens before
@@ -269,69 +126,13 @@ int Fl_X11_System_Driver::poll_or_select_with_delay(double time_to_wait) {
// unnecessarily and thus cause the file descriptor to not be ready,
// so we must check for already-read events:
if (fl_display && XQLength(fl_display)) {do_queued_events(); return 1;}
# if !USE_POLL
fd_set fdt[3];
fdt[0] = fdsets[0];
fdt[1] = fdsets[1];
fdt[2] = fdsets[2];
# endif
int n;
fl_unlock_function();
if (time_to_wait < 2147483.648) {
# if USE_POLL
n = ::poll(pollfds, nfds, int(time_to_wait*1000 + .5));
# else
timeval t;
t.tv_sec = int(time_to_wait);
t.tv_usec = int(1000000 * (time_to_wait-t.tv_sec));
n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t);
# endif
} else {
# if USE_POLL
n = ::poll(pollfds, nfds, -1);
# else
n = ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],0);
# endif
}
fl_lock_function();
if (n > 0) {
for (int i=0; i<nfds; i++) {
# if USE_POLL
if (pollfds[i].revents) fd[i].cb(pollfds[i].fd, fd[i].arg);
# else
int f = fd[i].fd;
short revents = 0;
if (FD_ISSET(f,&fdt[0])) revents |= POLLIN;
if (FD_ISSET(f,&fdt[1])) revents |= POLLOUT;
if (FD_ISSET(f,&fdt[2])) revents |= POLLERR;
if (fd[i].events & revents) fd[i].cb(f, fd[i].arg);
# endif
}
}
return n;
return Fl_Unix_System_Driver::poll_or_select_with_delay(time_to_wait);
}
// just like Fl_X11_System_Driver::poll_or_select_with_delay(0.0) except no callbacks are done:
int Fl_X11_System_Driver::poll_or_select() {
if (XQLength(fl_display)) return 1;
if (!nfds) return 0; // nothing to select or poll
# if USE_POLL
return ::poll(pollfds, nfds, 0);
# else
timeval t;
t.tv_sec = 0;
t.tv_usec = 0;
fd_set fdt[3];
fdt[0] = fdsets[0];
fdt[1] = fdsets[1];
fdt[2] = fdsets[2];
return ::select(maxfd+1,&fdt[0],&fdt[1],&fdt[2],&t);
# endif
return Fl_Unix_System_Driver::poll_or_select();
}
// replace \r\n by \n
@@ -883,28 +684,6 @@ static void read_int(uchar *c, int& i) {
i |= (*(++c))<<24;
}
// turn BMP image FLTK produced by create_bmp() back to Fl_RGB_Image
static Fl_RGB_Image *own_bmp_to_RGB(char *bmp) {
int w, h;
read_int((uchar*)bmp + 18, w);
read_int((uchar*)bmp + 22, h);
int R=(3*w+3)/4 * 4; // the number of bytes per row, rounded up to multiple of 4
bmp += 54;
uchar *data = new uchar[w*h*3];
uchar *p = data;
for (int i = h-1; i >= 0; i--) {
char *s = bmp + i * R;
for (int j = 0; j < w; j++) {
*p++=s[2];
*p++=s[1];
*p++=s[0];
s+=3;
}
}
Fl_RGB_Image *img = new Fl_RGB_Image(data, w, h, 3);
img->alloc_array = 1;
return img;
}
// Call this when a "paste" operation happens:
void Fl_X11_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char *type) {
@@ -918,7 +697,7 @@ void Fl_X11_Screen_Driver::paste(Fl_Widget &receiver, int clipboard, const char
Fl::e_length = fl_selection_length[clipboard];
if (!Fl::e_text) Fl::e_text = (char *)"";
} else if (clipboard == 1 && type == Fl::clipboard_image && fl_selection_type[1] == type) {
Fl::e_clipboard_data = own_bmp_to_RGB(fl_selection_buffer[1]);
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;
int retval = receiver.handle(FL_PASTE);
@@ -1074,53 +853,12 @@ static void write_int(unsigned char **cp, int i) {
*cp = c;
}
static unsigned char *create_bmp(const unsigned char *data, int W, int H, int *return_size){
int R=(3*W+3)/4 * 4; // the number of bytes per row, rounded up to multiple of 4
int s=H*R;
int fs=14+40+s;
unsigned char *b=new unsigned char[fs];
unsigned char *c=b;
// BMP header
*c++='B';
*c++='M';
write_int(&c,fs);
write_int(&c,0);
write_int(&c,14+40);
// DIB header:
write_int(&c,40);
write_int(&c,W);
write_int(&c,H);
write_short(&c,1);
write_short(&c,24);//bits ber pixel
write_int(&c,0);//RGB
write_int(&c,s);
write_int(&c,0);// horizontal resolution
write_int(&c,0);// vertical resolution
write_int(&c,0);//number of colors. 0 -> 1<<bits_per_pixel
write_int(&c,0);
// Pixel data
data+=3*W*H;
for (int y=0;y<H;++y){
data-=3*W;
const unsigned char *s=data;
unsigned char *p=c;
for (int x=0;x<W;++x){
*p++=s[2];
*p++=s[1];
*p++=s[0];
s+=3;
}
c+=R;
}
*return_size = fs;
return b;
}
// takes a raw RGB image and puts it in the copy/paste buffer
void Fl_X11_Screen_Driver::copy_image(const unsigned char *data, int W, int H, int clipboard){
if (!data || W <= 0 || H <= 0) return;
delete[] fl_selection_buffer[clipboard];
fl_selection_buffer[clipboard] = (char *) create_bmp(data,W,H,&fl_selection_length[clipboard]);
fl_selection_buffer[clipboard] = (char *) Fl_Unix_System_Driver::create_bmp(data,W,H,&fl_selection_length[clipboard]);
fl_selection_buffer_length[clipboard] = fl_selection_length[clipboard];
fl_i_own_selection[clipboard] = 1;
fl_selection_type[clipboard] = Fl::clipboard_image;
@@ -3182,13 +2920,6 @@ int Fl_X11_Window_Driver::set_cursor(const Fl_RGB_Image *image, int hotx, int ho
////////////////////////////////////////////////////////////////
// returns pointer to the filename, or null if name ends with '/'
const char *Fl_X11_System_Driver::filename_name(const char *name) {
const char *p,*q;
if (!name) return (0);
for (p=q=name; *p;) if (*p++ == '/') q = p;
return q;
}
void Fl_X11_Window_Driver::label(const char *name, const char *iname) {
if (shown() && !parent()) {

View File

@@ -206,6 +206,8 @@ GLCPPFILES_X11 = drivers/X11/Fl_X11_Gl_Window_Driver.cxx
GLCPPFILES_XFT = $(GLCPPFILES_X11)
GLCPPFILES_WIN = drivers/WinAPI/Fl_WinAPI_Gl_Window_Driver.cxx
GLCPPFILES_WAYLAND = drivers/Wayland/Fl_Wayland_Gl_Window_Driver.cxx
GLCPPFILES += $(GLCPPFILES_$(BUILD))
# the following file currently doesn't contribute code to GLCPPFILES
@@ -263,6 +265,7 @@ XLIBCPPFILES = \
drivers/X11/Fl_X11_Window_Driver.cxx \
drivers/X11/Fl_X11_Screen_Driver.cxx \
drivers/Posix/Fl_Posix_System_Driver.cxx \
drivers/Unix/Fl_Unix_System_Driver.cxx \
drivers/X11/Fl_X11_System_Driver.cxx \
drivers/Posix/Fl_Posix_Printer_Driver.cxx \
Fl_x.cxx \
@@ -271,6 +274,25 @@ XLIBCPPFILES = \
Fl_Native_File_Chooser_GTK.cxx\
Fl_Native_File_Chooser_Kdialog.cxx \
Fl_get_key.cxx
# These C++ files are used under condition: BUILD_WAYLAND
WLCPPFILES = \
drivers/Posix/Fl_Posix_Printer_Driver.cxx \
Fl_Native_File_Chooser_FLTK.cxx \
Fl_Native_File_Chooser_GTK.cxx \
Fl_Native_File_Chooser_Kdialog.cxx \
drivers/Posix/Fl_Posix_System_Driver.cxx \
drivers/Unix/Fl_Unix_System_Driver.cxx \
drivers/Wayland/Fl_Wayland_System_Driver.cxx \
drivers/Wayland/Fl_Wayland_Screen_Driver.cxx \
drivers/Wayland/Fl_Wayland_Window_Driver.cxx \
drivers/Wayland/Fl_Wayland_Image_Surface_Driver.cxx \
drivers/Wayland/Fl_Wayland_Copy_Surface_Driver.cxx \
drivers/Wayland/Fl_Wayland_Graphics_Driver.cxx \
drivers/Wayland/Fl_wayland.cxx
# fl_dnd_x.cxx Fl_Native_File_Chooser_GTK.cxx
# This C file is used under condition: BUILD_X11
XLIBCFILES = \
@@ -290,6 +312,15 @@ XLIBFONTFILES = \
XLIBXFTFILES = \
drivers/Xlib/Fl_Xlib_Graphics_Driver_font_xft.cxx \
drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
# This C file is used under condition: BUILD_WAYLAND
WLCFILES = \
xutf8/keysym2Ucs.c \
scandir_posix.c
# These C++ files are used under condition: BUILD_WAYLAND
WLXFTFILES = \
drivers/Cairo/Fl_Cairo_Graphics_Driver.cxx
# These C++ files are used under condition: BUILD_GDI
GDICPPFILES = \
@@ -325,7 +356,7 @@ FLTKFLAGS = -DFL_LIBRARY
include ../makeinclude
# makeinclude has set this variable:
# BUILD = {WIN|X11|XFT|OSX}
# BUILD = {WIN|X11|XFT|OSX|WAYLAND}
MMFILES_OSX = $(OBJCPPFILES)
MMFILES = $(MMFILES_$(BUILD))
@@ -336,6 +367,8 @@ CPPFILES_OSX = $(QUARTZCPPFILES)
CPPFILES_XFT = $(XLIBCPPFILES) $(XLIBXFTFILES)
CPPFILES_X11 = $(XLIBCPPFILES) $(XLIBFONTFILES)
CPPFILES_WAYLAND = $(WLCPPFILES) $(WLXFTFILES)
CPPFILES_WIN = $(GDICPPFILES)
CPPFILES += $(CPPFILES_$(BUILD))
@@ -344,12 +377,21 @@ CPPFILES += $(CPPFILES_$(BUILD))
CFILES_X11 = $(XLIBCFILES) $(XLIBXCFILES)
CFILES_XFT = $(XLIBCFILES)
CFILES_WAYLAND = $(WLCFILES)
EXTRA_OBJECTS_WAYLAND = ../libdecor/build/fl_libdecor.o ../libdecor/build/libdecor-cairo-blur.o \
../libdecor/build/fl_libdecor-plugins.o \
xdg-decoration-protocol.o xdg-shell-protocol.o text-input-protocol.o \
../libdecor/build/cursor-settings.o ../libdecor/build/os-compatibility.o
EXTRA_CXXFLAGS_WAYLAND = -I.
CFILES_WIN = $(GDICFILES)
CFILES += $(CFILES_$(BUILD))
CXXFLAGS += $(EXTRA_CXXFLAGS_$(BUILD))
OBJECTS = $(MMFILES:.mm=.o) $(CPPFILES:.cxx=.o) $(CFILES:.c=.o) $(UTF8CFILES:.c=.o)
OBJECTS += $(EXTRA_OBJECTS_$(BUILD))
GLOBJECTS = $(GLCPPFILES:.cxx=.o)
FLOBJECTS = $(FLCPPFILES:.cxx=.o)
IMGOBJECTS = $(IMGCPPFILES:.cxx=.o)
@@ -619,6 +661,7 @@ clean:
-$(RM) drivers/WinAPI/*.o
-$(RM) drivers/X11/*.o
-$(RM) drivers/Xlib/*.o
-$(RM) drivers/Wayland/*.o
-$(RM) $(DSONAME) $(FLDSONAME) $(GLDSONAME) $(IMGDSONAME) \
$(LIBNAME) $(FLLIBNAME) $(GLLIBNAME) \
$(IMGLIBNAME) \

View File

@@ -0,0 +1,57 @@
//
// Definition of Wayland system driver
// for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 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_NIX_SYSTEM_DRIVER_H
#define FL_NIX_SYSTEM_DRIVER_H
#include "../Posix/Fl_Posix_System_Driver.H"
class Fl_RGB_Image;
class FL_EXPORT Fl_Unix_System_Driver : public Fl_Posix_System_Driver {
public:
Fl_Unix_System_Driver() : Fl_Posix_System_Driver() {
}
virtual int clocale_snprintf(char *output, size_t output_size, const char *format, va_list args);
virtual int clocale_sscanf(const char *input, const char *format, va_list args);
virtual int clocale_printf(FILE *output, const char *format, va_list args);
virtual int filename_list(const char *d, dirent ***list,
int (*sort)(struct dirent **, struct dirent **),
char *errmsg=NULL, int errmsg_sz=0);
virtual int open_uri(const char *uri, char *msg, int msglen);
virtual int use_tooltip_timeout_condition() {return 1;}
virtual int file_browser_load_filesystem(Fl_File_Browser *browser, char *filename, int lname, Fl_File_Icon *icon);
virtual void newUUID(char *uuidBuffer);
virtual char *preference_rootnode(Fl_Preferences *prefs, Fl_Preferences::Root root, const char *vendor,
const char *application);
virtual int preferences_need_protection_check() {return 1;}
virtual int utf8locale();
virtual const char *filename_name(const char *buf);
virtual void add_fd(int fd, int when, Fl_FD_Handler cb, void* = 0);
virtual void add_fd(int fd, Fl_FD_Handler cb, void* = 0);
virtual void remove_fd(int, int when);
virtual void remove_fd(int);
double wait(double time_to_wait);
int ready();
// 3 additional virtual members
virtual int poll_or_select_with_delay(double time_to_wait);
virtual int poll_or_select();
virtual void *control_maximize_button(void *data);
static unsigned char *create_bmp(const unsigned char *data, int W, int H, int *return_size);
static Fl_RGB_Image *own_bmp_to_RGB(char *bmp);
};
#endif /* FL_NIX_SYSTEM_DRIVER_H */

File diff suppressed because it is too large Load Diff

View File

@@ -0,0 +1,33 @@
//
// Font definitions for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021 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_FONT_
#define FL_FONT_
#include <config.h>
#include "Fl_Wayland_Graphics_Driver.H"
class Fl_Wayland_Font_Descriptor : public Fl_Font_Descriptor {
public:
Fl_Wayland_Font_Descriptor(const char* fontname, Fl_Fontsize size);
FL_EXPORT ~Fl_Wayland_Font_Descriptor();
PangoFontDescription *fontref;
int **width; // array of arrays of character widths
};
extern FL_EXPORT Fl_Fontdesc *fl_fonts; // the table
#endif // FL_FONT_

View File

@@ -0,0 +1,74 @@
//
// Copy-to-clipboard code for the Fast Light Tool Kit (FLTK).
//
// Copyright 1998-2021 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>
#include <FL/Fl_Copy_Surface.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"
#include <FL/platform.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();
void translate(int x, int y);
void untranslate();
};
Fl_Copy_Surface_Driver *Fl_Copy_Surface_Driver::newCopySurfaceDriver(int w, int h)
{
return new Fl_Wayland_Copy_Surface_Driver(w, h);
}
Fl_Wayland_Copy_Surface_Driver::Fl_Wayland_Copy_Surface_Driver(int w, int h) : Fl_Copy_Surface_Driver(w, h) {
int os_scale = (fl_window ? fl_window->scale : 1);
img_surf = new Fl_Image_Surface(w * os_scale, h * os_scale);
driver(img_surf->driver());
driver()->scale(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_Wayland_Graphics_Driver*)driver())->activate(img_surf->offscreen(), driver()->scale());
}
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();
}

View File

@@ -0,0 +1,401 @@
//
// Class Fl_Wayland_Gl_Window_Driver for the Fast Light Tool Kit (FLTK).
//
// Copyright 2021-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
//
#include <config.h>
#if HAVE_GL
#include <FL/platform.H>
#include <FL/Fl_Image_Surface.H>
#include "../../Fl_Gl_Choice.H"
#include "../../Fl_Screen_Driver.H"
#include "Fl_Wayland_Window_Driver.H"
#include "Fl_Wayland_Graphics_Driver.H"
#include "../../Fl_Gl_Window_Driver.H"
#include <wayland-egl.h>
#include <EGL/egl.h>
#include <FL/gl.h>
/* Implementation note 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.
*/
class Fl_Wayland_Gl_Window_Driver : public Fl_Gl_Window_Driver {
friend class Fl_Gl_Window_Driver;
bool egl_resize_in_progress;
protected:
Fl_Wayland_Gl_Window_Driver(Fl_Gl_Window *win);
virtual float pixels_per_unit();
virtual void make_current_before();
virtual int mode_(int m, const int *a);
virtual void swap_buffers();
virtual void resize(int is_a_resize, int w, int h);
virtual char swap_type();
virtual Fl_Gl_Choice *find(int m, const int *alistp);
virtual GLContext create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer = 0);
virtual void set_gl_context(Fl_Window* w, GLContext context);
virtual void delete_gl_context(GLContext);
virtual void make_overlay_current();
virtual void redraw_overlay();
virtual void waitGL();
virtual void gl_start();
virtual Fl_RGB_Image* capture_gl_rectangle(int x, int y, int w, int h);
char *alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs);
public:
static EGLDisplay egl_display;
static EGLint configs_count;
static struct wl_event_queue *gl_event_queue;
void init();
struct wl_egl_window *egl_window;
EGLSurface egl_surface;
};
// 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;
}
};
EGLDisplay Fl_Wayland_Gl_Window_Driver::egl_display = EGL_NO_DISPLAY;
EGLint Fl_Wayland_Gl_Window_Driver::configs_count = 0;
struct wl_event_queue *Fl_Wayland_Gl_Window_Driver::gl_event_queue = NULL;
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;
egl_resize_in_progress = false;
}
void Fl_Wayland_Gl_Window_Driver::init() {
EGLint major, minor;
if (!fl_display) Fl::screen_driver()->open_display();
egl_display = eglGetDisplay((EGLNativeDisplayType) fl_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);
gl_event_queue = wl_display_create_queue(fl_display);
}
char *Fl_Wayland_Gl_Window_Driver::alpha_mask_for_string(const char *str, int n, int w, int h, Fl_Fontsize fs)
{
// write str to a bitmap just big enough
Window save_win = fl_window;
fl_window = NULL;
Fl_Image_Surface *surf = new Fl_Image_Surface(w, h);
fl_window = save_win;
Fl_Font f=fl_font();
Fl_Surface_Device::push_current(surf);
fl_color(FL_BLACK);
fl_rectf(0, 0, w, h);
fl_color(FL_WHITE);
fl_font(f, fs);
fl_draw(str, n, 0, fl_height() - fl_descent());
// get the R channel only of the bitmap
char *alpha_buf = new char[w*h], *r = alpha_buf, *q;
for (int i = 0; i < h; i++) {
q = (char*)surf->offscreen()->draw_buffer + i * surf->offscreen()->stride;
for (int j = 0; j < w; j++) {
*r++ = *q;
q += 4;
}
}
Fl_Surface_Device::pop_current();
delete surf;
return alpha_buf;
}
Fl_Gl_Choice *Fl_Wayland_Gl_Window_Driver::find(int m, const int *alistp)
{
m |= FL_DOUBLE;
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_NONE
};
if (m & FL_DEPTH) config_attribs[11] = 1;
if (m & FL_MULTISAMPLE) config_attribs[13] = 1;
if (m & FL_STENCIL) config_attribs[15] = 1;
static EGLConfig *configs = (void**)calloc(configs_count, sizeof(EGLConfig));
eglChooseConfig(egl_display, config_attribs, configs, configs_count, &n);
if (n == 0 && (m & FL_MULTISAMPLE)) {
config_attribs[13] = 0;
eglChooseConfig(egl_display, config_attribs, configs, configs_count, &n);
}
if (n == 0) {
Fl::fatal("failed to choose an EGL config\n");
}
g = new Fl_Wayland_Gl_Choice(m, alistp, first);
/*for (int i = 0; i < n; i++) {
EGLint size;
eglGetConfigAttrib(egl_display, configs[i], EGL_BUFFER_SIZE, &size);
printf("Buffer size for config %d is %d\n", i, size);
eglGetConfigAttrib(egl_display, configs[i], EGL_RED_SIZE, &size);
printf("Red size for config %d is %d\n", i, size);
// just choose the first one
g->egl_conf = configs[i];
break;
}*/
// just choose the first config
g->egl_conf = configs[0];
first = g;
return g;
}
GLContext Fl_Wayland_Gl_Window_Driver::create_gl_context(Fl_Window* window, const Fl_Gl_Choice* g, int layer) {
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?shared_ctx:EGL_NO_CONTEXT, context_attribs);
//fprintf(stderr, "eglCreateContext=%p shared_ctx=%p\n", ctx, shared_ctx);
if (ctx)
add_context(ctx);
return ctx;
}
void Fl_Wayland_Gl_Window_Driver::set_gl_context(Fl_Window* w, GLContext context) {
struct wld_window *win = fl_xid(w);
if (!win || !egl_surface) return;
if (context != cached_context || w != cached_window) {
cached_context = context;
cached_window = w;
if (eglMakeCurrent(egl_display, egl_surface, egl_surface, (EGLContext)context)) {
//fprintf(stderr, "EGLContext %p made current\n", context);
} else {
Fl::error("eglMakeCurrent() failed\n");
}
}
}
void Fl_Wayland_Gl_Window_Driver::delete_gl_context(GLContext context) {
if (cached_context == context) {
cached_context = 0;
cached_window = 0;
}
//EGLBoolean b =
eglDestroyContext(egl_display, context);
//fprintf(stderr,"EGL context %p destroyed %s\n", context, b==EGL_TRUE?"successfully":"w/ error");
//b =
eglDestroySurface(egl_display, egl_surface);
//fprintf(stderr,"EGLSurface %p destroyed %s\n", egl_surface, b==EGL_TRUE?"successfully":"w/ error");
egl_surface = NULL;
wl_egl_window_destroy(egl_window);
egl_window = NULL;
del_context(context);
}
void Fl_Wayland_Gl_Window_Driver::make_overlay_current() {
//fprintf(stderr, "make_overlay_current\n");
glDrawBuffer(GL_FRONT);
}
void Fl_Wayland_Gl_Window_Driver::redraw_overlay() {
//fprintf(stderr, "redraw_overlay\n");
pWindow->redraw();
}
Fl_Gl_Window_Driver *Fl_Gl_Window_Driver::newGlWindowDriver(Fl_Gl_Window *w)
{
return new Fl_Wayland_Gl_Window_Driver(w);
}
static void gl_frame_ready(void *data, struct wl_callback *cb, uint32_t time) {
*(bool*)data = true;
}
static const struct wl_callback_listener gl_surface_frame_listener = {
.done = gl_frame_ready,
};
void Fl_Wayland_Gl_Window_Driver::make_current_before() {
if (!egl_window) {
struct wld_window *win = fl_xid(pWindow);
struct wl_surface *surface = win->wl_surface;
egl_window = wl_egl_window_create(surface, pWindow->pixel_w(), pWindow->pixel_h());
if (egl_window == EGL_NO_SURFACE) {
Fl::fatal("Can't create egl window with wl_egl_window_create()\n");
} else {
//fprintf(stderr, "Created egl window=%p\n", egl_window);
}
Fl_Wayland_Gl_Choice *g = (Fl_Wayland_Gl_Choice*)this->g();
egl_surface = eglCreateWindowSurface(egl_display, g->egl_conf, egl_window, NULL);
//fprintf(stderr, "Created egl surface=%p at scale=%d\n", egl_surface, win->scale);
wl_surface_set_buffer_scale(surface, win->scale);
if (Fl_Wayland_Screen_Driver::compositor == Fl_Wayland_Screen_Driver::WESTON) {
bool done = false;
struct wl_callback *callback = wl_surface_frame(surface);
wl_surface_commit(surface);
wl_callback_add_listener(callback, &gl_surface_frame_listener, &done);
while (!done) wl_display_dispatch(fl_display);
}
}
}
float Fl_Wayland_Gl_Window_Driver::pixels_per_unit()
{
int ns = Fl_Window_Driver::driver(pWindow)->screen_num();
int wld_scale = pWindow->shown() ? fl_xid(pWindow)->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::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 Gl_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) {
//eglSwapInterval(egl_display, 0); // doesn't sem to have any effect in this context
if (!egl_resize_in_progress) {
while (wl_display_prepare_read(fl_display) != 0) {
wl_display_dispatch_pending(fl_display);
}
wl_display_read_events(fl_display);
wl_display_dispatch_queue_pending(fl_display, gl_event_queue);
}
egl_resize_in_progress = false;
eglSwapBuffers(Fl_Wayland_Gl_Window_Driver::egl_display, egl_surface);
}
}
class Fl_Wayland_Gl_Plugin : public Fl_Wayland_Plugin {
public:
Fl_Wayland_Gl_Plugin() : Fl_Wayland_Plugin(name()) { }
virtual const char *name() { return "gl.wayland.fltk.org"; }
virtual void do_swap(Fl_Window *w) {
Fl_Gl_Window_Driver *gldr = Fl_Gl_Window_Driver::driver(w->as_gl_window());
if (gldr->overlay() == w) gldr->swap_buffers();
}
virtual void invalidate(Fl_Window *w) {
w->as_gl_window()->valid(0);
}
};
static Fl_Wayland_Gl_Plugin Gl_Overlay_Plugin;
void Fl_Wayland_Gl_Window_Driver::resize(int is_a_resize, int W, int H) {
if (!egl_window) return;
struct wld_window *win = fl_xid(pWindow);
float f = Fl::screen_scale(pWindow->screen_num());
W = (W * win->scale) * f;
H = (H * win->scale) * f;
int W2, H2;
wl_egl_window_get_attached_size(egl_window, &W2, &H2);
if (W2 != W || H2 != H) {
wl_egl_window_resize(egl_window, W, H, 0, 0);
//fprintf(stderr, "Fl_Wayland_Gl_Window_Driver::resize to %dx%d\n", W, H);
egl_resize_in_progress = true;
}
}
char Fl_Wayland_Gl_Window_Driver::swap_type() {
return copy;
}
void Fl_Wayland_Gl_Window_Driver::waitGL() {
}
void Fl_Wayland_Gl_Window_Driver::gl_start() {
}
Fl_RGB_Image* Fl_Wayland_Gl_Window_Driver::capture_gl_rectangle(int x, int y, int w, int h) {
Fl_Surface_Device::push_current(Fl_Display_Device::display_device());
Fl_RGB_Image *rgb = Fl_Gl_Window_Driver::capture_gl_rectangle(x, y, w, h);
Fl_Surface_Device::pop_current();
return rgb;
}
#endif // HAVE_GL

View File

@@ -0,0 +1,158 @@
//
// Definition of class Fl_Wayland_Graphics_Driver.
//
// Copyright 2021-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
//
/**
\file Fl_Wayland_Graphics_Driver.H
\brief Definition of Wayland graphics driver.
*/
#ifndef FL_WAYLAND_GRAPHICS_DRIVER_H
#define FL_WAYLAND_GRAPHICS_DRIVER_H
/* Implementation note about buffers FLTK uses to support display graphics under Wayland.
Each window is associated to an FLTK-defined object of type struct wld_window
containing itself an FLTK-defined struct fl_wld_buffer object holding all graphics data.
Among members of this latter structure are:
- struct wl_buffer wl_buffer
is a Wayland-defined type for a graphics buffer able to be attached to a wl_surface;
- void *data
points to the beginning of the memory zone where wl_buffer stores its graphics data;
- unsigned char *draw_buffer
contains a graphics buffer to which all Cairo drawings are directed;
draw_buffer and data both have the same organization called CAIRO_FORMAT_ARGB32 in Cairo parlance
and WL_SHM_FORMAT_ARGB8888 in Wayland parlance which means BGRA byte order.
- int width
gives the pixel width of the graphics buffer;
- int stride
gives the stride of this buffer;
- size_t data_size
gives the total buffer size in bytes (thus, data_size / stride gives the buffer height);
- bool draw_buffer_needs_commit
is TRUE when draw_buffer has been modified and needs being committed for display, and
FALSE after having been committed but before having been modified;
- struct wl_callback *cb
is used to synchronize drawing with the compositor during progressive drawing.
When a graphics scene is to be committed, the data_size bytes of draw_buffer are copied by memcpy()
starting at data, and wl_buffer is attached to the wl_surface which is committed for display
by wl_surface_commit(). Finally, draw_buffer_needs_commit is set to FALSE.
All drawing functions have Cairo write to draw_buffer and turn draw_buffer_needs_commit to TRUE.
*/
#include "../Cairo/Fl_Cairo_Graphics_Driver.H"
#include <cairo/cairo.h>
#include <stdint.h> // for uint32_t
typedef struct _PangoLayout PangoLayout;
struct fl_wld_buffer {
struct wl_buffer *wl_buffer;
void *data;
size_t data_size; // of wl_buffer and draw_buffer
int stride;
int width;
unsigned char *draw_buffer;
struct wl_callback *cb;
bool draw_buffer_needs_commit;
cairo_t *cairo_;
PangoLayout *pango_layout_;
};
struct wld_window;
class FL_EXPORT Fl_Wayland_Graphics_Driver : public Fl_Cairo_Graphics_Driver {
private:
struct fl_wld_buffer *buffer_;
PangoLayout *dummy_pango_layout_; // used to measure text width before showing a window
int linestyle_;
void draw_cached_pattern_(Fl_Image *img, cairo_pattern_t *pat, int X, int Y, int W, int H, int cx, int cy);
public:
Fl_Wayland_Graphics_Driver();
~Fl_Wayland_Graphics_Driver();
static const uint32_t wld_format;
static const cairo_format_t cairo_format;
void activate(struct fl_wld_buffer *buffer, float scale);
void font(Fl_Font fnum, Fl_Fontsize s);
Fl_Font font() { return Fl_Graphics_Driver::font(); }
void draw(const char* s, int nBytes, int x, int y) { draw(s, nBytes, float(x), float(y)); }
void draw(const char* s, int nBytes, float x, float y);
void draw(int angle, const char *str, int n, int x, int y);
void rtl_draw(const char* str, int n, int x, int y);
int height();
int descent();
double width(const char *str, int n);
double width(unsigned c);
void text_extents(const char* txt, int n, int& dx, int& dy, int& w, int& h);
int not_clipped(int x, int y, int w, int h);
int clip_box(int x, int y, int w, int h, int &X, int &Y, int &W, int &H);
void restore_clip();
void clip_region(Fl_Region r);
void line_style(int style, int width=0, char* dashes=0);
Fl_Region XRectangleRegion(int x, int y, int w, int h);
void add_rectangle_to_region(Fl_Region r, int X, int Y, int W, int H);
void XDestroyRegion(Fl_Region r);
void set_color(Fl_Color i, unsigned c);
Fl_Font set_fonts(const char* pattern_name);
const char *font_name(int num);
void font_name(int num, const char *name);
const char* get_font_name(Fl_Font fnum, int* ap);
int get_font_sizes(Fl_Font fnum, int*& sizep);
void point(int x, int y);
void copy_offscreen(int x, int y, int w, int h, Fl_Offscreen osrc, int srcx, int srcy);
void draw_image(const uchar *data, int ix, int iy, int iw, int ih, int D, int LD);
void curve(double x, double y, double x1, double y1, double x2, double y2, double x3, double y3);
void begin_points();
void end_points();
void transformed_vertex(double x, double y);
void draw_rgb(Fl_RGB_Image *rgb,int XP, int YP, int WP, int HP, int cx, int cy);
void cache(Fl_RGB_Image *rgb);
void uncache(Fl_RGB_Image *img, fl_uintptr_t &id_, fl_uintptr_t &mask_);
void draw_bitmap(Fl_Bitmap *bm,int XP, int YP, int WP, int HP, int cx, int cy);
void cache(Fl_Bitmap *img);
void delete_bitmask(Fl_Bitmask bm);
void cache(Fl_Pixmap *pxm);
void draw_pixmap(Fl_Pixmap *rgb,int XP, int YP, int WP, int HP, int cx, int cy);
void uncache_pixmap(fl_uintptr_t p);
void overlay_rect(int x, int y, int w , int h);
static void init_built_in_fonts();
static struct fl_wld_buffer *create_shm_buffer(int width, int height);
static void buffer_release(struct wld_window *window);
static void buffer_commit(struct wld_window *window);
static void cairo_init(struct fl_wld_buffer *buffer, int width, int height, int stride, cairo_format_t format);
void line(int x1, int y1, int x2, int y2);
void line(int x1, int y1, int x2, int y2, int x3, int y3);
void xyline(int x, int y, int x1);
void xyline(int x, int y, int x1, int y2);
void xyline(int x, int y, int x1, int y2, int x3);
void yxline(int x, int y, int y1);
void yxline(int x, int y, int y1, int x2);
void yxline(int x, int y, int y1, int x2, int y3);
void loop(int x0, int y0, int x1, int y1, int x2, int y2);
void loop(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
void rect(int x, int y, int w, int h);
void rectf(int x, int y, int w, int h);
void polygon(int x0, int y0, int x1, int y1, int x2, int y2);
void polygon(int x0, int y0, int x1, int y1, int x2, int y2, int x3, int y3);
void end_loop();
void end_line();
void end_polygon();
void set_spot(int font, int height, int x, int y, int w, int h, Fl_Window *win);
void reset_spot();
};
#endif // FL_WAYLAND_GRAPHICS_DRIVER_H

Some files were not shown because too many files have changed in this diff Show More