13
0
Fork 0

Localize stripped down gtk2

This is intended mainly for GNU/Linux distros who will remove
GTK2 support in the near future.
This commit is contained in:
Robin Gareus 2023-12-13 06:45:00 +01:00
parent 2a928dae19
commit ad51c7c2ba
Signed by: rgareus
GPG Key ID: A090BCE02CF57F04
1528 changed files with 915658 additions and 57 deletions

2
.gitignore vendored
View File

@ -59,6 +59,8 @@ tags
/libs/ardour/libardour.pot
/libs/gtkmm2ext/po/*.mo
/libs/gtkmm2ext/libgtkmm2ext.pot
/libs/tk/ytk/po/*.mo
/libs/tk/ytk/*.pot
/gtk2_ardour/appdata/po/*.mo
/gtk2_ardour/appdata/*.pot
/gtk2_ardour/ardour.appdata.xml.in

View File

@ -32,6 +32,10 @@ export PBD_TEST_PATH=$TOP/libs/pbd/test
export EVORAL_TEST_PATH=$TOP/libs/evoral/test/testdata
export MIDIPP_TEST_PATH=$TOP/share/patchfiles
if test -d $libs/tk/suil; then
export SUIL_MODULE_DIR=$libs/tk/suil
fi
#
# even though we set the above variables, ardour requires that these
# two also be set. the above settings will override them.
@ -43,7 +47,7 @@ export ARDOUR_DLL_PATH=$libs
export GTK_PATH=~/.ardour3:$libs/clearlooks-newer
export VAMP_PATH=$libs/vamp-plugins:$libs/vamp-pyin${VAMP_PATH:+:$VAMP_PATH}
export LD_LIBRARY_PATH=$libs/ptformat:$libs/qm-dsp:$libs/vamp-sdk:$libs/surfaces:$libs/ctrl-interface/control_protocol:$libs/ctrl-interface/midi_surface:$libs/ardour:$libs/midi++2:$libs/pbd:$libs/rubberband:$libs/soundtouch:$libs/aaf:$libs/gtkmm2ext:$libs/widgets:$libs/appleutility:$libs/taglib:$libs/evoral:$libs/evoral/src/libsmf:$libs/audiographer:$libs/temporal:$libs/libltc:$libs/canvas:$libs/waveview:$libs/ardouralsautil${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
export LD_LIBRARY_PATH=$libs/tk/ydk-pixbuf:$libs/tk/ztk::$libs/tk/ydk:$libs/tk/ytk:$libs/tk/ztkmm:$libs/tk/ydkmm:$libs/tk/ytkmm:$libs/tk/suil:$libs/ptformat:$libs/qm-dsp:$libs/vamp-sdk:$libs/surfaces:$libs/ctrl-interface/control_protocol:$libs/ctrl-interface/midi_surface:$libs/ardour:$libs/midi++2:$libs/pbd:$libs/rubberband:$libs/soundtouch:$libs/aaf:$libs/gtkmm2ext:$libs/widgets:$libs/appleutility:$libs/taglib:$libs/evoral:$libs/evoral/src/libsmf:$libs/audiographer:$libs/temporal:$libs/libltc:$libs/canvas:$libs/waveview:$libs/ardouralsautil${LD_LIBRARY_PATH:+:$LD_LIBRARY_PATH}
# DYLD_LIBRARY_PATH is for darwin.
export DYLD_FALLBACK_LIBRARY_PATH=$LD_LIBRARY_PATH

View File

@ -196,7 +196,7 @@ UIConfiguration::reset_dpi ()
/* FT2 rendering - used by GnomeCanvas, sigh */
#ifndef PLATFORM_WINDOWS
#ifndef PLATFORM_WINDOWS // HAVE_PANGOFT2
pango_ft2_font_map_set_resolution ((PangoFT2FontMap*) pango_ft2_font_map_new(), val/1024, val/1024); // XXX pango_ft2_font_map_new leaks
#endif

View File

