########## Using Suil ########## .. default-domain:: c .. highlight:: c The complete API is declared in ``suil.h``: .. code-block:: c #include ************* 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.