diff options
author | Jens Georg <mail@jensge.org> | 2022-01-03 11:07:59 +0100 |
---|---|---|
committer | Jens Georg <mail@jensge.org> | 2022-01-03 19:10:51 +0100 |
commit | d2ad83d588759d005c7a3bae87f7523666e9a733 (patch) | |
tree | 35de8ceeb48fe817dfc03c5026150b7c35af1c8f | |
parent | 79a2cb24cd0079e9a025809d11dce13edce68bdd (diff) | |
download | gupnp-d2ad83d588759d005c7a3bae87f7523666e9a733.tar.gz |
docs: Use gi-docgen instead of gtk-doc
37 files changed, 1622 insertions, 485 deletions
diff --git a/doc/choosing-a-context-manager.md b/doc/choosing-a-context-manager.md new file mode 100644 index 0000000..bc98595 --- /dev/null +++ b/doc/choosing-a-context-manager.md @@ -0,0 +1,20 @@ +----- +Title: Choosing a Context Manager Implementation +----- + +# Choosing a Context Manager Implementation + +Ususally it is fine to trust the auto-detection. If the operating system is not Linux, +there is only one choice anyway. + +For Linux, four different implementations exist: + + - A basic polling implementation, the fall-back if nothing else works. + - A Netlink-based implementation + - Using NetworkManager to identify available network interfaces + - Using Connman to identify the available interfaces + - An Android-specific implementation + +With the exception of Android, It is generally recommended to use the Netlink-based implementation. +It should co-exist with any other network management implementation. + diff --git a/doc/client-tutorial.md b/doc/client-tutorial.md new file mode 100644 index 0000000..5d0b71e --- /dev/null +++ b/doc/client-tutorial.md @@ -0,0 +1,215 @@ +--- +Title: Interacting with remote UPnP devices +--- + +# UPnP Client Tutorial + +This chapter explains how to write an application which fetches the external IP address +from an UPnP-compliant modem. To do this, a Control Point is created, which searches for +services of the type `urn:schemas-upnp-org:service:WANIPConnection:1` which is part of +the Internet Gateway Devce specification. + +As services are discovered, ServiceProxy objects are created by GUPnP to allow interaction +with the service, on which we can invoke the action `GetExternalIPAddress` to fetch the +external IP address. + +## Finding Services + +First, we initialize GUPnP and create a control point targeting the service type. +Then we connect a signal handler so that we are notified when services we are interested in +are found. + + +```c +#include <ibgupnp/gupnp-control-point.h> + +static GMainLoop *main_loop; + +static void +service_proxy_available_cb (GUPnPControlPoint *cp, + GUPnPServiceProxy *proxy, + gpointer userdata) +{ + /* ... */ +} + +int +main (int argc, char **argv) +{ + GUPnPContext *context; + GUPnPControlPoint *cp; + + /* Create a new GUPnP Context. By here we are using the default GLib main + context, and connecting to the current machine's default IP on an + automatically generated port. */ + context = gupnp_context_new (NULL, 0, NULL); + + /* Create a Control Point targeting WAN IP Connection services */ + cp = gupnp_control_point_new + (context, "urn:schemas-upnp-org:service:WANIPConnection:1"); + + /* The service-proxy-available signal is emitted when any services which match + our target are found, so connect to it */ + g_signal_connect (cp, + "service-proxy-available2, + G_CALLBACK (service_proxy_available_cb), + NULL); + + /* Tell the Control Point to start searching */ + gssdp_resource_browser_set_active (GSSDP_RESOURCE_BROWSER (cp), TRUE); + + /* Enter the main loop. This will start the search and result in callbacks to + service_proxy_available_cb. */ + main_loop = g_main_loop_new (NULL, FALSE); + g_main_loop_run (main_loop); + + /* Clean up */ + g_main_loop_unref (main_loop); + g_object_unref (cp); + g_object_unref (context); + + return 0; +} +``` + +## Invoking Actions +Now we have an application which searches for the service we specified and +calls `service_proxy_available_cb` for each one it +found. To get the external IP address we need to invoke the +`GetExternalIPAddress` action. This action takes no in +arguments, and has a single out argument called "NewExternalIPAddress". +GUPnP has a set of methods to invoke actions where you pass a +`NULL`-terminated varargs list of (name, GType, value) +tuples for the in arguments, then a `NULL`-terminated +varargs list of (name, GType, return location) tuples for the out +arguments. + +```c +static void +service_proxy_available_cb (GUPnPControlPoint *cp, + GUPnPServiceProxy *proxy, + gpointer userdata) +{ + GError *error = NULL; + char *ip = NULL; + GUPnPServiceProxyAction *action = NULL; + + action = gupnp_service_proxy_action_new ( + /* Action name */ + "GetExternalIPAddress", + /* IN args */ + NULL); + gupnp_service_proxy_call_action (proxy, + action, + NULL, + &error); + if (error != NULL) { + goto out; + } + + gupnp_service_proxy_action_get_result (action, + /* Error location */ + &error, + /* OUT args */ + "NewExternalIPAddress", + G_TYPE_STRING, &ip, + NULL); + + if (error == NULL) { + g_print ("External IP address is %s\n", ip); + g_free (ip); + } + +out: + if (error != NULL) { + g_printerr ("Error: %s\n", error->message); + g_error_free (error); + } + + gupnp_service_proxy_action_unref (action); + g_main_loop_quit (main_loop); +} +``` + +Note that `gupnp_service_proxy_call_action()` blocks until the service has +replied. If you need to make non-blocking calls then use +`gupnp_service_proxy_call_action_async()`, which takes a callback that will be +called from the mainloop when the reply is received. + + +## Subscribing to state variable change notifications +It is possible to get change notifications for the service state variables +that have attribute `sendEvents="yes"`. We'll demonstrate +this by modifying `service_proxy_available_cb` and using +`gupnp_service_proxy_add_notify()` to setup a notification callback: + + +```c +static void +external_ip_address_changed (GUPnPServiceProxy *proxy, + const char *variable, + GValue *value, + gpointer userdata) +{ + g_print ("External IP address changed: %s\n", g_value_get_string (value)); +} + +static void +service_proxy_available_cb (GUPnPControlPoint *cp, + GUPnPServiceProxy *proxy, + gpointer userdata) +{ + g_print ("Found a WAN IP Connection service\n"); + + gupnp_service_proxy_set_subscribed (proxy, TRUE); + if (!gupnp_service_proxy_add_notify (proxy, + "ExternalIPAddress", + G_TYPE_STRING, + external_ip_address_changed, + NULL)) { + g_printerr ("Failed to add notify"); + } +} +``` + +## Generating wrappers + +Using `gupnp_service_proxy_call_action()` and `gupnp_service_proxy_add_notify()` +can become tedious, because of the requirement to specify the types and deal +with GValues. An +alternative is to use `gupnp-binding-tool`, which +generates wrappers that hide the boilerplate code from you. Using a +wrapper generated with prefix "ipconn" would replace +`gupnp_service_proxy_call_action()` with this code: + +```c +ipconn_get_external_ip_address (proxy, &ip, &error); +``` + +State variable change notifications are friendlier with wrappers as well: + +```c +static void +external_ip_address_changed (GUPnPServiceProxy *proxy, + const gchar *external_ip_address, + gpointer userdata) +{ + g_print ("External IP address changed: '%s'\n", external_ip_address); +} + +static void +service_proxy_available_cb (GUPnPControlPoint *cp, + GUPnPServiceProxy *proxy + gpointer userdata) +{ + g_print ("Found a WAN IP Connection service\n"); + + gupnp_service_proxy_set_subscribed (proxy, TRUE); + if (!ipconn_external_ip_address_add_notify (proxy, + external_ip_address_changed, + NULL)) { + g_printerr ("Failed to add notify"); + } +} +``` + diff --git a/doc/glossary.md b/doc/glossary.md new file mode 100644 index 0000000..0b9dbb2 --- /dev/null +++ b/doc/glossary.md @@ -0,0 +1,115 @@ +--- +Title: UPnP Glossary +--- + +# Action + +> An Action is a method call on a Service, which encapsulated a single piece of +functionality. Actions can have multiple input and output arguments, and +can return error codes. UPnP allows one of the output arguments to be +marked as the return value, but GUPnP doesn't treat return values specially. + +> Every action argument has a related State Variable, +which determines the type of the argument. Note that even if the argument +wouldn't need a state variable it is still required, due to historical +reasons. + +# Control Point + +> A Control Point is an entity on the network which +communicates with other Devices and +Services. In the client/server model the control +point is a client and the Service is a server, +although it is common for devices to also be a control point because +whilst a single control point/service connection is client/server, the +UPnP network as whole is peer-to-peer. + +# Device +> A Device is an entity on the network which +communicates using the UPnP standards. This can be a dedicated physical +device such as a router or printer, or a PC which is running software +implementing the UPnP standards. + +> A Device can contain sub-devices, for example a combination +printer/scanner could appear as a general device with a printer +sub-device and a scanner sub-device. + +> Every device has zero or more Services. UPnP defines many standard +device types, which specify services which are required to be implemented. +Alternatively, a non-standard device type could be used. Examples of +standard device types are `MediaRenderer` or +`InternetGatewayDevice`. + +# DIDL-Lite + +> Digital Item Declaration Language - Lite + +> An XML schema used to represent digital content metadata. Defined by +the UPnP Forum. + +# Service + +> A Service is a collection of related methods +(called Actions) and public variables (called +State Variables) which together form a logical interface. +> UPnP defines standard services that define actions and variables which +must be present and their semantics. Examples of these are +`AVTransport` and `WANIPConnection`. + +See also: + +- [Action](#action) +- [Device](#device) +- [State Variable](#state-variable) + +# SCDP +> Service Control Protocol Document + + +> An XML document which defines the set of <glossterm>Actions</glossterm> +and <glossterm>State Variables</glossterm> that a +<glossterm>Service</glossterm> implements. + +See also: + +- [Action](#action) +- [Device](#device) +- [State Variable](#state-variable) + +# SSDP +> <glossterm>Simple Service Discovery Protocol</glossterm> + +> UPnP device discovery protocol. Specifies how <glossterm>Devices</glossterm> +advertise their <glossterm>Services</glossterm> in the network and also how +<glossterm>Control Points</glossterm> search for +services and devices respond. + +See also: + +- [Device](#device) +- [Action](#controlpoint) +- [Service](#service) + +# State Variable + +> A <firstterm>State Variable</firstterm> is a public variable exposing some +aspect of the service's state. State variables are typed and optionally +are <firstterm>evented</firstterm>, which means that any changes will be +notified. Control points are said to <firstterm>subscribe</firstterm> to +a state variable to receive change notifications. + + +# UDN +> Unique Device Name + +> An unique identifier which is <emphasis>unique</emphasis> for every +device but <emphasis>never changes</emphasis> for each particular +device. + +> A common practise is to generate a unique UDN on first boot from a +random seed, or use some unique and persistent property such as the +device's MAC address to create the UDN. + +See also: + +- [Device](#device) diff --git a/doc/gupnp.toml.in b/doc/gupnp.toml.in new file mode 100644 index 0000000..e416445 --- /dev/null +++ b/doc/gupnp.toml.in @@ -0,0 +1,54 @@ +[library] +namespace = "GUPnP" +version = "@VERSION@" +browse_url = "https://gitlab.gnome.org/GNOME/gssdp/" +repository_url = "https://gitlab.gnome.org/GNOME/gssdp.git" +website_url = "https://gupnp.org" +logo_url = "gupnp-logo-short.svg" +license = "LGPL-2.1-or-later" +description = "UPnP implementation using GObject" +dependencies = [ "GObject-2.0", "GSSDP-1.2", "Soup-2.4", "libxml2-2.0" ] +devhelp = true +search_index = true +authors = "The GUPnP developers" + +[theme] +name="basic" +show_index_summary = true + +[source-location] +base_url = "https://gitlab.gnome.org/GNOME/gupnp/-/blob/master" + +[dependencies."GObject-2.0"] +name = "GObject" +description = "The base type system library" +docs_url = "https://developer.gnome.org/gobject/stable" + +[dependencies."GSSDP-1.2"] +name = "GSSDP" +description = "SSDP implementation using GObject" +docs_url = "https://gnome.pages.gitlab.gnome.org/gssdp/docs/" + +[dependencies."Soup-2.4"] +name = "Soup" +description = "A HTTP handling library" +docs_url = "https://developer.gnome.org/libsoup/stable" + +[dependencies."libxml2-2.0"] +name = "LibXML2" +description = "A XML handling library" +docs_url = "http://www.xmlsoft.org/html/index.html" + +[extra] +content_files = [ + "client-tutorial.md", + "server-tutorial.md", + "choosing-a-context-manager.md", + "glossary.md" +] + +content_images = [ + "images/gupnp-logo-short.svg" +] + +urlmap_file = "urlmap.js" diff --git a/doc/images/gupnp-logo-short.svg b/doc/images/gupnp-logo-short.svg new file mode 100644 index 0000000..6386c74 --- /dev/null +++ b/doc/images/gupnp-logo-short.svg @@ -0,0 +1,126 @@ +<?xml version="1.0" encoding="UTF-8" standalone="no"?> +<!-- Created with Inkscape (http://www.inkscape.org/) --> + +<svg + id="svg4194" + version="1.1" + inkscape:version="1.1 (c68e22c387, 2021-05-23)" + width="89.339256mm" + height="37.64888mm" + viewBox="0 0 316.55642 133.40154" + sodipodi:docname="gupnp-logo-short.svg" + inkscape:export-filename="/home/jgeorg/gupnp-logo-v1.svg.png" + inkscape:export-xdpi="90" + inkscape:export-ydpi="90" + xmlns:inkscape="http://www.inkscape.org/namespaces/inkscape" + xmlns:sodipodi="http://sodipodi.sourceforge.net/DTD/sodipodi-0.dtd" + xmlns="http://www.w3.org/2000/svg" + xmlns:svg="http://www.w3.org/2000/svg" + xmlns:rdf="http://www.w3.org/1999/02/22-rdf-syntax-ns#" + xmlns:cc="http://creativecommons.org/ns#" + xmlns:dc="http://purl.org/dc/elements/1.1/"> + <metadata + id="metadata4200"> + <rdf:RDF> + <cc:Work + rdf:about=""> + <dc:format>image/svg+xml</dc:format> + <dc:type + rdf:resource="http://purl.org/dc/dcmitype/StillImage" /> + <cc:license + rdf:resource="http://creativecommons.org/publicdomain/zero/1.0/" /> + </cc:Work> + <cc:License + rdf:about="http://creativecommons.org/publicdomain/zero/1.0/"> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Reproduction" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#Distribution" /> + <cc:permits + rdf:resource="http://creativecommons.org/ns#DerivativeWorks" /> + </cc:License> + </rdf:RDF> + </metadata> + <defs + id="defs4198" /> + <sodipodi:namedview + pagecolor="#ffffff" + bordercolor="#666666" + borderopacity="1" + objecttolerance="10" + gridtolerance="10" + guidetolerance="10" + inkscape:pageopacity="0" + inkscape:pageshadow="2" + inkscape:window-width="1920" + inkscape:window-height="1011" + id="namedview4196" + showgrid="false" + showguides="true" + inkscape:snap-page="false" + inkscape:zoom="1.6897519" + inkscape:cx="106.82042" + inkscape:cy="36.691777" + inkscape:window-x="0" + inkscape:window-y="32" + inkscape:window-maximized="1" + inkscape:current-layer="svg4194" + inkscape:guide-bbox="true" + inkscape:pagecheckerboard="0" + units="mm" + fit-margin-top="0" + fit-margin-left="0" + fit-margin-right="0" + fit-margin-bottom="0" + inkscape:document-units="mm"> + <inkscape:grid + type="xygrid" + id="grid5354" + originx="-2.7774772" + originy="-2.2013303" + spacingx="1" + spacingy="1" /> + <sodipodi:guide + position="311.44403,45.237576" + orientation="0,1" + id="guide4237" + inkscape:locked="false" /> + <sodipodi:guide + position="316.24124,64.031713" + orientation="1,0" + id="guide14" /> + </sodipodi:namedview> + <path + inkscape:connector-curvature="0" + id="path4222" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:111.914px;line-height:125%;font-family:moderna;-inkscape-font-specification:moderna;letter-spacing:0px;word-spacing:0px;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 59.874011,60.321668 q 0,12.7582 -9.176951,21.487495 9.288865,8.841209 9.288865,21.711327 0,16.11562 -13.205856,24.84491 -7.722069,5.03614 -16.675192,5.03614 -16.003708,0 -24.8449171,-13.31778 -5.1480458,-7.61015 -5.1480458,-16.56327 0,-5.819533 2.2382807,-11.191407 L 16.33945,97.92479 q -1.11914,2.68593 -1.11914,5.5957 0,6.15527 4.364647,10.408 4.476562,4.36465 10.51992,4.36465 6.043358,0 10.408006,-4.36465 4.364647,-4.36464 4.364647,-10.408 0,-9.848438 -9.288865,-13.76543 -2.797851,0.55957 -5.595702,0.55957 -12.534373,0 -21.2636682,-8.729295 Q 0,72.85604 0,60.321668 0,47.899209 8.7292948,39.169914 17.570504,30.440619 29.992963,30.440619 l 8.729295,-20.7040974 11.862888,5.0361324 -7.833983,18.57773 q 7.833983,3.805078 12.422459,11.07949 4.700389,7.274413 4.700389,15.891794 z m -15.108395,0 q 0,-6.043358 -4.364647,-10.408006 -4.364648,-4.364647 -10.408006,-4.364647 -6.155272,0 -10.51992,4.364647 -4.364647,4.252734 -4.364647,10.408006 0,6.155272 4.364647,10.519919 4.364648,4.364648 10.51992,4.364648 6.155272,0 10.408006,-4.364648 4.364647,-4.364647 4.364647,-10.519919 z" /> + <path + inkscape:connector-curvature="0" + id="path4224" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:111.914px;line-height:125%;font-family:moderna;-inkscape-font-specification:moderna;letter-spacing:0px;word-spacing:0px;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 97.753413,73.527524 q -6.15527,0 -10.519918,-4.252733 -4.252733,-4.364648 -4.252733,-10.51992 L 82.868848,0 H 67.760452 v 58.754871 q 0,12.422459 8.729296,21.151754 8.841209,8.729295 21.263665,8.729295 12.422457,0 21.151757,-8.729295 8.8412,-8.729295 8.8412,-21.151754 V 0 h -15.10839 v 58.754871 q 0,6.155272 -4.36465,10.51992 -4.36465,4.252733 -10.519917,4.252733 z" /> + <path + inkscape:connector-curvature="0" + id="path4226" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:111.914px;line-height:125%;font-family:moderna;-inkscape-font-specification:moderna;letter-spacing:0px;word-spacing:0px;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 190.13495,30.216791 Q 190.24687,17.682419 181.51757,9.0650376 172.78828,0.3357421 160.2539,0.2238281 L 135.5209,0.111914 V 88.63592 h 15.22031 V 59.985926 h 9.40078 q 12.42246,0 21.15175,-8.617381 8.7293,-8.729296 8.84121,-21.151754 z m -15.10839,-0.111914 q -0.11192,6.267186 -4.36465,10.51992 -4.25273,4.252733 -10.51992,4.252733 H 150.6293 V 15.22031 l 9.6246,0.111914 q 6.26719,0.111914 10.51992,4.364647 4.36465,4.252734 4.25274,10.408006 z" /> + <path + inkscape:connector-curvature="0" + id="path4228" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:111.914px;line-height:125%;font-family:moderna;-inkscape-font-specification:moderna;letter-spacing:0px;word-spacing:0px;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="m 221.80976,45.549015 q 6.04336,0 10.40801,4.364647 4.36465,4.364648 4.36465,10.408006 l 0.11191,28.314252 h 15.1084 V 60.321668 q 0,-12.422459 -8.84121,-21.151754 -8.7293,-8.729295 -21.15176,-8.729295 -12.42246,0 -21.26366,8.729295 -8.7293,8.729295 -8.7293,21.151754 V 88.63592 h 15.1084 V 60.321668 q 0,-6.155272 4.36464,-10.408006 4.36465,-4.364647 10.51992,-4.364647 z" /> + <path + inkscape:connector-curvature="0" + id="path4230" + style="font-style:normal;font-variant:normal;font-weight:normal;font-stretch:normal;font-size:111.914px;line-height:125%;font-family:moderna;-inkscape-font-specification:moderna;letter-spacing:0px;word-spacing:0px;fill:#204a87;fill-opacity:1;stroke:none;stroke-width:1px;stroke-linecap:butt;stroke-linejoin:miter;stroke-opacity:1" + d="M 314.19132,30.216791 Q 314.30323,17.682419 305.57394,9.0650376 296.84464,0.3357421 284.31027,0.2238281 L 259.57727,0.111914 V 88.63592 h 15.22031 V 59.985926 h 9.40078 q 12.42245,0 21.15175,-8.617381 8.7293,-8.729296 8.84121,-21.151754 z m -15.1084,-0.111914 q -0.11191,6.267186 -4.36464,10.51992 -4.25274,4.252733 -10.51992,4.252733 h -9.5127 V 15.22031 l 9.62461,0.111914 q 6.26719,0.111914 10.51992,4.364647 4.36465,4.252734 4.25273,10.408006 z" /> + <rect + style="fill:#204a87;fill-opacity:1;stroke:#204a87;stroke-width:0.630386;stroke-linejoin:miter;stroke-miterlimit:0;stroke-dasharray:none;stroke-opacity:1" + id="rect5352" + width="248.92432" + height="15.959336" + x="67.316925" + y="104.33861" + ry="0" /> +</svg> diff --git a/doc/meson.build b/doc/meson.build index c3b8fb3..c5ebbc0 100644 --- a/doc/meson.build +++ b/doc/meson.build @@ -1,5 +1,6 @@ entities = configuration_data() entities.set('VERSION', meson.project_version()) + version_xml = configure_file(input: 'version.xml.in', output: 'version.xml', configuration: entities) @@ -12,36 +13,42 @@ docbook_man_page = configure_file( ) if get_option('gtk_doc') - gnome.gtkdoc('gupnp', - content_files : files( - 'client-tutorial.xml', - 'fdl-1.1.xml', - 'glossary.xml', - 'gupnp-docs.xml', - 'overview.xml', - 'server-tutorial.xml' - ), - main_xml : 'gupnp-docs.xml', - src_dir : ['libgupnp'], - dependencies : [libgupnp, version_xml, docbook_man_page], - scan_args : ['--ignore-decorators', 'G_DEPRECATED|G_GNUC_DEPRECATED,G_DEPRECATED_FOR'], - ignore_headers : [ - 'gena-protocol.h', - 'xml-util.h', - 'gvalue-util.h', - 'http-headers.h', - 'gupnp-context-private.h', - 'gupnp-linux-context-manager.h', - 'gupnp-network-manager.h', - 'gupnp-unix-context-manager.h', - 'gupnp-device-info-private.h', - 'gupnp-error-private.h', - 'gupnp-resource-factory-private.h', - 'gupnp-service-introspection-private.h', - 'gupnp-service-proxy-action-private.h', - 'gupnp-types-private.h' - ], - install : true) + gidocgen = find_program('gi-docgen', required: true) + + gupnp_toml = configure_file ( + input: 'gupnp.toml.in', + output: 'gupnp.toml', + configuration: entities + ) + + docs_dir = join_paths(get_option('prefix'), get_option('datadir')) / 'doc/gupnp-1.2/reference' + + custom_target( + 'gupnp-doc', + input: [ gupnp_toml, gir[0] ], + output: 'GUPnP', + command : [ + gidocgen, + 'generate', + '--quiet', + '--add-include-path=@0@'.format(meson.current_build_dir() / '../libgupnp'), + '--config', gupnp_toml, + '--output-dir=@OUTPUT@', + '--no-namespace-dir', + '--content-dir=@0@'.format(meson.current_source_dir()), + '@INPUT1@', + ], + depend_files : [ + gupnp_toml, + 'client-tutorial.md', + 'server-tutorial.md', + 'choosing-a-context-manager.md', + 'glossary.md', + ], + build_by_default: true, + install: true, + install_dir : docs_dir, + ) endif xsltproc = find_program('xsltproc', required: false) diff --git a/doc/server-tutorial.md b/doc/server-tutorial.md new file mode 100644 index 0000000..d0c0ce2 --- /dev/null +++ b/doc/server-tutorial.md @@ -0,0 +1,373 @@ +--- +Title: Implementing UPnP devices +--- + +# UPnP Server Tutorial + +This chapter explains how to implement an UPnP service using GUPnP. For +this example we will create a virtual UPnP-enabled light bulb. + +Before any code can be written, the device and services that it implement +need to be described in XML. Although this can be frustrating, if you are +implementing a standardised service then the service description is +already written for you and the device description is trivial. UPnP has +standardised Lighting Controls, so we'll be using the device and service types defined +there. + +## Defining the Device + +The first step is to write the _device description_ +file. This is a short XML document which describes the device and what +services it provides (for more details see the [UPnP Device Architecture specification](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0.pdf), section 2.1). We'll be using +the `BinaryLight1` device type, but if none of the +existing device types are suitable a custom device type can be created. + +```xml +<?xml version="1.0" encoding="utf-8"?> +<root xmlns="urn:schemas-upnp-org:device-1-0"> + <specVersion> + <major>1</major> + <minor>0</minor> + </specVersion> + + <device> + <deviceType>urn:schemas-upnp-org:device:BinaryLight:1</deviceType> + <friendlyName>Kitchen Lights</friendlyName> + <manufacturer>OpenedHand</manufacturer> + <modelName>Virtual Light</modelName> + <UDN>uuid:cc93d8e6-6b8b-4f60-87ca-228c36b5b0e8</UDN> + + <serviceList> + <service> + <serviceType>urn:schemas-upnp-org:service:SwitchPower:1</serviceType> + <serviceId>urn:upnp-org:serviceId:SwitchPower:1</serviceId> + <SCPDURL>/SwitchPower1.xml</SCPDURL> + <controlURL>/SwitchPower/Control</controlURL> + <eventSubURL>/SwitchPower/Event</eventSubURL> + </service> + </serviceList> + </device> +</root> +``` +The `<specVersion>` tag defines what version of the UPnP +Device Architecture the document conforms to. At the time of writing the +only version is 1.0. + +Next there is the root `<device>` tag. This contains +metadata about the device, lists the services it provides and any +sub-devices present (there are none in this example). The +`<deviceType>` tag specifies the type of the device. + +Next we have `<friendlyName>`, `<manufacturer>` and `<modelName>`. The +friendly name is a human-readable name for the device, the manufacturer +and model name are self-explanatory. + +Next there is the UDN, or _Unique Device Name_. This +is an identifier which is unique for each device but persistent for each +particular device. Although it has to start with `uuid:` +note that it doesn't have to be an UUID. There are several alternatives +here: for example it could be computed at built-time if the software will +only be used on a single machine, or it could be calculated using the +device's serial number or MAC address. + +Finally we have the `<serviceList>` which describes the +services this device provides. Each service has a service type (again +there are types defined for standardised services or you can create your +own), service identifier, and three URLs. As a service type we're using +the standard `SwitchPower1` service. The +`<SCPDURL>` field specifies where the _Service +Control Protocol Document_ can be found, this describes the +service in more detail and will be covered next. Finally there are the +control and event URLs, which need to be unique on the device and will be +managed by GUPnP. + +## Defining Services + +Because we are using a standard service we can use the service description +from the specification. This is the `SwitchPower1` +service description file: + +```xml +<?xml version="1.0" encoding="utf-8"?> +<scpd xmlns="urn:schemas-upnp-org:service-1-0"> + <specVersion> + <major>1</major> + <minor>0</minor> + </specVersion> + <actionList> + <action> + <name>SetTarget</name> + <argumentList> + <argument> + <name>newTargetValue</name> + <relatedStateVariable>Target</relatedStateVariable> + <direction>in</direction> + </argument> + </argumentList> + </action> + <action> + <name>GetTarget</name> + <argumentList> + <argument> + <name>RetTargetValue</name> + <relatedStateVariable>Target</relatedStateVariable> + <direction>out</direction> + </argument> + </argumentList> + </action> + <action> + <name>GetStatus</name> + <argumentList> + <argument> + <name>ResultStatus</name> + <relatedStateVariable>Status</relatedStateVariable> + <direction>out</direction> + </argument> + </argumentList> + </action> + </actionList> + <serviceStateTable> + <stateVariable sendEvents="no"> + <name>Target</name> + <dataType>boolean</dataType> + <defaultValue>0</defaultValue> + </stateVariable> + <stateVariable sendEvents="yes"> + <name>Status</name> + <dataType>boolean</dataType> + <defaultValue>0</defaultValue> + </stateVariable> + </serviceStateTable> +</scpd> +``` + +Again, the `<specVersion>` tag defines the UPnP version +that is being used. The rest of the document consists of an +`<actionList>` defining the actions available and a +`<serviceStateTable>` defining the state variables. + +Every `<action>` has a `<name>` and a list +of `<argument>`s. Arguments also have a name, a direction +(`in` or `out` for input or output + arguments) and a related state variable. The state variable is used to +determine the type of the argument, and as such is a required element. +This can lead to the creation of otherwise unused state variables to +define the type for an argument (the `WANIPConnection` +service is a good example of this), thanks to the legacy behind UPnP. + +`<stateVariable>`s need to specify their +`<name>` and `<dataType>`. State variables +by default send notifications when they change, to specify that a variable +doesn't do this set the `<sendEvents>` attribute to +`no`. Finally there are optional +`<defaultValue>`, `<allowedValueList>` and +`<allowedValueRange>` elements which specify what the +default and valid values for the variable. + +For the full specification of the service definition file, including a +complete list of valid `<dataType>`s, see section 2.3 of +the [UPnP Device Architecture](http://upnp.org/specs/arch/UPnP-arch-DeviceArchitecture-v1.0.pdf) + +## Implementing the Device + +Before starting to implement the device, some boilerplate code is needed +to initialise GUPnP. A GUPnP context can be created using `gupnp_context_new()`. + +```c +GUPnPContext *context; +/* Create the GUPnP context with default host and port */ +context = gupnp_context_new (NULL, 0, NULL); +``` +Next the root device can be created. The name of the device description +file can be passed as an absolute file path or a relative path to the +second parameter of `gupnp_root_device_new()`. The service description +files referenced in the device description are expected to be at the path +given there as well. + +```c +GUPnPRootDevice *dev; +/* Create the root device object */ +dev = gupnp_root_device_new (context, "BinaryLight1.xml", "."); +/* Activate the root device, so that it announces itself */ +gupnp_root_device_set_available (dev, TRUE); +``` + +GUPnP scans the device description and any service description files it +refers to, so if the main loop was entered now the device and service +would be available on the network, albeit with no functionality. The +remaining task is to implement the services. + +## Implementing a Service + +To implement a service we first fetch the #GUPnPService from the root +device using gupnp_device_info_get_service() (#GUPnPRootDevice is a +subclass of #GUPnPDevice, which implements #GUPnPDeviceInfo). This +returns a #GUPnPServiceInfo which again is an interface, implemented by +#GUPnPService (on the server) and #GUPnPServiceProxy (on the client). + +```c +GUPnPServiceInfo *service; +service = gupnp_device_info_get_service (GUPNP_DEVICE_INFO (dev), "urn:schemas-upnp-org:service:SwitchPower:1"); +``` + +GUPnPService handles interacting with the network itself, leaving the +implementation of the service itself to signal handlers that we need to +connect. There are two signals: #GUPnPService::action-invoked and +#GUPnPService::query-variable. #GUPnPService::action-invoked is emitted +when a client invokes an action: the handler is passed a +#GUPnPServiceAction object that identifies which action was invoked, and +is used to return values using `gupnp_service_action_set()`. +#GUPnPService::query-variable is emitted for evented variables when a +control point subscribes to the service (to announce the initial value), +or whenever a client queries the value of a state variable (note that this +is now deprecated behaviour for UPnP control points): the handler is +passed the variable name and a #GValue which should be set to the current +value of the variable. + +Handlers should be targetted at specific actions or variables by using +the signal detail when connecting. For example, +this causes `on_get_status_action` to be called when +the `GetStatus` action is invoked: + +```c +static void on_get_status_action (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data); +// ... +g_signal_connect (service, "action-invoked::GetStatus", G_CALLBACK (on_get_status_action), NULL); +``` + +The implementation of action handlers is quite simple. The handler is +passed a #GUPnPServiceAction object which represents the in-progress +action. If required it can be queried using +gupnp_service_action_get_name() to identify the action (this isn't +required if detailed signals were connected). Any +in arguments can be retrieving using +`gupnp_service_action_get()`, and then return values can be set using +`gupnp_service_action_set()`. Once the action has been performed, either +`gupnp_service_action_return()` or `gupnp_service_action_return_error()` +should be called to either return successfully or return an error code. + +If any evented state variables were modified during the action then a +notification should be emitted using `gupnp_service_notify()`. This is an +example implementation of `GetStatus` and `SetTarget` + +```c +static gboolean status; + +static void +get_status_cb (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data) +{ + gupnp_service_action_set (action, + "ResultStatus", G_TYPE_BOOLEAN, status, + NULL); + gupnp_service_action_return (action); +} + +void +set_target_cb (GUPnPService *service, GUPnPServiceAction *action, gpointer user_data) +{ + gupnp_service_action_get (action, + "NewTargetValue", G_TYPE_BOOLEAN, &status, + NULL); + gupnp_service_action_return (action); + gupnp_service_notify (service, "Status", G_TYPE_STRING, status, NULL); +} + +//... + +g_signal_connect (service, "action-invoked::GetStatus", G_CALLBACK (get_status_cb), NULL); +g_signal_connect (service, "action-invoked::SetTarget", G_CALLBACK (set_target_cb), NULL); +``` + +State variable query handlers are called with the name of the variable and +a #GValue. This value should be initialized with the relevant type and +then set to the current value. Again signal detail can be used to connect +handlers to specific state variable callbacks. + +```c +static gboolean status; + +static void +query_status_cb (GUPnPService *service, char *variable, GValue *value, gpointer user_data) +{ + g_value_init (value, G_TYPE_BOOLEAN); + g_value_set_boolean (value, status); +} + +// ... + +g_signal_connect (service, "query-variable::Status", G_CALLBACK (query_status_cb), NULL); +``` + +The service is now fully implemented. To complete it, enter a GLib main +loop and wait for a client to connect. The complete source code for this +example is available as [examples/light-server.c](https://gitlab.gnome.org/GNOME/gupnp/-/blob/master/examples/light-server.c) in +the GUPnP sources. + +For services which have many actions and variables there is a convenience +method [method@GUPnP.Service.signals_autoconnect] which will automatically +connect specially named handlers to signals. See the documentation for +full details on how it works. + +## Generating Service-specific Wrappers + +Using service-specific wrappers can simplify the implementation of a service. +Wrappers can be generated with gupnp-binding-tool +using the option `--mode server`. + +In the following examples the wrapper has been created with + `--mode server --prefix switch`. Please note that the callback handlers + (`get_status_cb` and `set_target_cb`) are not automatically + generated by gupnp-binding-tool for you. + +```c +static gboolean status; + +static void +get_status_cb (GUPnPService *service, + GUPnPServiceAction *action, + gpointer user_data) +{ + switch_get_status_action_set (action, status); + + gupnp_service_action_return (action); +} + +static void +set_target_cb (GUPnPService *service, + GUPnPServiceAction *action, + gpointer user_data) +{ + switch_set_target_action_get (action, &status); + switch_status_variable_notify (service, status); + + gupnp_service_action_return (action); +} + +// ... + +switch_get_status_action_connect (service, G_CALLBACK(get_status_cb), NULL); +switch_set_target_action_connect (service, G_CALLBACK(set_target_cb), NULL); +``` + +Note how many possible problem situations that were run-time errors are +actually compile-time errors when wrappers are used: Action names, +argument names and argument types are easier to get correct (and available +in editor autocompletion). + +State variable query handlers are implemented in a similar manner, but +they are even simpler as the return value of the handler is the state +variable value. + +```c +static gboolean +query_status_cb (GUPnPService *service, + gpointer user_data) +{ + return status; +} + +// ... + + +switch_status_query_connect (service, query_status_cb, NULL); +``` diff --git a/doc/urlmap.js b/doc/urlmap.js new file mode 100644 index 0000000..4e19607 --- /dev/null +++ b/doc/urlmap.js @@ -0,0 +1,4 @@ +// A map between namespaces and base URLs for their online documentation +baseURLs = [ + [ 'GSSDP', 'https://gnome.pages.gitlab.gnome.org/gssdp/docs/' ], +] diff --git a/libgupnp/gupnp-acl.c b/libgupnp/gupnp-acl.c index 4a337c6..6a4cd1b 100644 --- a/libgupnp/gupnp-acl.c +++ b/libgupnp/gupnp-acl.c @@ -6,23 +6,23 @@ * SPDX-License-Identifier: LGPL-2.1-or-later */ -/** - * SECTION:gupnp-acl - * @short_description: Object providing a simple access control list for - * GUPnP. - * - * #GUPnPAcl provides either synchronous or asynchronous functions to check - * whether a peer sould be able to access a resource or not. - * - * Since: 0.20.11 - */ - #include <config.h> #include "gupnp-acl.h" #include "gupnp-acl-private.h" #include "gupnp-device.h" +/** + * GUPnPAcl: + * + * Access control provider for [class@GUPnP.Context] + * + * GUPnPAcl provides either synchronous or asynchronous functions to check + * whether a peer should be able to access a resource that is hosted by GUPnP or not. + * + * Since: 0.20.11 + */ + G_DEFINE_INTERFACE(GUPnPAcl, gupnp_acl, G_TYPE_OBJECT) static void @@ -33,14 +33,13 @@ gupnp_acl_default_init (GUPnPAclInterface *klass) /** * gupnp_acl_is_allowed: * @self: an instance of #GUPnPAcl - * @device: (nullable): The #GUPnPDevice associated with @path or %NULL if + * @device: (nullable): The [class@GUPnP.Device] associated with @path or %NULL if * unknown. - * @service: (nullable): The #GUPnPService associated with @path or %NULL if + * @service: (nullable): The [class@GUPnP.Service] associated with @path or %NULL if * unknown. * @path: The path being served. * @address: IP address of the peer. - * @agent: (nullable): The User-Agent header of the peer or %NULL if not - * unknown. + * @agent: (nullable): The User-Agent header of the peer or %NULL if unknown. * @returns %TRUE if the peer is allowed, %FALSE otherwise * * Check whether an IP address is allowed to access this resource. @@ -68,26 +67,30 @@ gupnp_acl_is_allowed (GUPnPAcl *self, /** * gupnp_acl_is_allowed_async: * @self: a #GUPnPAcl - * @device: (nullable): The #GUPnPDevice associated with @path or %NULL if + * @device: (nullable): The [class@GUPnP.Device] associated with @path or %NULL if * unknown. - * @service: (nullable): The #GUPnPService associated with @path or %NULL if + * @service: (nullable): The [class@GUPnP.Service] associated with @path or %NULL if * unknown. * @path: The path being served. * @address: IP address of the peer * @agent: (nullable): The User-Agent header of the peer or %NULL if not * unknown. - * @cancellable: (nullable): A #GCancellable which can be used to cancel the + * @cancellable: (nullable): A cancellable which can be used to cancel the * operation. * @callback: Callback to call after the function is done. * @user_data: Some user data. * - * Optional. Check asynchronously whether an IP address is allowed to access - * this resource. Use this function if the process of verifying the access right - * is expected to take some time, for example when using D-Bus etc. + * Check asynchronously whether an IP address is allowed to access + * this resource. + * + * This function is optional. [method@GUPnP.Acl.can_sync] should return %TRUE + * if the implementing class supports it. If it is supported, GUPnP will + * prefer to use this function over [method@GUPnP.Acl.is_allowed]. * - * If this function is supported, gupnp_acl_can_sync() should return %TRUE. + * Implement this function if the process of verifying the access right + * is expected to take some time, for example when using D-Bus etc. * - * Use gupnp_acl_is_allowed_finish() to retrieve the result. + * Use [method@GUPnP.Acl.is_allowed_finish] to retrieve the result. * * Since: 0.20.11 */ @@ -118,11 +121,13 @@ gupnp_acl_is_allowed_async (GUPnPAcl *self, /** * gupnp_acl_is_allowed_finish: * @self: An instance of #GUPnPAcl - * @res: %GAsyncResult obtained from the callback in gupnp_acl_is_allowed_async() + * @res: [iface@Gio.AsyncResult] obtained from the callback passed to [method@GUPnP.Acl.is_allowed_async] * @error: (inout)(optional)(nullable): A return location for a #GError describing the failure * @returns %TRUE if the authentication was successful, %FALSE otherwise and on * error. Check @error for details. * + * Get the result of [method@GUPnP.Acl.is_allowed_async]. + * * Since: 0.20.11 */ gboolean @@ -143,7 +148,7 @@ gupnp_acl_is_allowed_finish (GUPnPAcl *self, * @returns %TRUE, if gupnp_acl_is_allowed_async() is supported, %FALSE * otherwise. * - * Check whether gupnp_acl_is_allowed_async() is supported. + * Check whether [method@GUPnP.Acl.is_allowed_async] is supported. * * Since: 0.20.11 */ @@ -155,6 +160,10 @@ gupnp_acl_can_sync (GUPnPAcl *self) return GUPNP_ACL_GET_IFACE (self)->can_sync (self); } +/////////////////////////////////////////////////////////////////// +// Internal helper functions +// + /** * acl_server_handler_new: * @service: (nullable): A #GUPnPContext or %NULL if unknown diff --git a/libgupnp/gupnp-acl.h b/libgupnp/gupnp-acl.h index c382c9f..74d8ce5 100644 --- a/libgupnp/gupnp-acl.h +++ b/libgupnp/gupnp-acl.h @@ -18,25 +18,8 @@ G_BEGIN_DECLS #define GUPNP_TYPE_ACL (gupnp_acl_get_type()) G_DECLARE_INTERFACE (GUPnPAcl, gupnp_acl, GUPNP, ACL, GObject) -/** - * GUPnPAcl: - * - * Handle to an object implementing the #GUPnPAclInterface interface. - */ -typedef struct _GUPnPAcl GUPnPAcl; -/** - * GUPnPAclInterface: - * @parent: The parent interface. - * @is_allowed: Check whether access to the resource is granted. - * @is_allowed_async: Asynchronously check whether the access is granted. - * @is_allowed_finish: Conclude the @is_allowed_async operation. - * @can_sync: Whether the ACL can do sync queries. - * - * Implement a simple access control list for GUPnP. - * - * Since: 0.20.11 - */ +typedef struct _GUPnPAcl GUPnPAcl; typedef struct _GUPnPAclInterface GUPnPAclInterface; /* Forward declarations to avoid recursive includes */ @@ -71,11 +54,13 @@ struct _GUPnPAclInterface { /*< private >*/ +#ifndef GOBJECT_INTROSPECTION_SKIP /* future padding */ void (* _gupnp_reserved1) (void); void (* _gupnp_reserved2) (void); void (* _gupnp_reserved3) (void); void (* _gupnp_reserved4) (void); +#endif }; gboolean diff --git a/libgupnp/gupnp-connman-manager.c b/libgupnp/gupnp-connman-manager.c index f64e1b9..4dbd02c 100644 --- a/libgupnp/gupnp-connman-manager.c +++ b/libgupnp/gupnp-connman-manager.c @@ -54,6 +54,11 @@ struct _GUPnPConnmanManagerPrivate { typedef struct _GUPnPConnmanManagerPrivate GUPnPConnmanManagerPrivate; +/** + * GUPnPConnmanManager: + * + * Connman-based implementation of a [class@GUPnP.ContextManager] + */ struct _GUPnPConnmanManager { GUPnPContextManager parent; }; diff --git a/libgupnp/gupnp-context-filter.c b/libgupnp/gupnp-context-filter.c index e23f0eb..4770689 100644 --- a/libgupnp/gupnp-context-filter.c +++ b/libgupnp/gupnp-context-filter.c @@ -6,18 +6,6 @@ * SPDX-License-Identifier: LGPL-2.1-or-later */ -/** - * SECTION:gupnp-context-filter - * @short_description: Class for network filtering. - * - * #GUPnPContextFilter handles network filtering. It provides API to manage a - * list of entries that will be used to filter networks. The #GUPnPContextFilter - * could be enabled or not. If it's enabled but the entries list is empty, it - * behaves as disabled. - * - * Since: 1.4.0 - */ - #include "gupnp-context-filter.h" #include <string.h> @@ -31,12 +19,44 @@ typedef struct _GUPnPContextFilterPrivate GUPnPContextFilterPrivate; /** * GUPnPContextFilter: * - * Class for network context filtering. + * Network context filter, used by [class@GUPnP.ContextManager] * * #GUPnPContextFilter handles network filtering. It provides API to manage a * list of entries that will be used to filter networks. The #GUPnPContextFilter * could be enabled or not. If it's enabled but the entries list is empty, it - * behaves as disabled. + * behaves as if being disabled. + * + * The GUPnPContextFilter is used with the [class@GUPnP.ContextManager] + * to narrow down the contexts that are notified by it. + * + * Contexts can be filtered by the following criteria: + * + * - Their IP addresses + * - The network device they will live on + * - The name of the network the context would join + * + * To add or modify a context filter, you need to retrieve the current context filter + * from the context manger using [method@GUPnP.ContextManager.get_context_filter]. + * + * By default, a context filter is empty and disabled. + * + * For example, to only react to contexts that are appearing on eth0 or when being in the WiFi network with + * the SSID "HomeNetwork", and on IPv6 localhost, you should do: + * + * + * ```c + * GUPnPContextFilter* filter; + * + * filter = gupnp_context_manager_get_context_filter (manager); + * const char *filter_entries[] = { + * "eth0", + * "HomeNetwork", + * "::1", + * NULL + * }; + * gupnp_context_filter_add_entryv (filter, filter_entries); + * gupnp_context_filter_set_enabled (filter, TRUE); + * ``` * * Since: 1.4.0 */ @@ -142,7 +162,7 @@ gupnp_context_filter_class_init (GUPnPContextFilterClass *klass) object_class->finalize = gupnp_context_filter_class_finalize; /** - * GUPnPContextFilter:enabled: + * GUPnPContextFilter:enabled:(attributes org.gtk.Property.get=gupnp_context_filter_get_enabled org.gtk.Property.set=gupnp_context_filter_set_enabled) * * Whether this context filter is active or not. * @@ -159,7 +179,7 @@ gupnp_context_filter_class_init (GUPnPContextFilterClass *klass) G_PARAM_STATIC_STRINGS)); /** - * GUPnPContextFilter:entries: (type GList(utf8)) + * GUPnPContextFilter:entries: (type GList(utf8))(attributes org.gtk.Property.get=gupnp_context_filter_get_entries) * * A list of items to filter for. * @@ -170,7 +190,7 @@ gupnp_context_filter_class_init (GUPnPContextFilterClass *klass) PROP_ENTRIES, g_param_spec_pointer ( "entries", - "Entries", + "Filter entries", "GList of strings that compose the context filter.", G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); @@ -193,7 +213,7 @@ gupnp_context_filter_new (void) } /** - * gupnp_context_filter_set_enabled: + * gupnp_context_filter_set_enabled:(attributes org.gtk.Method.set_property=enabled) * @context_filter: A #GUPnPContextFilter * @enable: %TRUE to enable @context_filter, %FALSE otherwise * @@ -215,7 +235,7 @@ gupnp_context_filter_set_enabled (GUPnPContextFilter *context_filter, } /** - * gupnp_context_filter_get_enabled: + * gupnp_context_filter_get_enabled:(attributes org.gtk.Method.get_property=enabled) * @context_filter: A #GUPnPContextFilter * * Return the status of the #GUPnPContextFilter @@ -297,8 +317,8 @@ gupnp_context_filter_add_entry (GUPnPContextFilter *context_filter, * @entries: (array zero-terminated=1): A %NULL-terminated list of strings * * Add a list of entries to a #GUPnPContextFilter. This is a helper function to - * directly add a %NULL-terminated array of string usually aquired from - * commandline args. + * directly add a %NULL-terminated array of string usually acquired from + * command line arguments. * * Since: 1.4.0 */ @@ -400,11 +420,11 @@ gupnp_context_filter_clear (GUPnPContextFilter *context_filter) * @context: A #GUPnPContext to test. * * It will check if the @context is allowed or not. The @context_filter will - * check all its entries againt #GUPnPContext interface, host ip and network + * check all its entries against #GUPnPContext interface, host IP and network * fields information. This function doesn't take into account the * @context_filter status (enabled or not). * - * Return value: %TRUE if @context is matching the @context_filter criterias, + * Return value: %TRUE if @context is matching the @context_filter criteria, * %FALSE otherwise. * * Since: 1.4.0 diff --git a/libgupnp/gupnp-context-manager.c b/libgupnp/gupnp-context-manager.c index 35c2e50..5092005 100644 --- a/libgupnp/gupnp-context-manager.c +++ b/libgupnp/gupnp-context-manager.c @@ -11,17 +11,6 @@ * */ -/** - * SECTION:gupnp-context-manager - * @short_description: Manages GUPnPContext objects. - * - * A Utility class that takes care of creation and destruction of - * #GUPnPContext objects for all available network interfaces as they go up - * (connect) and down (disconnect), respectively. - * - * Since: 0.13.0 - */ - #define G_LOG_DOMAIN "gupnp-context-manager" #include <config.h> @@ -65,6 +54,23 @@ struct _GUPnPContextManagerPrivate { }; typedef struct _GUPnPContextManagerPrivate GUPnPContextManagerPrivate; +/** + * GUPnPContextManager: + * + * A manager for [class@GUPnP.Context] instances. + * + * This utility class that takes care of dynamic creation and destruction of + * #GUPnPContext objects for all available network interfaces as they go up + * (connect) and down (disconnect), respectively. + * + * The final implementation depends either on the underlying operating system + * or can configured during compile time. + * + * It also provides a simple filtering facility if required. See [method@GUPnP.ContextManager.get_context_filter] and + * [class@GUPnP.ContextFilter] for details. + * + * Since: 0.14.0 + */ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GUPnPContextManager, gupnp_context_manager, G_TYPE_OBJECT) @@ -483,7 +489,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass) object_class->dispose = gupnp_context_manager_dispose; /** - * GUPnPContextManager:port: + * GUPnPContextManager:port:(attributes org.gtk.Property.get=gupnp_context_manager_get_port) * * Port the contexts listen on, or 0 if you don't care what * port is used by #GUPnPContext objects created by this object. @@ -502,7 +508,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass) G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); /** - * GUPnPContextManager:family: + * GUPnPContextManager:family:(attributes org.gtk.Property.get=gupnp_context_manager_get_socket_family) * * The socket family to create contexts for. Use %G_SOCKET_FAMILY_INVALID * for any or %G_SOCKET_FAMILY_IPV4 for IPv4 contexts or @@ -523,7 +529,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass) G_PARAM_STATIC_STRINGS)); /** - * GUPnPContextManager:uda-version: + * GUPnPContextManager:uda-version:(attributes org.gtk.Property.get=gupnp_context_manager_get_uda_version) * * The UDA version the contexts will support. Use %GSSDP_UDA_VERSION_UNSPECIFIED * for using the default UDA version. @@ -543,7 +549,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass) G_PARAM_STATIC_STRINGS)); /** - * GUPnPContextManager:context-filter: + * GUPnPContextManager:context-filter:(attributes org.gtk.Property.get=gupnp_context_manager_get_context_filter) * * The context filter to use. **/ @@ -606,7 +612,7 @@ gupnp_context_manager_class_init (GUPnPContextManagerClass *klass) * * Factory-method to create a new #GUPnPContextManager. The final type of the * #GUPnPContextManager depends on the compile-time selection or - in case of - * NetworkManager - on its availability during runtime. If it is not available, + * NetworkManager - on its availability during run-time. If it is not available, * the implementation falls back to the basic Unix context manager instead. * * Equivalent to calling #gupnp_context_manager_create_full (%GSSDP_UDA_VERSION_1_0, %G_SOCKET_FAMILY_IPV4, port); @@ -632,7 +638,7 @@ gupnp_context_manager_create (guint port) * * Factory-method to create a new #GUPnPContextManager. The final type of the * #GUPnPContextManager depends on the compile-time selection or - in case of - * NetworkManager - on its availability during runtime. If it is not available, + * NetworkManager - on its availability during run-time. If it is not available, * the implementation falls back to the basic Unix context manager instead. * * Returns: (transfer full): A new #GUPnPContextManager object. @@ -739,9 +745,23 @@ gupnp_context_manager_rescan_control_points (GUPnPContextManager *manager) * * By calling this function, you are asking @manager to keep a reference to * @control_point until its associated #GUPnPContext is no longer available. - * You usually want to call this function from - * #GUPnPContextManager::context-available handler after you create a + * You usually want to call this function from your + * [signal@GUPnP.ContextManager::context-available] handler after you create a * #GUPnPControlPoint object for the newly available context. + * You usually then give up your own reference to the control point so it will be + * automatically destroyed if its context is no longer available. + * + * This function is mainly useful when implementing an UPnP client. + * + * ```c + * void on_context_available (GUPnPContextManager *manager, GUPnPContext *context, gpointer user_data) + * { + * GUPnPControlPoint *cp = gupnp_control_point_new (context, "urn:schemas-upnp-org:device:MediaRenderer:1"); + * gupnp_context_manager_manage_control_point (manager, cp); + * // Subscribe to control point's signals etc. + * g_object_unref (cp); + * } + * ``` * * Since: 0.14.0 **/ @@ -767,9 +787,25 @@ gupnp_context_manager_manage_control_point (GUPnPContextManager *manager, * By calling this function, you are asking @manager to keep a reference to * @root_device when its associated #GUPnPContext is no longer available. You * usually want to call this function from - * #GUPnPContextManager::context-available handler after you create a + * [signal@GUPnP.ContextManager::context-available] handler after you create a * #GUPnPRootDevice object for the newly available context. * + * You usually then give up your own reference to the root device so it will be + * automatically destroyed if its context is no longer available. + * + * This function is mainly useful when implementing an UPnP client. + * + * ```c + * void on_context_available (GUPnPContextManager *manager, GUPnPContext *context, gpointer user_data) + * { + * GError *error = NULL; + * + * GUPnPRootDevice *rd = gupnp_root_device_new (context, "BasicLight1.xml", ".", &error); + * gupnp_context_manager_manage_root_device (manager, rd); + * // Subscribe to control point's signals etc. + * g_object_unref (rd); + * } + * ``` * Since: 0.14.0 **/ void @@ -787,11 +823,11 @@ gupnp_context_manager_manage_root_device (GUPnPContextManager *manager, } /** - * gupnp_context_manager_get_port: + * gupnp_context_manager_get_port:(attributes org.gtk.Method.get_property=port) * @manager: A #GUPnPContextManager * * Get the network port associated with this context manager. - * Returns: The network port asssociated with this context manager. + * Returns: The network port associated with this context manager. * * Since: 0.20.0 */ @@ -808,13 +844,15 @@ gupnp_context_manager_get_port (GUPnPContextManager *manager) } /** - * gupnp_context_manager_get_context_filter: + * gupnp_context_manager_get_context_filter:(attributes org.gtk.Method.get_property=context-filter) * @manager: A #GUPnPContextManager * * Get the #GUPnPContextFilter associated with @manager. * - * Returns: (transfer none): The #GUPnPContextFilter asssociated with this + * Returns: (transfer none): The #GUPnPContextFilter associated with this * context manager. + * + * Since: 1.4.0 */ GUPnPContextFilter * gupnp_context_manager_get_context_filter (GUPnPContextManager *manager) @@ -834,9 +872,9 @@ gupnp_context_manager_get_context_filter (GUPnPContextManager *manager) * * Get the #GUPnPContextFilter associated with @manager. * - * Returns: (transfer none): The #GUPnPContextFilter asssociated with this + * Returns: (transfer none): The #GUPnPContextFilter associated with this * context manager. - * Deprecated: 1.4.0: Use gupnp_context_manager_get_context_filter() instead. + * Deprecated: 1.4.0: Use [method@GUPnP.ContextManager.get_context_filter] instead. */ GUPnPWhiteList * gupnp_context_manager_get_white_list (GUPnPContextManager *manager) @@ -845,7 +883,7 @@ gupnp_context_manager_get_white_list (GUPnPContextManager *manager) } /** - * gupnp_context_manager_get_socket_family: + * gupnp_context_manager_get_socket_family:(attributes org.gtk.Method.get_property=family) * @manager: A #GUPnPContextManager * * Get the #GSocketFamily the contexts are created for. Can be @@ -869,7 +907,7 @@ gupnp_context_manager_get_socket_family (GUPnPContextManager *manager) } /** - * gupnp_context_manager_get_uda_version: + * gupnp_context_manager_get_uda_version:(attributes org.gtk.Method.get_property=uda-version) * @manager: A #GUPnPContextManager * * Get the UDA protocol version the contexts are implementing diff --git a/libgupnp/gupnp-context.c b/libgupnp/gupnp-context.c index 335cce8..bef53f8 100644 --- a/libgupnp/gupnp-context.c +++ b/libgupnp/gupnp-context.c @@ -11,14 +11,15 @@ */ /** - * SECTION:gupnp-context - * @short_description: Context object wrapping shared networking bits. + * GUPnPContext: + * + * Context object wrapping shared networking bits. * * #GUPnPContext wraps the networking bits that are used by the various * GUPnP classes. It automatically starts a web server on demand. * * For debugging, it is possible to see the messages being sent and received by - * exporting <envar>GUPNP_DEBUG</envar>. + * setting the environment variable `GUPNP_DEBUG`. */ #define G_LOG_DOMAIN "gupnp-context" @@ -362,7 +363,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) object_class->finalize = gupnp_context_finalize; /** - * GUPnPContext:server: + * GUPnPContext:server:(attributes org.gtk.Property.get=gupnp_context_get_server) * * The #SoupServer HTTP server used by GUPnP. **/ @@ -379,7 +380,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) G_PARAM_STATIC_BLURB)); /** - * GUPnPContext:session: + * GUPnPContext:session:(attributes org.gtk.Property.get=gupnp_context_get_session) * * The #SoupSession object used by GUPnP. **/ @@ -396,7 +397,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) G_PARAM_STATIC_BLURB)); /** - * GUPnPContext:subscription-timeout: + * GUPnPContext:subscription-timeout:(attributes org.gtk.Property.get=gupnp_context_get_subscription_timeout org.gtk.Property.set=gupnp_context_set_subscription_timeout) * * The preferred subscription timeout: the number of seconds after * which subscriptions are renewed. Set to '0' if subscriptions @@ -417,7 +418,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); /** - * GUPnPContext:default-language: + * GUPnPContext:default-language:(attributes org.gtk.Property.get=gupnp_context_get_default_language org.gtk.Property.set=gupnp_context_set_default_language) * * The content of the Content-Language header id the client * sends Accept-Language and no language-specific pages to serve @@ -439,7 +440,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) G_PARAM_STATIC_BLURB)); /** - * GUPnPContext:acl: + * GUPnPContext:acl:(attributes org.gtk.Property.get=gupnp_context_get_acl org.gtk.Property.set=gupnp_context_set_acl) * * An access control list. * @@ -458,7 +459,7 @@ gupnp_context_class_init (GUPnPContextClass *klass) } /** - * gupnp_context_get_session: + * gupnp_context_get_session:(attributes org.gtk.Method.get_property=session) * @context: A #GUPnPContext * * Get the #SoupSession object that GUPnP is using. @@ -496,7 +497,7 @@ default_server_handler (G_GNUC_UNUSED SoupServer *server, } /** - * gupnp_context_get_server: + * gupnp_context_get_server:(attributes org.gtk.Method.get_property=server) * @context: A #GUPnPContext * * Get the #SoupServer HTTP server that GUPnP is using. @@ -613,6 +614,7 @@ gupnp_context_new (const char *iface, NULL); } +\ /** * gupnp_context_get_port: * @context: A #GUPnPContext @@ -624,19 +626,16 @@ gupnp_context_new (const char *iface, guint gupnp_context_get_port (GUPnPContext *context) { - GUPnPContextPrivate *priv; - g_return_val_if_fail (GUPNP_IS_CONTEXT (context), 0); - priv = gupnp_context_get_instance_private (context); - if (priv->server_uri == NULL) - priv->server_uri = make_server_uri (context); + GUri *uri = _gupnp_context_get_server_uri (context); + g_uri_unref (uri); - return g_uri_get_port (priv->server_uri); + return g_uri_get_port (uri); } /** - * gupnp_context_set_subscription_timeout: + * gupnp_context_set_subscription_timeout:(attributes org.gtk.Method.set_property=subscription-timeout) * @context: A #GUPnPContext * @timeout: Event subscription timeout in seconds * @@ -659,7 +658,7 @@ gupnp_context_set_subscription_timeout (GUPnPContext *context, } /** - * gupnp_context_get_subscription_timeout: + * gupnp_context_get_subscription_timeout:(attributes org.gtk.Method.get_property=subscription-timeout) * @context: A #GUPnPContext * * Get the event subscription timeout (in seconds), or 0 meaning there is no @@ -693,7 +692,7 @@ host_path_data_set_language (HostPathData *data, const char *language) } /** - * gupnp_context_set_default_language: + * gupnp_context_set_default_language:(attributes org.gtk.Method.set_property=default-language) * @context: A #GUPnPContext * @language: A language tag as defined in RFC 2616 3.10 * @@ -733,7 +732,7 @@ gupnp_context_set_default_language (GUPnPContext *context, } /** - * gupnp_context_get_default_language: + * gupnp_context_get_default_language:(attributes org.gtk.Method.get_property=default-language) * @context: A #GUPnPContext * * Get the default Content-Language header for this context. @@ -1334,7 +1333,7 @@ gupnp_context_unhost_path (GUPnPContext *context, } /** - * gupnp_context_get_acl: + * gupnp_context_get_acl:(attributes org.gtk.Method.get_property=acl) * @context: A #GUPnPContext * * Access the #GUPnPAcl associated with this client. If there isn't any, @@ -1357,7 +1356,7 @@ gupnp_context_get_acl (GUPnPContext *context) } /** - * gupnp_context_set_acl: + * gupnp_context_set_acl:(attributes org.gtk.Method.set_property=acl) * @context: A #GUPnPContext * @acl: (nullable): The new access control list or %NULL to remove the * current list. diff --git a/libgupnp/gupnp-context.h b/libgupnp/gupnp-context.h index d722ed7..79b3e30 100644 --- a/libgupnp/gupnp-context.h +++ b/libgupnp/gupnp-context.h @@ -26,7 +26,16 @@ struct _GUPnPContextClass { GSSDPClientClass parent_class; /* future padding */ + /*<private>*/ + /** + * _gupnp_reserved1:(skip): + * + * Padding + */ void (* _gupnp_reserved1) (void); + /** + * _gupnp_reserved2:(skip): + */ void (* _gupnp_reserved2) (void); void (* _gupnp_reserved3) (void); void (* _gupnp_reserved4) (void); diff --git a/libgupnp/gupnp-control-point.c b/libgupnp/gupnp-control-point.c index 97bdfa5..41d56c6 100644 --- a/libgupnp/gupnp-control-point.c +++ b/libgupnp/gupnp-control-point.c @@ -8,13 +8,16 @@ */ /** - * SECTION:gupnp-control-point - * @short_description: Class for resource discovery. + * GUPnPControlPoint: + * + * Network resource discovery. * * #GUPnPControlPoint handles device and service discovery. After creating - * a control point and activating it using gssdp_resource_browser_set_active(), - * the ::device-proxy-available, ::service-proxy-available, - * ::device-proxy-unavailable and ::service-proxy-unavailable signals will + * a control point and activating it using [method@GSSDP.ResourceBrowser.set_active], + * the [signal@GUPnP.ControlPoint::device-proxy-available], + * [signal@GUPnP.ControlPoint::service-proxy-available], + * [signal@GUPnP.ControlPoint::device-proxy-unavailable] and + * [signal@GUPnP.ControlPoint::service-proxy-unavailable] signals will * be emitted whenever the availability of a device or service matching * the specified discovery target changes. */ @@ -1044,7 +1047,7 @@ gupnp_control_point_class_init (GUPnPControlPointClass *klass) gupnp_control_point_resource_unavailable; /** - * GUPnPControlPoint:resource-factory: + * GUPnPControlPoint:resource-factory:(attributes org.gtk.Property.get=gupnp_control_point_get_resource_factory) * * The resource factory to use. Set to NULL for default factory. **/ @@ -1154,8 +1157,8 @@ gupnp_control_point_class_init (GUPnPControlPointClass *klass) * Create a new #GUPnPControlPoint with the specified @context and @target. * * @target should be a service or device name, such as - * <literal>urn:schemas-upnp-org:service:WANIPConnection:1</literal> or - * <literal>urn:schemas-upnp-org:device:MediaRenderer:1</literal>. + * `urn:schemas-upnp-org:service:WANIPConnection:1` or + * `urn:schemas-upnp-org:device:MediaRenderer:1`. * * Return value: A new #GUPnPControlPoint object. **/ @@ -1182,8 +1185,12 @@ gupnp_control_point_new (GUPnPContext *context, * @target. * * @target should be a service or device name, such as - * <literal>urn:schemas-upnp-org:service:WANIPConnection:1</literal> or - * <literal>urn:schemas-upnp-org:device:MediaRenderer:1</literal>. + * `urn:schemas-upnp-org:service:WANIPConnection:1` or + * `urn:schemas-upnp-org:device:MediaRenderer:1`. + * + * By passing a custom `GUPnPResourceFactory`, the proxies handed out in ::device-available and + * ::service-available can be overridden to hand out custom classes instead of the generic + * [class@GUPnP.ServiceProxy] and [class@GUPnP.DeviceProxy]. * * Return value: A new #GUPnPControlPoint object. **/ @@ -1211,6 +1218,7 @@ gupnp_control_point_new_full (GUPnPContext *context, * Get the #GUPnPControlPoint associated with @control_point. * * Returns: (transfer none): The #GUPnPContext. + * Deprecated: 1.4.0: Use [method@GSSDP.ResourceBrowser.get_client] instead. **/ GUPnPContext * gupnp_control_point_get_context (GUPnPControlPoint *control_point) @@ -1229,11 +1237,17 @@ gupnp_control_point_get_context (GUPnPControlPoint *control_point) * gupnp_control_point_list_device_proxies: * @control_point: A #GUPnPControlPoint * - * Get the #GList of discovered #GUPnPDeviceProxy objects. Do not free the list - * nor its elements. + * Get the list of #GUPnPDeviceProxy objects the control point currently assumes to + * be active. + * + * Since a device might have gone offline without signalizing it, but + * the automatic resource timeout has not happened yet, it is possible that some of + * the devices listed are not available anymore on the network. * - * Return value: (element-type GUPnP.DeviceProxy) (transfer none): a #GList of - * #GUPnPDeviceProxy objects. + * Do not free the list nor its elements. + * + * Return value: (element-type GUPnP.DeviceProxy) (transfer none): Device proxies + * currently assumed to be active. **/ const GList * gupnp_control_point_list_device_proxies (GUPnPControlPoint *control_point) @@ -1251,11 +1265,17 @@ gupnp_control_point_list_device_proxies (GUPnPControlPoint *control_point) * gupnp_control_point_list_service_proxies: * @control_point: A #GUPnPControlPoint * - * Get the #GList of discovered #GUPnPServiceProxy objects. Do not free the - * list nor its elements. + * Get the list of discovered #GUPnPServiceProxy objects the control point currently assumes to + * be active. + * + * Since a device might have gone offline without signalizing it, but + * the automatic resource timeout has not happened yet, it is possible that some of + * the services listed are not available anymore on the network. + * + * Do not free the list nor its elements. * - * Return value: (element-type GUPnP.ServiceProxy) (transfer none): a #GList - * of #GUPnPServiceProxy objects. + * Return value: (element-type GUPnP.ServiceProxy) (transfer none): Service proxies + * currently assumed to be active. **/ const GList * gupnp_control_point_list_service_proxies (GUPnPControlPoint *control_point) @@ -1270,12 +1290,14 @@ gupnp_control_point_list_service_proxies (GUPnPControlPoint *control_point) } /** - * gupnp_control_point_get_resource_factory: + * gupnp_control_point_get_resource_factory:(attributes org.gtk.Method.get_property=resource-factory) * @control_point: A #GUPnPControlPoint * - * Get the #GUPnPResourceFactory used by the @control_point. + * Get the #GUPnPResourceFactory used by the @control_point. If none was set during construction + * by calling [ctor@GUPnP.ControlPoint.new_full], equivalent to calling + * [func@GUPnP.ResourceFactory.get_default] * - * Returns: (transfer none): A #GUPnPResourceFactory. + * Returns: (transfer none): The #GUPnPResourceFactory used by this control point **/ GUPnPResourceFactory * gupnp_control_point_get_resource_factory (GUPnPControlPoint *control_point) diff --git a/libgupnp/gupnp-device-info.c b/libgupnp/gupnp-device-info.c index b329748..09e17e3 100644 --- a/libgupnp/gupnp-device-info.c +++ b/libgupnp/gupnp-device-info.c @@ -7,13 +7,7 @@ * */ -/** - * SECTION:gupnp-device-info - * @short_description: Base abstract class for querying device information. - * - * The #GUPnPDeviceInfo base abstract class provides methods for querying - * device information. - */ + #include <config.h> #include <string.h> @@ -39,6 +33,15 @@ struct _GUPnPDeviceInfoPrivate { }; typedef struct _GUPnPDeviceInfoPrivate GUPnPDeviceInfoPrivate; +/** + * GUPnPDeviceInfo: + * + * Device information shared by local and remote devices + * + * This class aggregates the information that is shared between remote and local + * devices. + */ + G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GUPnPDeviceInfo, gupnp_device_info, G_TYPE_OBJECT) @@ -195,98 +198,87 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass) object_class->finalize = gupnp_device_info_finalize; /** - * GUPnPDeviceInfo:resource-factory: + * GUPnPDeviceInfo:resource-factory:(attributes org.gtk.Property.get=gupnp_device_info_get_resource_factory): * * The resource factory to use. Set to NULL for default factory. **/ - g_object_class_install_property - (object_class, - PROP_RESOURCE_FACTORY, - g_param_spec_object ("resource-factory", - "Resource Factory", - "The resource factory to use", - GUPNP_TYPE_RESOURCE_FACTORY, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_RESOURCE_FACTORY, + g_param_spec_object ("resource-factory", + "Resource Factory", + "The resource factory to use", + GUPNP_TYPE_RESOURCE_FACTORY, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); /** - * GUPnPDeviceInfo:context: + * GUPnPDeviceInfo:context:(attributes org.gtk.Property.get=gupnp_device_info_get_context): * * The #GUPnPContext to use. **/ - g_object_class_install_property - (object_class, - PROP_CONTEXT, - g_param_spec_object ("context", - "Context", - "The GUPnPContext", - GUPNP_TYPE_CONTEXT, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_CONTEXT, + g_param_spec_object ("context", + "Context", + "The GUPnPContext", + GUPNP_TYPE_CONTEXT, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); /** - * GUPnPDeviceInfo:location: + * GUPnPDeviceInfo:location:(attributes org.gtk.Property.get=gupnp_device_info_get_location): * * The location of the device description file. **/ - g_object_class_install_property - (object_class, - PROP_LOCATION, - g_param_spec_string ("location", - "Location", - "The location of the device description " - "file", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_LOCATION, + g_param_spec_string ("location", + "Location", + "The location of the device description " + "file", + NULL, + G_PARAM_READWRITE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); /** - * GUPnPDeviceInfo:udn: + * GUPnPDeviceInfo:udn:(attributes org.gtk.Property.get=gupnp_device_info_get_udn): * * The UDN of this device. **/ - g_object_class_install_property - (object_class, - PROP_UDN, - g_param_spec_string ("udn", - "UDN", - "The UDN", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_UDN, + g_param_spec_string ("udn", + "UDN", + "The Unique Device Name", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); /** - * GUPnPDeviceInfo:device-type: + * GUPnPDeviceInfo:device-type:(attributes org.gtk.Property.get=gupnp_device_info_get_device_type): * - * The device type. + * The device type, e.g. `urn:schemas-upnp-org:device:InternetGatewayDevice:1` **/ - g_object_class_install_property - (object_class, - PROP_DEVICE_TYPE, - g_param_spec_string ("device-type", - "Device type", - "The device type", - NULL, - G_PARAM_READWRITE | - G_PARAM_CONSTRUCT_ONLY | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_DEVICE_TYPE, + g_param_spec_string ("device-type", + "Device type", + "The device type", + NULL, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); /** - * GUPnPDeviceInfo:url-base: + * GUPnPDeviceInfo:url-base:(attributes org.gtk.Property.get=gupnp_device_info_get_url_base): * * The URL base (#SoupURI). **/ @@ -298,9 +290,7 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass) "The URL base", G_TYPE_URI, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + G_PARAM_STATIC_STRINGS)); /** * GUPnPDeviceInfo:document: @@ -318,9 +308,7 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass) "device", GUPNP_TYPE_XML_DOC, G_PARAM_READWRITE | G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + G_PARAM_STATIC_STRINGS)); /** * GUPnPDeviceInfo:element: @@ -329,18 +317,15 @@ gupnp_device_info_class_init (GUPnPDeviceInfoClass *klass) * * Stability: Private **/ - g_object_class_install_property - (object_class, - PROP_ELEMENT, - g_param_spec_pointer ("element", - "Element", - "The XML element related to this " - "device", - G_PARAM_WRITABLE | - G_PARAM_CONSTRUCT | - G_PARAM_STATIC_NAME | - G_PARAM_STATIC_NICK | - G_PARAM_STATIC_BLURB)); + g_object_class_install_property ( + object_class, + PROP_ELEMENT, + g_param_spec_pointer ("element", + "Element", + "The XML element related to this " + "device", + G_PARAM_WRITABLE | G_PARAM_CONSTRUCT | + G_PARAM_STATIC_STRINGS)); } /** @@ -399,7 +384,7 @@ gupnp_device_info_create_service_instance (GUPnPDeviceInfo *info, } /** - * gupnp_device_info_get_resource_factory: + * gupnp_device_info_get_resource_factory:(attributes org.gtk.Method.get_property=resource-factory): * @device_info: A #GUPnPDeviceInfo * * Get the #GUPnPResourceFactory used by the @device_info. @@ -419,12 +404,12 @@ gupnp_device_info_get_resource_factory (GUPnPDeviceInfo *info) } /** - * gupnp_device_info_get_context: + * gupnp_device_info_get_context:(attributes org.gtk.Method.get_property=context): * @info: A #GUPnPDeviceInfo * * Get the associated #GUPnPContext. * - * Returns: (transfer none): A #GUPnPContext. + * Returns: (transfer none): The #GUPnPContext the devices is operating on. **/ GUPnPContext * gupnp_device_info_get_context (GUPnPDeviceInfo *info) @@ -442,9 +427,9 @@ gupnp_device_info_get_context (GUPnPDeviceInfo *info) * gupnp_device_info_get_location: * @info: A #GUPnPDeviceInfo * - * Get the location of the device description file. + * Get the URL of the device file * - * Returns: A constant string. + * Returns: A s **/ const char * gupnp_device_info_get_location (GUPnPDeviceInfo *info) @@ -459,7 +444,7 @@ gupnp_device_info_get_location (GUPnPDeviceInfo *info) } /** - * gupnp_device_info_get_url_base: + * gupnp_device_info_get_url_base:(attributes org.gtk.Method.get_property=url-base): * @info: A #GUPnPDeviceInfo * * Get the URL base of this device. @@ -479,7 +464,7 @@ gupnp_device_info_get_url_base (GUPnPDeviceInfo *info) } /** - * gupnp_device_info_get_udn: + * gupnp_device_info_get_udn:(attributes org.gtk.Method.get_property=udn): * @info: A #GUPnPDeviceInfo * * Get the Unique Device Name of the device. @@ -504,10 +489,10 @@ gupnp_device_info_get_udn (GUPnPDeviceInfo *info) } /** - * gupnp_device_info_get_device_type: + * gupnp_device_info_get_device_type:(attributes org.gtk.Method.get_property=device-type): * @info: A #GUPnPDeviceInfo * - * Get the UPnP device type. + * Get the UPnP device type of this #GUPnPDeviceInfo, e.g. `urn:schemas-upnp-org:device:InternetGatewayDevice:1` * * Returns: A constant string, or %NULL. **/ @@ -534,7 +519,8 @@ gupnp_device_info_get_device_type (GUPnPDeviceInfo *info) * * Get the friendly name of the device. * - * Return value: A string, or %NULL. g_free() after use. + * Return value:(nullable)(transfer full):A newly allocated string containing the + * "friendly name" of the device, or %NULL if not available. g_free() after use. **/ char * gupnp_device_info_get_friendly_name (GUPnPDeviceInfo *info) @@ -555,7 +541,8 @@ gupnp_device_info_get_friendly_name (GUPnPDeviceInfo *info) * * Get the manufacturer of the device. * - * Return value:(nullable)(transfer full): A string, or %NULL. g_free() after use. + * Return value:(nullable)(transfer full): A newly allocated string containing the + * manufacturer of the device, or %NULL if not available. g_free() after use. **/ char * gupnp_device_info_get_manufacturer (GUPnPDeviceInfo *info) @@ -724,7 +711,7 @@ gupnp_device_info_get_upc (GUPnPDeviceInfo *info) * @info: A #GUPnPDeviceInfo * * Get an URL pointing to the device's presentation page, for web-based - * administration. + * administration, if available. * * Return value:(nullable)(transfer full): A string, or %NULL. g_free() after use. **/ @@ -776,12 +763,8 @@ icon_parse (xmlNode *element) static void icon_free (Icon *icon) { - if (icon->mime_type) - xmlFree (icon->mime_type); - - if (icon->url) - xmlFree (icon->url); - + g_clear_pointer (&icon->mime_type, xmlFree); + g_clear_pointer (&icon->url, xmlFree); g_slice_free (Icon, icon); } @@ -806,7 +789,9 @@ icon_free (Icon *icon) * returned icon, or %NULL * * Get an URL pointing to the icon most closely matching the - * given criteria, or %NULL. If @requested_mime_type is set, only icons with + * given criteria, or %NULL. + * + * If @requested_mime_type is set, only icons with * this mime type will be returned. If @requested_depth is set, only icons with * this or lower depth will be returned. If @requested_width and/or * @requested_height are set, only icons that are this size or smaller are @@ -1053,11 +1038,12 @@ resource_type_match (const char *query, * gupnp_device_info_list_dlna_device_class_identifier: * @info: A #GUPnPDeviceInfo * - * Get a #GList of strings that represent the device class and version as - * announced in the device description file using the <dlna:X_DLNADOC> - * element. + * Get a list of strings that represent the device class and version as + * announced in the device description file using the `<dlna:X_DLNADOC>` + * element, e.g. `DMS-1.51`, `M-DMS-1.51` and so on. + * * Returns:(nullable)(transfer full) (element-type utf8): a #GList of newly allocated strings or - * %NULL if the device description doesn't contain the <dlna:X_DLNADOC> + * %NULL if the device description doesn't contain any `<dlna:X_DLNADOC>` * element. * * Since: 0.20.4 @@ -1163,8 +1149,8 @@ gupnp_device_info_list_dlna_capabilities (GUPnPDeviceInfo *info) * This function provides generic access to the contents of arbitrary elements * in the device description file. * - * Return value:(nullable)(transfer full): a newly allocated string or %NULL if the device - * description doesn't contain the given @element + * Return value:(nullable)(transfer full): a newly allocated string containing the + * requested value or %NULL if the device description doesn't contain the given @element * * Since: 0.14.0 **/ @@ -1188,8 +1174,7 @@ gupnp_device_info_get_description_value (GUPnPDeviceInfo *info, * @info: A #GUPnPDeviceInfo * * Get a #GList of new objects implementing #GUPnPDeviceInfo - * representing the devices directly contained in @info. The returned list - * should be g_list_free()'d and the elements should be g_object_unref()'d. + * representing the devices directly contained in @info, excluding itself. * * Note that devices are not cached internally, so that every time you * call this function new objects are created. The application @@ -1197,7 +1182,7 @@ gupnp_device_info_get_description_value (GUPnPDeviceInfo *info, * them. * * Return value:(nullable)(element-type GUPnP.DeviceInfo) (transfer full): a #GList of - * new #GUPnPDeviceInfo objects. + * new #GUPnPDeviceInfo objects or %NULL if no devices are **/ GList * gupnp_device_info_list_devices (GUPnPDeviceInfo *info) @@ -1285,7 +1270,7 @@ gupnp_device_info_list_device_types (GUPnPDeviceInfo *info) * @info: A #GUPnPDeviceInfo * @type: The type of the device to be retrieved. * - * Get the service with type @type directly contained in @info as + * Get the device with type @type directly contained in @info as * a new object implementing #GUPnPDeviceInfo, or %NULL if no such device * was found. The returned object should be unreffed when done. * @@ -1406,7 +1391,7 @@ gupnp_device_info_list_services (GUPnPDeviceInfo *info) * @info: A #GUPnPDeviceInfo * * Get a #GList of strings representing the types of the services - * directly contained in @info. + * directly contained in @info, but not in its subdevices. * * Return value: (nullable)(element-type utf8) (transfer full): A #GList of strings. The * elements should be g_free()'d and the list should be g_list_free()'d. @@ -1452,8 +1437,7 @@ gupnp_device_info_list_service_types (GUPnPDeviceInfo *info) * @type: The type of the service to be retrieved. * * Get the service with type @type directly contained in @info as a new object - * implementing #GUPnPServiceInfo, or %NULL if no such device was found. The - * returned object should be unreffed when done. + * implementing #GUPnPServiceInfo, or %NULL if no such device was found. * * Note that services are not cached internally, so that every time you call * this function a new object is created. The application must cache any used diff --git a/libgupnp/gupnp-device-proxy.c b/libgupnp/gupnp-device-proxy.c index cb87904..fde10ec 100644 --- a/libgupnp/gupnp-device-proxy.c +++ b/libgupnp/gupnp-device-proxy.c @@ -7,13 +7,6 @@ * */ -/** - * SECTION:gupnp-device-proxy - * @short_description: Proxy class for remote devices. - * - * #GUPnPDeviceProxy allows for retrieving proxies for a device's subdevices - * and services. #GUPnPDeviceProxy implements the #GUPnPDeviceInfo interface. - */ #include <config.h> #include <string.h> @@ -23,6 +16,14 @@ #include "gupnp-resource-factory-private.h" #include "xml-util.h" +/** + * GUPnPDeviceProxy: + * + * Interaction with remote UPnP devices. + * + * #GUPnPDeviceProxy allows for retrieving proxies for a device's sub-devices + * and services. It implements the [class@GUPnP.DeviceInfo] abstract class. + */ G_DEFINE_TYPE (GUPnPDeviceProxy, gupnp_device_proxy, GUPNP_TYPE_DEVICE_INFO) diff --git a/libgupnp/gupnp-device.c b/libgupnp/gupnp-device.c index 523a248..893a647 100644 --- a/libgupnp/gupnp-device.c +++ b/libgupnp/gupnp-device.c @@ -7,15 +7,6 @@ * */ -/** - * SECTION:gupnp-device - * @short_description: Class for device implementations. - * - * #GUPnPDevice allows for retrieving a device's subdevices - * and services. #GUPnPDevice implements the #GUPnPDeviceInfo - * interface. - */ - #include <config.h> #include <string.h> @@ -30,6 +21,15 @@ struct _GUPnPDevicePrivate { }; typedef struct _GUPnPDevicePrivate GUPnPDevicePrivate; +/** + * GUPnPDevice: + * + * Base class for UPnP device implementations. + * + * #GUPnPDevice allows for retrieving a device's sub-devices + * and services. #GUPnPDevice implements the #GUPnPDeviceInfo + * interface. + */ G_DEFINE_TYPE_WITH_PRIVATE (GUPnPDevice, gupnp_device, GUPNP_TYPE_DEVICE_INFO) diff --git a/libgupnp/gupnp-error.h b/libgupnp/gupnp-error.h index 2baa4ff..ad84064 100644 --- a/libgupnp/gupnp-error.h +++ b/libgupnp/gupnp-error.h @@ -27,8 +27,7 @@ gupnp_server_error_quark (void) G_GNUC_CONST; * @GUPNP_SERVER_ERROR_INVALID_URL: Invalid URL. * @GUPNP_SERVER_ERROR_OTHER: Unknown/unhandled error. * - * #GError codes used for errors in the #GUPNP_SERVER_ERROR domain, when there - * is communication with another server. + * Error codes during communication with another server. */ typedef enum { GUPNP_SERVER_ERROR_INTERNAL_SERVER_ERROR, @@ -50,8 +49,7 @@ gupnp_eventing_error_quark (void) G_GNUC_CONST; * @GUPNP_EVENTING_ERROR_SUBSCRIPTION_LOST: The subscription was lost. * @GUPNP_EVENTING_ERROR_NOTIFY_FAILED: The notification failed. * - * #GError codes used for errors in the #GUPNP_EVENTING_ERROR domain, during - * eventing of state variables. + * Error codes during eventing of state variables. */ typedef enum { GUPNP_EVENTING_ERROR_SUBSCRIPTION_FAILED, @@ -71,8 +69,7 @@ gupnp_control_error_quark (void) G_GNUC_CONST; * @GUPNP_CONTROL_ERROR_OUT_OF_SYNC: Out of sync (deprecated). * @GUPNP_CONTROL_ERROR_ACTION_FAILED: The action failed. * - * #GError codes used for errors in the #GUPNP_CONTROL_ERROR domain, during - * invocation of service actions. + * Error codes used during invocation of service actions. */ typedef enum { GUPNP_CONTROL_ERROR_INVALID_ACTION = 401, @@ -94,8 +91,7 @@ gupnp_xml_error_quark (void) G_GNUC_CONST; * @GUPNP_XML_ERROR_INVALID_ATTRIBUTE: An XML node has an unknown attribute. * @GUPNP_XML_ERROR_OTHER: Unknown/unhandled XML related errors. * - * #GError codes used for errors in the #GUPNP_XML_ERROR domain, during - * processing of XML data. + * Errors during occuring during processing of XML data. */ typedef enum { GUPNP_XML_ERROR_PARSE, @@ -111,13 +107,13 @@ gupnp_rootdevice_error_quark (void) G_GNUC_CONST; #define GUPNP_ROOT_DEVICE_ERROR (gupnp_rootdevice_error_quark ()) /** - * GUPnPRootDeviceError: + * GUPnPRootdeviceError: * @GUPNP_ROOT_DEVICE_ERROR_NO_CONTEXT: No #GUPnPContext was passed to the root device. * @GUPNP_ROOT_DEVICE_ERROR_NO_DESCRIPTION_PATH: Device description path was missing * @GUPNP_ROOT_DEVICE_ERROR_NO_DESCRIPTION_FOLDER: Description folder was missing * @GUPNP_ROOT_DEVICE_ERROR_NO_NETWORK: Network interface is not usable * - * #GError codes used for errors during #GUPnPRootDevice creation + * Errors during [class@GUPnP.RootDevice] creation */ typedef enum { GUPNP_ROOT_DEVICE_ERROR_NO_CONTEXT, @@ -135,7 +131,9 @@ gupnp_service_introspection_error_quark (void) G_GNUC_CONST; /** * GUPnPServiceIntrospectionError: - * @GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER@: Unknown error + * @GUPNP_SERVICE_INTROSPECTION_ERROR_OTHER: Unknown error + * + * Errors during service introspection */ typedef enum { @@ -151,7 +149,9 @@ gupnp_service_error_quark (void) G_GNUC_CONST; /** * GUPnPServiceError: - * @GUPNP_SERVICE_ERROR_AUTOCONNECT@: [method@GUPnP.Service.signals_autoconnect] failed + * @GUPNP_SERVICE_ERROR_AUTOCONNECT: [method@GUPnP.Service.signals_autoconnect] failed + * + * Errors during service handling */ typedef enum { diff --git a/libgupnp/gupnp-linux-context-manager.c b/libgupnp/gupnp-linux-context-manager.c index 04a464a..5d95a58 100644 --- a/libgupnp/gupnp-linux-context-manager.c +++ b/libgupnp/gupnp-linux-context-manager.c @@ -26,7 +26,7 @@ * accordingly. */ -#define G_LOG_DOMAIN "GUPnP-ContextManager-Linux" +#define G_LOG_DOMAIN "gupnp-context-manager" #include <config.h> diff --git a/libgupnp/gupnp-resource-factory.c b/libgupnp/gupnp-resource-factory.c index 9e441dc..b651f91 100644 --- a/libgupnp/gupnp-resource-factory.c +++ b/libgupnp/gupnp-resource-factory.c @@ -10,16 +10,19 @@ */ /** - * SECTION:gupnp-resource-factory - * @short_description: Class for resource and resource proxy object creation. + * GUPnPResourceFactory: * - * #GUPnPResourceFactory objects are used by #GUPnPControlPoint, - * #GUPnPDeviceProxy and #GUPnPDevice to create resource proxy and resource - * objects. Register UPnP type - #GType pairs to have resource or resource proxy + * Associating custom Services, Devices, ServiceProxies and DeviceProxies with UPnP types. + * + * #GUPnPResourceFactory objects are used by [class@GUPnP.ControlPoint], + * [class@GUPnP.DeviceProxy] and [class@GUPnP.Device] to create resource proxy and resource + * objects. + * + * Register UPnP type - [alias@GLib.Type] pairs to have resource or resource proxy * objects created with the specified #GType whenever an object for a resource - * of the specified UPnP type is requested. The #GType<!-- -->s need + * of the specified UPnP type is requested. The #GType needs * to be derived from the relevant resource or resource proxy type (e.g. - * a device proxy type needs to be derived from #GUPnPDeviceProxy). + * a device proxy type needs to be derived from [class@GUPnP.DeviceProxy]). */ #include <config.h> @@ -187,7 +190,6 @@ lookup_type_with_fallback (GHashTable *resource_types, * @location: The location of the device description file * @url_base: The URL base for this device, or %NULL if none * - * * Create a #GUPnPDeviceProxy for the device with element @element, as * read from the device description file specified by @location. * diff --git a/libgupnp/gupnp-root-device.c b/libgupnp/gupnp-root-device.c index 73734a3..8430fa9 100644 --- a/libgupnp/gupnp-root-device.c +++ b/libgupnp/gupnp-root-device.c @@ -7,12 +7,7 @@ * */ -/** - * SECTION:gupnp-root-device - * @short_description: Class for root device implementations. - * - * #GUPnPRootDevice allows for implementing root devices. - */ + #include <config.h> #include <string.h> @@ -44,6 +39,13 @@ struct _GUPnPRootDevicePrivate { }; typedef struct _GUPnPRootDevicePrivate GUPnPRootDevicePrivate; +/** + * GUPnPRootDevice: + * + * Implementation of an UPnP root device. + * + * #GUPnPRootDevice allows for implementing root devices. + */ G_DEFINE_TYPE_EXTENDED (GUPnPRootDevice, gupnp_root_device, GUPNP_TYPE_DEVICE, @@ -346,7 +348,7 @@ gupnp_root_device_initable_init (GInitable *initable, g_set_error_literal (error, GUPNP_XML_ERROR, GUPNP_XML_ERROR_PARSE, - "Coupld not parse description document"); + "Could not parse description document"); goto DONE; } @@ -396,7 +398,7 @@ gupnp_root_device_initable_init (GInitable *initable, priv->relative_location, NULL); - /* Host the description file and dir */ + /* Host the description file and folder */ gupnp_context_host_path (context, desc_path, relative_location); gupnp_context_host_path (context, priv->description_dir, ""); @@ -466,7 +468,7 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) object_class->finalize = gupnp_root_device_finalize; /** - * GUPnPRootDevice:description-path: + * GUPnPRootDevice:description-path:(attributes org.gtk.Property.get=gupnp_root_device_get_description_path) * * The path to device description document. This could either be an * absolute path or path relative to GUPnPRootDevice:description-dir. @@ -478,7 +480,7 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) PROP_DESCRIPTION_PATH, g_param_spec_string ("description-path", "Description Path", - "The path to device descrition document", + "The path to device description document", NULL, G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | @@ -487,9 +489,9 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) G_PARAM_STATIC_BLURB)); /** - * GUPnPRootDevice:description-dir: + * GUPnPRootDevice:description-dir:(attributes org.gtk.Property.get=gupnp_root_device_get_description_dir) * - * The path to directory where description documents are provided. + * The path to a folder where description documents are provided. **/ g_object_class_install_property (object_class, @@ -506,7 +508,7 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) G_PARAM_STATIC_BLURB)); /** - * GUPnPRootDevice:available: + * GUPnPRootDevice:available:(attributes org.gtk.Property.get=gupnp_root_device_get_available org.gtk.Property.set=gupnp_root_device_set_available) * * TRUE if this device is available. **/ @@ -527,8 +529,8 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) * gupnp_root_device_new: * @context: The #GUPnPContext * @description_path: Path to device description document. This could either - * be an absolute path or path relative to @description_dir. - * @description_dir: Path to directory where description documents are provided. + * be an absolute path or path relative to @description_folder. + * @description_folder: Path to directory where description documents are provided. * @error: (inout)(optional)(nullable): The location for a #GError to report issue with * creation on or %NULL. * @@ -540,7 +542,7 @@ gupnp_root_device_class_init (GUPnPRootDeviceClass *klass) GUPnPRootDevice * gupnp_root_device_new (GUPnPContext *context, const char *description_path, - const char *description_dir, + const char *description_folder, GError **error) { GUPnPResourceFactory *factory; @@ -551,7 +553,7 @@ gupnp_root_device_new (GUPnPContext *context, factory, NULL, description_path, - description_dir, + description_folder, error); } @@ -562,7 +564,7 @@ gupnp_root_device_new (GUPnPContext *context, * @description_doc: Device description document, or %NULL * @description_path: Path to device description document. This could either * be an absolute path or path relative to @description_dir. - * @description_dir: Path to directory where description documents are provided. + * @description_folder: Path to folder where description documents are provided. * @error: (inout)(optional)(nullable): The location for a #GError to report issue with * creation on or %NULL. * @@ -577,7 +579,7 @@ gupnp_root_device_new_full (GUPnPContext *context, GUPnPResourceFactory *factory, GUPnPXMLDoc *description_doc, const char *description_path, - const char *description_dir, + const char *description_folder, GError **error) { g_return_val_if_fail (GUPNP_IS_CONTEXT (context), NULL); @@ -597,16 +599,16 @@ gupnp_root_device_new_full (GUPnPContext *context, "description-path", description_path, "description-dir", - description_dir, + description_folder, NULL); } /** - * gupnp_root_device_set_available: + * gupnp_root_device_set_available:(attributes org.gtk.Method.get_property=available) * @root_device: A #GUPnPRootDevice * @available: %TRUE if @root_device should be available * - * Controls whether or not @root_device is available (announcing + * Sets the availability of @root_device on the network (announcing * its presence). **/ void @@ -625,10 +627,10 @@ gupnp_root_device_set_available (GUPnPRootDevice *root_device, } /** - * gupnp_root_device_get_available: + * gupnp_root_device_get_available:(attributes org.gtk.Method.get_property=available) * @root_device: A #GUPnPRootDevice * - * Get whether or not @root_device is available (announcing its presence). + * Checks whether @root_device is available on the network (announcing its presence). * * Return value: %TRUE if @root_device is available, %FALSE otherwise. **/ @@ -645,15 +647,15 @@ gupnp_root_device_get_available (GUPnPRootDevice *root_device) } /** - * gupnp_root_device_get_relative_location: + * gupnp_root_device_get_description_document_name: * @root_device: A #GUPnPRootDevice * - * Get the relative location of @root_device. + * Gets the name of the description document as hosted via HTTP. * * Return value: The relative location of @root_device. **/ const char * -gupnp_root_device_get_relative_location (GUPnPRootDevice *root_device) +gupnp_root_device_get_description_document_name (GUPnPRootDevice *root_device) { GUPnPRootDevicePrivate *priv; @@ -665,10 +667,10 @@ gupnp_root_device_get_relative_location (GUPnPRootDevice *root_device) } /** - * gupnp_root_device_get_description_path: + * gupnp_root_device_get_description_path:(attributes org.gtk.Method.get_property=description-path) * @root_device: A #GUPnPRootDevice * - * Get the path to the device description document of @root_device. + * Gets the path to the device description document of @root_device. * * Return value: The path to device description document of @root_device. **/ @@ -685,10 +687,10 @@ gupnp_root_device_get_description_path (GUPnPRootDevice *root_device) } /** - * gupnp_root_device_get_description_dir: + * gupnp_root_device_get_description_dir:(attributes org.gtk.Method.get_property=description-dir) * @root_device: A #GUPnPRootDevice * - * Get the path to the directory containing description documents related to + * Gets the path to the directory containing description documents related to * @root_device. * * Return value: The path to description document directory of @root_device. @@ -709,7 +711,7 @@ gupnp_root_device_get_description_dir (GUPnPRootDevice *root_device) * gupnp_root_device_get_ssdp_resource_group: * @root_device: A #GUPnPRootDevice * - * Get the #GSSDPResourceGroup used by @root_device. + * Gets the #GSSDPResourceGroup used by @root_device. * * Returns: (transfer none): The #GSSDPResourceGroup of @root_device. * diff --git a/libgupnp/gupnp-root-device.h b/libgupnp/gupnp-root-device.h index ef53683..6e3dcd1 100644 --- a/libgupnp/gupnp-root-device.h +++ b/libgupnp/gupnp-root-device.h @@ -43,7 +43,7 @@ struct _GUPnPRootDeviceClass { GUPnPRootDevice * gupnp_root_device_new (GUPnPContext *context, const char *description_path, - const char *description_dir, + const char *description_folder, GError **error); GUPnPRootDevice * @@ -51,7 +51,7 @@ gupnp_root_device_new_full (GUPnPContext *context, GUPnPResourceFactory *factory, GUPnPXMLDoc *description_doc, const char *description_path, - const char *description_dir, + const char *description_folder, GError **error); void @@ -62,7 +62,7 @@ gboolean gupnp_root_device_get_available (GUPnPRootDevice *root_device); const char * -gupnp_root_device_get_relative_location +gupnp_root_device_get_description_document_name (GUPnPRootDevice *root_device); const char * diff --git a/libgupnp/gupnp-service-action.c b/libgupnp/gupnp-service-action.c index 4bcd032..cd5f52a 100644 --- a/libgupnp/gupnp-service-action.c +++ b/libgupnp/gupnp-service-action.c @@ -476,7 +476,7 @@ gupnp_service_action_set_value (GUPnPServiceAction *action, * gupnp_service_action_return_success: * @action: A #GUPnPServiceAction * - * Return succesfully. + * Return successfully. * * Since: 1.4.2 **/ @@ -485,7 +485,7 @@ gupnp_service_action_return_success (GUPnPServiceAction *action) { g_return_if_fail (action != NULL); - soup_server_message_set_status (action->msg, SOUP_STATUS_OK, "Ok"); + soup_server_message_set_status (action->msg, SOUP_STATUS_OK, NULL); finalize_action (action); } diff --git a/libgupnp/gupnp-service-info.c b/libgupnp/gupnp-service-info.c index 97ad4cc..39a0324 100644 --- a/libgupnp/gupnp-service-info.c +++ b/libgupnp/gupnp-service-info.c @@ -8,15 +8,8 @@ * */ -/** - * SECTION:gupnp-service-info - * @short_description: Base abstract class for querying service information. - * - * The #GUPnPDeviceInfo base abstract class provides methods for querying - * service information. - */ -#define G_LOG_DOMAIN "GUPnPServiceInfo" +#define G_LOG_DOMAIN "gupnp-service-info" #include <config.h> #include <libsoup/soup.h> @@ -50,6 +43,14 @@ struct _GUPnPServiceInfoPrivate { typedef struct _GUPnPServiceInfoPrivate GUPnPServiceInfoPrivate; + +/** + * GUPnPServiceInfo: + * + * Service information shared by local and remote services. + * + * A class that contains the common parts between local and remote services. + */ G_DEFINE_ABSTRACT_TYPE_WITH_PRIVATE (GUPnPServiceInfo, gupnp_service_info, G_TYPE_OBJECT) @@ -205,8 +206,7 @@ gupnp_service_info_dispose (GObject *object) } /* Unref context */ - g_object_unref (priv->context); - priv->context = NULL; + g_clear_object (&priv->context); } g_clear_object (&priv->doc); @@ -707,7 +707,7 @@ gupnp_service_info_get_introspection_async * gupnp_service_info_get_introspection_async_full: * @info: A #GUPnPServiceInfo * @callback: (scope async) : callback to be called when introspection object is ready. - * @cancellable: GCancellable that can be used to cancel the call, or %NULL. + * @cancellable: (nullable): GCancellable that can be used to cancel the call. * @user_data: user_data to be passed to the callback. * * Note that introspection object is created from the information in service @@ -777,8 +777,6 @@ gupnp_service_info_get_introspection_async_full g_main_context_get_thread_default ()); return; - - return; } @@ -827,8 +825,8 @@ prv_introspection_cb (GUPnPServiceInfo *info, /** * gupnp_service_info_introspect_async: * @info: A #GUPnPServiceInfo - * @cancellable: (nullable) : #GCancellable that can be used to cancel the call, or %NULL. - * @callback: (scope async) : callback to be called when introspeciton object is ready. + * @cancellable: (nullable) : a #GCancellable that can be used to cancel the call. + * @callback: (scope async) : callback to be called when introspection object is ready. * @user_data: user_data to be passed to the callback. * * Note that introspection object is created from the information in service @@ -861,7 +859,7 @@ gupnp_service_info_introspect_async (GUPnPServiceInfo *info, * gupnp_service_info_introspect_finish: * @info: A GUPnPServiceInfo * @res: A #GAsyncResult - * @error: (inout)(optional)(nullable): Return location for a #GError, or %NULL + * @error: (inout)(optional): Return location for a #GError, or %NULL * * Finish an asynchronous call initiated with * gupnp_service_info_introspect_async(). diff --git a/libgupnp/gupnp-service-info.h b/libgupnp/gupnp-service-info.h index 2c561c0..0f346d1 100644 --- a/libgupnp/gupnp-service-info.h +++ b/libgupnp/gupnp-service-info.h @@ -16,8 +16,7 @@ G_BEGIN_DECLS -#define GUPNP_TYPE_SERVICE_INFO \ - (gupnp_service_info_get_type ()) +#define GUPNP_TYPE_SERVICE_INFO (gupnp_service_info_get_type ()) G_DECLARE_DERIVABLE_TYPE (GUPnPServiceInfo, gupnp_service_info, @@ -38,8 +37,8 @@ struct _GUPnPServiceInfoClass { /** * GUPnPServiceIntrospectionCallback: * @info: The #GUPnPServiceInfo introspection was requested for - * @introspection: (nullable): The new #GUPnPServiceIntrospection object, or NULL - * @error: (nullable): The #GError that occurred, or NULL + * @introspection: (nullable): The new #GUPnPServiceIntrospection object + * @error: (nullable): The #GError that occurred * @user_data: User data * * Callback notifying that @introspection for @info has been obtained. diff --git a/libgupnp/gupnp-service-introspection.c b/libgupnp/gupnp-service-introspection.c index 68f09d7..a56d280 100644 --- a/libgupnp/gupnp-service-introspection.c +++ b/libgupnp/gupnp-service-introspection.c @@ -9,27 +9,6 @@ * */ -/** - * SECTION:gupnp-service-introspection - * @short_description: Service introspection class. - * - * The #GUPnPServiceIntrospection class provides methods for service - * introspection based on information contained in its service description - * document (SCPD). There is no constructor provided for this class, please use - * #gupnp_service_info_get_introspection or - * #gupnp_service_info_get_introspection_async to create an - * #GUPnPServiceIntrospection object for a specific service. - * - * Note that all the introspection information is retreived from the service - * description document (SCPD) provided by the service and hence can not be - * guaranteed to be complete. A UPnP service is required to provide a SCPD but - * unfortunately, many services either do not provide this document or the - * document does not provide any or all of the introspection information. - * - * This class exposes internals of the UPnP protocol and should not need - * to be used for regular device or control point development. - * - **/ #include <config.h> #include <libsoup/soup.h> @@ -67,6 +46,28 @@ static GInitableIface *initable_parent_iface = NULL; static void gupnp_service_introspection_initable_iface_init (gpointer g_iface, gpointer iface_data); + +/** + * GUPnPServiceIntrospection: + * + * Introspection of local and remote services.. + * + * The #GUPnPServiceIntrospection class provides methods for service + * introspection based on information contained in its service description + * document (SCPD). There is no constructor provided for this class, please use + * [method@GUPnP.ServiceInfo.introspect_async] to create a + * #GUPnPServiceIntrospection object for a specific service. + * + * Note that all the introspection information is retrieved from the service + * description document (SCPD) provided by the service and hence can not be + * guaranteed to be complete. An UPnP service is required to provide a SCPD but + * unfortunately, many services either do not provide this document or the + * document does not provide any or all of the introspection information. + * + * This class exposes internals of the UPnP protocol and should not need + * to be used for regular device or control point development. + * + **/ G_DEFINE_TYPE_EXTENDED ( GUPnPServiceIntrospection, gupnp_service_introspection, diff --git a/libgupnp/gupnp-service-introspection.h b/libgupnp/gupnp-service-introspection.h index fecfc8e..9036976 100644 --- a/libgupnp/gupnp-service-introspection.h +++ b/libgupnp/gupnp-service-introspection.h @@ -63,7 +63,7 @@ gupnp_service_action_arg_info_get_type (void); /** * GUPnPServiceActionInfo: * @name: The name of the action argument. - * @arguments: (type GList) (element-type GUPnP.ServiceActionArgInfo):A GList of all the arguments + * @arguments:(element-type GUPnP.ServiceActionArgInfo):A GList of all the arguments * (of type #GUPnPServiceActionArgInfo) of this action. * * This structure contains information about a service action. diff --git a/libgupnp/gupnp-service-proxy-action.c b/libgupnp/gupnp-service-proxy-action.c index 15ba28c..aeb90cd 100644 --- a/libgupnp/gupnp-service-proxy-action.c +++ b/libgupnp/gupnp-service-proxy-action.c @@ -213,6 +213,16 @@ gupnp_service_proxy_action_new_internal (const char *action) { return ret; } + +/** + * gupnp_service_proxy_action_ref: + * @action: an action + * + * Increases reference count of `action` + * + * Returns: (nullable): @action with an increased reference count + * Since: 1.2.0 + */ GUPnPServiceProxyAction * gupnp_service_proxy_action_ref (GUPnPServiceProxyAction *action) { @@ -246,6 +256,15 @@ action_dispose (GUPnPServiceProxyAction *action) g_free (action->name); } +/** + * gupnp_service_proxy_action_unref: + * @action: an action + * + * Decreases reference count of `action`. If reference count drops to 0, + * the action and its contents will be freed. + * + * Since: 1.2.0 + */ void gupnp_service_proxy_action_unref (GUPnPServiceProxyAction *action) { @@ -499,11 +518,11 @@ gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action, * @error:(inout)(optional)(nullable): The location where to store any error, or %NULL * * A variant of gupnp_service_proxy_action_get_result() that takes lists of - * out-parameter names, types and place-holders for values. The returned list - * in @out_values must be freed using #g_list_free and each element in it using - * #g_value_unset and #g_free. - * <informalexample> - * <programlisting> + * out-parameter names, types and place-holders for values. + * + * The returned list in @out_values must be freed using `g_list_free` and each element + * in it using `g_value_unset` and `g_free`. + * ```c * void on_action_finished(GObject *object, GAsyncResult *res, gpointer user_data) * { * GUPnPServiceProxyAction *action; @@ -547,8 +566,7 @@ gupnp_service_proxy_action_serialize (GUPnPServiceProxyAction *action, * } * g_list_free (out_values); * } - * </programlisting> - * </informalexample> + *``` * * Return value : %TRUE on success. * diff --git a/libgupnp/gupnp-service-proxy.c b/libgupnp/gupnp-service-proxy.c index 3c65414..4fce193 100644 --- a/libgupnp/gupnp-service-proxy.c +++ b/libgupnp/gupnp-service-proxy.c @@ -7,15 +7,6 @@ * */ -/** - * SECTION:gupnp-service-proxy - * @short_description: Proxy class for remote services. - * - * #GUPnPServiceProxy sends commands to a remote UPnP service and handles - * incoming event notifications. #GUPnPServiceProxy implements the - * #GUPnPServiceInfo interface. - */ - #include <config.h> #include <libsoup/soup.h> #include <gobject/gvaluecollector.h> @@ -53,6 +44,14 @@ struct _GUPnPServiceProxyPrivate { }; typedef struct _GUPnPServiceProxyPrivate GUPnPServiceProxyPrivate; +/** + * GUPnPServiceProxy: + * + * Proxy class for remote services. + * + * #GUPnPServiceProxy sends commands to a remote UPnP service and handles + * incoming event notifications. + */ G_DEFINE_TYPE_WITH_PRIVATE (GUPnPServiceProxy, gupnp_service_proxy, GUPNP_TYPE_SERVICE_INFO) @@ -375,10 +374,12 @@ gupnp_service_proxy_class_init (GUPnPServiceProxyClass *klass) * out parameter type, and out parameter value location, terminated with %NULL * * Sends action @action with parameters @Varargs to the service exposed by - * @proxy synchronously. If an error occurred, @error will be set. In case of - * an UPnPError the error code will be the same in @error. + * @proxy synchronously. * - * Return value: %TRUE if sending the action was succesful. + * If an error occurred, @error will be set. In case of + * an UPnP error the error code will be the same in @error. + * + * Return value: %TRUE if sending the action was successful. * * Deprecated: 1.2.0: Use gupnp_service_proxy_action_new() and * gupnp_service_proxy_call_action() @@ -415,7 +416,7 @@ gupnp_service_proxy_send_action (GUPnPServiceProxy *proxy, * * See gupnp_service_proxy_send_action(). * - * Return value: %TRUE if sending the action was succesful. + * Return value: %TRUE if sending the action was successful. * * Deprecated: 1.2.0 **/ @@ -486,10 +487,10 @@ out: * (as #GValue) that line up with @out_names and @out_types. * @error: (inout)(optional)(nullable): The location where to store any error, or %NULL * - * The synchronous variant of #gupnp_service_proxy_begin_action_list and - * #gupnp_service_proxy_end_action_list. + * The synchronous variant of [class@GUPnP.ServiceProxy.begin_action_list] and + * [class@GUPnP.ServiceProxy.end_action_list]. * - * Return value: %TRUE if sending the action was succesful. + * Return value: %TRUE if sending the action was successful. * * Deprecated: 1.2.0: Use gupnp_service_proxy_action_new_from_list() and gupnp_service_proxy_call_action() * @@ -994,7 +995,9 @@ gupnp_service_proxy_end_action_valist (GUPnPServiceProxy *proxy, * (as #GValue) that line up with @out_names and @out_types. * * A variant of #gupnp_service_proxy_end_action that takes lists of - * out-parameter names, types and place-holders for values. The returned list + * out-parameter names, types and place-holders for values. + * + * The returned list * in @out_values must be freed using #g_list_free and each element in it using * #g_value_unset and #g_slice_free. * @@ -1212,8 +1215,9 @@ gupnp_service_proxy_add_notify_full (GUPnPServiceProxy *proxy, * @user_data: User data for @callback * @notify: (allow-none): A #GDestroyNotify for @user_data * - * Get a notification for anything that happens on the peer. @value in - * @callback will be of type #G_TYPE_POINTER and contain the pre-parsed + * Get a notification for anything that happens on the peer. + * + * @value in @callback will be of type #G_TYPE_POINTER and contain the pre-parsed * #xmlDoc. Do NOT free or modify this document. * * Return value: %TRUE on success. diff --git a/libgupnp/gupnp-service-proxy.h b/libgupnp/gupnp-service-proxy.h index 107416a..7c4b8e9 100644 --- a/libgupnp/gupnp-service-proxy.h +++ b/libgupnp/gupnp-service-proxy.h @@ -30,14 +30,21 @@ struct _GUPnPServiceProxyClass { GUPnPServiceInfoClass parent_class; /* signals */ + /** + * subscription_lost: + * + * Test + */ void (* subscription_lost) (GUPnPServiceProxy *proxy, const GError *reason); +#ifndef GOBJECT_INTROSPECTION_SKIP /* future padding */ void (* _gupnp_reserved1) (void); void (* _gupnp_reserved2) (void); void (* _gupnp_reserved3) (void); void (* _gupnp_reserved4) (void); +#endif }; /** @@ -55,6 +62,7 @@ typedef struct _GUPnPServiceProxyAction GUPnPServiceProxyAction; * * Callback notifying that @action on @proxy has returned and * gupnp_service_proxy_end_action() etc can be called. + * Deprecated: 1.2.0 **/ typedef void (* GUPnPServiceProxyActionCallback) ( GUPnPServiceProxy *proxy, diff --git a/libgupnp/gupnp-service.c b/libgupnp/gupnp-service.c index a20f2e1..d75a655 100644 --- a/libgupnp/gupnp-service.c +++ b/libgupnp/gupnp-service.c @@ -7,13 +7,6 @@ * */ -/** - * SECTION:gupnp-service - * @short_description: Class for service implementations. - * - * #GUPnPService allows for handling incoming actions and state variable - * notification. #GUPnPService implements the #GUPnPServiceInfo interface. - */ #include <config.h> @@ -59,6 +52,21 @@ struct _GUPnPServicePrivate { }; typedef struct _GUPnPServicePrivate GUPnPServicePrivate; + +/** + * GUPnPService: + * + * Implementation of an UPnP service + * + * #GUPnPService allows for handling incoming actions and state variable + * notification. It implements the [class@GUPnP.ServiceInfo] interface. + * + * To implement a service, you can either connect to the [signal@GUPnP.Service::action-invoked] + * and [signal@GUPnP.Service::query-variable] or derive from the `GUPnPService` class and override + * the virtual functions [vfunc@GUPnP.Service.action_invoked] and [vfunc@GUPnP.Service.query_variable]. + * + * For more details, see the ["Implementing UPnP devices"](server-tutorial.html#implementing-a-service) document + */ G_DEFINE_TYPE_WITH_PRIVATE (GUPnPService, gupnp_service, GUPNP_TYPE_SERVICE_INFO) @@ -1236,12 +1244,12 @@ gupnp_service_class_init (GUPnPServiceClass *klass) /** * GUPnPService::action-invoked: - * @service: The #GUPnPService that received the signal - * @action: The invoked #GUPnPServiceAction + * @service: the #GUPnPService that received the signal + * @action: the invoked #GUPnPServiceAction * * Emitted whenever an action is invoked. Handler should process - * @action and must call either gupnp_service_action_return() or - * gupnp_service_action_return_error(). + * @action and must call either [method@GUPnP.ServiceAction.return_success] or + * [method@GUPnP.ServiceAction.return_error]. **/ signals[ACTION_INVOKED] = g_signal_new ("action-invoked", @@ -1258,9 +1266,9 @@ gupnp_service_class_init (GUPnPServiceClass *klass) /** * GUPnPService::query-variable: - * @service: The #GUPnPService that received the signal - * @variable: The variable that is being queried - * @value: (type GValue)(inout):The location of the #GValue of the variable + * @service: the #GUPnPService that received the signal + * @variable: the variable that is being queried + * @value: (type GValue)(inout):the location of the #GValue of the variable * * Emitted whenever @service needs to know the value of @variable. * Handler should fill @value with the value of @variable. @@ -1282,9 +1290,9 @@ gupnp_service_class_init (GUPnPServiceClass *klass) /** * GUPnPService::notify-failed: - * @service: The #GUPnPService that received the signal - * @callback_url: (type GList)(element-type GUri):A #GList of callback URLs - * @reason: (type GError): A pointer to a #GError describing why the notify failed + * @service: the #GUPnPService that received the signal + * @callback_url: (type GList)(element-type GUri):a #GList of callback URLs + * @reason: (type GError): a pointer to a #GError describing why the notify failed * * Emitted whenever notification of a client fails. **/ @@ -1306,11 +1314,18 @@ gupnp_service_class_init (GUPnPServiceClass *klass) /** * gupnp_service_notify: * @service: A #GUPnPService - * @...: Tuples of variable name, variable type, and variable value, + * @...: a list of tuples, consisting of the variable name, variable type and variable value, * terminated with %NULL. * - * Notifies listening clients that the properties listed in @Varargs - * have changed to the specified values. + * Notifies remote clients that the properties have changed to the specified values. + * + * ```c + * gupnp_service_notify (service, + * "Volume", G_TYPE_FLOAT, 0.5, + * "PlaybackSpeed", G_TYPE_INT, -1, + * NULL); + * + * ``` **/ void gupnp_service_notify (GUPnPService *service, @@ -1548,11 +1563,11 @@ flush_notifications (GUPnPService *service) /** * gupnp_service_notify_value: - * @service: A #GUPnPService - * @variable: The name of the variable to notify - * @value: The value of the variable + * @service: a #GUPnPService + * @variable: the name of the variable to notify + * @value: the value of the variable * - * Notifies listening clients that @variable has changed to @value. + * Notifies remote clients that @variable has changed to @value. **/ void gupnp_service_notify_value (GUPnPService *service, @@ -1585,10 +1600,11 @@ gupnp_service_notify_value (GUPnPService *service, /** * gupnp_service_freeze_notify: - * @service: A #GUPnPService + * @service: a #GUPnPService * - * Causes new notifications to be queued up until gupnp_service_thaw_notify() - * is called. + * Stops sending out notifications to remote clients. + * + * It causes new notifications to be queued up until [method@GUPnP.Service.thaw_notify] is called. **/ void gupnp_service_freeze_notify (GUPnPService *service) @@ -1604,7 +1620,7 @@ gupnp_service_freeze_notify (GUPnPService *service) /** * gupnp_service_thaw_notify: - * @service: A #GUPnPService + * @service: a #GUPnPService * * Sends out any pending notifications, and stops queuing of new ones. **/ @@ -1637,7 +1653,7 @@ strip_camel_case (char *camel_str) for (i = 0, j = 0; i <= strlen (camel_str); i++) { /* Convert every upper case letter to lower case and unless - * it's the first character, the last charachter, in the + * it's the first character, the last character, in the * middle of an abbreviation or there is already an underscore * before it, add an underscore before it */ if (g_ascii_isupper (camel_str[i])) { @@ -1745,35 +1761,39 @@ connect_names_to_signal_handlers (GUPnPService *service, } /** - * gupnp_service_signals_autoconnect: - * @service: A #GUPnPService + * gupnp_service_signals_autoconnect:(skip): + * @service: a #GUPnPService * @user_data: the data to pass to each of the callbacks - * @error: (inout)(optional)(nullable): return location for a #GError, or %NULL + * @error: (inout)(optional)(nullable): the return location for a #GError + * + * Connects call-back functions to the corresponding signals for variables and actions. + * + * It attempts to connect all possible [signal@GUPnP.Service::action-invoked] and + * [signal@GUPnP.Service::query-variable] signals to appropriate callbacks for + * the service. * - * A convenience function that attempts to connect all possible - * #GUPnPService::action-invoked and #GUPnPService::query-variable signals to - * appropriate callbacks for the service @service. It uses service introspection - * and #GModule<!-- -->'s introspective features. It is very simillar to - * gtk_builder_connect_signals() except that it attempts to guess the names of - * the signal handlers on its own. + * It is very similar to [method@Gtk.Builder.connect_signals] except that it attempts + * to guess the names of the signal handlers on its own. * * For this function to do its magic, the application must name the callback - * functions for #GUPnPService::action-invoked signals by striping the CamelCase - * off the action names and either prepend "on_" or append "_cb" to them. Same - * goes for #GUPnPService::query-variable signals, except that "query_" should - * be prepended to the variable name. For example, callback function for - * <varname>GetSystemUpdateID</varname> action should be either named as - * "get_system_update_id_cb" or "on_get_system_update_id" and callback function - * for the query of "SystemUpdateID" state variable should be named - * <function>query_system_update_id_cb</function> or - * <function>on_query_system_update_id</function>. + * functions for [signal@GUPnP.Service::action-invoked] signals by striping the CamelCase + * off the action names and either prefix them with `on_` or append `_cb` to them. * - * <note>This function will not work correctly if #GModule is not supported - * on the platform or introspection is not available for @service.</note> + * Similar, for [signal@GUPnP.Service::query-variable] signals, except that the functions + * shoul be prefixed with `query_` to the variable name. * - * <warning>This function can not and therefore does not guarantee that the + * For example, the callback function for the `GetSystemUpdateID` action should be + * either named as + * `get_system_update_id_cb` or `on_get_system_update_id` and the callback function + * for the query of the `SystemUpdateID` state variable should be named + * `query_system_update_id_cb` or `on_query_system_update_id`. + * + * Note: This function will not work correctly if #GModule is not supported + * on the platform or introspection is not available for @service. + * + * Warning: This function can not and therefore does not guarantee that the * resulting signal connections will be correct as it depends heavily on a - * particular naming schemes described above.</warning> + * particular naming schemes described above. **/ void gupnp_service_signals_autoconnect (GUPnPService *service, @@ -1832,3 +1852,63 @@ gupnp_service_signals_autoconnect (GUPnPService *service, g_module_close (module); } + +/** + * gupnp_service_action_invoked: + * @service: a `GUPnPService` + * @action: a `GUPnPServiceAction` + * + * Default handler for [signal@GUPnP.Service::action_invoked]. See its documentation for details. + * + * Can be overridden by child classes instead of connecting to the signal. + */ +void +gupnp_service_action_invoked (GUPnPService *service, GUPnPServiceAction *action) +{ + g_return_if_fail (GUPNP_IS_SERVICE (service)); + + if (GUPNP_SERVICE_GET_CLASS (service)->action_invoked != NULL) + GUPNP_SERVICE_GET_CLASS (service)->action_invoked (service, action); +} + +/** + * gupnp_service_query_variable: + * @service: a `GUPnPService` + * @variable: the name of the variable that was queried + * @value: a value that should be filled to the current value of @variable + * + * Default handler for [signal@GUPnP.Service::query_variable]. See its documentation for details. + * + * Can be overridden by child classes instead of connecting to the signal. + */ +void +gupnp_service_query_variable (GUPnPService *service, + const char *variable, + GValue *value) +{ + g_return_if_fail (GUPNP_IS_SERVICE (service)); + + if (GUPNP_SERVICE_GET_CLASS (service)->query_variable != NULL) + GUPNP_SERVICE_GET_CLASS (service)->query_variable (service, variable, value); +} + +/** + * gupnp_service_notify_failed: + * @service: a `GUPnPService` + * @callback_urls:(element-type GUri): a list of call-back urls that failed the notification + * @reason: An error that describes why the notification failed + * + * Default handler for [signal@GUPnP.Service::notify_failed]. See its documentation for details. + * + * Can be overridden by child classes instead of connecting to the signal. + */ +void +gupnp_service_notify_failed (GUPnPService *service, + const GList *callback_urls, + const GError *reason) +{ + g_return_if_fail (GUPNP_IS_SERVICE (service)); + + if (GUPNP_SERVICE_GET_CLASS (service)->notify_failed != NULL) + GUPNP_SERVICE_GET_CLASS (service)->notify_failed (service, callback_urls, reason); +} diff --git a/libgupnp/gupnp-service.h b/libgupnp/gupnp-service.h index e0db942..fc9d3a8 100644 --- a/libgupnp/gupnp-service.h +++ b/libgupnp/gupnp-service.h @@ -133,6 +133,20 @@ gupnp_service_signals_autoconnect (GUPnPService *service, gpointer user_data, GError **error); +void +gupnp_service_action_invoked (GUPnPService *service, + GUPnPServiceAction *action); + +void +gupnp_service_query_variable (GUPnPService *service, + const char *variable, + GValue *value); + +void +gupnp_service_notify_failed (GUPnPService *service, + const GList *callback_urls, + const GError *reason); + G_END_DECLS #endif /* GUPNP_SERVICE_H */ diff --git a/libgupnp/gupnp-types.h b/libgupnp/gupnp-types.h index 78f2fab..ea36c30 100644 --- a/libgupnp/gupnp-types.h +++ b/libgupnp/gupnp-types.h @@ -105,9 +105,21 @@ gupnp_uri_get_type (void) G_GNUC_CONST; /* string */ GType gupnp_uuid_get_type (void) G_GNUC_CONST; /* string */ +/** + * gupnp_value_get_xml_node: + * @value: a [GLib.Value] + * + * Helper macro to get the xmlNode* from a `GValue` + */ #define gupnp_value_get_xml_node( value ) \ (xmlNode *) g_value_get_boxed ((value)) +/** + * gupnp_value_get_string: + * @value: a [GLib.Value] + * + * Helper macro to get a char* from a `GValue` + */ #define gupnp_value_get_string( value ) \ (const char *) g_value_get_boxed ((value)) diff --git a/meson.build b/meson.build index 8dcda0c..5f7eebd 100644 --- a/meson.build +++ b/meson.build @@ -44,6 +44,12 @@ dependencies = [ subdir('libgupnp') subdir('tests') subdir('tools') + +gidocgen_dep = dependency('gi-docgen', version: '>= 2021.1', + fallback: ['gi-docgen', 'dummy_dep'], + required: get_option('gtk_doc') and get_option('introspection') + ) + subdir('doc') if get_option('vapi') and get_option('introspection') diff --git a/subprojects/gi-docgen.wrap b/subprojects/gi-docgen.wrap new file mode 100644 index 0000000..fb001c2 --- /dev/null +++ b/subprojects/gi-docgen.wrap @@ -0,0 +1,7 @@ +[wrap-git] +directory=gi-docgen +url=https://gitlab.gnome.org/GNOME/gi-docgen.git +push-url=ssh://git@gitlab.gnome.org:GNOME/gi-docgen.git +revision=main +depth=1 + |