@ -445,15 +445,15 @@ def configure(conf):
atleast_version='1.2.1')
autowaf.check_pkg(conf, 'gthread-2.0', uselib_store='GTHREAD',
atleast_version='2.10.1')
autowaf.check_pkg(conf, 'gtk+-2.0', uselib_store='GTK',
atleast_version='2.18')
autowaf.check_pkg(conf, 'gtkmm-2.4', uselib_store='GTKMM',
atleast_version='2.18')
autowaf.check_pkg(conf, 'ogg', uselib_store='OGG', atleast_version='1.1.2')
autowaf.check_pkg(conf, 'x11', uselib_store='X11', atleast_version='1.1', mandatory=False)
autowaf.check_pkg(conf, 'pangoft2', uselib_store='PANGOFT2', atleast_version='1.36.8', mandatory=False)
autowaf.check_pkg(conf, 'fontconfig', uselib_store='FONTCONFIG')
if not conf.is_defined('YTK'):
autowaf.check_pkg(conf, 'gtk+-2.0', uselib_store='GTK', atleast_version='2.18')
autowaf.check_pkg(conf, 'gtkmm-2.4', uselib_store='GTKMM', atleast_version='2.18', mandatory=True)
if conf.env.CC_NAME == 'gcc' and Options.options.strict:
conf.define('GLIB_DISABLE_DEPRECATION_WARNINGS', 1)
for var in ['CFLAGS', 'CXXFLAGS']:
@ -516,14 +516,22 @@ def build(bld):
'LOCALEDIR="' + os.path.normpath(bld.env['LOCALEDIR']) + '"',
]
obj.linkflags = ''
obj.uselib = 'UUID FLAC FONTCONFIG GLIBMM GTHREAD GTK OGG CURL DL GTKMM CANVAS FFTW3F LO TAGLIB XML LILV RUBBERBAND AUBIO LRDF ARCHIVE VAMPSDK VAMPHOSTSDK'
obj.uselib = 'UUID FLAC FONTCONFIG GTHREAD GTK OGG PANGOMM CURL DL CANVAS FFTW3F LO TAGLIB XML LILV RUBBERBAND AUBIO LRDF ARCHIVE VAMPSDK VAMPHOSTSDK'
obj.source += [ 'luadoc.cc', 'bundle_env_linux.cc' ]
obj.use += [ 'X11' ]
if bld.is_defined('YTK'):
obj.use += [ 'libytk', 'libytkmm' ]
obj.uselib += ' GLIBMM GIOMM PANGOMM PANGOFT2 LIBPNG'
else:
obj.uselib += ' GTKMM'
if bld.is_defined('HAVE_USB'):
obj.uselib += ' USB'
if bld.is_defined('HAVE_SUIL'):
obj.source += [ 'lv2_plugin_ui.cc' ]
obj.use += [ 'SUIL' ]
if bld.is_defined('YTK'):
obj.use += [ 'libsuil' ]
else:
obj.uselib += ' SUIL'
if bld.is_defined('LXVST_SUPPORT'):
obj.source += [ 'vst_plugin_ui.cc' ]
obj.source += [ 'linux_vst_gui_support.cc', 'lxvst_plugin_ui.cc' ]
@ -605,8 +613,13 @@ def build(bld):
]
obj.install_path = bld.env['DLLDIR']
obj.linkflags = ''
obj.uselib = 'UUID FLAC FONTCONFIG GLIBMM GTHREAD GTK OGG CURL DL GTKMM CANVAS FFTW3F LO TAGLIB XML LILV RUBBERBAND AUBIO LRDF ARCHIVE VAMPSDK VAMPHOSTSDK'
obj.uselib = 'UUID FLAC FONTCONFIG GTHREAD OGG PANGOMM CURL DL CANVAS FFTW3F LO TAGLIB XML LILV RUBBERBAND AUBIO LRDF ARCHIVE VAMPSDK VAMPHOSTSDK'
if bld.is_defined('YTK'):
obj.use += [ 'libytk', 'libytkmm' ]
obj.uselib += ' GLIBMM GIOMM PANGOFT2 LIBPNG'
else:
obj.uselib += ' GTKMM GTK'
if bld.is_defined('HAVE_USB'):
obj.uselib += ' USB'
if sys.platform == 'darwin':

View File

@ -40,7 +40,10 @@ def build(bld):
obj.uselib += ' FFTW3F LO TAGLIB LILV RUBBERBAND AUBIO LRDF ARCHIVE VAMPSDK VAMPHOSTSDK'
if bld.is_defined('HAVE_SUIL'):
obj.uselib += ' SUIL'
if bld.is_defined('YTK'):
obj.use += [ 'libsuil' ]
else:
obj.uselib += ' SUIL'
if bld.is_defined('HAVE_USB'):
obj.uselib += ' USB'

View File

@ -317,8 +317,6 @@ def configure(conf):
atleast_version='0.2.0', mandatory=True)
autowaf.check_pkg(conf, 'lilv-0', uselib_store='LILV',
atleast_version='0.24.2', mandatory=True)
autowaf.check_pkg(conf, 'suil-0', uselib_store='SUIL',
atleast_version='0.6.0', mandatory=False)
conf.define ('LV2_SUPPORT', 1)
# non-standard LV2 extention -- TODO: add option to disable??
@ -427,7 +425,10 @@ def build(bld):
obj.source += ['lv2_plugin.cc', 'lv2_evbuf.c', 'uri_map.cc']
obj.uselib += ['LILV']
if bld.is_defined('HAVE_SUIL'):
obj.uselib += ['SUIL']
if bld.is_defined('YTK'):
obj.use += [ 'libsuil' ]
else:
obj.uselib += ['SUIL']
if bld.is_defined('WINDOWS_VST_SUPPORT'):
obj.source += [ 'windows_vst_plugin.cc']

View File

@ -76,7 +76,7 @@ def build(bld):
obj.export_includes = ['.']
obj.includes = ['.']
obj.uselib = 'SIGCPP CAIROMM GTKMM BOOST XML OSX'
obj.uselib = 'SIGCPP CAIROMM PANGOMM BOOST XML OSX'
obj.use = [ 'libpbd', 'libgtkmm2ext' ]
obj.name = 'libcanvas'
obj.target = 'canvas'
@ -84,6 +84,12 @@ def build(bld):
obj.install_path = bld.env['LIBDIR']
obj.defines += [ 'PACKAGE="' + I18N_PACKAGE + '"' ]
if bld.is_defined('YTK'):
obj.use += [ 'libytkmm' ]
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'
# canvas unit-tests are outdated
if False and bld.env['BUILD_TESTS'] and bld.is_defined('HAVE_CPPUNIT'):
unit_testobj = bld(features = 'cxx cxxprogram')

View File

@ -27,11 +27,16 @@ def build(bld):
obj.name = 'clearlooks-newer'
obj.target = 'clearlooks'
obj.uselib = 'GTK'
obj.includes = '.'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'engines')
autowaf.ensure_visible_symbols (obj, True)
if bld.is_defined('YTK'):
obj.use = [ 'libztk', 'libytk', 'libydk-pixbuf' ]
obj.uselib = ' CAIRO PANGO'
else:
obj.uselib = 'GTK'
if sys.platform == 'darwin':
# Bit of a hack: make a symlink to the .dylib that meets GTK's criteria for finding it (namely that the library must be a *.so
# and that it must reside in a directory called `engines')

