diff options
Diffstat (limited to 'doc')
-rw-r--r-- | doc/c/overview.rst | 189 |
1 files changed, 186 insertions, 3 deletions
diff --git a/doc/c/overview.rst b/doc/c/overview.rst index e8d61b1..e6d4e63 100644 --- a/doc/c/overview.rst +++ b/doc/c/overview.rst @@ -1,6 +1,6 @@ -######## -Overview -######## +########## +Using Suil +########## .. default-domain:: c .. highlight:: c @@ -10,3 +10,186 @@ The complete API is declared in ``suil.h``: .. code-block:: c #include <suil/suil.h> + +************* +Library Setup +************* + +In order to work properly on certain platforms, +suil must be set up by the application before any GUI toolkits are loaded. +This is done with :func:`suil_init`, +which takes command line arguments and an optional list of arguments, +terminated by :enumerator:`SUIL_ARG_NONE`: + +.. code-block:: c + + int main(int argc, char** argv) + { + suil_init(&argc, &argv, SUIL_ARG_NONE); + return 0; + } + +There are currently no defined Suil arguments, +the facility exists for future extensibility. + +********** +Host Setup +********** + +After the library is prepared, +a :struct:`SuilHost` must be created. +This represents the plugin UI host, +in particular the callbacks that will fire when there is UI activity. +There are five types of host callback: + +- :type:`SuilPortWriteFunc` +- :type:`SuilPortIndexFunc` +- :type:`SuilPortSubscribeFunc` +- :type:`SuilPortUnsubscribeFunc` +- :type:`SuilTouchFunc` + +These callbacks all take a :type:`SuilController`, +which is an opaque pointer that can be used to describe the context +(including which UI is responsible for the call), +as well as extra arguments specific to the callback. + +Assuming these are implemented in the host as ``my_write_func``, ``my_port_index_func``, ``my_port_subscribe_func``, ``my_port_unsubscribe_func``, and ``my_touch_func``, respectively, +the host can be allocated with :func:`suil_host_new`: + +.. code-block:: c + + SuilHost* host = suil_host_new(my_write_func, + my_index_func, + my_subscribe_func, + my_unsubscribe_func); + +Touch functionality was added to the API later, +so the touch function is set with the separate :func:`suil_host_set_touch_func`: + +.. code-block:: c + + suil_host_set_touch_func(host, my_touch_func); + +********************* +Finding Supported UIs +********************* + +Suil does not access data directly itself, +so UI discovery is the responsibility of the application. +Most hosts will use :func:`lilv_plugin_get_uis` to discover the available UIs for a particular plugin. + +Suil provides :func:`suil_ui_supported`, +which can be used to determine if a particular UI can be embedded in the host. +It requires two URIs, +one that describes the host UI type, +and one that describes the plugin UI type. +They are typically URIs defined in the LV2 UI extension, +such as https://lv2plug.in/ns/extensions/ui#X11UI, +which are defined for convenience with names like :var:`LV2_UI__X11UI`. + +If a specific UI type is already known, +this can be used directly, +for example an X11 host might do something like this: + +.. code-block:: c + + if (suil_ui_supported(LV2_UI__X11UI, plugin_ui_type) > 0) { + // Use this UI... + } + +More commonly, +this function is used as a utility along with :func:`lilv_ui_is_supported`: + +.. code-block:: c + + LilvUI* ui = this_plugin_ui(); + LilvNode* host_type = lilv_new_uri(LV2_UI__X11UI); + LilvNode* ui_type = NULL; + + if (lilv_ui_is_supported(ui, suil_ui_supported, host_type, &ui_type)) { + // Use this UI, which has type ui_type... + } + +********************* +Loading a UI Instance +********************* + +An instance of a plugin UI is represented by a :struct:`SuilInstance`, +which can be created with :func:`suil_instance_new`. +For example, +given a :struct:`LilvPlugin` ``plugin``, +and a :struct:`LilvUI` ``ui``: + +.. code-block:: c + + SuilController* controller = my_controller_for(ui); + const LV2_Feature** features = my_features_for(ui); + + const char* bundle_uri = lilv_node_as_uri(lilv_ui_get_bundle_uri(ui)); + const char* binary_uri = lilv_node_as_uri(lilv_ui_get_binary_uri(ui)); + char* bundle_path = serd_parse_file_uri(bundle_uri, NULL); + char* binary_path = serd_parse_file_uri(binary_uri, NULL); + + SuilInstance* instance = suil_instance_new( + host, + controller, + LV2_UI__X11UI, + lilv_node_as_uri(lilv_plugin_get_uri(plugin)), + lilv_node_as_uri(lilv_ui_get_uri(ui)), + lilv_node_as_uri(ui_type), + bundle_path, + binary_path, + ui_features); + +********************* +Retrieving the Widget +********************* + +With the UI instantiated, +the actual widget can be retrieved with :func:`suil_instance_get_widget`. +This returns a :type:`SuilWidget` handle which has the container type passed to :func:`suil_instance_new`. +In this example, +the host is a LV2_UI__X11UI, +so the returned widget is a ``Window``: + +.. code-block:: c + + Window window = (Window)suil_instance_get_widget(instance); + +The host may be responsible for displaying or embedding the widget, +depending on the windowing system or toolkit used. + +*************** +Updating the UI +*************** + +Updates can be sent to a UI instance with :func:`suil_instance_port_event`. +This takes a port index, a value size and format, and a pointer to a value. +For example, to update a control port, the special format ``0`` can be used: + +.. code-block:: c + + const float value = 42.0f; + + suil_instance_port_event(instance, 2, sizeof(float), 0, &value); + +******* +Cleanup +******* + +When the host is finished with the UI, +and has removed any references to it in the windowing system or toolkit, +it must destroy the UI with :func:`suil_instance_free`: + +.. code-block:: c + + suil_instance_free(instance); + +When all UIs have been destroyed and the host is ready to shut down, +it must free its description with :func:`suil_host_free`: + +.. code-block:: c + + suil_host_free(host); + +Note that the host must outlive any UI instances that were created for it. |