summaryrefslogtreecommitdiffstats
path: root/doc
diff options
context:
space:
mode:
Diffstat (limited to 'doc')
-rw-r--r--doc/c/overview.rst189
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.