View File

@ -51,8 +51,9 @@ def options(opt):
pass
def configure(conf):
autowaf.check_pkg(conf, 'gtkmm-2.4', uselib_store='GTKMM', atleast_version='2.8')
autowaf.check_pkg(conf, 'gtk+-2.0', uselib_store='GTK', atleast_version='2.12.1')
if not conf.is_defined('YTK'):
autowaf.check_pkg(conf, 'gtkmm-2.4', uselib_store='GTKMM', atleast_version='2.8')
autowaf.check_pkg(conf, 'gtk+-2.0', uselib_store='GTK', atleast_version='2.12.1')
def build(bld):
# operate on copy to avoid adding sources twice
@ -71,7 +72,7 @@ def build(bld):
obj.includes = ['.']
obj.name = 'libgtkmm2ext'
obj.target = 'gtkmm2ext'
obj.uselib = 'GTKMM GTK XML'
obj.uselib = 'XML CAIROMM PANGOMM'
obj.use = [ 'libpbd' ]
obj.vnum = GTKMM2EXT_LIB_VERSION
obj.install_path = bld.env['LIBDIR']
@ -79,6 +80,11 @@ def build(bld):
'PACKAGE="' + I18N_PACKAGE + '"',
'LOCALEDIR="' + os.path.join(
os.path.normpath(bld.env['DATADIR']), 'locale') + '"']
if bld.is_defined('YTK'):
obj.use += [ 'libydk', 'libydkmm', 'libytkmm' ]
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM GTK'
if sys.platform == 'darwin':
obj.source += ['gtkapplication_quartz.mm', 'nsglview.mm']
obj.uselib += ' OSX'

View File

@ -20,6 +20,11 @@ def build(bld):
obj.includes = [ '.', './cc121']
obj.name = 'libardour_cc121'
obj.target = 'ardour_cc121'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM PANGOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -22,9 +22,11 @@ def build(bld):
obj.includes = [ '.', './console1']
obj.name = 'libardour_console1'
obj.target = 'ardour_console1'
obj.uselib = 'GTKMM SIGCPP XML OSX'
obj.uselib = 'SIGCPP XML OSX'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM PANGOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -21,6 +21,11 @@ def build(bld):
obj.includes = ['.', '../libs', '../../widgets']
obj.name = 'libardour_contourdesign'
obj.target = 'ardour_contourdesign'
obj.uselib = 'GTKMM USB XML OSX'
obj.uselib = 'USB XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd libwidgets'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -20,6 +20,11 @@ def build(bld):
obj.includes = [ '.', './faderport']
obj.name = 'libardour_faderport'
obj.target = 'ardour_faderport'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -25,9 +25,14 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_faderport8'
obj.target = 'ardour_faderport8'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX CAIROMM PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'
obj = bld(features = 'cxx cxxshlib')
obj.source = list(fp8_16_sources)
@ -38,9 +43,14 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_faderport16'
obj.target = 'ardour_faderport16'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX CAIROMM PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'
obj = bld(features = 'cxx cxxshlib')
obj.source = list(fp8_16_sources)
@ -51,6 +61,11 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_faderport2'
obj.target = 'ardour_faderport2'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX CAIROMM PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -24,6 +24,11 @@ def build(bld):
obj.includes = [ '.', './generic_midi']
obj.name = 'libardour_generic_midi'
obj.target = 'ardour_generic_midi'
obj.uselib = 'GTKMM GTK GDK XML OSX'
obj.uselib = 'XML OSX'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM PANGOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -23,6 +23,11 @@ def build(bld):
obj.includes = ['.', './launch_control_xl']
obj.name = 'libardour_launch_control_xl'
obj.target = 'ardour_launch_control_xl'
obj.uselib = 'GTKMM SIGCPP XML OSX'
obj.uselib = 'SIGCPP XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libpbd libevoral libcanvas libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -22,9 +22,11 @@ def build(bld):
obj.includes = ['.', '..', './launchpad_pro']
obj.name = 'libardour_launchpad_pro'
obj.target = 'ardour_launchpad_pro'
obj.uselib = 'CAIROMM PANGOMM USB GTKMM SIGCPP XML OSX'
obj.uselib = 'CAIROMM PANGOMM USB SIGCPP XML OSX'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libcanvas libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -25,9 +25,14 @@ def build(bld):
obj.includes = ['.', ]
obj.name = 'libardour_launchpad_mini'
obj.target = 'ardour_launchpad_mini'
obj.uselib = 'CAIROMM PANGOMM USB GTKMM SIGCPP XML OSX'
obj.uselib = 'CAIROMM PANGOMM USB SIGCPP XML OSX'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libcanvas libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'
obj = bld(features = 'cxx cxxshlib')
obj.source = list(lpxm_sources)
@ -37,9 +42,11 @@ def build(bld):
obj.includes = ['.', ]
obj.name = 'libardour_launchpad_x'
obj.target = 'ardour_launchpad_x'
obj.uselib = 'CAIROMM PANGOMM USB GTKMM SIGCPP XML OSX'
obj.uselib = 'CAIROMM PANGOMM USB SIGCPP XML OSX'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libcanvas libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
def shutdown():
autowaf.shutdown()
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -38,9 +38,14 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_mcp'
obj.target = 'ardour_mcp'
obj.uselib = 'GTKMM XML OSX'
obj.uselib = 'XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'
obj = bld(features = 'cxx cxxshlib')
obj.source = list(mackie_sources)
@ -51,6 +56,11 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_ssl_uf8'
obj.target = 'ardour_ssl_uf8'
obj.uselib = 'GTKMM XML OSX'
obj.uselib = 'XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -30,6 +30,11 @@ def build(bld):
obj.includes = [ '.', './maschine2']
obj.name = 'libardour_maschine2'
obj.target = 'ardour_maschine2'
obj.uselib = 'CAIROMM PANGOMM GTKMM GTK XML OSX'
obj.uselib = 'CAIROMM PANGOMM XML OSX'
obj.use = 'libardour libardour_cp libpbd libcanvas hidapi libgtkmm2ext'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -24,6 +24,11 @@ def build(bld):
obj.includes = ['.', './osc']
obj.name = 'libardour_osc'
obj.target = 'ardour_osc'
obj.uselib = 'LO GTKMM GTK GDK XML OSX'
obj.uselib = 'LO XML OSX'
obj.use = 'libardour libardour_cp libgtkmm2ext libpbd'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM PANGOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -36,6 +36,11 @@ def build(bld):
obj.includes = ['.', '..', './push2']
obj.name = 'libardour_push2'
obj.target = 'ardour_push2'
obj.uselib = 'CAIROMM PANGOMM USB GTKMM SIGCPP XML OSX'
obj.uselib = 'CAIROMM PANGOMM USB SIGCPP XML OSX'
obj.use = 'libardour libardour_cp libardour_midisurface libgtkmm2ext libpbd libevoral libcanvas libtemporal'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -35,6 +35,11 @@ def build(bld):
obj.includes = [ '.' ]
obj.name = 'libardour_us2400'
obj.target = 'ardour_us2400'
obj.uselib = 'GTKMM XML OSX'
obj.uselib = 'XML OSX PANGOMM'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += ' libytkmm'
obj.uselib += ' GLIBMM GIOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -18,6 +18,11 @@ def build(bld):
obj.includes = ['.', '../libs']
obj.name = 'libardour_wiimote'
obj.target = 'ardour_wiimote'
obj.uselib = 'GTKMM CWIID XML'
obj.uselib = 'CWIID XML'
obj.use = 'libardour libardour_cp libgtkmm2ext'
obj.install_path = os.path.join(bld.env['LIBDIR'], 'surfaces')
if bld.is_defined('YTK'):
obj.use += 'libytkmm'
obj.uselib += ' GLIBMM GIOMM PANGOMM'
else:
obj.uselib += ' GTKMM'

