diff options
-rw-r--r-- | .clang-tidy | 9 | ||||
-rw-r--r-- | .gitignore | 11 | ||||
-rw-r--r-- | .gitmodules | 3 | ||||
-rw-r--r-- | .reuse/dep5 | 15 | ||||
-rw-r--r-- | COPYING | 16 | ||||
-rw-r--r-- | INSTALL | 59 | ||||
-rw-r--r-- | INSTALL.md | 80 | ||||
-rw-r--r-- | LICENSES/0BSD.txt | 12 | ||||
l--------- | LICENSES/ISC.txt | 1 | ||||
-rw-r--r-- | NEWS | 80 | ||||
-rw-r--r-- | PACKAGING | 49 | ||||
-rw-r--r-- | PACKAGING.md | 34 | ||||
-rw-r--r-- | README.md | 3 | ||||
-rw-r--r-- | doc/Doxyfile.in (renamed from doc/c/Doxyfile) | 11 | ||||
-rw-r--r-- | doc/api/meson.build | 9 | ||||
-rw-r--r-- | doc/c/index.rst | 5 | ||||
-rw-r--r-- | doc/c/reference.rst | 11 | ||||
-rw-r--r-- | doc/c/wscript | 39 | ||||
-rw-r--r-- | doc/conf.py.in | 13 | ||||
-rw-r--r-- | doc/html/meson.build | 32 | ||||
-rw-r--r-- | doc/index.rst (renamed from doc/suil.rst) | 9 | ||||
-rw-r--r-- | doc/meson.build | 77 | ||||
-rw-r--r-- | doc/overview.rst (renamed from doc/c/overview.rst) | 4 | ||||
-rw-r--r-- | doc/singlehtml/meson.build | 33 | ||||
-rw-r--r-- | doc/xml/meson.build | 30 | ||||
-rw-r--r-- | include/suil/suil.h | 108 | ||||
-rw-r--r-- | meson.build | 348 | ||||
-rw-r--r-- | meson/suppressions/meson.build | 157 | ||||
-rw-r--r-- | meson_options.txt | 32 | ||||
-rwxr-xr-x | scripts/dox_to_sphinx.py | 674 | ||||
-rw-r--r-- | src/cocoa_in_gtk2.mm | 19 | ||||
-rw-r--r-- | src/cocoa_in_qt5.mm | 17 | ||||
-rw-r--r-- | src/dylib.h | 22 | ||||
-rw-r--r-- | src/gtk2_in_qt5.cpp | 170 | ||||
-rw-r--r-- | src/host.c | 19 | ||||
-rw-r--r-- | src/instance.c | 76 | ||||
-rw-r--r-- | src/qt5_in_gtk.cpp | 252 | ||||
-rw-r--r-- | src/suil_config.h | 17 | ||||
-rw-r--r-- | src/suil_internal.h | 54 | ||||
-rw-r--r-- | src/warnings.h | 17 | ||||
-rw-r--r-- | src/win_in_gtk2.cpp | 23 | ||||
-rw-r--r-- | src/x11.c | 19 | ||||
-rw-r--r-- | src/x11_in_gtk2.c | 17 | ||||
-rw-r--r-- | src/x11_in_gtk3.c | 30 | ||||
-rw-r--r-- | src/x11_in_qt5.cpp | 48 | ||||
-rw-r--r-- | subprojects/sphinxygen.wrap | 14 | ||||
-rw-r--r-- | suil.pc.in | 11 | ||||
-rw-r--r-- | suil.ttl | 29 | ||||
-rwxr-xr-x | waf | 27 | ||||
m--------- | waflib | 0 | ||||
-rw-r--r-- | wscript | 472 |
51 files changed, 1164 insertions, 2153 deletions
diff --git a/.clang-tidy b/.clang-tidy index 86f28da..92d3c36 100644 --- a/.clang-tidy +++ b/.clang-tidy @@ -1,3 +1,6 @@ +# Copyright 2020-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + Checks: > *, -*-magic-numbers, @@ -8,9 +11,9 @@ Checks: > -altera-*, -bugprone-easily-swappable-parameters, -bugprone-suspicious-string-compare, + -cert-err33-c, -clang-analyzer-core.CallAndMessage, -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, - -clang-analyzer-security.insecureAPI.DeprecatedOrUnsafeBufferHandling, -concurrency-mt-unsafe, -cppcoreguidelines-avoid-non-const-global-variables, -cppcoreguidelines-macro-usage, @@ -24,11 +27,13 @@ Checks: > -hicpp-signed-bitwise, -llvm-header-guard, -llvmlibc-*, + -modernize-use-nodiscard, -modernize-use-trailing-return-type, -performance-no-int-to-ptr, -readability-function-cognitive-complexity, + -readability-identifier-length, -readability-implicit-bool-conversion, -readability-non-const-parameter, WarningsAsErrors: '*' -HeaderFilterRegex: '.*' +HeaderFilterRegex: '' FormatStyle: file @@ -1,4 +1,9 @@ -build/** -.waf-* -.lock-waf* +# Copyright 2017-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +.meson-subproject-wrap-hash.txt __pycache__ +build/** +subprojects/packagecache/ +subprojects/sphinxygen-1.0.4/ +subprojects/sphinxygen/ diff --git a/.gitmodules b/.gitmodules deleted file mode 100644 index cc8b569..0000000 --- a/.gitmodules +++ /dev/null @@ -1,3 +0,0 @@ -[submodule "waflib"] - path = waflib - url = ../../drobilla/autowaf.git diff --git a/.reuse/dep5 b/.reuse/dep5 new file mode 100644 index 0000000..f08dd19 --- /dev/null +++ b/.reuse/dep5 @@ -0,0 +1,15 @@ +Format: https://www.debian.org/doc/packaging-manuals/copyright-format/1.0/ +Upstream-Name: suil +Upstream-Contact: David Robillard <d@drobilla.net> +Source: https://gitlab.com/drobilla/suil + +Files: AUTHORS NEWS suil.ttl +Copyright: 2011-2022 David Robillard <d@drobilla.net> +Comment: Contributed to the Commons as a representation of simple facts +License: 0BSD OR ISC + +Files: .clant.json .includes.imp +Copyright: 2020 David Robillard <d@drobilla.net> +Comment: Contributed to the Commons as a tool configuration +License: 0BSD OR ISC + @@ -1,13 +1,13 @@ -Copyright 2007-2020 David Robillard <d@drobilla.net> +Copyright 2007-2022 David Robillard <d@drobilla.net> Permission to use, copy, modify, and/or distribute this software for any purpose with or without fee is hereby granted, provided that the above copyright notice and this permission notice appear in all copies. -THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/INSTALL b/INSTALL deleted file mode 100644 index 623cddd..0000000 --- a/INSTALL +++ /dev/null @@ -1,59 +0,0 @@ -Installation Instructions -========================= - -Basic Installation ------------------- - -Building this software requires only Python. To install with default options: - - ./waf configure - ./waf - ./waf install - -You may need to become root for the install stage, for example: - - sudo ./waf install - -Configuration Options ---------------------- - -All supported options can be viewed using the command: - - ./waf --help - -Most options only need to be passed during the configure stage, for example: - - ./waf configure --prefix=/usr - ./waf - ./waf install - -Compiler Configuration ----------------------- - -Several standard environment variables can be used to control how compilers are -invoked: - - * CC: Path to C compiler - * CFLAGS: C compiler options - * CXX: Path to C++ compiler - * CXXFLAGS: C++ compiler options - * CPPFLAGS: C preprocessor options - * LINKFLAGS: Linker options - -Installation Directories ------------------------- - -The --prefix option (or the PREFIX environment variable) can be used to change -the prefix which all files are installed under. There are also several options -allowing for more fine-tuned control, see the --help output for details. - -Packaging ---------- - -Everything can be installed to a specific root directory by passing a --destdir -option to the install stage (or setting the DESTDIR environment variable), -which adds a prefix to all install paths. For example: - - ./waf configure --prefix=/usr - ./waf - ./waf install --destdir=/tmp/package diff --git a/INSTALL.md b/INSTALL.md new file mode 100644 index 0000000..fcba723 --- /dev/null +++ b/INSTALL.md @@ -0,0 +1,80 @@ +<!-- Copyright 2022 David Robillard <d@drobilla.net> --> +<!-- SPDX-License-Identifier: ISC --> + +Installation Instructions +========================= + +Prerequisites +------------- + +To build from source, you will need: + + * A relatively modern C and optionally C++ compiler (GCC, Clang, and MSVC are + known to work). + + * [Meson](http://mesonbuild.com/), which depends on + [Python](http://python.org/). + +This is a brief overview of building this project with meson. See the meson +documentation for more detailed information. + +Configuration +------------- + +The build is configured with the `setup` command, which creates a new build +directory with the given name: + + meson setup build + +Some environment variables are read during `setup` and stored with the +configuration: + + * `CC`: Path to C compiler. + * `CFLAGS`: C compiler options. + * `CXX`: Path to C++ compiler. + * `CXXFLAGS`: C++ compiler options. + * `LDFLAGS`: Linker options. + +However, it is better to use meson options for configuration. All options can +be inspected with the `configure` command from within the build directory: + + cd build + meson configure + +Options can be set by passing C-style "define" options to `configure`: + + meson configure -Dc_args="-march=native" -Dprefix="/opt/mypackage/" + +Note that some options, such as `strict` and `werror` are for +developer/maintainer use only. Please don't file issues about anything that +happens when they are enabled. + +Building +-------- + +From within a configured build directory, everything can be built with the +`compile` command: + + meson compile + +Similarly, tests can be run with the `test` command: + + meson test + +Meson can also generate a project for several popular IDEs, see the `backend` +option for details. + +Installation +------------ + +A compiled project can be installed with the `install` command: + + meson install + +You may need to acquire root permissions to install to a system-wide prefix. +For packaging, the installation may be staged to a directory using the +`DESTDIR` environment variable or the `--destdir` option: + + DESTDIR=/tmp/mypackage/ meson install + + meson install --destdir=/tmp/mypackage/ diff --git a/LICENSES/0BSD.txt b/LICENSES/0BSD.txt new file mode 100644 index 0000000..7d3e0ca --- /dev/null +++ b/LICENSES/0BSD.txt @@ -0,0 +1,12 @@ +Copyright 2007-2022 David Robillard <d@drobilla.net> + +Permission to use, copy, modify, and/or distribute this software for any +purpose with or without fee is hereby granted. + +THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES WITH +REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF MERCHANTABILITY AND +FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY SPECIAL, DIRECT, +INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES WHATSOEVER RESULTING FROM +LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION OF CONTRACT, NEGLIGENCE OR +OTHER TORTIOUS ACTION, ARISING OUT OF OR IN CONNECTION WITH THE USE OR +PERFORMANCE OF THIS SOFTWARE. diff --git a/LICENSES/ISC.txt b/LICENSES/ISC.txt new file mode 120000 index 0000000..012065c --- /dev/null +++ b/LICENSES/ISC.txt @@ -0,0 +1 @@ +../COPYING
\ No newline at end of file @@ -1,4 +1,40 @@ -suil (0.10.12) stable; +suil (0.10.19) unstable; urgency=medium + + * Allow SUIL_API to be defined by the user + * Fix dependencies in pkg-config file + * Only check for Gtk Quartz support on MacOS + * Override pkg-config dependency within meson + * Remove Gtk in Qt and Qt in Gtk wrappers + * Remove junk files from documentation install + * Replace duplicated dox_to_sphinx script with sphinxygen dependency + + -- David Robillard <d@drobilla.net> Sat, 02 Sep 2023 23:22:07 +0000 + +suil (0.10.18) stable; urgency=medium + + * Add project metadata + * Adopt REUSE machine-readable licensing standard + * Fix MacOS build when Gtk3 and Qt5 are present without X11 + * Fix opening wrapped UIs multiple times in Gtk + + -- David Robillard <d@drobilla.net> Fri, 09 Sep 2022 17:29:12 +0000 + +suil (0.10.16) stable; urgency=medium + + * Fix wrapper module installation path + + -- David Robillard <d@drobilla.net> Fri, 12 Aug 2022 22:17:10 +0000 + +suil (0.10.14) stable; urgency=medium + + * Fix MacOS build + * Fix documentation install path + * Remove dead Qt4 support code + * Switch to meson build system + + -- David Robillard <d@drobilla.net> Tue, 19 Jul 2022 01:14:05 +0000 + +suil (0.10.12) stable; urgency=medium * Fix build issues with newer toolchains * Fix some compiler warnings @@ -6,14 +42,14 @@ suil (0.10.12) stable; -- David Robillard <d@drobilla.net> Fri, 27 May 2022 01:43:47 +0000 -suil (0.10.10) stable; +suil (0.10.10) stable; urgency=medium * Clean up minor code issues * Remove the need for a generated configuration header -- David Robillard <d@drobilla.net> Thu, 07 Jan 2021 21:40:54 +0000 -suil (0.10.8) stable; +suil (0.10.8) stable; urgency=medium * Fix X11 in Gtk size regressions (thanks Robin Gareus) * Fix compilation on MacOS older than 10.12 @@ -22,21 +58,21 @@ suil (0.10.8) stable; -- David Robillard <d@drobilla.net> Sun, 27 Sep 2020 12:22:08 +0000 -suil (0.10.6) stable; +suil (0.10.6) stable; urgency=medium * Add no-cocoa configure flag * Update build system -- David Robillard <d@drobilla.net> Sun, 10 Nov 2019 21:35:59 +0000 -suil (0.10.4) stable; +suil (0.10.4) stable; urgency=medium * Add support for Qt5 in Gtk3 * Add support for min/base size hints for X11 in Gtk (thanks Hermann Meyer) -- David Robillard <d@drobilla.net> Thu, 06 Jun 2019 19:02:47 +0000 -suil (0.10.2) stable; +suil (0.10.2) stable; urgency=medium * Add support for Cocoa in Qt5 * Fix resizing and add idle and update rate support for Qt5 in Gtk2 @@ -44,7 +80,7 @@ suil (0.10.2) stable; -- David Robillard <d@drobilla.net> Thu, 20 Dec 2018 17:22:19 +0000 -suil (0.10.0) stable; +suil (0.10.0) stable; urgency=medium * Add suil_init() to support early initialization and passing any necessary information that may be needed in the future (thanks Stefan Westerfeld) @@ -56,7 +92,7 @@ suil (0.10.0) stable; -- David Robillard <d@drobilla.net> Tue, 03 Oct 2017 20:11:49 +0000 -suil (0.8.4) stable; +suil (0.8.4) stable; urgency=medium * Add Cocoa in Gtk wrapper (patch from Robin Gareus) * Add Gtk2 and X11 in Qt5 wrappers (patch from Rui Nuno Capela) @@ -73,7 +109,7 @@ suil (0.8.4) stable; -- David Robillard <d@drobilla.net> Tue, 20 Sep 2016 02:47:44 +0000 -suil (0.8.2) stable; +suil (0.8.2) stable; urgency=medium * Add configure options to disable all Gtk or Qt support * Fix embedding several Qt UIs in Gtk @@ -81,7 +117,7 @@ suil (0.8.2) stable; -- David Robillard <d@drobilla.net> Fri, 08 Aug 2014 22:18:00 +0000 -suil (0.8.0) stable; +suil (0.8.0) stable; urgency=medium * Add suil_instance_get_handle (patch from Rui Nuno Capela) * Fix compilation errors on some systems @@ -89,14 +125,14 @@ suil (0.8.0) stable; -- David Robillard <d@drobilla.net> Sat, 04 Jan 2014 21:06:56 +0000 -suil (0.6.16) stable; +suil (0.6.16) stable; urgency=medium * Fix crashes and resizing for X11 in Qt (patch from Rui Nuno Capela) * Fix suil_instance_extension_data() for UIs with NULL extension_data -- David Robillard <d@drobilla.net> Tue, 17 Sep 2013 03:48:57 +0000 -suil (0.6.14) stable; +suil (0.6.14) stable; urgency=medium * Add support for new LV2 idle interface * Lower dependency from Gtk 2.24 introduced in 0.6.12 @@ -106,7 +142,7 @@ suil (0.6.14) stable; -- David Robillard <d@drobilla.net> Fri, 09 Aug 2013 04:16:48 +0000 -suil (0.6.12) stable; +suil (0.6.12) stable; urgency=medium * Fix compilation on BSD * Fix crash when a broken UI returns a NULL descriptor @@ -114,14 +150,14 @@ suil (0.6.12) stable; -- David Robillard <d@drobilla.net> Fri, 22 Feb 2013 18:03:48 +0000 -suil (0.6.10) stable; +suil (0.6.10) stable; urgency=medium * Downgrade to waf 1.7.5, previous version does not build modules due to package check breakage in waf 1.7.6 -- David Robillard <d@drobilla.net> Sun, 23 Dec 2012 04:08:06 +0000 -suil (0.6.8) stable; +suil (0.6.8) stable; urgency=medium * Fix crash in x11_in_gtk2 when event_filter fires before widget is realized * Update to waf 1.7.8 and autowaf r90 (install docs to versioned directory) @@ -130,7 +166,7 @@ suil (0.6.8) stable; -- David Robillard <d@drobilla.net> Sun, 23 Dec 2012 02:11:23 +0000 -suil (0.6.6) stable; +suil (0.6.6) stable; urgency=medium * Disable timestamps in HTML documentation for reproducible build * Fix embedding Gtk in Qt as a child widget (support reparenting) @@ -141,14 +177,14 @@ suil (0.6.6) stable; -- David Robillard <d@drobilla.net> Wed, 14 Nov 2012 16:17:03 +0000 -suil (0.6.4) stable; +suil (0.6.4) stable; urgency=medium * Correctly handle resizing for Gtk2 in Qt4 * Improve documentation -- David Robillard <d@drobilla.net> Mon, 09 Jul 2012 19:11:06 +0000 -suil (0.6.2) stable; +suil (0.6.2) stable; urgency=medium * Allow run-time configuration of module directory via environment variable SUIL_MODULE_DIR @@ -158,7 +194,7 @@ suil (0.6.2) stable; -- David Robillard <d@drobilla.net> Fri, 25 May 2012 03:18:18 +0000 -suil (0.6.0) stable; +suil (0.6.0) stable; urgency=medium * Add support for embedding X11 UIs (ui:X11UI) * Support new LV2 UI features automatically if provided by host @@ -166,20 +202,20 @@ suil (0.6.0) stable; -- David Robillard <d@drobilla.net> Wed, 18 Apr 2012 23:32:43 +0000 -suil (0.4.4) stable; +suil (0.4.4) stable; urgency=medium * Fix embedding Gtk2 Qt4 UIs in Qt4 hosts that do not link to Gtk2 -- David Robillard <d@drobilla.net> Sat, 11 Jun 2011 15:20:11 +0000 -suil (0.4.2) stable; +suil (0.4.2) stable; urgency=medium * Fix build system Python 3 compatibility * Fix compilation issues on some systems -- David Robillard <d@drobilla.net> Wed, 25 May 2011 23:00:00 +0000 -suil (0.4.0) stable; +suil (0.4.0) stable; urgency=medium * Initial release diff --git a/PACKAGING b/PACKAGING deleted file mode 100644 index 735a1c6..0000000 --- a/PACKAGING +++ /dev/null @@ -1,49 +0,0 @@ -These are generic guidelines, but please see below for important Suil specific -information. - -This library is designed to allow parallel installation of different major -versions. To facilitate this, the shared library name, include directory, and -pkg-config file are suffixed with the major version number of the library. - -For example, if this library was named "foo" and at version 1.x.y: - -/usr/include/foo-1/foo/foo.h -/usr/lib/foo-1.so.1.x.y -/usr/lib/pkgconfig/foo-1.pc - -Dependencies check for pkg-config name "foo-1" and will build -against a compatible version 1, regardless any other installed versions. - -*** IMPORTANT GUIDELINES FOR PACKAGERS *** - -Packages should follow the same conventions as above, i.e. include the major -version (and only the major version) in the name of the package. Continuing the -example above, the package(s) would be named foo-1 and foo-1-dev. This way, -if/when version 2 comes out, it may be installed at the same time as version 1 -without breaking anything. - -Please do not create packages of this library that do not follow these -guidelines, you will break things and cause unnecessary headaches. Please do -not use any number as a suffix other than the actual major version number of the -upstream source package. - -Because program and documentation names are not versioned, these should be -included in separate packages which may replace previous versions, since -there is little use in having parallel installations of them. - -*** IMPORTANT GUIDELINES FOR PACKAGING SUIL *** - -The purpose of Suil is to abstract plugin UI toolkits away from host code. To -achieve this, Suil performs its magic by dynamically loading modules for each -toolkit. The main Suil library does NOT depend on any toolkit libraries, and -thus neither should your package. Please package the individual modules -(e.g. libsuil_gtk2_in_qt4.so) as separate packages, which themselves depend on -the involved toolkits. These packages should also be versioned as described -above to support parallel installation. - -Please do not make the main Suil package depend on any toolkit package, this -defeats the purpose of Suil and will severely irritate those who for whatever -reason do not want a particular toolkit dependency. The main Suil package may -have a weak dependency (e.g. "recommends") on the individual wrapper modules, -and it's fine if these are installed by default, but it must be possible to -install Suil without installing them if the user explicitly wishes to do so. diff --git a/PACKAGING.md b/PACKAGING.md new file mode 100644 index 0000000..6b0debb --- /dev/null +++ b/PACKAGING.md @@ -0,0 +1,34 @@ +<!-- Copyright 2011-2022 David Robillard <d@drobilla.net> --> +<!-- SPDX-License-Identifier: ISC --> + +Packaging Suil +============== + +This library is designed to allow parallel installation of different major +versions. To facilitate this, the shared library name, include directory, and +pkg-config file are suffixed with the major version number of the library. + +Dependencies check for the pkg-config package `suil-0` and will build against a +compatible version 0, regardless any other installed major versions. + +Packages should follow the same conventions as above, that is, include the +major version (and only the major version) in the name of the package so that +it can be installed in parallel with future major versions. + +Dependencies +------------ + +The purpose of Suil is to abstract plugin UI toolkits away from host code. To +achieve this, Suil dynamically loads modules for the toolkits in use. The main +Suil library does NOT depend on any toolkit libraries, and its package +shouldn't either (otherwise, for example, every LV2 host in the distribution +would depend directly on Gtk and Qt). Individual modules (like +`libsuil_x11_in_gtk3.so`) should be packaged separately and themselves depend +on the involved libraries or toolkits. These packages should also be versioned +as described above to support parallel installation. + +Please do not make the main Suil package strongly depend on any toolkit +package, this defeats the purpose of Suil and will cause problems for users who +need to avoid a particular toolkit dependency for whatever reason. "Weak" or +"recommended" dependencies are fine, the important thing is that users are able +to avoid particular toolkits if they choose. @@ -1,3 +1,6 @@ +<!-- Copyright 2011-2019 David Robillard <d@drobilla.net> --> +<!-- SPDX-License-Identifier: ISC --> + Suil ==== diff --git a/doc/c/Doxyfile b/doc/Doxyfile.in index ee7a427..0d787bc 100644 --- a/doc/c/Doxyfile +++ b/doc/Doxyfile.in @@ -1,3 +1,6 @@ +# Copyright 2021-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + PROJECT_NAME = Suil PROJECT_BRIEF = "A library for loading LV2 plugin UIs" @@ -19,8 +22,10 @@ XML_PROGRAMLISTING = NO SHOW_FILES = NO MACRO_EXPANSION = YES -PREDEFINED = SUIL_API \ +PREDEFINED = SUIL_API -INPUT = ../../include/suil/suil.h +RECURSIVE = YES +STRIP_FROM_PATH = @SUIL_SRCDIR@ +INPUT = @SUIL_SRCDIR@/include -OUTPUT_DIRECTORY = . +OUTPUT_DIRECTORY = @DOX_OUTPUT@ diff --git a/doc/api/meson.build b/doc/api/meson.build new file mode 100644 index 0000000..a5cecf8 --- /dev/null +++ b/doc/api/meson.build @@ -0,0 +1,9 @@ +# Copyright 2021-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +api_suil_rst = custom_target( + 'suil.rst', + command: [sphinxygen, '-f', '@INPUT0@', '@OUTDIR@'], + input: doxygen_xml, + output: 'suil.rst', +) diff --git a/doc/c/index.rst b/doc/c/index.rst deleted file mode 100644 index b616761..0000000 --- a/doc/c/index.rst +++ /dev/null @@ -1,5 +0,0 @@ -.. toctree:: - - suil - overview - reference diff --git a/doc/c/reference.rst b/doc/c/reference.rst deleted file mode 100644 index 893bc4f..0000000 --- a/doc/c/reference.rst +++ /dev/null @@ -1,11 +0,0 @@ -############# -API Reference -############# - -This section contains the generated documentation for all symbols in the public -API. - -.. toctree:: - - api/suil - diff --git a/doc/c/wscript b/doc/c/wscript deleted file mode 100644 index ae074bc..0000000 --- a/doc/c/wscript +++ /dev/null @@ -1,39 +0,0 @@ -#!/usr/bin/env python - -def build(bld): - dox_to_sphinx = bld.path.find_node("../../scripts/dox_to_sphinx.py") - index_xml = bld.path.get_bld().make_node("xml/index.xml") - - files = [ - ("../suil.rst", "sphinx/suil.rst"), - ("index.rst", "sphinx/index.rst"), - ("overview.rst", "sphinx/overview.rst"), - ("reference.rst", "sphinx/reference.rst"), - ] - - # Run Doxygen to generate XML documentation - bld(features="doxygen", doxyfile="Doxyfile") - - # Substitute variables to make Sphinx configuration file - bld(features="subst", - source="../conf.py.in", - target="sphinx/conf.py", - SERD_VERSION=bld.env.SERD_VERSION) - - # Copy static documentation files to Sphinx build directory - for f in files: - bld(features="subst", is_copy=True, source=f[0], target=f[1]) - - # Generate Sphinx markup from Doxygen XML - bld.add_group() - bld(rule="${PYTHON} " + dox_to_sphinx.abspath() + " -f ${SRC} ${TGT}", - source=index_xml, - target="sphinx/api/") - - # Run Sphinx to generate HTML documentation - doc_dir = bld.env.DOCDIR + "/suil-%s/" % bld.env.SUIL_MAJOR_VERSION - bld(features="sphinx", - sphinx_source=bld.path.get_bld().make_node("sphinx"), - sphinx_output_format="singlehtml", - sphinx_options=["-E", "-q", "-t", "singlehtml"], - install_path=doc_dir + "c/singlehtml/") diff --git a/doc/conf.py.in b/doc/conf.py.in index 423bbea..7b6a2db 100644 --- a/doc/conf.py.in +++ b/doc/conf.py.in @@ -1,9 +1,14 @@ +# Copyright 2020-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: ISC + # Project information -project = "Suil" -copyright = "2020, David Robillard" +project = "@SUIL_TITLE@" +copyright = "2023, David Robillard" author = "David Robillard" release = "@SUIL_VERSION@" +version = "@SUIL_VERSION@" +desc = "A library for loading LV2 plugin UIs" # General configuration @@ -39,7 +44,7 @@ if tags.has("singlehtml"): html_theme_options = { "body_max_width": "48em", "body_min_width": "48em", - "description": "A library for loading LV2 plugin UIs", + "description": desc, "globaltoc_collapse": False, "globaltoc_maxdepth": 3, "logo_name": True, @@ -54,7 +59,7 @@ else: html_theme_options = { "body_max_width": "60em", "body_min_width": "40em", - "description": "A library for loading LV2 plugin UIs", + "description": desc, "globaltoc_collapse": True, "globaltoc_maxdepth": 1, "logo_name": True, diff --git a/doc/html/meson.build b/doc/html/meson.build new file mode 100644 index 0000000..7a41dc5 --- /dev/null +++ b/doc/html/meson.build @@ -0,0 +1,32 @@ +# Copyright 2021-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +html_dir = docdir / versioned_name / 'html' + +# TODO: Add install_tag: 'doc' after requiring meson 0.60.0 + +custom_target( + 'html', + build_by_default: true, + command: sphinx_build_command + [ + '-b', 'html', + '-t', 'html', + sphinx_in_dir, + '@OUTDIR@', + ], + input: [api_suil_rst, conf_py, sphinx_input], + install: true, + install_dir: html_dir, + output: [ + 'index.html', + + '_static', + 'api', + 'genindex.html', + 'overview.html', + ], +) + +if not meson.is_subproject() + summary('HTML', get_option('prefix') / html_dir, section: 'Directories') +endif diff --git a/doc/suil.rst b/doc/index.rst index c5dc5ab..7f81dbd 100644 --- a/doc/suil.rst +++ b/doc/index.rst @@ -1,3 +1,7 @@ +.. + Copyright 2020-2023 David Robillard <d@drobilla.net> + SPDX-License-Identifier: ISC + #### Suil #### @@ -12,3 +16,8 @@ a Gtk host can embed a Qt UI without linking against Qt at compile time. Suil also handles the embedding of native platform UIs (which are recommended) in common toolkits, for example embedding an X11 UI in a Gtk host. + +.. toctree:: + + overview + api/suil diff --git a/doc/meson.build b/doc/meson.build new file mode 100644 index 0000000..4db8c74 --- /dev/null +++ b/doc/meson.build @@ -0,0 +1,77 @@ +# Copyright 2021-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +docdir = get_option('datadir') / 'doc' + +############# +# Reference # +############# + +# Find required programs +doxygen = find_program('doxygen', required: get_option('docs')) +sphinx_build = find_program('sphinx-build', required: get_option('docs')) + +# Find sphinxygen or fall back to subproject +sphinxygen = disabler() +if doxygen.found() and sphinx_build.found() + sphinxygen = find_program('sphinxygen', required: false) + if not sphinxygen.found() + subproject('sphinxygen') + sphinxygen = find_program('sphinxygen', required: get_option('docs')) + endif +endif + +# Build documentation if all required tools are found +build_docs = doxygen.found() and sphinxygen.found() and sphinx_build.found() +if build_docs + # Warn if the "official" theme isn't present + pymod = import('python') + doc_modules = ['sphinx_lv2_theme'] + py = pymod.find_installation('python3', modules: doc_modules, required: false) + if not py.found() + warning('Missing sphinx_lv2_theme module, falling back to alabaster') + endif + + # Configure conf.py for Sphinx + conf_config = configuration_data() + conf_config.set('SUIL_SRCDIR', suil_src_root) + conf_config.set('SUIL_TITLE', get_option('title')) + conf_config.set('SUIL_VERSION', meson.project_version()) + conf_py = configure_file( + configuration: conf_config, + input: files('conf.py.in'), + output: 'conf.py', + ) + + # Copy hand-written documentation files + rst_sources = files('index.rst', 'overview.rst') + sphinx_input = [] + foreach f : rst_sources + sphinx_input += [ + configure_file(copy: true, input: f, output: '@PLAINNAME@'), + ] + endforeach + + # Generate reference documentation input with Doxygen and Sphinxygen + subdir('xml') + subdir('api') + + # Build strict Sphinx flags, with termination on warnings if werror=true + sphinx_in_dir = meson.current_build_dir() + sphinx_flags = ['-E', '-a', '-q'] + if get_option('werror') + sphinx_flags += ['-W'] + endif + + # Run Sphinx to generate final documentation for each format + sphinx_build_command = [sphinx_build] + sphinx_flags + foreach format : ['html', 'singlehtml'] + if not get_option(format).disabled() + subdir(format) + endif + endforeach +endif + +if not meson.is_subproject() + summary('Documentation', build_docs, bool_yn: true, section: 'Components') +endif diff --git a/doc/c/overview.rst b/doc/overview.rst index e8d61b1..71937b2 100644 --- a/doc/c/overview.rst +++ b/doc/overview.rst @@ -1,3 +1,7 @@ +.. + Copyright 2020-2022 David Robillard <d@drobilla.net> + SPDX-License-Identifier: ISC + ######## Overview ######## diff --git a/doc/singlehtml/meson.build b/doc/singlehtml/meson.build new file mode 100644 index 0000000..0398b32 --- /dev/null +++ b/doc/singlehtml/meson.build @@ -0,0 +1,33 @@ +# Copyright 2021-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +singlehtml_dir = docdir / versioned_name / 'singlehtml' + +# TODO: Add install_tag: 'doc' after requiring meson 0.60.0 + +custom_target( + 'singlehtml', + build_by_default: true, + command: sphinx_build_command + [ + '-b', 'singlehtml', + '-t', 'singlehtml', + sphinx_in_dir, + '@OUTDIR@', + ], + input: [api_suil_rst, conf_py, sphinx_input], + install: true, + install_dir: singlehtml_dir, + output: [ + 'index.html', + + '_static', + ], +) + +if not meson.is_subproject() + summary( + 'Single HTML', + get_option('prefix') / singlehtml_dir, + section: 'Directories', + ) +endif diff --git a/doc/xml/meson.build b/doc/xml/meson.build new file mode 100644 index 0000000..e49aeaf --- /dev/null +++ b/doc/xml/meson.build @@ -0,0 +1,30 @@ +# Copyright 2021-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +doxygen = find_program('doxygen') + +config = configuration_data() +config.set('SUIL_SRCDIR', suil_src_root) +config.set('DOX_OUTPUT', meson.current_build_dir() / '..') + +doxyfile = configure_file( + configuration: config, + input: files('../Doxyfile.in'), + output: 'Doxyfile', +) + +doxygen_xml = custom_target( + 'index.xml', + command: [doxygen, '@INPUT0@'], + input: [doxyfile] + c_headers, + output: [ + 'index.xml', + + 'group__suil.xml', + 'group__suil__callbacks.xml', + 'group__suil__host.xml', + 'group__suil__instance.xml', + 'group__suil__library.xml', + 'suil_8h.xml', + ], +) diff --git a/include/suil/suil.h b/include/suil/suil.h index ec2ea5e..ba55a91 100644 --- a/include/suil/suil.h +++ b/include/suil/suil.h @@ -1,18 +1,5 @@ -/* - Copyright 2011-2017 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2017 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC /// @file suil.h Public API for Suil @@ -24,6 +11,7 @@ #include <stdbool.h> #include <stdint.h> +// SUIL_LIB_IMPORT and SUIL_LIB_EXPORT mark the entry points of shared libraries #ifdef _WIN32 # define SUIL_LIB_IMPORT __declspec(dllimport) # define SUIL_LIB_EXPORT __declspec(dllexport) @@ -32,14 +20,15 @@ # define SUIL_LIB_EXPORT __attribute__((visibility("default"))) #endif -#ifndef SUIL_STATIC -# ifdef SUIL_INTERNAL +// SUIL_API exposes symbols in the public API +#ifndef SUIL_API +# ifdef SUIL_STATIC +# define SUIL_API +# elif defined(SUIL_INTERNAL) # define SUIL_API SUIL_LIB_EXPORT # else # define SUIL_API SUIL_LIB_IMPORT # endif -#else -# define SUIL_API #endif #ifdef __cplusplus @@ -47,27 +36,14 @@ extern "C" { #endif /** - @defgroup suil Suil + @defgroup suil Suil C API @{ */ /** - UI host descriptor. - - This contains the various functions that a plugin UI may use to communicate - with the plugin. It is passed to suil_instance_new() to provide these - functions to the UI. + @defgroup suil_callbacks Callbacks + @{ */ -typedef struct SuilHostImpl SuilHost; - -/// An instance of an LV2 plugin UI -typedef struct SuilInstanceImpl SuilInstance; - -/// Opaque pointer to a UI handle -typedef void* SuilHandle; - -/// Opaque pointer to a UI widget -typedef void* SuilWidget; /** UI controller. @@ -112,6 +88,12 @@ typedef void (*SuilTouchFunc)( // uint32_t port_index, bool grabbed); +/** + @} + @defgroup suil_library Library + @{ +*/ + /// Initialization argument typedef enum { SUIL_ARG_NONE } SuilArg; @@ -128,6 +110,37 @@ void suil_init(int* argc, char*** argv, SuilArg key, ...); /** + Check if suil can wrap a UI type. + + @param host_type_uri The URI of the desired widget type of the host, + corresponding to the `type_uri` parameter of suil_instance_new(). + + @param ui_type_uri The URI of the UI widget type. + + @return 0 if wrapping is unsupported, otherwise the quality of the wrapping + where 1 is the highest quality (direct native embedding with no wrapping) + and increasing values are of a progressively lower quality and/or stability. +*/ +SUIL_API +unsigned +suil_ui_supported(const char* host_type_uri, const char* ui_type_uri); + +/** + @} + @defgroup suil_host Host + @{ +*/ + +/** + UI host descriptor. + + This contains the various functions that a plugin UI may use to communicate + with the plugin. It is passed to suil_instance_new() to provide these + functions to the UI. +*/ +typedef struct SuilHostImpl SuilHost; + +/** Create a new UI host descriptor. @param write_func Function to send a value to a plugin port. @@ -159,20 +172,22 @@ void suil_host_free(SuilHost* host); /** - Check if suil can wrap a UI type. + @} +*/ - @param host_type_uri The URI of the desired widget type of the host, - corresponding to the `type_uri` parameter of suil_instance_new(). +/** + @defgroup suil_instance Instance + @{ +*/ - @param ui_type_uri The URI of the UI widget type. +/// An instance of an LV2 plugin UI +typedef struct SuilInstanceImpl SuilInstance; - @return 0 if wrapping is unsupported, otherwise the quality of the wrapping - where 1 is the highest quality (direct native embedding with no wrapping) - and increasing values are of a progressively lower quality and/or stability. -*/ -SUIL_API -unsigned -suil_ui_supported(const char* host_type_uri, const char* ui_type_uri); +/// Opaque pointer to a UI handle +typedef void* SuilHandle; + +/// Opaque pointer to a UI widget +typedef void* SuilWidget; /** Instantiate a UI for an LV2 plugin. @@ -277,6 +292,7 @@ suil_instance_extension_data(SuilInstance* instance, const char* uri); /** @} + @} */ #ifdef __cplusplus diff --git a/meson.build b/meson.build new file mode 100644 index 0000000..94847dd --- /dev/null +++ b/meson.build @@ -0,0 +1,348 @@ +# Copyright 2021-2022 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +project( + 'suil', + ['c', 'cpp'], + default_options: [ + 'b_ndebug=if-release', + 'buildtype=release', + 'c_std=c99', + 'cpp_std=c++14', + ], + license: 'ISC', + meson_version: '>= 0.56.0', + version: '0.10.19', +) + +suil_src_root = meson.current_source_dir() +major_version = meson.project_version().split('.')[0] +version_suffix = '-@0@'.format(major_version) +versioned_name = 'suil' + version_suffix +suil_module_dir = get_option('libdir') / versioned_name + +####################### +# Compilers and Flags # +####################### + +# Load build tools +pkg = import('pkgconfig') +cc = meson.get_compiler('c') +cpp = meson.get_compiler('cpp') + +# Enable Objective C support if we're building for MacOS +if host_machine.system() == 'darwin' + add_languages(['objcpp'], native: false) + objcpp = meson.get_compiler('objcpp') +endif + +# Set global warning flags +subdir('meson/suppressions') + +########################## +# Platform Configuration # +########################## + +suil_abs_module_dir = get_option('prefix') / suil_module_dir +platform_defines = ['-DSUIL_MODULE_DIR="@0@"'.format(suil_abs_module_dir)] + +nodelete_c_link_args = cc.get_supported_link_arguments(['-Wl,-z,nodelete']) +nodelete_cpp_link_args = cpp.get_supported_link_arguments(['-Wl,-z,nodelete']) + +# Use versioned name everywhere to support parallel major version installations +if host_machine.system() == 'windows' + if get_option('default_library') == 'both' + error('default_library=both is not supported on Windows') + endif + soversion = '' +else + soversion = meson.project_version().split('.')[0] +endif + +################ +# Dependencies # +################ + +dl_dep = cc.find_library('dl', required: false) + +lv2_dep = dependency('lv2', fallback: 'lv2', version: '>= 1.18.3') + +x11_dep = dependency( + 'x11', + include_type: 'system', + required: get_option('x11'), +) + +gtk2_dep = dependency( + 'gtk+-2.0', + include_type: 'system', + version: '>=2.18.0', + required: get_option('gtk2').enabled(), +) + +gtk2_x11_dep = dependency( + 'gtk+-x11-2.0', + include_type: 'system', + required: get_option('gtk2').enabled() and get_option('x11').enabled(), +) + +if host_machine.system() == 'darwin' + gtk2_quartz_dep = dependency( + 'gtk+-quartz-2.0', + include_type: 'system', + required: get_option('gtk2').enabled() and get_option('cocoa').enabled(), + ) +else + gtk2_quartz_dep = disabler() +endif + +gtk3_dep = dependency( + 'gtk+-3.0', + include_type: 'system', + version: '>=3.14.0', + required: get_option('gtk3'), +) + +gtk3_x11_dep = dependency( + 'gtk+-x11-3.0', + include_type: 'system', + version: '>=3.14.0', + required: get_option('gtk3').enabled() and get_option('x11').enabled(), +) + +qt5_dep = dependency( + 'Qt5Widgets', + include_type: 'system', + version: '>=5.1.0', + required: get_option('qt5'), +) + +qt5_x11_dep = dependency( + 'Qt5X11Extras', + include_type: 'system', + version: '>=5.1.0', + required: get_option('qt5').enabled() and get_option('x11').enabled(), +) + +if host_machine.system() == 'darwin' and not get_option('cocoa').disabled() + objcpp.has_header( + 'QMacCocoaViewContainer', + dependencies: qt5_dep, + required: get_option('qt5').enabled() and get_option('cocoa').enabled(), + ) +endif + +########### +# Library # +########### + +include_dirs = include_directories('include') +c_headers = files('include/suil/suil.h') + +sources = files( + 'src/host.c', + 'src/instance.c', +) + +# Set appropriate arguments for building against the library type +extra_c_args = [] +if get_option('default_library') == 'static' + extra_c_args = ['-DSUIL_STATIC'] +endif + +# Build shared and/or static library +libsuil = library( + versioned_name, + sources, + c_args: c_suppressions + extra_c_args + platform_defines + ['-DSUIL_INTERNAL'], + dependencies: [dl_dep, lv2_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + soversion: soversion, + version: meson.project_version(), +) + +# Declare dependency for internal meson dependants +suil_dep = declare_dependency( + compile_args: extra_c_args, + dependencies: [dl_dep], + include_directories: include_dirs, + link_with: libsuil, +) + +# Generage pkg-config file for external dependants +pkg.generate( + libsuil, + description: 'Library for loading and wrapping LV2 plugin UIs', + extra_cflags: extra_c_args, + filebase: versioned_name, + name: 'Suil', + requires: ['lv2'], + subdirs: [versioned_name], + version: meson.project_version(), +) + +# Override pkg-config dependency for internal meson dependants +meson.override_dependency(versioned_name, suil_dep) + +# Install header to a versioned include directory +install_headers(c_headers, subdir: versioned_name / 'suil') + +##################### +# Host Init Modules # +##################### + +if x11_dep.found() + shared_module( + 'suil_x11', + files('src/x11.c'), + c_args: c_suppressions + platform_defines, + dependencies: [lv2_dep, x11_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + ) +endif + +################### +# Wrapper Modules # +################### + +gtk_args = [] +if cc.get_id() == 'clang' + gtk_args += [ + '-Wno-reserved-identifier', + ] +endif + +gtk_c_args = cc.get_supported_arguments(gtk_args) +gtk_cpp_args = cpp.get_supported_arguments(gtk_args) + +if gtk2_dep.found() and gtk2_x11_dep.found() and x11_dep.found() + shared_module( + 'suil_x11_in_gtk2', + files('src/x11_in_gtk2.c'), + c_args: c_suppressions + gtk_c_args + platform_defines, + dependencies: [gtk2_dep, gtk2_x11_dep, lv2_dep, x11_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + link_args: nodelete_c_link_args, + ) +endif + +if gtk3_dep.found() and gtk3_x11_dep.found() and x11_dep.found() + shared_module( + 'suil_x11_in_gtk3', + files('src/x11_in_gtk3.c'), + c_args: c_suppressions + gtk_c_args + platform_defines, + dependencies: [gtk3_dep, gtk3_x11_dep, lv2_dep, x11_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + link_args: nodelete_c_link_args, + ) +endif + +if gtk2_dep.found() and gtk2_quartz_dep.found() + shared_module( + 'suil_cocoa_in_gtk2', + files('src/cocoa_in_gtk2.mm'), + dependencies: [gtk2_dep, gtk2_quartz_dep, lv2_dep, qt5_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + objcpp_args: objcpp_suppressions + gtk_cpp_args + platform_defines, + ) +endif + +if gtk2_dep.found() and host_machine.system() == 'windows' + shared_module( + 'suil_win_in_gtk2', + files('src/win_in_gtk2.cpp'), + cpp_args: cpp_suppressions + gtk_cpp_args + platform_defines, + dependencies: [gtk2_dep, lv2_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + link_args: nodelete_cpp_link_args, + ) +endif + +if qt5_dep.found() and qt5_x11_dep.found() + shared_module( + 'suil_x11_in_qt5', + files('src/x11_in_qt5.cpp'), + cpp_args: cpp_suppressions + platform_defines, + dependencies: [lv2_dep, qt5_dep, qt5_x11_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + ) +endif + +if host_machine.system() == 'darwin' + if qt5_dep.found() and not get_option('cocoa').disabled() + cocoa_suppressions = [ + '-Wno-deprecated-declarations', + ] + + shared_module( + 'suil_cocoa_in_qt5', + files('src/cocoa_in_qt5.mm'), + dependencies: [lv2_dep, qt5_dep], + gnu_symbol_visibility: 'hidden', + include_directories: include_dirs, + install: true, + install_dir: suil_module_dir, + objcpp_args: cocoa_suppressions + objcpp_suppressions + platform_defines, + ) + endif +endif + +######### +# Tests # +######### + +if get_option('warning_level') == 'everything' + # Check release metadata + if not meson.is_subproject() + autoship = find_program('autoship', required: false) + if autoship.found() + test('autoship', autoship, args: ['test', suil_src_root], suite: 'data') + endif + endif + + # Check licensing metadata + reuse = find_program('reuse', required: false) + if reuse.found() + test('REUSE', reuse, args: ['--root', suil_src_root, 'lint'], suite: 'data') + endif +endif + +################# +# Documentation # +################# + +if not get_option('docs').disabled() + subdir('doc') +endif + +# Display top-level summary (augmented in subdirectories) +if not meson.is_subproject() + summary( + { + 'Install prefix': get_option('prefix'), + 'Headers': get_option('prefix') / get_option('includedir'), + 'Libraries': get_option('prefix') / get_option('libdir'), + }, + section: 'Directories', + ) +endif diff --git a/meson/suppressions/meson.build b/meson/suppressions/meson.build new file mode 100644 index 0000000..87af4d6 --- /dev/null +++ b/meson/suppressions/meson.build @@ -0,0 +1,157 @@ +# Copyright 2020-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +# Project-specific warning suppressions + +warning_level = get_option('warning_level') + +##### +# C # +##### + +if is_variable('cc') + c_suppressions = [] + + if cc.get_id() in ['clang', 'emscripten'] + if warning_level == 'everything' + c_suppressions += [ + '-Wno-atomic-implicit-seq-cst', + '-Wno-cast-function-type-strict', + '-Wno-cast-qual', + '-Wno-declaration-after-statement', + '-Wno-disabled-macro-expansion', + '-Wno-padded', + '-Wno-reserved-id-macro', + '-Wno-unsafe-buffer-usage', + '-Wno-variadic-macros', + ] + + if not meson.is_cross_build() + c_suppressions += [ + '-Wno-poison-system-directories', + ] + endif + endif + + if host_machine.system() == 'windows' + c_suppressions += [ + '-Wno-deprecated-declarations', + '-Wno-nonportable-system-include-path', + ] + endif + + elif cc.get_id() == 'gcc' + if warning_level == 'everything' + c_suppressions += [ + '-Wno-padded', + '-Wno-suggest-attribute=const', + '-Wno-suggest-attribute=pure', + ] + endif + + elif cc.get_id() == 'msvc' + c_suppressions += [ + '/experimental:external', + '/external:W0', + '/external:anglebrackets', + ] + + if warning_level == 'everything' + c_suppressions += [ + '/wd4191', # unsafe function conversion + '/wd4514', # unreferenced inline function has been removed + '/wd4710', # function not inlined + '/wd4820', # padding added after construct + '/wd5045', # will insert Spectre mitigation for memory load + ] + endif + + if warning_level in ['everything', '3', '2'] + c_suppressions += [ + '/wd4996', # function or variable may be unsafe + ] + endif + endif + + c_suppressions = cc.get_supported_arguments(c_suppressions) +endif + +####### +# C++ # +####### + +if is_variable('cpp') + cpp_suppressions = [] + + if cpp.get_id() in ['clang', 'emscripten'] + if warning_level == 'everything' + cpp_suppressions += [ + '-Wno-atomic-implicit-seq-cst', + '-Wno-c++98-compat', + '-Wno-c++98-compat-pedantic', + '-Wno-cast-function-type-strict', + '-Wno-cast-qual', + '-Wno-disabled-macro-expansion', + '-Wno-old-style-cast', + '-Wno-padded', + '-Wno-reserved-id-macro', + '-Wno-unsafe-buffer-usage', + '-Wno-variadic-macros', + '-Wno-zero-as-null-pointer-constant', + ] + endif + elif cpp.get_id() == 'gcc' + if warning_level == 'everything' + cpp_suppressions += [ + '-Wno-arith-conversion', + '-Wno-cast-qual', + '-Wno-padded', + '-Wno-suggest-attribute=const', + '-Wno-suggest-attribute=pure', + '-Wno-useless-cast', + '-Wno-volatile', + ] + endif + endif + + cpp_suppressions = cpp.get_supported_arguments(cpp_suppressions) +endif + +################# +# Objective C++ # +################# + +if is_variable('objcpp') + objcpp_suppressions = [] + + if objcpp.get_id() in ['clang', 'emscripten'] + if warning_level == 'everything' + objcpp_suppressions += [ + '-Wno-c++98-compat-pedantic', + '-Wno-deprecated-declarations', + '-Wno-old-style-cast', + '-Wno-padded', + '-Wno-reserved-id-macro', + '-Wno-weak-vtables', + '-Wno-zero-as-null-pointer-constant', + ] + + if not meson.is_cross_build() + objcpp_suppressions += [ + '-Wno-poison-system-directories', + ] + endif + endif + + elif objcpp.get_id() == 'gcc' + if warning_level == 'everything' + objcpp_suppressions = ( + gcc_common_warnings + [ + '-Wno-direct-ivar-access', + ] + ) + endif + endif + + objcpp_suppressions = objcpp.get_supported_arguments(objcpp_suppressions) +endif diff --git a/meson_options.txt b/meson_options.txt new file mode 100644 index 0000000..b468923 --- /dev/null +++ b/meson_options.txt @@ -0,0 +1,32 @@ +# Copyright 2021-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +option('cocoa', type: 'feature', value: 'auto', yield: true, + description : 'Build Cocoa wrappers') + +option('docs', type: 'feature', value: 'auto', yield: true, + description: 'Build documentation') + +option('gtk2', type: 'feature', value: 'auto', yield: true, + description : 'Build Gtk2 wrappers') + +option('gtk3', type: 'feature', value: 'auto', yield: true, + description : 'Build Gtk3 wrappers') + +option('html', type: 'feature', value: 'auto', yield: true, + description: 'Build paginated HTML documentation') + +option('qt5', type: 'feature', value: 'auto', yield: true, + description : 'Build Qt5 wrappers') + +option('singlehtml', type: 'feature', value: 'auto', yield: true, + description: 'Build single-page HTML documentation') + +option('tests', type: 'feature', value: 'auto', yield: true, + description: 'Build tests') + +option('title', type: 'string', value: 'Suil', + description: 'Project title') + +option('x11', type: 'feature', value: 'auto', yield: true, + description : 'Build X11 wrappers') diff --git a/scripts/dox_to_sphinx.py b/scripts/dox_to_sphinx.py deleted file mode 100755 index c9d401c..0000000 --- a/scripts/dox_to_sphinx.py +++ /dev/null @@ -1,674 +0,0 @@ -#!/usr/bin/env python3 - -# Copyright 2020 David Robillard <d@drobilla.net> -# -# Permission to use, copy, modify, and/or distribute this software for any -# purpose with or without fee is hereby granted, provided that the above -# copyright notice and this permission notice appear in all copies. -# -# THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES -# WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF -# MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR -# ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES -# WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN -# ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF -# OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. - -""" -Write Sphinx markup from Doxygen XML. - -Takes a path to a directory of XML generated by Doxygen, and emits a directory -with a reStructuredText file for every documented symbol. -""" - -import argparse -import os -import sys -import textwrap -import xml.etree.ElementTree - -__author__ = "David Robillard" -__date__ = "2020-11-18" -__email__ = "d@drobilla.net" -__license__ = "ISC" -__version__ = __date__.replace("-", ".") - - -def load_index(index_path): - """ - Load the index from XML. - - :returns: A dictionary from ID to skeleton records with basic information - for every documented entity. Some records have an ``xml_filename`` key - with the filename of a definition file. These files will be loaded later - to flesh out the records in the index. - """ - - root = xml.etree.ElementTree.parse(index_path).getroot() - index = {} - - for compound in root: - compound_id = compound.get("refid") - compound_kind = compound.get("kind") - compound_name = compound.find("name").text - if compound_kind in ["dir", "file", "page"]: - continue - - # Add record for compound (compounds appear only once in the index) - assert compound_id not in index - index[compound_id] = { - "kind": compound_kind, - "name": compound_name, - "xml_filename": compound_id + ".xml", - "children": [], - } - - name_prefix = ( - ("%s::" % compound_name) if compound_kind == "namespace" else "" - ) - - for child in compound.findall("member"): - if child.get("refid") in index: - assert compound_kind == "group" - continue - - # Everything has a kind and a name - child_record = { - "kind": child.get("kind"), - "name": name_prefix + child.find("name").text, - } - - if child.get("kind") == "enum": - # Enums are not compounds, but we want to resolve the parent of - # their values so they are not written as top level documents - child_record["children"] = [] - - if child.get("kind") == "enumvalue": - # Remove namespace prefix - child_record["name"] = child.find("name").text - - index[child.get("refid")] = child_record - - return index - - -def resolve_index(index, root): - """ - Walk a definition document and extend the index for linking. - - This does two things: sets the "parent" and "children" fields of all - applicable records, and sets the "strong" field of enums so that the - correct Sphinx role can be used when referring to them. - """ - - def add_child(index, parent_id, child_id): - parent = index[parent_id] - child = index[child_id] - - if child["kind"] == "enumvalue": - assert parent["kind"] == "enum" - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - else: - if parent["kind"] in ["class", "struct", "union"]: - assert "parent" not in child or child["parent"] == parent_id - child["parent"] = parent_id - - if child_id not in parent["children"]: - parent["children"] += [child_id] - - compound = root.find("compounddef") - compound_kind = compound.get("kind") - - if compound_kind == "group": - for subgroup in compound.findall("innergroup"): - add_child(index, compound.get("id"), subgroup.get("refid")) - - for klass in compound.findall("innerclass"): - add_child(index, compound.get("id"), klass.get("refid")) - - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - for member in section.findall("memberdef"): - if member.get("id") in index: - del index[member.get("id")] - else: - for member in section.findall("memberdef"): - member_id = member.get("id") - add_child(index, compound.get("id"), member_id) - - if member.get("kind") == "enum": - index[member_id]["strong"] = member.get("strong") == "yes" - for value in member.findall("enumvalue"): - add_child(index, member_id, value.get("id")) - - -def sphinx_role(record, lang): - """ - Return the Sphinx role used for a record. - - This is used for the description directive like ".. c:function::", and - links like ":c:func:`foo`. - """ - - kind = record["kind"] - - if kind in ["class", "function", "namespace", "struct", "union"]: - return lang + ":" + kind - - if kind == "define": - return "c:macro" - - if kind == "enum": - return lang + (":enum-class" if record["strong"] else ":enum") - - if kind == "typedef": - return lang + ":type" - - if kind == "enumvalue": - return lang + ":enumerator" - - if kind == "variable": - return lang + (":member" if "parent" in record else ":var") - - raise RuntimeError("No known role for kind '%s'" % kind) - - -def child_identifier(lang, parent_name, child_name): - """ - Return the identifier for an enum value or struct member. - - Sphinx, for some reason, uses a different syntax for this in C and C++. - """ - - separator = "::" if lang == "cpp" else "." - - return "%s%s%s" % (parent_name, separator, child_name) - - -def link_markup(index, lang, refid): - """Return a Sphinx link for a Doxygen reference.""" - - record = index[refid] - kind, name = record["kind"], record["name"] - role = sphinx_role(record, lang) - - if kind in ["class", "enum", "struct", "typedef", "union"]: - return ":%s:`%s`" % (role, name) - - if kind == "function": - return ":%s:func:`%s`" % (lang, name) - - if kind == "enumvalue": - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - if kind == "variable": - if "parent" not in record: - return ":%s:var:`%s`" % (lang, name) - - parent_name = index[record["parent"]]["name"] - return ":%s:`%s`" % (role, child_identifier(lang, parent_name, name)) - - raise RuntimeError("Unknown link target kind: %s" % kind) - - -def indent(markup, depth): - """ - Indent markup to a depth level. - - Like textwrap.indent() but takes an integer and works in reST indentation - levels for clarity." - """ - - return textwrap.indent(markup, " " * depth) - - -def heading(text, level): - """ - Return a ReST heading at a given level. - - Follows the style in the Python documentation guide, see - <https://devguide.python.org/documenting/#sections>. - """ - - assert 1 <= level <= 6 - - chars = ("#", "*", "=", "-", "^", '"') - line = chars[level] * len(text) - - return "%s\n%s\n%s\n\n" % (line if level < 3 else "", text, line) - - -def dox_to_rst(index, lang, node): - """ - Convert documentation commands (docCmdGroup) to Sphinx markup. - - This is used to convert the content of descriptions in the documentation. - It recursively parses all children tags and raises a RuntimeError if any - unknown tag is encountered. - """ - - def field_value(markup): - """Return a value for a field as a single line or indented block.""" - if "\n" in markup.strip(): - return "\n" + indent(markup, 1) - - return " " + markup.strip() - - if node.tag == "computeroutput": - # assert len(node) == 0 FIXME - return "``%s``" % node.text - - if node.tag == "itemizedlist": - markup = "" - for item in node.findall("listitem"): - assert len(item) == 1 - markup += "\n- %s" % dox_to_rst(index, lang, item[0]) - - return markup - - if node.tag == "para": - markup = node.text if node.text is not None else "" - for child in node: - markup += dox_to_rst(index, lang, child) - markup += child.tail if child.tail is not None else "" - - return markup.strip() + "\n\n" - - if node.tag == "parameterlist": - markup = "" - for item in node.findall("parameteritem"): - name = item.find("parameternamelist/parametername") - description = item.find("parameterdescription") - assert len(description) == 1 - markup += "\n\n:param %s:%s" % ( - name.text, - field_value(dox_to_rst(index, lang, description[0])), - ) - - return markup + "\n" - - if node.tag == "programlisting": - return "\n.. code-block:: %s\n\n%s" % ( - lang, - indent(plain_text(node), 1), - ) - - if node.tag == "ref": - refid = node.get("refid") - if refid not in index: - sys.stderr.write("warning: Unresolved link: %s\n" % refid) - return node.text - - assert len(node) == 0 - assert len(link_markup(index, lang, refid)) > 0 - return link_markup(index, lang, refid) - - if node.tag == "simplesect": - assert len(node) == 1 - - if node.get("kind") == "return": - return "\n:returns:" + field_value( - dox_to_rst(index, lang, node[0]) - ) - - if node.get("kind") == "see": - return dox_to_rst(index, lang, node[0]) - - raise RuntimeError("Unknown simplesect kind: %s" % node.get("kind")) - - if node.tag == "ulink": - return "`%s <%s>`_" % (node.text, node.get("url")) - - raise RuntimeError("Unknown documentation command: %s" % node.tag) - - -def description_markup(index, lang, node): - """Return the markup for a brief or detailed description.""" - - assert node.tag == "briefdescription" or node.tag == "detaileddescription" - assert not (node.tag == "briefdescription" and len(node) > 1) - assert len(node.text.strip()) == 0 - - return "".join([dox_to_rst(index, lang, child) for child in node]) - - -def set_descriptions(index, lang, definition, record): - """Set a record's brief/detailed descriptions from the XML definition.""" - - for tag in ["briefdescription", "detaileddescription"]: - node = definition.find(tag) - if node is not None: - record[tag] = description_markup(index, lang, node) - - -def set_template_params(node, record): - """Set a record's template_params from the XML definition.""" - - template_param_list = node.find("templateparamlist") - if template_param_list is not None: - params = [] - for param in template_param_list.findall("param"): - if param.find("declname") is not None: - # Value parameter - type_text = plain_text(param.find("type")) - name_text = plain_text(param.find("declname")) - - params += ["%s %s" % (type_text, name_text)] - else: - # Type parameter - params += ["%s" % (plain_text(param.find("type")))] - - record["template_params"] = "%s" % ", ".join(params) - - -def plain_text(node): - """ - Return the plain text of a node with all tags ignored. - - This is needed where Doxygen may include refs but Sphinx needs plain text - because it parses things itself to generate links. - """ - - if node.tag == "sp": - markup = " " - elif node.text is not None: - markup = node.text - else: - markup = "" - - for child in node: - markup += plain_text(child) - markup += child.tail if child.tail is not None else "" - - return markup - - -def local_name(name): - """Return a name with all namespace prefixes stripped.""" - - return name[name.rindex("::") + 2 :] if "::" in name else name - - -def read_definition_doc(index, lang, root): - """Walk a definition document and update described records in the index.""" - - # Set descriptions for the compound itself - compound = root.find("compounddef") - compound_record = index[compound.get("id")] - set_descriptions(index, lang, compound, compound_record) - set_template_params(compound, compound_record) - - if compound.find("title") is not None: - compound_record["title"] = compound.find("title").text.strip() - - # Set documentation for all children - for section in compound.findall("sectiondef"): - if section.get("kind").startswith("private"): - continue - - for member in section.findall("memberdef"): - kind = member.get("kind") - record = index[member.get("id")] - set_descriptions(index, lang, member, record) - set_template_params(member, record) - - if compound.get("kind") in ["class", "struct", "union"]: - assert kind in ["function", "typedef", "variable"] - record["type"] = plain_text(member.find("type")) - - if kind == "enum": - for value in member.findall("enumvalue"): - set_descriptions( - index, lang, value, index[value.get("id")] - ) - - elif kind == "function": - record["prototype"] = "%s %s%s" % ( - plain_text(member.find("type")), - member.find("name").text, - member.find("argsstring").text, - ) - - elif kind == "typedef": - name = local_name(record["name"]) - args_text = member.find("argsstring").text - target_text = plain_text(member.find("type")) - if args_text is not None: # Function pointer - assert target_text[-2:] == "(*" and args_text[0] == ")" - record["type"] = target_text + args_text - record["definition"] = target_text + name + args_text - else: # Normal named typedef - assert target_text is not None - record["type"] = target_text - if member.find("definition").text.startswith("using"): - record["definition"] = "%s = %s" % ( - name, - target_text, - ) - else: - record["definition"] = "%s %s" % ( - target_text, - name, - ) - - elif kind == "variable": - record["definition"] = member.find("definition").text - - -def declaration_string(record): - """ - Return the string that describes a declaration. - - This is what follows the directive, and is in C/C++ syntax, except without - keywords like "typedef" and "using" as expected by Sphinx. For example, - "struct ThingImpl Thing" or "void run(int value)". - """ - - kind = record["kind"] - result = "" - - if "template_params" in record: - result = "template <%s> " % record["template_params"] - - if kind == "function": - result += record["prototype"] - elif kind == "typedef": - result += record["definition"] - elif kind == "variable": - if "parent" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += record["definition"] - elif "type" in record: - result += "%s %s" % (record["type"], local_name(record["name"])) - else: - result += local_name(record["name"]) - - return result - - -def document_markup(index, lang, record): - """Return the complete document that describes some documented entity.""" - - kind = record["kind"] - role = sphinx_role(record, lang) - name = record["name"] - markup = "" - - if name != local_name(name): - markup += ".. cpp:namespace:: %s\n\n" % name[0 : name.rindex("::")] - - # Write top-level directive - markup += ".. %s:: %s\n" % (role, declaration_string(record)) - - # Write main description blurb - markup += "\n" - markup += indent(record["briefdescription"], 1) - markup += indent(record["detaileddescription"], 1) - - assert ( - kind in ["class", "enum", "namespace", "struct", "union"] - or "children" not in record - ) - - # Sphinx C++ namespaces work by setting a scope, they have no content - child_indent = 0 if kind == "namespace" else 1 - - # Write inline children if applicable - markup += "\n" - for child_id in record.get("children", []): - child_record = index[child_id] - child_role = sphinx_role(child_record, lang) - - child_header = ".. %s:: %s\n\n" % ( - child_role, - declaration_string(child_record), - ) - - markup += "\n" - markup += indent(child_header, child_indent) - markup += indent(child_record["briefdescription"], child_indent + 1) - markup += indent(child_record["detaileddescription"], child_indent + 1) - markup += "\n" - - return markup - - -def symbol_filename(name): - """Adapt the name of a symbol to be suitable for use as a filename.""" - - return name.replace("::", "__") - - -def emit_symbols(index, lang, symbol_dir, force): - """Write a description file for every symbol documented in the index.""" - - for record in index.values(): - if ( - record["kind"] in ["group", "namespace"] - or "parent" in record - and index[record["parent"]]["kind"] != "group" - ): - continue - - name = record["name"] - filename = os.path.join(symbol_dir, symbol_filename("%s.rst" % name)) - if not force and os.path.exists(filename): - raise FileExistsError("File already exists: '%s'" % filename) - - with open(filename, "w") as rst: - rst.write(heading(local_name(name), 3)) - rst.write(document_markup(index, lang, record)) - - -def emit_groups(index, output_dir, symbol_dir_name, force): - """Write a description file for every group documented in the index.""" - - for record in index.values(): - if record["kind"] != "group": - continue - - name = record["name"] - filename = os.path.join(output_dir, "%s.rst" % name) - if not force and os.path.exists(filename): - raise FileExistsError("File already exists: '%s'" % filename) - - with open(filename, "w") as rst: - rst.write(heading(record["title"], 2)) - - # Get all child group and symbol names - group_names = [] - symbol_names = [] - for child_id in record["children"]: - child = index[child_id] - if child["kind"] == "group": - group_names += [child["name"]] - else: - symbol_names += [child["name"]] - - # Emit description (document body) - rst.write(record["briefdescription"] + "\n\n") - rst.write(record["detaileddescription"] + "\n\n") - - # Emit TOC - rst.write(".. toctree::\n") - - # Emit groups at the top of the TOC - for group_name in group_names: - rst.write("\n" + indent(group_name, 1)) - - # Emit symbols in sorted order - for symbol_name in sorted(symbol_names): - path = "/".join( - [symbol_dir_name, symbol_filename(symbol_name)] - ) - rst.write("\n" + indent(path, 1)) - - rst.write("\n") - - -def run(index_xml_path, output_dir, symbol_dir_name, language, force): - """Write a directory of Sphinx files from a Doxygen XML directory.""" - - # Build skeleton index from index.xml - xml_dir = os.path.dirname(index_xml_path) - index = load_index(index_xml_path) - - # Load all definition documents - definition_docs = [] - for record in index.values(): - if "xml_filename" in record: - xml_path = os.path.join(xml_dir, record["xml_filename"]) - definition_docs += [xml.etree.ElementTree.parse(xml_path)] - - # Do an initial pass of the definition documents to resolve the index - for root in definition_docs: - resolve_index(index, root) - - # Finally read the documentation from definition documents - for root in definition_docs: - read_definition_doc(index, language, root) - - # Emit output files - symbol_dir = os.path.join(output_dir, symbol_dir_name) - os.makedirs(symbol_dir, exist_ok=True) - emit_symbols(index, language, symbol_dir, force) - emit_groups(index, output_dir, symbol_dir_name, force) - - -if __name__ == "__main__": - ap = argparse.ArgumentParser( - usage="%(prog)s [OPTION]... XML_DIR OUTPUT_DIR", - description=__doc__, - formatter_class=argparse.RawDescriptionHelpFormatter, - ) - - ap.add_argument( - "-f", - "--force", - action="store_true", - help="overwrite files", - ) - - ap.add_argument( - "-l", - "--language", - default="c", - choices=["c", "cpp"], - help="language domain for output", - ) - - ap.add_argument( - "-s", - "--symbol-dir-name", - default="symbols", - help="name for subdirectory of symbol documentation files", - ) - - ap.add_argument("index_xml_path", help="path index.xml from Doxygen") - ap.add_argument("output_dir", help="output directory") - - run(**vars(ap.parse_args(sys.argv[1:]))) diff --git a/src/cocoa_in_gtk2.mm b/src/cocoa_in_gtk2.mm index 204976b..8a505ed 100644 --- a/src/cocoa_in_gtk2.mm +++ b/src/cocoa_in_gtk2.mm @@ -1,19 +1,6 @@ -/* - Copyright 2011-2017 David Robillard <d@drobilla.net> - Copyright 2014 Robin Gareus <robin@gareus.org> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2022 David Robillard <d@drobilla.net> +// Copyright 2014 Robin Gareus <robin@gareus.org> +// SPDX-License-Identifier: ISC #include "suil_internal.h" #include "warnings.h" diff --git a/src/cocoa_in_qt5.mm b/src/cocoa_in_qt5.mm index 4f2e699..e0ac4e6 100644 --- a/src/cocoa_in_qt5.mm +++ b/src/cocoa_in_qt5.mm @@ -1,18 +1,5 @@ -/* - Copyright 2017 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2022 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "suil_config.h" #include "suil_internal.h" diff --git a/src/dylib.h b/src/dylib.h index 3ea98ef..ac8bfbc 100644 --- a/src/dylib.h +++ b/src/dylib.h @@ -1,18 +1,5 @@ -/* - Copyright 2020 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2020-2023 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #ifndef SUIL_DYLIB_H #define SUIL_DYLIB_H @@ -24,12 +11,13 @@ enum DylibFlags { DYLIB_GLOBAL = 0, DYLIB_LAZY = 1, - DYLIB_NOW = 2, + DYLIB_NOW = 2 }; static inline void* dylib_open(const char* const filename, const int flags) { + (void)flags; return LoadLibrary(filename); } @@ -52,7 +40,7 @@ dylib_error(void) enum DylibFlags { DYLIB_GLOBAL = RTLD_GLOBAL, DYLIB_LAZY = RTLD_LAZY, - DYLIB_NOW = RTLD_NOW, + DYLIB_NOW = RTLD_NOW }; static inline void* diff --git a/src/gtk2_in_qt5.cpp b/src/gtk2_in_qt5.cpp deleted file mode 100644 index a5c98f1..0000000 --- a/src/gtk2_in_qt5.cpp +++ /dev/null @@ -1,170 +0,0 @@ -/* - Copyright 2011-2015 David Robillard <d@drobilla.net> - Copyright 2015 Rui Nuno Capela <rncbc@rncbc.org> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "dylib.h" -#include "suil_config.h" // IWYU pragma: keep -#include "suil_internal.h" -#include "warnings.h" - -#include "lv2/core/lv2.h" -#include "suil/suil.h" - -SUIL_DISABLE_QT_WARNINGS -#include <QVBoxLayout> -#include <QWidget> -#include <QWindow> -#include <Qt> -#include <QtGui> -SUIL_RESTORE_WARNINGS - -#undef signals - -SUIL_DISABLE_GTK_WARNINGS -#include <gdk/gdk.h> -#include <glib-object.h> -#include <glib.h> -#include <gobject/gclosure.h> -#include <gtk/gtk.h> -SUIL_RESTORE_WARNINGS - -#include <cstdlib> - -extern "C" { - -struct SuilGtk2InQt5Wrapper { - QWidget* host_widget; - QWindow* window; - GtkWidget* plug; -}; - -static void -on_size_request(GtkWidget*, GtkRequisition* requisition, gpointer user_data) -{ - auto* const wrap = static_cast<QWidget*>(user_data); - wrap->setMinimumSize(requisition->width, requisition->height); -} - -static void -on_size_allocate(GtkWidget*, GdkRectangle* allocation, gpointer user_data) -{ - auto* const wrap = static_cast<QWidget*>(user_data); - wrap->resize(allocation->width, allocation->height); -} - -static void -wrapper_free(SuilWrapper* wrapper) -{ - auto* impl = static_cast<SuilGtk2InQt5Wrapper*>(wrapper->impl); - - if (impl->window) { - impl->window->setParent(nullptr); - delete impl->window; - } - - if (impl->plug) { - gtk_widget_destroy(impl->plug); - } - - delete impl->host_widget; - - free(impl); -} - -static int -wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) -{ - auto* const impl = static_cast<SuilGtk2InQt5Wrapper*>(wrapper->impl); - auto* const wrap = new QWidget(nullptr, Qt::Window); - GtkWidget* const plug = gtk_plug_new(0); - auto* const widget = static_cast<GtkWidget*>(instance->ui_widget); - - gtk_container_add(GTK_CONTAINER(plug), widget); - gtk_widget_show_all(plug); - - const WId wid = - static_cast<WId>(gtk_plug_get_id(reinterpret_cast<GtkPlug*>(plug))); - - QWindow* window = QWindow::fromWinId(wid); - QWidget* container = - QWidget::createWindowContainer(window, wrap, Qt::WindowFlags()); - - auto* layout = new QVBoxLayout(); - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(container, 0, Qt::Alignment()); - wrap->setLayout(layout); - -#ifdef SUIL_OLD_GTK - wrap->resize(widget->allocation.width, widget->allocation.height); -#else - GtkAllocation alloc; - gtk_widget_get_allocation(widget, &alloc); - wrap->resize(alloc.width, alloc.height); -#endif - - g_signal_connect( - G_OBJECT(plug), "size-request", G_CALLBACK(on_size_request), wrap); - - g_signal_connect( - G_OBJECT(plug), "size-allocate", G_CALLBACK(on_size_allocate), wrap); - - impl->host_widget = wrap; - impl->window = window; - impl->plug = plug; - instance->host_widget = wrap; - - return 0; -} - -SUIL_LIB_EXPORT -SuilWrapper* -suil_wrapper_new(SuilHost* host, - const char*, - const char*, - LV2_Feature***, - unsigned) -{ - /* We have to open libgtk here, so Gtk type symbols are present and will be - found by the introspection stuff. This is required at least to make - GtkBuilder use in UIs work, otherwise they will cause "Invalid object - type" errors. - */ - if (!host->gtk_lib) { - dylib_error(); - host->gtk_lib = dylib_open(SUIL_GTK2_LIB_NAME, DYLIB_LAZY | DYLIB_GLOBAL); - if (!host->gtk_lib) { - SUIL_ERRORF( - "Failed to open %s (%s)\n", SUIL_GTK2_LIB_NAME, dylib_error()); - return nullptr; - } - - gtk_init(nullptr, nullptr); - } - - /* Create wrapper implementation. */ - auto* const impl = - static_cast<SuilGtk2InQt5Wrapper*>(calloc(1, sizeof(SuilGtk2InQt5Wrapper))); - - auto* wrapper = static_cast<SuilWrapper*>(calloc(1, sizeof(SuilWrapper))); - wrapper->wrap = wrapper_wrap; - wrapper->free = wrapper_free; - wrapper->impl = impl; - - return wrapper; -} - -} // extern "C" @@ -1,19 +1,6 @@ -/* - Copyright 2011-2017 David Robillard <d@drobilla.net> - Copyright 2017 Stefan Westerfeld <stefan@space.twc.de> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// Copyright 2017 Stefan Westerfeld <stefan@space.twc.de> +// SPDX-License-Identifier: ISC #include "dylib.h" #include "suil_config.h" diff --git a/src/instance.c b/src/instance.c index 05357b2..441176c 100644 --- a/src/instance.c +++ b/src/instance.c @@ -1,18 +1,5 @@ -/* - Copyright 2007-2017 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2007-2022 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "dylib.h" #include "suil_internal.h" @@ -29,7 +16,6 @@ #define GTK2_UI_URI LV2_UI__GtkUI #define GTK3_UI_URI LV2_UI__Gtk3UI -#define QT4_UI_URI LV2_UI__Qt4UI #define QT5_UI_URI LV2_UI__Qt5UI #define X11_UI_URI LV2_UI__X11UI #define WIN_UI_URI LV2_UI_PREFIX "WindowsUI" @@ -50,29 +36,14 @@ suil_ui_supported(const char* host_type_uri, const char* ui_type_uri) } if ((!strcmp(host_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, QT4_UI_URI)) || - (!strcmp(host_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, QT5_UI_URI)) || - (!strcmp(host_type_uri, QT4_UI_URI) && - !strcmp(ui_type_uri, GTK2_UI_URI)) || - (!strcmp(host_type_uri, QT5_UI_URI) && - !strcmp(ui_type_uri, GTK2_UI_URI)) || - (!strcmp(host_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, X11_UI_URI)) || - (!strcmp(host_type_uri, GTK3_UI_URI) && - !strcmp(ui_type_uri, X11_UI_URI)) || + (!strcmp(ui_type_uri, COCOA_UI_URI) || + !strcmp(ui_type_uri, WIN_UI_URI) || + !strcmp(ui_type_uri, X11_UI_URI))) || (!strcmp(host_type_uri, GTK3_UI_URI) && - !strcmp(ui_type_uri, QT5_UI_URI)) || - (!strcmp(host_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, WIN_UI_URI)) || - (!strcmp(host_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, COCOA_UI_URI)) || - (!strcmp(host_type_uri, QT4_UI_URI) && !strcmp(ui_type_uri, X11_UI_URI)) || (!strcmp(host_type_uri, QT5_UI_URI) && - !strcmp(ui_type_uri, X11_UI_URI)) || - (!strcmp(host_type_uri, QT5_UI_URI) && - !strcmp(ui_type_uri, COCOA_UI_URI))) { + (!strcmp(ui_type_uri, COCOA_UI_URI) || + !strcmp(ui_type_uri, X11_UI_URI)))) { return SUIL_WRAPPING_EMBEDDED; } @@ -88,29 +59,6 @@ open_wrapper(SuilHost* host, { const char* module_name = NULL; - if (!strcmp(container_type_uri, QT4_UI_URI) && - !strcmp(ui_type_uri, GTK2_UI_URI)) { - module_name = "suil_gtk2_in_qt4"; - } - - - if (!strcmp(container_type_uri, QT5_UI_URI) && - !strcmp(ui_type_uri, GTK2_UI_URI)) { - module_name = "suil_gtk2_in_qt5"; - } - - - if (!strcmp(container_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, QT4_UI_URI)) { - module_name = "suil_qt4_in_gtk2"; - } - - - if (!strcmp(container_type_uri, GTK2_UI_URI) && - !strcmp(ui_type_uri, QT5_UI_URI)) { - module_name = "suil_qt5_in_gtk2"; - } - if (!strcmp(container_type_uri, GTK2_UI_URI) && !strcmp(ui_type_uri, X11_UI_URI)) { module_name = "suil_x11_in_gtk2"; @@ -121,11 +69,6 @@ open_wrapper(SuilHost* host, module_name = "suil_x11_in_gtk3"; } - if (!strcmp(container_type_uri, GTK3_UI_URI) && - !strcmp(ui_type_uri, QT5_UI_URI)) { - module_name = "suil_qt5_in_gtk3"; - } - if (!strcmp(container_type_uri, GTK2_UI_URI) && !strcmp(ui_type_uri, WIN_UI_URI)) { module_name = "suil_win_in_gtk2"; @@ -136,11 +79,6 @@ open_wrapper(SuilHost* host, module_name = "suil_cocoa_in_gtk2"; } - if (!strcmp(container_type_uri, QT4_UI_URI) && - !strcmp(ui_type_uri, X11_UI_URI)) { - module_name = "suil_x11_in_qt4"; - } - if (!strcmp(container_type_uri, QT5_UI_URI) && !strcmp(ui_type_uri, X11_UI_URI)) { module_name = "suil_x11_in_qt5"; diff --git a/src/qt5_in_gtk.cpp b/src/qt5_in_gtk.cpp deleted file mode 100644 index 6277daa..0000000 --- a/src/qt5_in_gtk.cpp +++ /dev/null @@ -1,252 +0,0 @@ -/* - Copyright 2011-2017 David Robillard <d@drobilla.net> - Copyright 2018 Rui Nuno Capela <rncbc@rncbc.org> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ - -#include "suil_internal.h" -#include "warnings.h" - -#include "lv2/core/lv2.h" -#include "lv2/options/options.h" -#include "lv2/ui/ui.h" -#include "lv2/urid/urid.h" -#include "suil/suil.h" - -SUIL_DISABLE_QT_WARNINGS -#include <QVBoxLayout> -#include <QWidget> -#include <QWindow> -#include <Qt> -#include <QtGui> -SUIL_RESTORE_WARNINGS - -#undef signals - -SUIL_DISABLE_GTK_WARNINGS - -#include <glib-object.h> -#include <glib.h> -#include <gobject/gclosure.h> -#include <gtk/gtk.h> - -#if GTK_MAJOR_VERSION == 3 -# include <gtk/gtkx.h> -#endif - -SUIL_RESTORE_WARNINGS - -#include <cstdlib> -#include <cstring> - -extern "C" { - -struct SuilQtWrapper { - GtkSocket socket; - QWidget* qembed; - SuilWrapper* wrapper; - SuilInstance* instance; - const LV2UI_Idle_Interface* idle_iface; - guint idle_id; - guint idle_ms; -}; - -struct SuilQtWrapperClass { - GtkSocketClass parent_class; -}; - -GType -suil_qt_wrapper_get_type(void); // Accessor for SUIL_TYPE_QT_WRAPPER - -#define SUIL_TYPE_QT_WRAPPER (suil_qt_wrapper_get_type()) -#define SUIL_QT_WRAPPER(obj) \ - (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_QT_WRAPPER, SuilQtWrapper)) - -G_DEFINE_TYPE(SuilQtWrapper, suil_qt_wrapper, GTK_TYPE_SOCKET) - -static void -suil_qt_wrapper_finalize(GObject* gobject) -{ - SuilQtWrapper* const self = SUIL_QT_WRAPPER(gobject); - - if (self->idle_id) { - g_source_remove(self->idle_id); - self->idle_id = 0; - } - - if (self->instance->handle) { - self->instance->descriptor->cleanup(self->instance->handle); - self->instance->handle = nullptr; - } - - if (self->qembed) { - self->qembed->deleteLater(); - } - - self->qembed = nullptr; - self->idle_iface = nullptr; - self->wrapper->impl = nullptr; - - G_OBJECT_CLASS(suil_qt_wrapper_parent_class)->finalize(gobject); -} - -static void -suil_qt_wrapper_class_init(SuilQtWrapperClass* klass) -{ - GObjectClass* const gobject_class = G_OBJECT_CLASS(klass); - - gobject_class->finalize = suil_qt_wrapper_finalize; -} - -static void -suil_qt_wrapper_init(SuilQtWrapper* self) -{ - self->qembed = nullptr; - self->wrapper = nullptr; - self->instance = nullptr; - self->idle_iface = nullptr; - self->idle_id = 0; - self->idle_ms = 1000 / 30; // 30 Hz default -} - -static void -suil_qt_wrapper_realize(GtkWidget* w, gpointer) -{ - SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(w); - GtkSocket* const s = GTK_SOCKET(w); - const WId id = static_cast<WId>(gtk_socket_get_id(s)); - - wrap->qembed->winId(); - wrap->qembed->windowHandle()->setParent(QWindow::fromWinId(id)); - wrap->qembed->show(); -} - -static int -suil_qt_wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) -{ - gtk_widget_set_size_request(GTK_WIDGET(handle), width, height); - - return 0; -} - -static gboolean -suil_qt_wrapper_idle(void* data) -{ - SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(data); - - if (wrap->idle_iface) { - wrap->idle_iface->idle(wrap->instance->handle); - return TRUE; // Continue calling - } - - return FALSE; -} - -static int -wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) -{ - SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(wrapper->impl); - - wrap->qembed = new QWidget(nullptr, Qt::WindowFlags()); - wrap->wrapper = wrapper; - wrap->instance = instance; - - auto* qwidget = static_cast<QWidget*>(instance->ui_widget); - auto* layout = new QVBoxLayout(); - layout->setMargin(0); - layout->setSpacing(0); - layout->addWidget(qwidget, 0, Qt::Alignment()); - - wrap->qembed->setLayout(layout); - - g_signal_connect_after( - G_OBJECT(wrap), "realize", G_CALLBACK(suil_qt_wrapper_realize), nullptr); - - instance->host_widget = GTK_WIDGET(wrap); - - const LV2UI_Idle_Interface* idle_iface = nullptr; - if (instance->descriptor->extension_data) { - idle_iface = static_cast<const LV2UI_Idle_Interface*>( - instance->descriptor->extension_data(LV2_UI__idleInterface)); - } - - if (idle_iface) { - wrap->idle_iface = idle_iface; - wrap->idle_id = g_timeout_add(wrap->idle_ms, suil_qt_wrapper_idle, wrap); - } - - return 0; -} - -static void -wrapper_free(SuilWrapper* wrapper) -{ - if (wrapper->impl) { - SuilQtWrapper* const wrap = SUIL_QT_WRAPPER(wrapper->impl); - gtk_widget_destroy(GTK_WIDGET(wrap)); - } -} - -SUIL_LIB_EXPORT -SuilWrapper* -suil_wrapper_new(SuilHost*, - const char*, - const char*, - LV2_Feature*** features, - unsigned n_features) -{ - auto* wrapper = static_cast<SuilWrapper*>(calloc(1, sizeof(SuilWrapper))); - wrapper->wrap = wrapper_wrap; - wrapper->free = wrapper_free; - - SuilQtWrapper* const wrap = - SUIL_QT_WRAPPER(g_object_new(SUIL_TYPE_QT_WRAPPER, nullptr)); - - wrap->wrapper = nullptr; - wrapper->impl = wrap; - - wrapper->resize.handle = wrap; - wrapper->resize.ui_resize = suil_qt_wrapper_resize; - - suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize); - suil_add_feature(features, &n_features, LV2_UI__idleInterface, nullptr); - - // Scan for URID map and options - LV2_URID_Map* map = nullptr; - LV2_Options_Option* options = nullptr; - for (LV2_Feature** f = *features; *f && (!map || !options); ++f) { - if (!strcmp((*f)->URI, LV2_OPTIONS__options)) { - options = static_cast<LV2_Options_Option*>((*f)->data); - } else if (!strcmp((*f)->URI, LV2_URID__map)) { - map = static_cast<LV2_URID_Map*>((*f)->data); - } - } - - if (map && options) { - // Set UI update rate if given - LV2_URID ui_updateRate = map->map(map->handle, LV2_UI__updateRate); - for (LV2_Options_Option* o = options; o->key; ++o) { - if (o->key == ui_updateRate) { - wrap->idle_ms = - static_cast<guint>(1000.0f / *static_cast<const float*>(o->value)); - - break; - } - } - } - - return wrapper; -} - -} // extern "C" diff --git a/src/suil_config.h b/src/suil_config.h index d4a740c..ce0fe33 100644 --- a/src/suil_config.h +++ b/src/suil_config.h @@ -1,18 +1,5 @@ -/* - Copyright 2021 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC /* Configuration header that defines reasonable defaults at compile time. diff --git a/src/suil_internal.h b/src/suil_internal.h index ac6e563..753bfb1 100644 --- a/src/suil_internal.h +++ b/src/suil_internal.h @@ -1,18 +1,5 @@ -/* - Copyright 2007-2017 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2007-2023 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #ifndef SUIL_INTERNAL_H #define SUIL_INTERNAL_H @@ -34,11 +21,6 @@ #ifdef __cplusplus extern "C" { -# if defined(__GNUC__) -# pragma GCC diagnostic push -# pragma GCC diagnostic ignored "-Wold-style-cast" -# pragma GCC diagnostic ignored "-Wzero-as-null-pointer-constant" -# endif #endif #define SUIL_ERRORF(fmt, ...) fprintf(stderr, "suil error: " fmt, __VA_ARGS__) @@ -113,21 +95,25 @@ suil_host_init(void); static inline void* suil_open_module(const char* module_name) { +#define N_SLICES 4 + const char* const env_dir = getenv("SUIL_MODULE_DIR"); const char* const mod_dir = env_dir ? env_dir : SUIL_MODULE_DIR; - const size_t path_len = - strlen(mod_dir) + strlen(SUIL_DIR_SEP SUIL_MODULE_PREFIX SUIL_MODULE_EXT) + - strlen(module_name) + 2; - - char* const path = (char*)calloc(path_len, 1); - snprintf(path, - path_len, - "%s%s%s%s%s", - mod_dir, - SUIL_DIR_SEP, - SUIL_MODULE_PREFIX, - module_name, - SUIL_MODULE_EXT); + + const char* const slices[N_SLICES] = { + mod_dir, SUIL_DIR_SEP SUIL_MODULE_PREFIX, module_name, SUIL_MODULE_EXT}; + + const size_t lengths[N_SLICES] = { + strlen(slices[0]), strlen(slices[1]), strlen(slices[2]), strlen(slices[3])}; + + const size_t path_len = lengths[0] + lengths[1] + lengths[2] + lengths[3]; + char* const path = (char*)calloc(path_len + 1, 1); + + size_t offset = 0; + for (size_t i = 0; i < N_SLICES; ++i) { + memcpy(path + offset, slices[i], lengths[i]); + offset += lengths[i]; + } dylib_error(); void* lib = dylib_open(path, DYLIB_NOW); @@ -137,6 +123,8 @@ suil_open_module(const char* module_name) free(path); return lib; + +#undef N_SLICES } typedef void (*SuilVoidFunc)(void); diff --git a/src/warnings.h b/src/warnings.h index b7a03aa..0622397 100644 --- a/src/warnings.h +++ b/src/warnings.h @@ -1,18 +1,5 @@ -/* - Copyright 2021 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #ifndef SUIL_WARNINGS_H #define SUIL_WARNINGS_H diff --git a/src/win_in_gtk2.cpp b/src/win_in_gtk2.cpp index 14b82e8..9c295e2 100644 --- a/src/win_in_gtk2.cpp +++ b/src/win_in_gtk2.cpp @@ -1,18 +1,5 @@ -/* - Copyright 2011-2015 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "suil_internal.h" #include "warnings.h" @@ -40,9 +27,6 @@ extern "C" { #define SUIL_WIN_WRAPPER(obj) \ (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_WIN_WRAPPER, SuilWinWrapper)) -using SuilWinWrapper = _SuilWinWrapper; -using SuilWinWrapperClass = _SuilWinWrapperClass; - struct _SuilWinWrapper { GtkDrawingArea area; SuilWrapper* wrapper; @@ -57,6 +41,9 @@ struct _SuilWinWrapperClass { GtkDrawingAreaClass parent_class; }; +using SuilWinWrapper = _SuilWinWrapper; +using SuilWinWrapperClass = _SuilWinWrapperClass; + GType suil_win_wrapper_get_type(void); // Accessor for SUIL_TYPE_WIN_WRAPPER @@ -1,19 +1,6 @@ -/* - Copyright 2017 David Robillard <d@drobilla.net> - Copyright 2017 Stefan Westerfeld <stefan@space.twc.de> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2017-2021 David Robillard <d@drobilla.net> +// Copyright 2017 Stefan Westerfeld <stefan@space.twc.de> +// SPDX-License-Identifier: ISC #include "suil_internal.h" diff --git a/src/x11_in_gtk2.c b/src/x11_in_gtk2.c index 80eef1a..78164c0 100644 --- a/src/x11_in_gtk2.c +++ b/src/x11_in_gtk2.c @@ -1,18 +1,5 @@ -/* - Copyright 2011-2020 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "suil_internal.h" #include "warnings.h" diff --git a/src/x11_in_gtk3.c b/src/x11_in_gtk3.c index c93f3dd..bd0ee3b 100644 --- a/src/x11_in_gtk3.c +++ b/src/x11_in_gtk3.c @@ -1,18 +1,5 @@ -/* - Copyright 2011-2020 David Robillard <d@drobilla.net> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2021 David Robillard <d@drobilla.net> +// SPDX-License-Identifier: ISC #include "suil_internal.h" #include "warnings.h" @@ -50,6 +37,7 @@ typedef struct { const LV2UI_Idle_Interface* idle_iface; guint idle_id; guint idle_ms; + guint idle_size_request_id; int initial_width; int initial_height; int req_width; @@ -114,6 +102,11 @@ on_plug_removed(GtkSocket* sock, gpointer data) self->idle_id = 0; } + if (self->idle_size_request_id) { + g_source_remove(self->idle_size_request_id); + self->idle_size_request_id = 0; + } + if (self->instance->handle) { self->instance->descriptor->cleanup(self->instance->handle); self->instance->handle = NULL; @@ -207,8 +200,11 @@ forward_key_event(SuilX11Wrapper* socket, GdkEvent* gdk_event) static gboolean idle_size_request(gpointer user_data) { - GtkWidget* w = GTK_WIDGET(user_data); + SuilX11Wrapper* socket = (SuilX11Wrapper*)user_data; + GtkWidget* w = GTK_WIDGET(socket->plug); + gtk_widget_queue_resize(w); + socket->idle_size_request_id = 0; return FALSE; } @@ -264,7 +260,7 @@ forward_size_request(SuilX11Wrapper* socket, GtkAllocation* allocation) } else { /* Child has not been realized, so unable to resize now. Queue an idle resize. */ - g_idle_add(idle_size_request, socket->plug); + socket->idle_size_request_id = g_idle_add(idle_size_request, socket); } } diff --git a/src/x11_in_qt5.cpp b/src/x11_in_qt5.cpp index a288319..7e3d6ac 100644 --- a/src/x11_in_qt5.cpp +++ b/src/x11_in_qt5.cpp @@ -1,19 +1,6 @@ -/* - Copyright 2011-2020 David Robillard <d@drobilla.net> - Copyright 2015 Rui Nuno Capela <rncbc@rncbc.org> - - Permission to use, copy, modify, and/or distribute this software for any - purpose with or without fee is hereby granted, provided that the above - copyright notice and this permission notice appear in all copies. - - THIS SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES - WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF - MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR - ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES - WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN - ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF - OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE. -*/ +// Copyright 2011-2022 David Robillard <d@drobilla.net> +// Copyright 2015 Rui Nuno Capela <rncbc@rncbc.org> +// SPDX-License-Identifier: ISC #include "suil_internal.h" #include "warnings.h" @@ -34,28 +21,23 @@ SUIL_DISABLE_QT_WARNINGS #include <X11/Xutil.h> SUIL_RESTORE_WARNINGS -#include <cstdint> #include <cstdlib> #undef signals -extern "C" { +namespace { class SuilQX11Widget : public QWidget { public: SuilQX11Widget(QWidget* parent, Qt::WindowFlags wflags) : QWidget(parent, wflags) - , _instance(nullptr) - , _idle_iface(nullptr) - , _window(0) - , _ui_timer(0) {} - SuilQX11Widget(const SuilQX11Widget&) = delete; + SuilQX11Widget(const SuilQX11Widget&) = delete; SuilQX11Widget& operator=(const SuilQX11Widget&) = delete; - SuilQX11Widget(SuilQX11Widget&&) = delete; + SuilQX11Widget(SuilQX11Widget&&) = delete; SuilQX11Widget& operator=(SuilQX11Widget&&) = delete; ~SuilQX11Widget() override; @@ -130,10 +112,10 @@ protected: } private: - SuilInstance* _instance; - const LV2UI_Idle_Interface* _idle_iface; - Window _window; - int _ui_timer; + SuilInstance* _instance{}; + const LV2UI_Idle_Interface* _idle_iface{}; + Window _window{}; + int _ui_timer{}; }; SuilQX11Widget::~SuilQX11Widget() = default; @@ -143,7 +125,7 @@ struct SuilX11InQt5Wrapper { SuilQX11Widget* parent; }; -static void +void wrapper_free(SuilWrapper* wrapper) { auto* impl = static_cast<SuilX11InQt5Wrapper*>(wrapper->impl); @@ -153,7 +135,7 @@ wrapper_free(SuilWrapper* wrapper) free(impl); } -static int +int wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) { auto* const impl = static_cast<SuilX11InQt5Wrapper*>(wrapper->impl); @@ -196,7 +178,7 @@ wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance) return 0; } -static int +int wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) { auto* const ew = static_cast<QWidget*>(handle); @@ -204,6 +186,10 @@ wrapper_resize(LV2UI_Feature_Handle handle, int width, int height) return 0; } +} // namespace + +extern "C" { + SUIL_LIB_EXPORT SuilWrapper* suil_wrapper_new(SuilHost*, diff --git a/subprojects/sphinxygen.wrap b/subprojects/sphinxygen.wrap new file mode 100644 index 0000000..9707d1a --- /dev/null +++ b/subprojects/sphinxygen.wrap @@ -0,0 +1,14 @@ +# Copyright 2022-2023 David Robillard <d@drobilla.net> +# SPDX-License-Identifier: 0BSD OR ISC + +[wrap-file] +directory = sphinxygen-1.0.4 +source_url = https://download.drobilla.net/sphinxygen-1.0.4.tar.gz +source_filename = sphinxygen-1.0.4.tar.gz +source_hash = 12fa9f18ed9fca608f272520072257ba61fd9eff25613f86d83d4fce14fc01f5 + +# [wrap-git] +# url = https://gitlab.com/drobilla/sphinxygen.git +# push-url = ssh://git@gitlab.com:drobilla/sphinxygen.git +# revision = v1.0.4 +# depth = 1 diff --git a/suil.pc.in b/suil.pc.in deleted file mode 100644 index 66810a6..0000000 --- a/suil.pc.in +++ /dev/null @@ -1,11 +0,0 @@ -prefix=@PREFIX@ -exec_prefix=@EXEC_PREFIX@ -libdir=@LIBDIR@ -includedir=@INCLUDEDIR@ - -Name: Suil -Version: @SUIL_VERSION@ -Description: LV2 plugin UI hosting library -Requires: @SUIL_PKG_DEPS@ -Libs: -L${libdir} -l@LIB_SUIL@ -Cflags: -I${includedir}/suil-@SUIL_MAJOR_VERSION@ diff --git a/suil.ttl b/suil.ttl new file mode 100644 index 0000000..8ee0388 --- /dev/null +++ b/suil.ttl @@ -0,0 +1,29 @@ +@prefix rdf: <http://www.w3.org/1999/02/22-rdf-syntax-ns#> . +@prefix rdfs: <http://www.w3.org/2000/01/rdf-schema#> . +@prefix doap: <http://usefulinc.com/ns/doap#> . +@prefix foaf: <http://xmlns.com/foaf/0.1/> . + +<http://drobilla.net/drobilla#me> + a foaf:Person ; + rdfs:seeAlso <http://drobilla.net/drobilla> ; + foaf:mbox <mailto:d@drobilla.net> ; + foaf:name "David Robillard" ; + foaf:nick "drobilla" . + +<http://drobilla.net/software/suil> + a doap:Project ; + doap:blog <https://drobilla.net/category/suil/> ; + doap:bug-database <https://gitlab.com/lv2/suil/issues> ; + doap:description "Library for loading and wrapping LV2 plugin UIs" ; + doap:developer <http://drobilla.net/drobilla#me> ; + doap:download-page <http://download.drobilla.net/> ; + doap:homepage <http://drobilla.net/software/suil> ; + doap:implements <http://lv2plug.in/ns/extensions/ui> ; + doap:license <http://opensource.org/licenses/isc> ; + doap:maintainer <http://drobilla.net/drobilla#me> ; + doap:name "Suil" ; + doap:programming-language "C" ; + doap:repository [ + a doap:GitBranch ; + doap:location <https://gitlab.com/lv2/suil.git> + ] . @@ -1,27 +0,0 @@ -#!/usr/bin/env python - -# Minimal waf script for projects that include waflib directly - -import sys -import inspect -import os - -try: - from waflib import Context, Scripting -except Exception as e: - sys.stderr.write('error: Failed to import waf (%s)\n' % e) - if os.path.exists('.git'): - sys.stderr.write("Are submodules up to date? " - "Try 'git submodule update --init --recursive'\n") - - sys.exit(1) - - -def main(): - script_path = os.path.abspath(inspect.getfile(inspect.getmodule(main))) - project_path = os.path.dirname(script_path) - Scripting.waf_entry_point(os.getcwd(), Context.WAFVERSION, project_path) - - -if __name__ == '__main__': - main() diff --git a/waflib b/waflib deleted file mode 160000 -Subproject b600c928b221a001faeab7bd92786d0b25714bc diff --git a/wscript b/wscript deleted file mode 100644 index f7cdddf..0000000 --- a/wscript +++ /dev/null @@ -1,472 +0,0 @@ -#!/usr/bin/env python - -from waflib import Build, Logs, Options, TaskGen -from waflib.extras import autowaf - -# Semver package/library version -SUIL_VERSION = '0.10.12' -SUIL_MAJOR_VERSION = SUIL_VERSION[0:SUIL_VERSION.find('.')] - -# Mandatory waf variables -APPNAME = 'suil' # Package name for waf dist -VERSION = SUIL_VERSION # Package version for waf dist -top = '.' # Source directory -out = 'build' # Build directory - -# Release variables -uri = 'http://drobilla.net/sw/suil' -dist_pattern = 'http://download.drobilla.net/suil-%d.%d.%d.tar.bz2' -post_tags = ['Hacking', 'LAD', 'LV2', 'Suil'] - - -def options(ctx): - ctx.load('compiler_c') - ctx.load('compiler_cxx') - opt = ctx.configuration_options() - - opt.add_option('--gtk2-lib-name', type='string', dest='gtk2_lib_name', - default="libgtk-x11-2.0.so.0", - help="Gtk2 library name [Default: libgtk-x11-2.0.so.0]") - opt.add_option('--gtk3-lib-name', type='string', dest='gtk3_lib_name', - default="libgtk-x11-3.0.so.0", - help="Gtk3 library name [Default: libgtk-x11-3.0.so.0]") - - ctx.add_flags( - opt, - {'static': 'build static library', - 'no-shared': 'do not build shared library', - 'no-cocoa': 'do not build support for Cocoa/Quartz', - 'no-gtk': 'do not build support for Gtk', - 'no-qt': 'do not build support for Qt (any version)', - 'no-qt5': 'do not build support for Qt5', - 'no-x11': 'do not build support for X11'}) - - -def configure(conf): - conf.load('compiler_c', cache=True) - conf.load('compiler_cxx', cache=True) - conf.load('autowaf', cache=True) - autowaf.set_c_lang(conf, 'c99') - autowaf.set_cxx_lang(conf, 'c++11') - - conf.env.BUILD_SHARED = not conf.options.no_shared - conf.env.BUILD_STATIC = conf.options.static - - if not conf.env.BUILD_SHARED and not conf.env.BUILD_STATIC: - conf.fatal('Neither a shared nor a static build requested') - - if conf.env.DOCS: - conf.load('sphinx') - - if Options.options.strict: - # Check for programs used by lint target - conf.find_program("flake8", var="FLAKE8", mandatory=False) - conf.find_program("clang-tidy", var="CLANG_TIDY", mandatory=False) - conf.find_program("iwyu_tool", var="IWYU_TOOL", mandatory=False) - - if Options.options.ultra_strict: - autowaf.add_compiler_flags(conf.env, '*', { - 'gcc': [ - '-Wno-padded', - '-Wno-suggest-attribute=const', - '-Wno-suggest-attribute=pure', - ], - 'clang': [ - '-Wno-cast-qual', - '-Wno-deprecated-declarations', # Mac - '-Wno-disabled-macro-expansion', - '-Wno-padded', - '-Wno-reserved-id-macro', # Mac - '-Wno-switch-enum', # Mac - ] - }) - - autowaf.add_compiler_flags(conf.env, 'c', { - 'msvc': [ - '/wd4514', # unreferenced inline function has been removed - '/wd4820', # padding added after construct - '/wd4191', # unsafe function conversion - '/wd5045', # will insert Spectre mitigation for memory load - ], - }) - - conf.env.NODELETE_FLAGS = [] - if (not conf.env.MSVC_COMPILER and - conf.check(linkflags = ['-Wl,-z,nodelete'], - msg = 'Checking for link flags -Wl,-z,-nodelete', - mandatory = False)): - conf.env.NODELETE_FLAGS = ['-Wl,-z,nodelete'] - - conf.check_pkg('lv2 >= 1.16.0', uselib_store='LV2') - - if not conf.options.no_x11: - conf.check_pkg('x11', uselib_store='X11', system=True, mandatory=False) - - def enable_module(var_name): - conf.env[var_name] = 1 - - if not conf.options.no_gtk: - conf.check_pkg('gtk+-2.0 >= 2.18.0', - uselib_store='GTK2', - system=True, - mandatory=False) - if not conf.env.HAVE_GTK2: - conf.check_pkg('gtk+-2.0', - uselib_store='GTK2', - system=True, - mandatory=False) - if conf.env.HAVE_GTK2: - conf.define('SUIL_OLD_GTK', 1) - - if not conf.options.no_x11: - conf.check_pkg('gtk+-x11-2.0', - uselib_store='GTK2_X11', - system=True, - mandatory=False) - - if not conf.options.no_cocoa: - conf.check_pkg('gtk+-quartz-2.0', - uselib_store='GTK2_QUARTZ', - system=True, - mandatory=False) - - conf.check_pkg('gtk+-3.0 >= 3.14.0', - uselib_store='GTK3', - system=True, - mandatory=False) - - if not conf.options.no_x11: - conf.check_pkg('gtk+-x11-3.0 >= 3.14.0', - uselib_store='GTK3_X11', - system=True, - mandatory=False) - - if not conf.options.no_qt: - if not conf.options.no_qt5: - conf.check_pkg('Qt5Widgets >= 5.1.0', - uselib_store='QT5', - system=True, - mandatory=False) - - if not conf.options.no_x11: - conf.check_pkg('Qt5X11Extras >= 5.1.0', - uselib_store='QT5_X11', - system=True, - mandatory=False) - - if not conf.options.no_cocoa: - if conf.check_cxx(header_name = 'QMacCocoaViewContainer', - uselib = 'QT5_COCOA', - system=True, - mandatory = False): - enable_module('SUIL_WITH_COCOA_IN_QT5') - - conf.check_cc(define_name = 'HAVE_LIBDL', - lib = 'dl', - mandatory = False) - - conf.define('SUIL_MODULE_DIR', - conf.env.LIBDIR + '/suil-' + SUIL_MAJOR_VERSION) - - conf.define('SUIL_GTK2_LIB_NAME', conf.options.gtk2_lib_name) - conf.define('SUIL_GTK3_LIB_NAME', conf.options.gtk3_lib_name) - - if conf.env.HAVE_GTK2 and conf.env.HAVE_QT5: - enable_module('SUIL_WITH_GTK2_IN_QT5') - enable_module('SUIL_WITH_QT5_IN_GTK2') - - if conf.env.HAVE_GTK2 and conf.env.HAVE_GTK2_X11: - enable_module('SUIL_WITH_X11_IN_GTK2') - - if conf.env.HAVE_GTK3 and conf.env.HAVE_GTK3_X11: - enable_module('SUIL_WITH_X11_IN_GTK3') - - if conf.env.HAVE_GTK3 and conf.env.HAVE_GTK3_X11 and conf.env.HAVE_QT5: - enable_module('SUIL_WITH_QT5_IN_GTK3') - - if conf.env.HAVE_GTK2 and conf.env.HAVE_GTK2_QUARTZ: - enable_module('SUIL_WITH_COCOA_IN_GTK2') - - if conf.env.HAVE_GTK2 and conf.env.DEST_OS == 'win32': - enable_module('SUIL_WITH_WIN_IN_GTK2') - - if conf.env.HAVE_QT5 and conf.env.HAVE_QT5_X11: - enable_module('SUIL_WITH_X11_IN_QT5') - - if conf.env.HAVE_X11: - enable_module('SUIL_WITH_X11') - - conf.run_env.append_unique('SUIL_MODULE_DIR', [conf.build_path()]) - - # Set up environment for building/using as a subproject - autowaf.set_lib_env(conf, 'suil', SUIL_VERSION, - include_path=str(conf.path.find_node('include'))) - - conf.define('SUIL_NO_DEFAULT_CONFIG', 1) - - autowaf.display_summary( - conf, - {'Static library': bool(conf.env.BUILD_STATIC), - 'Shared library': bool(conf.env.BUILD_SHARED)}) - - if conf.env.HAVE_GTK2: - autowaf.display_msg(conf, "Gtk2 Library Name", - conf.get_define('SUIL_GTK2_LIB_NAME')) - if conf.env.HAVE_GTK3: - autowaf.display_msg(conf, "Gtk3 Library Name", - conf.get_define('SUIL_GTK3_LIB_NAME')) - - # Print summary message for every potentially supported wrapper - wrappers = [('cocoa', 'gtk2'), - ('gtk2', 'qt5'), - ('qt5', 'gtk2'), - ('win', 'gtk2'), - ('x11', 'gtk2'), - ('x11', 'gtk3'), - ('qt5', 'gtk3'), - ('x11', 'qt5'), - ('cocoa', 'qt5')] - for w in wrappers: - var = 'SUIL_WITH_%s_IN_%s' % (w[0].upper(), w[1].upper()) - autowaf.display_msg(conf, 'Support for %s in %s' % (w[0], w[1]), - bool(conf.env[var])) - - -def build(bld): - # C Headers - includedir = '${INCLUDEDIR}/suil-%s/suil' % SUIL_MAJOR_VERSION - bld.install_files(includedir, bld.path.ant_glob('include/suil/*.h')) - TaskGen.task_gen.mappings['.mm'] = TaskGen.task_gen.mappings['.cc'] - - # Pkgconfig file - autowaf.build_pc(bld, 'SUIL', SUIL_VERSION, SUIL_MAJOR_VERSION, [], - {'SUIL_MAJOR_VERSION': SUIL_MAJOR_VERSION, - 'SUIL_PKG_DEPS': 'lv2'}) - - cflags = [] - lib = [] - modlib = [] - if bld.env.DEST_OS == 'win32': - modlib += ['user32'] - else: - cflags += ['-fvisibility=hidden'] - if bld.is_defined('HAVE_LIBDL'): - lib += ['dl'] - modlib += ['dl'] - - module_dir = '${LIBDIR}/suil-' + SUIL_MAJOR_VERSION - - # Shared Library - if bld.env.BUILD_SHARED: - bld(features = 'c cshlib', - export_includes = ['include'], - source = 'src/host.c src/instance.c', - target = 'suil-%s' % SUIL_MAJOR_VERSION, - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - name = 'libsuil', - vnum = SUIL_VERSION, - install_path = '${LIBDIR}', - cflags = cflags, - lib = lib, - uselib = 'LV2') - - # Static library - if bld.env.BUILD_STATIC: - bld(features = 'c cstlib', - export_includes = ['include'], - source = 'src/host.c src/instance.c', - target = 'suil-%s' % SUIL_MAJOR_VERSION, - includes = ['.', 'include'], - defines = ['SUIL_STATIC', 'SUIL_INTERNAL'], - name = 'libsuil_static', - vnum = SUIL_VERSION, - install_path = '${LIBDIR}', - cflags = cflags, - lib = lib, - uselib = 'LV2') - - if bld.env.SUIL_WITH_GTK2_IN_QT5: - bld(features = 'cxx cxxshlib', - source = 'src/gtk2_in_qt5.cpp', - target = 'suil_gtk2_in_qt5', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cxxflags = cflags, - lib = modlib, - uselib = 'GTK2 QT5 LV2') - - if bld.env.SUIL_WITH_QT5_IN_GTK2: - bld(features = 'cxx cxxshlib', - source = 'src/qt5_in_gtk.cpp', - target = 'suil_qt5_in_gtk2', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cxxflags = cflags, - lib = modlib, - uselib = 'GTK2 QT5 LV2', - linkflags = bld.env.NODELETE_FLAGS) - - if bld.env.SUIL_WITH_X11_IN_GTK2: - bld(features = 'c cshlib', - source = 'src/x11_in_gtk2.c', - target = 'suil_x11_in_gtk2', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib + ['X11'], - uselib = 'GTK2 GTK2_X11 LV2', - linkflags = bld.env.NODELETE_FLAGS) - - if bld.env.SUIL_WITH_X11_IN_GTK3: - bld(features = 'c cshlib', - source = 'src/x11_in_gtk3.c', - target = 'suil_x11_in_gtk3', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib + ['X11'], - uselib = 'GTK3 GTK3_X11 LV2', - linkflags = bld.env.NODELETE_FLAGS) - - if bld.env.SUIL_WITH_QT5_IN_GTK3: - bld(features = 'cxx cxxshlib', - source = 'src/qt5_in_gtk.cpp', - target = 'suil_qt5_in_gtk3', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'GTK3 QT5 LV2', - linkflags = bld.env.NODELETE_FLAGS) - - if bld.env.SUIL_WITH_COCOA_IN_GTK2: - bld(features = 'cxx cshlib', - source = 'src/cocoa_in_gtk2.mm', - target = 'suil_cocoa_in_gtk2', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'GTK2 LV2', - linkflags = ['-framework', 'Cocoa']) - - if bld.env.SUIL_WITH_WIN_IN_GTK2: - bld(features = 'cxx cxxshlib', - source = 'src/win_in_gtk2.cpp', - target = 'suil_win_in_gtk2', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'GTK2 LV2', - linkflags = bld.env.NODELETE_FLAGS) - - if bld.env.SUIL_WITH_X11_IN_QT5: - bld(features = 'cxx cxxshlib', - source = 'src/x11_in_qt5.cpp', - target = 'suil_x11_in_qt5', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'QT5 QT5_X11 LV2 X11') - - if bld.env.SUIL_WITH_COCOA_IN_QT5: - bld(features = 'cxx cxxshlib', - source = 'src/cocoa_in_qt5.mm', - target = 'suil_cocoa_in_qt5', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'QT5 QT5_COCOA LV2', - linkflags = ['-framework', 'Cocoa']) - - if bld.env.SUIL_WITH_X11: - bld(features = 'c cshlib', - source = 'src/x11.c', - target = 'suil_x11', - includes = ['.', 'include'], - defines = ['SUIL_INTERNAL'], - install_path = module_dir, - cflags = cflags, - lib = modlib, - uselib = 'X11 LV2') - - # Documentation - if bld.env.DOCS: - bld.recurse('doc/c') - - bld.add_post_fun(autowaf.run_ldconfig) - - -class LintContext(Build.BuildContext): - fun = cmd = 'lint' - - -def lint(ctx): - "checks code for style issues" - import glob - import os - import subprocess - import sys - - st = 0 - - if "FLAKE8" in ctx.env: - Logs.info("Running flake8") - st = subprocess.call([ctx.env.FLAKE8[0], - "wscript", - "--ignore", - "E101,E129,W191,E221,W504,E251,E241,E741"]) - else: - Logs.warn("Not running flake8") - - if "IWYU_TOOL" in ctx.env: - Logs.info("Running include-what-you-use") - - qt_mapping_file = "/usr/share/include-what-you-use/qt5_11.imp" - extra_args = [] - if os.path.exists(qt_mapping_file): - extra_args += ["--", "-Xiwyu", "--mapping_file=" + qt_mapping_file] - - cmd = [ctx.env.IWYU_TOOL[0], "-o", "clang", "-p", "build"] + extra_args - output = subprocess.check_output(cmd).decode('utf-8') - if 'error: ' in output: - sys.stdout.write(output) - st += 1 - else: - Logs.warn("Not running include-what-you-use") - - if "CLANG_TIDY" in ctx.env and "clang" in ctx.env.CC[0]: - Logs.info("Running clang-tidy") - sources = glob.glob('src/*.c') + glob.glob('tests/*.c') - sources = list(map(os.path.abspath, sources)) - procs = [] - for source in sources: - cmd = [ctx.env.CLANG_TIDY[0], "--quiet", "-p=.", source] - procs += [subprocess.Popen(cmd, cwd="build")] - - for proc in procs: - stdout, stderr = proc.communicate() - st += proc.returncode - else: - Logs.warn("Not running clang-tidy") - - if st != 0: - sys.exit(st) - - -def dist(ctx): - ctx.base_path = ctx.path - ctx.excl = ctx.get_excl() + ' .gitmodules' |