View File

@ -0,0 +1,439 @@
/*
Copyright 2011-2017 David Robillard <http://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.
*/
#include "suil_internal.h"
#include "lv2/options/options.h"
#include "lv2/urid/urid.h"
#include <gtk/gtk.h>
#include <gdk/gdkquartz.h>
#include <string.h>
#ifndef MAC_OS_X_VERSION_10_12
#define MAC_OS_X_VERSION_10_12 101200
#endif
#if MAC_OS_X_VERSION_MAX_ALLOWED < MAC_OS_X_VERSION_10_12
#define NSEventTypeFlagsChanged NSFlagsChanged
#define NSEventTypeLeftMouseDown NSLeftMouseDown
#define NSEventTypeLeftMouseDragged NSLeftMouseDragged
#define NSEventTypeLeftMouseUp NSLeftMouseUp
#define NSEventTypeMouseEntered NSMouseEntered
#define NSEventTypeMouseExited NSMouseExited
#define NSEventTypeMouseMoved NSMouseMoved
#define NSEventTypeRightMouseDown NSRightMouseDown
#define NSEventTypeRightMouseUp NSRightMouseUp
#define NSEventTypeScrollWheel NSScrollWheel
#endif
extern "C" {
#define SUIL_TYPE_COCOA_WRAPPER (suil_cocoa_wrapper_get_type())
#define SUIL_COCOA_WRAPPER(obj) (G_TYPE_CHECK_INSTANCE_CAST((obj), SUIL_TYPE_COCOA_WRAPPER, SuilCocoaWrapper))
typedef struct _SuilCocoaWrapper SuilCocoaWrapper;
typedef struct _SuilCocoaWrapperClass SuilCocoaWrapperClass;
struct _SuilCocoaWrapper {
GtkWidget widget;
SuilWrapper* wrapper;
SuilInstance* instance;
GdkWindow* flt_win;
bool custom_size;
bool mapped;
int req_width;
int req_height;
int alo_width;
int alo_height;
const LV2UI_Idle_Interface* idle_iface;
guint idle_id;
guint idle_ms;
};
struct _SuilCocoaWrapperClass {
GtkWidgetClass parent_class;
};
GType suil_cocoa_wrapper_get_type(void); // Accessor for SUIL_TYPE_COCOA_WRAPPER
G_DEFINE_TYPE(SuilCocoaWrapper, suil_cocoa_wrapper, GTK_TYPE_WIDGET)
static void
suil_cocoa_wrapper_finalize(GObject* gobject)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(gobject);
self->wrapper->impl = NULL;
G_OBJECT_CLASS(suil_cocoa_wrapper_parent_class)->finalize(gobject);
}
static void
suil_cocoa_realize(GtkWidget* widget)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
g_return_if_fail(self != NULL);
GTK_WIDGET_SET_FLAGS(widget, GTK_REALIZED);
GdkWindowAttr attrs;
attrs.x = widget->allocation.x;
attrs.y = widget->allocation.y;
attrs.width = widget->allocation.width;
attrs.height = widget->allocation.height;
attrs.wclass = GDK_INPUT_OUTPUT;
attrs.window_type = GDK_WINDOW_CHILD;
attrs.visual = gtk_widget_get_visual(widget);
attrs.colormap = gtk_widget_get_colormap(widget);
attrs.event_mask = gtk_widget_get_events(widget) |
GDK_EXPOSURE_MASK | GDK_BUTTON_PRESS_MASK |
GDK_BUTTON_RELEASE_MASK | GDK_POINTER_MOTION_MASK |
GDK_POINTER_MOTION_HINT_MASK;
widget->window = gdk_window_new(
widget->parent->window,
&attrs,
GDK_WA_X | GDK_WA_Y | GDK_WA_VISUAL | GDK_WA_COLORMAP);
widget->style = gtk_style_attach(widget->style, widget->window);
gdk_window_set_user_data(widget->window, widget);
gtk_style_set_background(widget->style, widget->window, GTK_STATE_ACTIVE);
gtk_widget_queue_resize(widget);
}
static void
suil_cocoa_size_request(GtkWidget* widget, GtkRequisition* requisition)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
if (self->custom_size) {
requisition->width = self->req_width;
requisition->height = self->req_height;
} else {
NSView* view = (NSView*)self->instance->ui_widget;
NSRect frame = [view frame];
requisition->width = CGRectGetWidth(NSRectToCGRect(frame));
requisition->height = CGRectGetHeight(NSRectToCGRect(frame));
}
}
static void
suil_cocoa_size_allocate(GtkWidget* widget, GtkAllocation* allocation)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
self->alo_width = allocation->width;
self->alo_height = allocation->height;
if (!self->mapped) {
return;
}
gint xx, yy;
gtk_widget_translate_coordinates(
gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy);
NSView* view = (NSView*)self->instance->ui_widget;
[view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)];
}
static void
suil_cocoa_map(GtkWidget* widget)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
self->mapped = true;
if (self->alo_width == 0 || self->alo_height ==0) {
return;
}
gint xx, yy;
gtk_widget_translate_coordinates(
gtk_widget_get_parent(widget), widget, 0, 0, &xx, &yy);
NSView* view = (NSView*)self->instance->ui_widget;
[view setHidden:NO];
[view setFrame:NSMakeRect(xx, yy, self->alo_width, self->alo_height)];
}
static void
suil_cocoa_unmap(GtkWidget* widget)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
NSView* view = (NSView*)self->instance->ui_widget;
self->mapped = false;
[view setHidden:YES];
}
static gboolean
suil_cocoa_key_press(GtkWidget* widget, GdkEventKey* event)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
if (!self->instance || !self->wrapper || !self->wrapper->impl) {
return FALSE;
}
NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event);
NSView* view = (NSView*)self->instance->ui_widget;
[view keyDown:nsevent];
return TRUE;
}
static gboolean
suil_cocoa_key_release(GtkWidget* widget, GdkEventKey* event)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
if (!self->instance || !self->wrapper || !self->wrapper->impl) {
return FALSE;
}
NSEvent* nsevent = gdk_quartz_event_get_nsevent((GdkEvent*)event);
NSView* view = (NSView*)self->instance->ui_widget;
[view keyUp:nsevent];
return TRUE;
}
static gboolean
suil_cocoa_expose(GtkWidget* widget, GdkEventExpose* event)
{
SuilCocoaWrapper* const self = SUIL_COCOA_WRAPPER(widget);
NSView* view = (NSView*)self->instance->ui_widget;
[view drawRect:NSMakeRect(event->area.x,
event->area.y,
event->area.width,
event->area.height)];
return TRUE;
}
static void
suil_cocoa_wrapper_class_init(SuilCocoaWrapperClass* klass)
{
GObjectClass* const gobject_class = G_OBJECT_CLASS(klass);
GtkWidgetClass* const widget_class = (GtkWidgetClass*)(klass);
gobject_class->finalize = suil_cocoa_wrapper_finalize;
widget_class->realize = suil_cocoa_realize;
widget_class->expose_event = suil_cocoa_expose;
widget_class->size_request = suil_cocoa_size_request;
widget_class->size_allocate = suil_cocoa_size_allocate;
widget_class->map = suil_cocoa_map;
widget_class->unmap = suil_cocoa_unmap;
widget_class->key_press_event = suil_cocoa_key_press;
widget_class->key_release_event = suil_cocoa_key_release;
}
static void
suil_cocoa_wrapper_init(SuilCocoaWrapper* self)
{
self->wrapper = NULL;
self->instance = NULL;
self->flt_win = NULL;
self->custom_size = false;
self->mapped = false;
self->req_width = self->req_height = 0;
self->alo_width = self->alo_height = 0;
self->idle_iface = NULL;
self->idle_ms = 1000 / 30; // 30 Hz default
}
static int
wrapper_resize(LV2UI_Feature_Handle handle, int width, int height)
{
SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(handle);
wrap->req_width = width;
wrap->req_height = height;
wrap->custom_size = true;
gtk_widget_queue_resize(GTK_WIDGET(handle));
return 0;
}
static gboolean
suil_cocoa_wrapper_idle(void* data)
{
SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(data);
wrap->idle_iface->idle(wrap->instance->handle);
return TRUE; // Continue calling
}
static GdkFilterReturn
event_filter(GdkXEvent* xevent, GdkEvent* event, gpointer data)
{
SuilCocoaWrapper* wrap = (SuilCocoaWrapper*)data;
if (!wrap->instance || !wrap->wrapper || !wrap->wrapper->impl) {
return GDK_FILTER_CONTINUE;
}
NSEvent* nsevent = (NSEvent*)xevent;
NSView* view = (NSView*)wrap->instance->ui_widget;
if (view && nsevent) {
switch([nsevent type]) {
case NSEventTypeFlagsChanged:
[view flagsChanged:nsevent];
return GDK_FILTER_REMOVE;
#if 0
case NSEventTypeMouseEntered:
[view mouseEntered:nsevent];
return GDK_FILTER_REMOVE;
case NSEventTypeMouseExited:
[view mouseExited:nsevent];
return GDK_FILTER_REMOVE;
/* Explicitly pass though mouse events. Needed for mouse-drags leaving
the window, and mouse-up after that. */
case NSEventTypeMouseMoved:
[view mouseMoved:nsevent];
break;
case NSEventTypeLeftMouseDragged:
[view mouseDragged:nsevent];
break;
case NSEventTypeLeftMouseDown:
[view mouseDown:nsevent];
break;
case NSEventTypeLeftMouseUp:
[view mouseUp:nsevent];
break;
case NSEventTypeRightMouseDown:
[view rightMouseDown:nsevent];
break;
case NSEventTypeRightMouseUp:
[view rightMouseUp:nsevent];
break;
case NSEventTypeScrollWheel:
[view scrollWheel:nsevent];
break;
#endif
default:
break;
}
}
return GDK_FILTER_CONTINUE;
}
static int
wrapper_wrap(SuilWrapper* wrapper, SuilInstance* instance)
{
SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl);
instance->host_widget = GTK_WIDGET(wrap);
wrap->wrapper = wrapper;
wrap->instance = instance;
const LV2UI_Idle_Interface* idle_iface = NULL;
if (instance->descriptor->extension_data) {
idle_iface = (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_cocoa_wrapper_idle, wrap);
}
return 0;
}
static void
wrapper_free(SuilWrapper* wrapper)
{
if (wrapper->impl) {
SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(wrapper->impl);
if (wrap->idle_id) {
g_source_remove(wrap->idle_id);
wrap->idle_id = 0;
}
gdk_window_remove_filter(wrap->flt_win, event_filter, wrapper->impl);
gtk_object_destroy(GTK_OBJECT(wrap));
}
}
SUIL_LIB_EXPORT
SuilWrapper*
suil_wrapper_new(SuilHost* host,
const char* host_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
GtkWidget* parent = NULL;
for (unsigned i = 0; i < n_features; ++i) {
if (!strcmp((*features)[i]->URI, LV2_UI__parent)) {
parent = (GtkWidget*)(*features)[i]->data;
}
}
if (!GTK_CONTAINER(parent)) {
SUIL_ERRORF("No GtkContainer parent given for %s UI\n",
ui_type_uri);
return NULL;
}
SuilWrapper* wrapper = (SuilWrapper*)calloc(1, sizeof(SuilWrapper));
wrapper->wrap = wrapper_wrap;
wrapper->free = wrapper_free;
SuilCocoaWrapper* const wrap = SUIL_COCOA_WRAPPER(
g_object_new(SUIL_TYPE_COCOA_WRAPPER, NULL));
wrapper->impl = wrap;
wrapper->resize.handle = wrap;
wrapper->resize.ui_resize = wrapper_resize;
gtk_container_add(GTK_CONTAINER(parent), GTK_WIDGET(wrap));
gtk_widget_set_can_focus(GTK_WIDGET(wrap), TRUE);
gtk_widget_set_sensitive(GTK_WIDGET(wrap), TRUE);
gtk_widget_realize(GTK_WIDGET(wrap));
GdkWindow* window = gtk_widget_get_window(GTK_WIDGET(wrap));
wrap->flt_win = gtk_widget_get_window(parent);
gdk_window_add_filter(wrap->flt_win, event_filter, wrap);
NSView* parent_view = gdk_quartz_window_get_nsview(window);
suil_add_feature(features, &n_features, LV2_UI__parent, parent_view);
suil_add_feature(features, &n_features, LV2_UI__resize, &wrapper->resize);
suil_add_feature(features, &n_features, LV2_UI__idleInterface, NULL);
// Scan for URID map and options
LV2_URID_Map* map = NULL;
LV2_Options_Option* options = NULL;
for (LV2_Feature** f = *features; *f && (!map || !options); ++f) {
if (!strcmp((*f)->URI, LV2_OPTIONS__options)) {
options = (LV2_Options_Option*)(*f)->data;
} else if (!strcmp((*f)->URI, LV2_URID__map)) {
map = (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 = 1000.0f / *(const float*)o->value;
break;
}
}
}
return wrapper;
}
} // extern "C"

78
libs/tk/suil/dylib.h Normal file
View File

@ -0,0 +1,78 @@
/*
Copyright 2020 David Robillard <http://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.
*/
#ifndef SUIL_DYLIB_H
#define SUIL_DYLIB_H
#ifdef _WIN32
#include <windows.h>
enum DylibFlags {
DYLIB_GLOBAL = 0,
DYLIB_LAZY = 1,
DYLIB_NOW = 2,
};
static inline void*
dylib_open(const char* const filename, const int flags)
{
return LoadLibrary(filename);
}
static inline int
dylib_close(void* const handle)
{
return !FreeLibrary((HMODULE)handle);
}
static inline const char*
dylib_error(void)
{
return "Unknown error";
}
#else
#include <dlfcn.h>
enum DylibFlags {
DYLIB_GLOBAL = RTLD_GLOBAL,
DYLIB_LAZY = RTLD_LAZY,
DYLIB_NOW = RTLD_NOW,
};
static inline void*
dylib_open(const char* const filename, const int flags)
{
return dlopen(filename, flags);
}
static inline int
dylib_close(void* const handle)
{
return dlclose(handle);
}
static inline const char*
dylib_error(void)
{
return dlerror();
}
#endif
#endif // SUIL_DYLIB_H

98
libs/tk/suil/host.c Normal file
View File

@ -0,0 +1,98 @@
/*
Copyright 2011-2017 David Robillard <http://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.
*/
#include "dylib.h"
#include "suil_config.h"
#include "suil_internal.h"
#include "suil/suil.h"
#include <stdlib.h>
int suil_argc = 0;
char** suil_argv = NULL;
SUIL_API
SuilHost*
suil_host_new(SuilPortWriteFunc write_func,
SuilPortIndexFunc index_func,
SuilPortSubscribeFunc subscribe_func,
SuilPortUnsubscribeFunc unsubscribe_func)
{
SuilHost* host = (SuilHost*)calloc(1, sizeof(struct SuilHostImpl));
host->write_func = write_func;
host->index_func = index_func;
host->subscribe_func = subscribe_func;
host->unsubscribe_func = unsubscribe_func;
host->argc = suil_argc;
host->argv = suil_argv;
return host;
}
SUIL_API
void
suil_host_set_touch_func(SuilHost* host,
SuilTouchFunc touch_func)
{
host->touch_func = touch_func;
}
SUIL_API
void
suil_host_free(SuilHost* host)
{
if (host) {
if (host->gtk_lib) {
dylib_close(host->gtk_lib);
}
free(host);
}
}
#ifdef SUIL_WITH_X11
static void
suil_load_init_module(const char* module_name)
{
void* const lib = suil_open_module(module_name);
if (!lib) {
return;
}
SuilVoidFunc init_func = suil_dlfunc(lib, "suil_host_init");
if (init_func) {
(*init_func)();
} else {
SUIL_ERRORF("Corrupt init module %s\n", module_name);
}
dylib_close(lib);
}
#endif
SUIL_API
void
suil_init(int* argc, char*** argv, SuilArg key, ...)
{
(void)key;
suil_argc = argc ? *argc : 0;
suil_argv = argv ? *argv : NULL;
#ifdef SUIL_WITH_X11
suil_load_init_module("suil_x11");
#endif
}

409
libs/tk/suil/instance.c Normal file
View File

@ -0,0 +1,409 @@
/*
Copyright 2007-2017 David Robillard <http://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.
*/
#include "dylib.h"
#include "suil_config.h"
#include "suil_internal.h"
#include "lv2/core/lv2.h"
#include "lv2/ui/ui.h"
#include "suil/suil.h"
#include <stdbool.h>
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#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"
#define COCOA_UI_URI LV2_UI__CocoaUI
SUIL_API
unsigned
suil_ui_supported(const char* host_type_uri,
const char* ui_type_uri)
{
enum {
SUIL_WRAPPING_UNSUPPORTED = 0,
SUIL_WRAPPING_NATIVE = 1,
SUIL_WRAPPING_EMBEDDED = 2
};
if (!strcmp(host_type_uri, ui_type_uri)) {
return SUIL_WRAPPING_NATIVE;
}
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(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))) {
return SUIL_WRAPPING_EMBEDDED;
}
return SUIL_WRAPPING_UNSUPPORTED;
}
static SuilWrapper*
open_wrapper(SuilHost* host,
const char* container_type_uri,
const char* ui_type_uri,
LV2_Feature*** features,
unsigned n_features)
{
const char* module_name = NULL;
#ifdef SUIL_WITH_GTK2_IN_QT4
if (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, GTK2_UI_URI)) {
module_name = "suil_gtk2_in_qt4";
}
#endif
#ifdef SUIL_WITH_GTK2_IN_QT5
if (!strcmp(container_type_uri, QT5_UI_URI)
&& !strcmp(ui_type_uri, GTK2_UI_URI)) {
module_name = "suil_gtk2_in_qt5";
}
#endif
#ifdef SUIL_WITH_QT4_IN_GTK2
if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, QT4_UI_URI)) {
module_name = "suil_qt4_in_gtk2";
}
#endif
#ifdef SUIL_WITH_QT5_IN_GTK2
if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, QT5_UI_URI)) {
module_name = "suil_qt5_in_gtk2";
}
#endif
#ifdef SUIL_WITH_X11_IN_GTK2
if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_gtk2";
}
#endif
#ifdef SUIL_WITH_X11_IN_GTK3
if (!strcmp(container_type_uri, GTK3_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_gtk3";
}
#endif
#ifdef SUIL_WITH_QT5_IN_GTK3
if (!strcmp(container_type_uri, GTK3_UI_URI)
&& !strcmp(ui_type_uri, QT5_UI_URI)) {
module_name = "suil_qt5_in_gtk3";
}
#endif
#ifdef SUIL_WITH_WIN_IN_GTK2
if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, WIN_UI_URI)) {
module_name = "suil_win_in_gtk2";
}
#endif
#ifdef SUIL_WITH_COCOA_IN_GTK2
if (!strcmp(container_type_uri, GTK2_UI_URI)
&& !strcmp(ui_type_uri, COCOA_UI_URI)) {
module_name = "suil_cocoa_in_gtk2";
}
#endif
#ifdef SUIL_WITH_X11_IN_QT4
if (!strcmp(container_type_uri, QT4_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_qt4";
}
#endif
#ifdef SUIL_WITH_X11_IN_QT5
if (!strcmp(container_type_uri, QT5_UI_URI)
&& !strcmp(ui_type_uri, X11_UI_URI)) {
module_name = "suil_x11_in_qt5";
}
#endif
#ifdef SUIL_WITH_COCOA_IN_QT5
if (!strcmp(container_type_uri, QT5_UI_URI)
&& !strcmp(ui_type_uri, COCOA_UI_URI)) {
module_name = "suil_cocoa_in_qt5";
}
#endif
if (!module_name) {
SUIL_ERRORF("Unable to wrap UI type <%s> as type <%s>\n",
ui_type_uri, container_type_uri);
return NULL;
}
void* const lib = suil_open_module(module_name);
if (!lib) {
return NULL;
}
SuilWrapperNewFunc wrapper_new = (SuilWrapperNewFunc)suil_dlfunc(
lib, "suil_wrapper_new");
SuilWrapper* wrapper = wrapper_new
? wrapper_new(host,
container_type_uri,
ui_type_uri,
features,
n_features)
: NULL;
if (wrapper) {
wrapper->lib = lib;
} else {
SUIL_ERRORF("Corrupt wrap module %s\n", module_name);
dylib_close(lib);
}
return wrapper;
}
SUIL_API
SuilInstance*
suil_instance_new(SuilHost* host,
SuilController controller,
const char* container_type_uri,
const char* plugin_uri,
const char* ui_uri,
const char* ui_type_uri,
const char* ui_bundle_path,
const char* ui_binary_path,
const LV2_Feature* const* features)
{
// Open UI library
dylib_error();
void* lib = dylib_open(ui_binary_path, DYLIB_NOW);
if (!lib) {
SUIL_ERRORF("Unable to open UI library %s (%s)\n",
ui_binary_path, dylib_error());
return NULL;
}
// Get discovery function
LV2UI_DescriptorFunction df = (LV2UI_DescriptorFunction)
suil_dlfunc(lib, "lv2ui_descriptor");
if (!df) {
SUIL_ERRORF("Broken LV2 UI %s (no lv2ui_descriptor symbol found)\n",
ui_binary_path);
dylib_close(lib);
return NULL;
}
// Get UI descriptor
const LV2UI_Descriptor* descriptor = NULL;
for (uint32_t i = 0; true; ++i) {
const LV2UI_Descriptor* ld = df(i);
if (!ld) {
break;
}
if (!strcmp(ld->URI, ui_uri)) {
descriptor = ld;
break;
}
}
if (!descriptor) {
SUIL_ERRORF("Failed to find descriptor for <%s> in %s\n",
ui_uri, ui_binary_path);
dylib_close(lib);
return NULL;
}
// Create SuilInstance
SuilInstance* instance = (SuilInstance*)calloc(1, sizeof(SuilInstance));
if (!instance) {
SUIL_ERRORF("Failed to allocate memory for <%s> instance\n", ui_uri);
dylib_close(lib);
return NULL;
}
instance->lib_handle = lib;
instance->descriptor = descriptor;
// Make UI features array
instance->features = (LV2_Feature**)malloc(sizeof(LV2_Feature*));
instance->features[0] = NULL;
// Copy user provided features
const LV2_Feature* const* fi = features;
unsigned n_features = 0;
while (fi && *fi) {
const LV2_Feature* f = *fi++;
suil_add_feature(&instance->features, &n_features, f->URI, f->data);
}
// Add additional features implemented by SuilHost functions
if (host->index_func) {
instance->port_map.handle = controller;
instance->port_map.port_index = host->index_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__portMap, &instance->port_map);
}
if (host->subscribe_func && host->unsubscribe_func) {
instance->port_subscribe.handle = controller;
instance->port_subscribe.subscribe = host->subscribe_func;
instance->port_subscribe.unsubscribe = host->unsubscribe_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__portSubscribe, &instance->port_subscribe);
}
if (host->touch_func) {
instance->touch.handle = controller;
instance->touch.touch = host->touch_func;
suil_add_feature(&instance->features, &n_features,
LV2_UI__touch, &instance->touch);
}
// Open wrapper (this may add additional features)
if (container_type_uri && strcmp(container_type_uri, ui_type_uri)) {
instance->wrapper = open_wrapper(host,
container_type_uri, ui_type_uri,
&instance->features, n_features);
if (!instance->wrapper) {
suil_instance_free(instance);
return NULL;
}
}
// Instantiate UI
instance->handle = descriptor->instantiate(
descriptor,
plugin_uri,
ui_bundle_path,
host->write_func,
controller,
&instance->ui_widget,
(const LV2_Feature* const*)instance->features);
// Failed to instantiate UI
if (!instance->handle) {
SUIL_ERRORF("Failed to instantiate UI <%s> in %s\n",
ui_uri, ui_binary_path);
suil_instance_free(instance);
return NULL;
}
if (instance->wrapper) {
if (instance->wrapper->wrap(instance->wrapper, instance)) {
SUIL_ERRORF("Failed to wrap UI <%s> in type <%s>\n",
ui_uri, container_type_uri);
suil_instance_free(instance);
return NULL;
}
} else {
instance->host_widget = instance->ui_widget;
}
return instance;
}
SUIL_API
void
suil_instance_free(SuilInstance* instance)
{
if (instance) {
for (unsigned i = 0; instance->features[i]; ++i) {
free(instance->features[i]);
}
free(instance->features);
// Call wrapper free function to destroy widgets and drop references
if (instance->wrapper && instance->wrapper->free) {
instance->wrapper->free(instance->wrapper);
}
// Call cleanup to destroy UI (if it still exists at this point)
if (instance->handle) {
instance->descriptor->cleanup(instance->handle);
}
dylib_close(instance->lib_handle);
// Close libraries and free everything
if (instance->wrapper) {
#ifndef _WIN32
// Never unload modules on windows, causes mysterious segfaults
dylib_close(instance->wrapper->lib);
#endif
free(instance->wrapper);
}
free(instance);
}
}
SUIL_API
SuilHandle
suil_instance_get_handle(SuilInstance* instance)
{
return instance->handle;