mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-01-23 20:46:14 +01:00
Merge branch 'migrate-to-gi-docgen' into 'main'
Switch to using gi-docgen for docs (batch 1) See merge request GNOME/glib!3591
This commit is contained in:
commit
c140f83922
@ -11,10 +11,10 @@ cache:
|
||||
- _ccache/
|
||||
|
||||
variables:
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v20"
|
||||
FEDORA_IMAGE: "registry.gitlab.gnome.org/gnome/glib/fedora:v21"
|
||||
COVERITY_IMAGE: "registry.gitlab.gnome.org/gnome/glib/coverity:v7"
|
||||
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v14"
|
||||
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v10"
|
||||
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v15"
|
||||
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v11"
|
||||
MESON_TEST_TIMEOUT_MULTIPLIER: 4
|
||||
G_MESSAGES_DEBUG: all
|
||||
MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings"
|
||||
@ -61,6 +61,7 @@ variables:
|
||||
extends: .only-default
|
||||
before_script:
|
||||
- rm -rf subprojects/gvdb
|
||||
- git config --global --add safe.directory $(pwd)
|
||||
- git submodule update --init --depth 1
|
||||
variables:
|
||||
GIT_SUBMODULE_STRATEGY: "none"
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM debian:bullseye
|
||||
FROM debian:bookworm
|
||||
|
||||
RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
||||
bindfs \
|
||||
@ -16,6 +16,7 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
||||
gdb \
|
||||
g++ \
|
||||
gettext \
|
||||
gi-docgen \
|
||||
git \
|
||||
libc6-dev \
|
||||
gtk-doc-tools \
|
||||
@ -37,6 +38,7 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
||||
python3-pip \
|
||||
python3-setuptools \
|
||||
python3-wheel \
|
||||
reuse \
|
||||
shared-mime-info \
|
||||
shellcheck \
|
||||
systemtap-sdt-dev \
|
||||
@ -66,10 +68,7 @@ RUN locale-gen de_DE.UTF-8 \
|
||||
|
||||
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
||||
|
||||
RUN pip3 install meson==0.60.3
|
||||
|
||||
# FIXME: Once we use Debian Bookworm, we can just install the `reuse` package
|
||||
RUN pip3 install reuse==1.0.0
|
||||
RUN pip3 install --break-system-packages meson==0.60.3
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
|
@ -1,4 +1,4 @@
|
||||
FROM fedora:34
|
||||
FROM fedora:37
|
||||
|
||||
RUN dnf -y update \
|
||||
&& dnf -y install \
|
||||
@ -15,6 +15,7 @@ RUN dnf -y update \
|
||||
gcc-c++ \
|
||||
gdb \
|
||||
gettext \
|
||||
gi-docgen \
|
||||
git \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
|
@ -1,72 +1,17 @@
|
||||
FROM fedora:34
|
||||
FROM registry.gitlab.gnome.org/gnome/glib/fedora:v21
|
||||
|
||||
USER root
|
||||
|
||||
RUN dnf -y install \
|
||||
bindfs \
|
||||
clang \
|
||||
clang-analyzer \
|
||||
desktop-file-utils \
|
||||
elfutils-libelf-devel \
|
||||
findutils \
|
||||
fuse \
|
||||
gcc \
|
||||
gcc-c++ \
|
||||
gettext \
|
||||
git \
|
||||
glibc-devel \
|
||||
glibc-headers \
|
||||
glibc-langpack-de \
|
||||
glibc-langpack-el \
|
||||
glibc-langpack-el \
|
||||
glibc-langpack-en \
|
||||
glibc-langpack-es \
|
||||
glibc-langpack-es \
|
||||
glibc-langpack-fa \
|
||||
glibc-langpack-fr \
|
||||
glibc-langpack-hr \
|
||||
glibc-langpack-ja \
|
||||
glibc-langpack-lt \
|
||||
glibc-langpack-pl \
|
||||
glibc-langpack-ru \
|
||||
glibc-langpack-tr \
|
||||
gtk-doc \
|
||||
itstool \
|
||||
lcov \
|
||||
libattr-devel \
|
||||
libffi-devel \
|
||||
libmount-devel \
|
||||
libselinux-devel \
|
||||
libxslt \
|
||||
mingw64-gcc \
|
||||
mingw64-gcc-c++ \
|
||||
mingw64-gettext \
|
||||
mingw64-libffi \
|
||||
mingw64-zlib \
|
||||
ncurses-compat-libs \
|
||||
ninja-build \
|
||||
pcre2-devel \
|
||||
python3 \
|
||||
python3-pip \
|
||||
python3-wheel \
|
||||
systemtap-sdt-devel \
|
||||
unzip \
|
||||
wget \
|
||||
xz \
|
||||
zlib-devel \
|
||||
&& dnf clean all
|
||||
|
||||
WORKDIR /opt
|
||||
COPY cross_file_mingw64.txt /opt
|
||||
|
||||
RUN pip3 install meson==0.60.3
|
||||
|
||||
ARG HOST_USER_ID=5555
|
||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||
RUN useradd -u $HOST_USER_ID -ms /bin/bash user
|
||||
|
||||
USER user
|
||||
WORKDIR /home/user
|
||||
|
||||
COPY cache-subprojects.sh .
|
||||
RUN ./cache-subprojects.sh
|
||||
|
||||
ENV LANG C.UTF-8
|
||||
WORKDIR /home/user
|
136814
docs/reference/gio/Gio-2.0.gir
Normal file
136814
docs/reference/gio/Gio-2.0.gir
Normal file
File diff suppressed because it is too large
Load Diff
@ -15,8 +15,6 @@
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<xi:include href="xml/overview.xml"/>
|
||||
|
||||
<part>
|
||||
<title>API Reference</title>
|
||||
<chapter id="file_ops">
|
||||
@ -270,9 +268,6 @@
|
||||
<part id="migrating">
|
||||
<title>Migrating to GIO</title>
|
||||
<xi:include href="xml/migrating-posix.xml"/>
|
||||
<xi:include href="xml/migrating-gnome-vfs.xml"/>
|
||||
<xi:include href="xml/migrating-gconf.xml"/>
|
||||
<xi:include href="xml/migrating-gdbus.xml"/>
|
||||
</part>
|
||||
|
||||
<chapter id="gio-hierarchy">
|
||||
|
53
docs/reference/gio/gio.toml.in
Normal file
53
docs/reference/gio/gio.toml.in
Normal file
@ -0,0 +1,53 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# Copyright 2023 Matthias Clasen
|
||||
# Copyright 2023 Philip Withnall
|
||||
|
||||
[library]
|
||||
name = "Gio"
|
||||
version = "@VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/glib/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/glib.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_urls = "https://docs.gtk.org/gio/"
|
||||
authors = "GLib Development Team"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "Gio is a library providing useful classes for general purpose I/O, networking, IPC, settings, and other high level application functionality"
|
||||
dependencies = [ "GLib-2.0", "GModule-2.0", "GObject-2.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "The base utility library"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
|
||||
[dependencies."GModule-2.0"]
|
||||
name = "GModule"
|
||||
description = "Portable API for dynamically loading modules"
|
||||
docs_url = "https://docs.gtk.org/gmodule/"
|
||||
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[extra]
|
||||
urlmap_file = "urlmap.js"
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"overview.md",
|
||||
|
||||
"migrating-gdbus.md",
|
||||
"migrating-gconf.md",
|
||||
"migrating-gnome-vfs.md",
|
||||
]
|
||||
content_images = [
|
||||
"gvfs-overview.png",
|
||||
"menu-example.png",
|
||||
"menu-model.png",
|
||||
]
|
@ -161,11 +161,7 @@ if get_option('gtk_doc')
|
||||
)
|
||||
|
||||
content_files = [
|
||||
'overview.xml',
|
||||
'migrating-posix.xml',
|
||||
'migrating-gnome-vfs.xml',
|
||||
'migrating-gconf.xml',
|
||||
'migrating-gdbus.xml',
|
||||
'gio-querymodules.xml',
|
||||
'glib-compile-schemas.xml',
|
||||
'glib-compile-resources.xml',
|
||||
@ -198,11 +194,7 @@ if get_option('gtk_doc')
|
||||
],
|
||||
content_files : content_files,
|
||||
expand_content_files : [
|
||||
'overview.xml',
|
||||
'migrating-posix.xml',
|
||||
'migrating-gnome-vfs.xml',
|
||||
'migrating-gconf.xml',
|
||||
'migrating-gdbus.xml',
|
||||
'gdbus-codegen.xml',
|
||||
],
|
||||
html_assets : [
|
||||
@ -216,7 +208,7 @@ if get_option('gtk_doc')
|
||||
'--extra-dir=' + join_paths('gio', '..', 'gobject', 'html'),
|
||||
],
|
||||
install: true,
|
||||
check: true,
|
||||
check: false,
|
||||
)
|
||||
endif
|
||||
|
||||
@ -234,3 +226,32 @@ if get_option('man')
|
||||
install_dir: man1_dir)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
# gi-docgen version
|
||||
expand_content_files = [
|
||||
'migrating-gconf.md',
|
||||
'migrating-gdbus.md',
|
||||
'migrating-gnome-vfs.md',
|
||||
'overview.md',
|
||||
]
|
||||
|
||||
gio_gir = meson.current_source_dir() / 'Gio-2.0.gir'
|
||||
gio_toml = configure_file(input: 'gio.toml.in', output: 'gio.toml', configuration: toml_conf)
|
||||
|
||||
custom_target('gio-docs',
|
||||
input: [ gio_toml, gio_gir ],
|
||||
output: 'gio',
|
||||
command: [
|
||||
gidocgen,
|
||||
'generate',
|
||||
gidocgen_common_args,
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'--add-include-path=@0@'.format(meson.current_source_dir() / '../glib'),
|
||||
'--add-include-path=@0@'.format(meson.current_source_dir() / '../gobject'),
|
||||
'@INPUT1@',
|
||||
],
|
||||
build_by_default: true,
|
||||
depend_files: expand_content_files,
|
||||
)
|
||||
|
466
docs/reference/gio/migrating-gconf.md
Normal file
466
docs/reference/gio/migrating-gconf.md
Normal file
@ -0,0 +1,466 @@
|
||||
Title: Migrating from GConf to GSettings
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2010, 2012 Matthias Clasen
|
||||
SPDX-FileCopyrightText: 2010 Allison Lortie
|
||||
SPDX-FileCopyrightText: 2011 Ray Strode
|
||||
|
||||
# Migrating from GConf to GSettings
|
||||
|
||||
## Before you start
|
||||
|
||||
Converting individual applications and their settings from GConf to
|
||||
GSettings can be done at will. But desktop-wide settings like font or theme
|
||||
settings often have consumers in multiple modules. Therefore, some
|
||||
consideration has to go into making sure that all users of a setting are
|
||||
converted to GSettings at the same time or that the program responsible for
|
||||
configuring that setting continues to update the value in both places.
|
||||
|
||||
It is always a good idea to have a look at how others have handled similar
|
||||
problems before.
|
||||
|
||||
## Conceptual differences
|
||||
|
||||
Conceptually, GConf and GSettings are fairly similar. Both have a concept of
|
||||
pluggable backends. Both keep information about keys and their types in
|
||||
schemas. Both have a concept of mandatory values, which lets you implement
|
||||
lock-down.
|
||||
|
||||
There are some differences in the approach to schemas. GConf installs the
|
||||
schemas into the database and has API to handle schema information
|
||||
(`gconf_client_get_default_from_schema()`, `gconf_value_get_schema()`, etc).
|
||||
GSettings on the other hand assumes that an application knows its own
|
||||
schemas, and does not provide API to handle schema information at runtime.
|
||||
GSettings is also more strict about requiring a schema whenever you want to
|
||||
read or write a key. To deal with more free-form information that would
|
||||
appear in schema-less entries in GConf, GSettings allows for schemas to be
|
||||
'relocatable'.
|
||||
|
||||
One difference in the way applications interact with their settings is that
|
||||
with GConf you interact with a tree of settings (ie the keys you pass to
|
||||
functions when reading or writing values are actually paths with the actual
|
||||
name of the key as the last element. With GSettings, you create a GSettings
|
||||
object which has an implicit prefix that determines where the settings get
|
||||
stored in the global tree of settings, but the keys you pass when reading or
|
||||
writing values are just the key names, not the full path.
|
||||
|
||||
## GConfClient (and GConfBridge) API conversion
|
||||
|
||||
Most people use GConf via the high-level `GConfClient` API. The
|
||||
corresponding API is the [class@Gio.Settings] object. While not every
|
||||
`GConfClient` function has a direct GSettings equivalent, many do:
|
||||
|
||||
| GConfClient | GSettings |
|
||||
|-------------|-----------|
|
||||
| `gconf_client_get_default()` | no direct equivalent, instead you call [`ctor@Gio.Settings.new`] for the schemas you use |
|
||||
| `gconf_client_set()` | [`method@Gio.Settings.set`] |
|
||||
| `gconf_client_get()` | `g_settings_get()` |
|
||||
| `gconf_client_get_bool()` | `g_settings_get_boolean()` |
|
||||
| `gconf_client_set_bool()` | `g_settings_set_boolean()` |
|
||||
| `gconf_client_get_int()` | `g_settings_get_int()` |
|
||||
| `gconf_client_set_int()` | `g_settings_set_int()` |
|
||||
| `gconf_client_get_float()` | `g_settings_get_double()` |
|
||||
| `gconf_client_set_float()` | `g_settings_set_double()` |
|
||||
| `gconf_client_get_string()` | `g_settings_get_string()` |
|
||||
| `gconf_client_set_string()` | `g_settings_set_string()` |
|
||||
| `gconf_client_get_list()` | for string lists, see `g_settings_get_strv()`, else see `g_settings_get_value()` and GVariant API |
|
||||
| `gconf_client_set_list()` | for string lists, see `g_settings_set_strv()`, else see `g_settings_set_value()` and GVariant API |
|
||||
| `gconf_entry_get_is_writable()` | `g_settings_is_writable()` |
|
||||
| `gconf_client_notify_add()` | not required, the “changed” signal is emitted automatically |
|
||||
| `gconf_client_add_dir()` | not required, each GSettings instance automatically watches all keys in its path |
|
||||
| `GConfChangeSet` | `g_settings_delay()`, `g_settings_apply()` |
|
||||
| `gconf_client_get_default_from_schema()` | no equivalent, applications are expected to know their schema |
|
||||
| `gconf_client_all_entries()` | no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries |
|
||||
| `gconf_client_get_without_default()` | no equivalent |
|
||||
| `gconf_bridge_bind_property()` | `g_settings_bind()` |
|
||||
| `gconf_bridge_bind_property_full()` | `g_settings_bind_with_mapping()` |
|
||||
|
||||
GConfBridge was a third-party library that used GConf to bind an object
|
||||
property to a particular configuration key. GSettings offers this service
|
||||
itself.
|
||||
|
||||
There is a pattern that is sometimes used for GConf, where a setting can
|
||||
have explicit 'value A', explicit 'value B' or 'use the system default'.
|
||||
With GConf, 'use the system default' is sometimes implemented by unsetting
|
||||
the user value. This is not possible in GSettings, since it does not have
|
||||
API to determine if a value is the default and does not let you unset
|
||||
values. The recommended way (and much clearer) way in which this can be
|
||||
implemented in GSettings is to have a separate 'use-system-default' boolean
|
||||
setting.
|
||||
|
||||
## Change notification
|
||||
|
||||
GConf requires you to call `gconf_client_add_dir()` and
|
||||
`gconf_client_notify_add()` to get change notification. With GSettings, this
|
||||
is not necessary; signals get emitted automatically for every change.
|
||||
|
||||
The [signal@Gio.Settings::changed] signal is emitted for each changed key.
|
||||
There is also a [`signal@Gio.Settings::change-event`] signal that you can
|
||||
handle if you need to see groups of keys that get changed at the same time.
|
||||
|
||||
GSettings also notifies you about changes in writability of keys, with the
|
||||
[signal@Gio.Settings::writable-changed] signal (and the
|
||||
[signal@Gio.Settings::writable-change-event] signal).
|
||||
|
||||
## Change sets
|
||||
|
||||
GConf has a concept of a set of changes which can be applied or reverted at
|
||||
once: `GConfChangeSet` (GConf doesn't actually apply changes atomically,
|
||||
which is one of its shortcomings).
|
||||
|
||||
Instead of a separate object to represent a change set, GSettings has a
|
||||
'delayed-apply' mode, which can be turned on for a [class@Gio.Settings]
|
||||
object by calling [method@Gio.Settings.delay]. In this mode, changes done to
|
||||
the GSettings object are not applied - they are still visible when calling
|
||||
[method@Gio.Settings.get] on the same object, but not to other GSettings
|
||||
instances or even other processes.
|
||||
|
||||
To apply the pending changes all at once (GSettings does atomicity here),
|
||||
call [method@Gio.Settings.apply]. To revert the pending changes, call
|
||||
[method@Gio.Settings.revert] or just drop the reference to the GSettings
|
||||
object.
|
||||
|
||||
## Schema conversion
|
||||
|
||||
If you are porting your application from GConf, most likely you already have
|
||||
a GConf schema. GConf comes with a commandline tool
|
||||
`gsettings-schema-convert` that can help with the task of converting a GConf
|
||||
schema into an equivalent GSettings schema. The tool is not perfect and may
|
||||
need assistance in some cases.
|
||||
|
||||
### An example for using gsettings-schema-convert
|
||||
|
||||
Running `gsettings-schema-convert --gconf --xml --schema-id
|
||||
"org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml
|
||||
destop_gnome_font_rendering.schemas` on the following
|
||||
`desktop_gnome_font_rendering.schemas` file:
|
||||
|
||||
```xml
|
||||
<?xml version="1.0"?>
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/font_rendering/dpi</key>
|
||||
<applyto>/desktop/gnome/font_rendering/dpi</applyto>
|
||||
<owner>gnome</owner>
|
||||
<type>int</type>
|
||||
<default>96</default>
|
||||
<locale name="C">
|
||||
<short>DPI</short>
|
||||
<long>The resolution used for converting font sizes to pixel sizes, in dots per inch.</long>
|
||||
</locale>
|
||||
</schema>
|
||||
</schemalist>
|
||||
</gconfschemafile>
|
||||
```
|
||||
|
||||
produces an `org.gnome.font-rendering.gschema.xml` file with the following content:
|
||||
|
||||
```xml
|
||||
<schemalist>
|
||||
<schema id="org.gnome.font-rendering" path="/desktop/gnome/font_rendering/">
|
||||
<key name="dpi" type="i">
|
||||
<default>96</default>
|
||||
<summary>DPI</summary>
|
||||
<description>The resolution used for converting font sizes to pixel sizes, in dots per inch.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
```
|
||||
|
||||
GSettings schemas are identified at runtime by their id (as specified in the
|
||||
XML source file). It is recommended to use a dotted name as schema id,
|
||||
similar in style to a D-Bus bus name, e.g. "org.gnome.SessionManager". In
|
||||
cases where the settings are general and not specific to one application,
|
||||
the id should not use StudlyCaps, e.g. "org.gnome.font-rendering". The
|
||||
filename used for the XML schema source is immaterial, but schema compiler
|
||||
expects the files to have the extension `.gschema.xml`. It is recommended to
|
||||
simply use the schema id as the filename, followed by this extension, e.g.
|
||||
`org.gnome.SessionManager.gschema.xml`.
|
||||
|
||||
The XML source file for your GSettings schema needs to get installed into
|
||||
`$datadir/glib-2.0/schemas`, and needs to be compiled into a binary form. At
|
||||
runtime, GSettings looks for compiled schemas in the `glib-2.0/schemas`
|
||||
subdirectories of all `XDG_DATA_DIRS` directories, so if you install your
|
||||
schema in a different location, you need to set the `XDG_DATA_DIRS`
|
||||
environment variable appropriately.
|
||||
|
||||
Schemas are compiled into binary form by the `glib-compile-schemas` utility.
|
||||
GIO provides a `glib_compile_schemas` variable in its pkg-config file
|
||||
pointing to the schema compiler binary.
|
||||
|
||||
### Using schemas with Meson
|
||||
|
||||
You should use `install_data()` to install the `.gschema.xml` file in the
|
||||
correct directory, e.g.
|
||||
|
||||
```
|
||||
install_data('my.app.gschema.xml', install_dir: get_option('datadir') / 'glib-2.0/schemas')
|
||||
```
|
||||
|
||||
Schema compilation is done at installation time; if you are using Meson 0.57 or newer, you can use the `gnome.post_install()` function from the GNOME module:
|
||||
|
||||
```
|
||||
gnome.post_install(glib_compile_schemas: true)
|
||||
```
|
||||
|
||||
Alternatively, you can use `meson.add_install_script()` and the following
|
||||
Python script:
|
||||
|
||||
```py
|
||||
#!/usr/bin/env python3
|
||||
# build-aux/compile-schemas.py
|
||||
|
||||
import os
|
||||
import subprocess
|
||||
|
||||
install_prefix = os.environ['MESON_INSTALL_PREFIX']
|
||||
schemadir = os.path.join(install_prefix, 'share', 'glib-2.0', 'schemas')
|
||||
|
||||
if not os.environ.get('DESTDIR'):
|
||||
print('Compiling gsettings schemas...')
|
||||
subprocess.call(['glib-compile-schemas', schemadir])
|
||||
```
|
||||
|
||||
```
|
||||
meson.add_install_script('build-aux/compile-schemas.py')
|
||||
```
|
||||
|
||||
### Using schemas with Autotools
|
||||
|
||||
GLib provides m4 macros for hiding the various complexities and reduce the
|
||||
chances of getting things wrong.
|
||||
|
||||
To handle schemas in your Autotools build, start by adding this to your
|
||||
`configure.ac`:
|
||||
|
||||
```
|
||||
GLIB_GSETTINGS
|
||||
```
|
||||
|
||||
Then add this fragment to your `Makefile.am`:
|
||||
|
||||
```
|
||||
# gsettings_SCHEMAS is a list of all the schemas you want to install
|
||||
gsettings_SCHEMAS = my.app.gschema.xml
|
||||
|
||||
# include the appropriate makefile rules for schema handling
|
||||
@GSETTINGS_RULES@
|
||||
```
|
||||
|
||||
This is not sufficient on its own. You need to mention what the source of
|
||||
the `my.app.gschema.xml` file is. If the schema file is distributed directly
|
||||
with your project's tarball then a mention in `EXTRA_DIST` is appropriate. If
|
||||
the schema file is generated from another source then you will need the
|
||||
appropriate rule for that, plus probably an item in `EXTRA_DIST` for the
|
||||
source files used by that rule.
|
||||
|
||||
One possible pitfall in doing schema conversion is that the default values
|
||||
in GSettings schemas are parsed by the GVariant parser. This means that
|
||||
strings need to include quotes in the XML. Also note that the types are now
|
||||
specified as GVariant type strings.
|
||||
|
||||
```xml
|
||||
<type>string</type>
|
||||
<default>rgb</default>
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```xml
|
||||
<key name="rgba-order" type="s">
|
||||
<default>'rgb'</default> <!-- note quotes -->
|
||||
</key>
|
||||
```
|
||||
|
||||
Another possible complication is that GConf specifies full paths for each
|
||||
key, while a GSettings schema has a 'path' attribute that contains the
|
||||
prefix for all the keys in the schema, and individual keys just have a
|
||||
simple name. So
|
||||
|
||||
```xml
|
||||
<key>/schemas/desktop/gnome/font_rendering/antialiasing</key>
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```xml
|
||||
<schema id="org.gnome.font" path="/desktop/gnome/font_rendering/">
|
||||
<key name="antialiasing" type="s">
|
||||
```
|
||||
|
||||
|
||||
Default values can be localized in both GConf and GSettings schemas, but
|
||||
GSettings uses gettext for the localization. You can specify the gettext
|
||||
domain to use in the gettext-domain attribute. Therefore, when converting
|
||||
localized defaults in GConf,
|
||||
|
||||
```xml
|
||||
<key>/schemas/apps/my_app/font_size</key>
|
||||
<locale name="C">
|
||||
<default>18</default>
|
||||
</locale>
|
||||
<locale name="be">
|
||||
<default>24</default>
|
||||
</locale>
|
||||
</key>
|
||||
```
|
||||
|
||||
becomes
|
||||
|
||||
```xml
|
||||
<schema id="..." gettext-domain="your-domain">
|
||||
...
|
||||
<key name="font-size" type="i">
|
||||
<default l10n="messages" context="font_size">18</default>
|
||||
</key>
|
||||
```
|
||||
|
||||
GSettings uses gettext for translation of default values. The string that is
|
||||
translated is exactly the string that appears inside of the `<default>`
|
||||
element. This includes the quotation marks that appear around strings.
|
||||
Default values must be marked with the l10n attribute in the `<default>` tag,
|
||||
which should be set as equal to 'messages' or 'time' depending on the
|
||||
desired category. An optional translation context can also be specified with
|
||||
the context attribute, as in the example. This is usually recommended, since
|
||||
the string "18" is not particularly easy to translate without context. The
|
||||
translated version of the default value should be stored in the specified
|
||||
gettext-domain. Care must be taken during translation to ensure that all
|
||||
translated values remain syntactically valid; mistakes here will cause
|
||||
runtime errors.
|
||||
|
||||
GSettings schemas have optional `<summary>` and `<description>` elements for
|
||||
each key which correspond to the `<short>` and `<long>` elements in the
|
||||
GConf schema and can be used in the same way by a GUI editor, so you should
|
||||
use the same conventions for them: The summary is just a short label with no
|
||||
punctuation, the description can be one or more complete sentences. If
|
||||
multiple paragraphs are desired for the description, the paragraphs should
|
||||
be separated by a completely empty line.
|
||||
|
||||
Translations for these strings will also be handled via gettext, so you
|
||||
should arrange for these strings to be extracted into your gettext catalog.
|
||||
Gettext supports GSettings schemas natively since version 0.19, so all you
|
||||
have to do is add the XML schema file to the list of translatable files
|
||||
inside your `POTFILES.in`.
|
||||
|
||||
GSettings is a bit more restrictive about key names than GConf. Key names in
|
||||
GSettings can be at most 32 characters long, and must only consist of
|
||||
lowercase characters, numbers and dashes, with no consecutive dashes. The
|
||||
first character must not be a number or dash, and the last character cannot
|
||||
be '-'.
|
||||
|
||||
If you are using the GConf backend for GSettings during the transition, you
|
||||
may want to keep your key names the same they were in GConf, so that
|
||||
existing settings in the users GConf database are preserved. You can achieve
|
||||
this by using the `--allow-any-name` with the `glib-compile-schemas` schema
|
||||
compiler. Note that this option is only meant to ease the process of porting
|
||||
your application, allowing parts of your application to continue to access
|
||||
GConf and parts to use GSettings. By the time you have finished porting your
|
||||
application you must ensure that all key names are valid.
|
||||
|
||||
## Data conversion
|
||||
|
||||
GConf comes with a GSettings backend that can be used to facility the
|
||||
transition to the GSettings API until you are ready to make the jump to a
|
||||
different backend (most likely dconf). To use it, you need to set the
|
||||
`GSETTINGS_BACKEND` to 'gconf', e.g. by using
|
||||
|
||||
```c
|
||||
g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE);
|
||||
```
|
||||
|
||||
early on in your program. Note that this backend is meant purely as a
|
||||
transition tool, and should not be used in production.
|
||||
|
||||
GConf also comes with a utility called `gsettings-data-convert`, which is
|
||||
designed to help with the task of migrating user settings from GConf into
|
||||
another GSettings backend. It can be run manually, but it is designed to be
|
||||
executed automatically, every time a user logs in. It keeps track of the
|
||||
data migrations that it has already done, and it is harmless to run it more
|
||||
than once.
|
||||
|
||||
To make use of this utility, you must install a keyfile in the directory
|
||||
`/usr/share/GConf/gsettings` which lists the GSettings keys and GConf paths
|
||||
to map to each other, for each schema that you want to migrate user data
|
||||
for.
|
||||
|
||||
Here is an example:
|
||||
|
||||
```
|
||||
[org.gnome.fonts]
|
||||
antialiasing = /desktop/gnome/font_rendering/antialiasing
|
||||
dpi = /desktop/gnome/font_rendering/dpi
|
||||
hinting = /desktop/gnome/font_rendering/hinting
|
||||
rgba-order = /desktop/gnome/font_rendering/rgba_order
|
||||
|
||||
[apps.myapp:/path/to/myapps/]
|
||||
some-odd-key1 = /apps/myapp/some_ODD-key1
|
||||
```
|
||||
|
||||
The last key demonstrates that it may be necessary to modify the key name to
|
||||
comply with stricter GSettings key name rules. Of course, that means your
|
||||
application must use the new key names when looking up settings in
|
||||
GSettings.
|
||||
|
||||
The last group in the example also shows how to handle the case of
|
||||
'relocatable' schemas, which don't have a fixed path. You can specify the
|
||||
path to use in the group name, separated by a colon.
|
||||
|
||||
There are some limitations: `gsettings-data-convert` does not do any
|
||||
transformation of the values. And it does not handle complex GConf types
|
||||
other than lists of strings or integers.
|
||||
|
||||
**Don't forget to require GConf 2.31.1 or newer in your configure script if
|
||||
you are making use of the GConf backend or the conversion utility.**
|
||||
|
||||
If, as an application developer, you are interested in manually ensuring
|
||||
that `gsettings-data-convert` has been invoked (for example, to deal with the
|
||||
case where the user is logged in during a distribution upgrade or for
|
||||
non-XDG desktop environments which do not run the command as an autostart)
|
||||
you may invoke it manually during your program initialisation. This is not
|
||||
recommended for all application authors -- it is your choice if this use
|
||||
case concerns you enough.
|
||||
|
||||
Internally, `gsettings-data-convert` uses a keyfile to track which settings
|
||||
have been migrated. The following code fragment will check that keyfile to
|
||||
see if your data conversion script has been run yet and, if not, will
|
||||
attempt to invoke the tool to run it. You should adapt it to your
|
||||
application as you see fit.
|
||||
|
||||
```c
|
||||
static void
|
||||
ensure_migrated (const gchar *name)
|
||||
{
|
||||
gboolean needed = TRUE;
|
||||
GKeyFile *kf;
|
||||
gchar **list;
|
||||
gsize i, n;
|
||||
|
||||
kf = g_key_file_new ();
|
||||
|
||||
g_key_file_load_from_data_dirs (kf, "gsettings-data-convert",
|
||||
NULL, G_KEY_FILE_NONE, NULL);
|
||||
list = g_key_file_get_string_list (kf, "State", "converted", &n, NULL);
|
||||
|
||||
if (list)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
if (strcmp (list[i], name) == 0)
|
||||
{
|
||||
needed = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
g_strfreev (list);
|
||||
}
|
||||
|
||||
g_key_file_free (kf);
|
||||
|
||||
if (needed)
|
||||
g_spawn_command_line_sync ("gsettings-data-convert",
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
```
|
||||
|
||||
Although there is the possibility that the `gsettings-data-convert` script
|
||||
will end up running multiple times concurrently with this approach, it is
|
||||
believed that this is safe.
|
@ -1,515 +0,0 @@
|
||||
<chapter>
|
||||
<title>Migrating from GConf to GSettings</title>
|
||||
|
||||
<section>
|
||||
<title>Before you start</title>
|
||||
|
||||
<para>
|
||||
Converting individual applications and their settings from GConf to
|
||||
GSettings can be done at will. But desktop-wide settings like font or
|
||||
theme settings often have consumers in multiple modules. Therefore,
|
||||
some consideration has to go into making sure that all users of a setting
|
||||
are converted to GSettings at the same time or that the program
|
||||
responsible for configuring that setting continues to update the value in
|
||||
both places.
|
||||
</para>
|
||||
<para>
|
||||
It is always a good idea to have a look at how others have handled
|
||||
similar problems before.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Conceptual differences</title>
|
||||
|
||||
<para>
|
||||
Conceptually, GConf and GSettings are fairly similar. Both
|
||||
have a concept of pluggable backends. Both keep information
|
||||
about keys and their types in schemas. Both have a concept of
|
||||
mandatory values, which lets you implement lock-down.
|
||||
</para>
|
||||
<para>
|
||||
There are some differences in the approach to schemas. GConf
|
||||
installs the schemas into the database and has API to handle
|
||||
schema information (gconf_client_get_default_from_schema(),
|
||||
gconf_value_get_schema(), etc). GSettings on the other hand
|
||||
assumes that an application knows its own schemas, and does
|
||||
not provide API to handle schema information at runtime.
|
||||
GSettings is also more strict about requiring a schema whenever
|
||||
you want to read or write a key. To deal with more free-form
|
||||
information that would appear in schema-less entries in GConf,
|
||||
GSettings allows for schemas to be 'relocatable'.
|
||||
</para>
|
||||
<para>
|
||||
One difference in the way applications interact with their
|
||||
settings is that with GConf you interact with a tree of
|
||||
settings (ie the keys you pass to functions when reading
|
||||
or writing values are actually paths with the actual name
|
||||
of the key as the last element. With GSettings, you create
|
||||
a GSettings object which has an implicit prefix that determines
|
||||
where the settings get stored in the global tree of settings,
|
||||
but the keys you pass when reading or writing values are just
|
||||
the key names, not the full path.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>GConfClient (and GConfBridge) API conversion</title>
|
||||
|
||||
<para>
|
||||
Most people use GConf via the high-level #GConfClient API.
|
||||
The corresponding API is the #GSettings object. While not
|
||||
every GConfClient function has a direct GSettings equivalent,
|
||||
many do:
|
||||
<table id="gconf-client-vs-gsettings">
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>GConfClient</entry><entry>GSettings</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>gconf_client_get_default()</entry><entry>no direct equivalent,
|
||||
instead you call g_settings_new() for the schemas you use</entry></row>
|
||||
<row><entry>gconf_client_set()</entry><entry>g_settings_set()</entry></row>
|
||||
<row><entry>gconf_client_get()</entry><entry>g_settings_get()</entry></row>
|
||||
<row><entry>gconf_client_get_bool()</entry><entry>g_settings_get_boolean()</entry></row>
|
||||
<row><entry>gconf_client_set_bool()</entry><entry>g_settings_set_boolean()</entry></row>
|
||||
<row><entry>gconf_client_get_int()</entry><entry>g_settings_get_int()</entry></row>
|
||||
<row><entry>gconf_client_set_int()</entry><entry>g_settings_set_int()</entry></row>
|
||||
<row><entry>gconf_client_get_float()</entry><entry>g_settings_get_double()</entry></row>
|
||||
<row><entry>gconf_client_set_float()</entry><entry>g_settings_set_double()</entry></row>
|
||||
<row><entry>gconf_client_get_string()</entry><entry>g_settings_get_string()</entry></row>
|
||||
<row><entry>gconf_client_set_string()</entry><entry>g_settings_set_string()</entry></row>
|
||||
<row><entry>gconf_client_get_list()</entry><entry>for string lists, see g_settings_get_strv(), else see g_settings_get_value() and #GVariant API</entry></row>
|
||||
<row><entry>gconf_client_set_list()</entry><entry>for string lists, see g_settings_set_strv(), else see g_settings_set_value() and #GVariant API</entry></row>
|
||||
<row><entry>gconf_entry_get_is_writable()</entry><entry>g_settings_is_writable()</entry></row>
|
||||
<row><entry>gconf_client_notify_add()</entry><entry>not required, the #GSettings::changed signal is emitted automatically</entry></row>
|
||||
<row><entry>gconf_client_add_dir()</entry><entry>not required, each GSettings instance automatically watches all keys in its path</entry></row>
|
||||
<row><entry>#GConfChangeSet</entry><entry>g_settings_delay(), g_settings_apply()</entry></row>
|
||||
<row><entry>gconf_client_get_default_from_schema()</entry><entry>no equivalent, applications are expected to know their schema</entry></row>
|
||||
<row><entry>gconf_client_all_entries()</entry><entry>no equivalent, applications are expected to know their schema, and GSettings does not allow schema-less entries</entry></row>
|
||||
<row><entry>gconf_client_get_without_default()</entry><entry>no equivalent</entry></row>
|
||||
<row><entry>gconf_bridge_bind_property()</entry><entry>g_settings_bind()</entry></row>
|
||||
<row><entry>gconf_bridge_bind_property_full()</entry><entry>g_settings_bind_with_mapping()</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
<para>
|
||||
GConfBridge was a third-party library that used GConf to bind an object property
|
||||
to a particular configuration key. GSettings offers this service itself.
|
||||
</para>
|
||||
<para>
|
||||
There is a pattern that is sometimes used for GConf, where a setting can have
|
||||
explicit 'value A', explicit 'value B' or 'use the system default'. With GConf,
|
||||
'use the system default' is sometimes implemented by unsetting the user value.
|
||||
</para>
|
||||
<para>
|
||||
This is not possible in GSettings, since it does not have API to determine if a value
|
||||
is the default and does not let you unset values. The recommended way (and much
|
||||
clearer) way in which this can be implemented in GSettings is to have a separate
|
||||
'use-system-default' boolean setting.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Change notification</title>
|
||||
|
||||
<para>
|
||||
GConf requires you to call gconf_client_add_dir() and
|
||||
gconf_client_notify_add() to get change notification. With
|
||||
GSettings, this is not necessary; signals get emitted automatically
|
||||
for every change.
|
||||
</para>
|
||||
<para>
|
||||
The #GSettings::changed signal is emitted for each changed key.
|
||||
There is also a #GSettings::change-event signal that you can handle
|
||||
if you need to see groups of keys that get changed at the same time.
|
||||
</para>
|
||||
<para>
|
||||
GSettings also notifies you about changes in writability of keys,
|
||||
with the #GSettings::writable-changed signal (and the
|
||||
#GSettings::writable-change-event signal).
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Change sets</title>
|
||||
<para>
|
||||
GConf has a concept of a set of changes which can be applied or reverted
|
||||
at once: #GConfChangeSet (GConf doesn't actually apply changes atomically,
|
||||
which is one of its shortcomings).
|
||||
</para>
|
||||
<para>
|
||||
Instead of a separate object to represent a change set, GSettings has a
|
||||
'delayed-apply' mode, which can be turned on for a GSettings object by
|
||||
calling g_settings_delay(). In this mode, changes done to the GSettings
|
||||
object are not applied - they are still visible when calling g_settings_get()
|
||||
<emphasis>on the same object</emphasis>, but not to other GSettings instances
|
||||
or even other processes.
|
||||
</para>
|
||||
<para>
|
||||
To apply the pending changes all at once (GSettings <emphasis>does</emphasis>
|
||||
atomicity here), call g_settings_apply(). To revert the pending changes,
|
||||
call g_settings_revert() or just drop the reference to the #GSettings object.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Schema conversion</title>
|
||||
|
||||
<para>
|
||||
If you are porting your application from GConf, most likely you already
|
||||
have a GConf schema. GConf comes with a commandline tool
|
||||
gsettings-schema-convert that can help with the task of converting
|
||||
a GConf schema into an equivalent GSettings schema. The tool is not
|
||||
perfect and may need assistance in some cases.
|
||||
</para>
|
||||
<example><title>An example for using gsettings-schema-convert</title>
|
||||
<para>Running <userinput>gsettings-schema-convert --gconf --xml --schema-id "org.gnome.font-rendering" --output org.gnome.font-rendering.gschema.xml destop_gnome_font_rendering.schemas</userinput> on the following <filename>desktop_gnome_font_rendering.schemas</filename> file:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<?xml version="1.0"?>
|
||||
<gconfschemafile>
|
||||
<schemalist>
|
||||
<schema>
|
||||
<key>/schemas/desktop/gnome/font_rendering/dpi</key>
|
||||
<applyto>/desktop/gnome/font_rendering/dpi</applyto>
|
||||
<owner>gnome</owner>
|
||||
<type>int</type>
|
||||
<default>96</default>
|
||||
<locale name="C">
|
||||
<short>DPI</short>
|
||||
<long>The resolution used for converting font sizes to pixel sizes, in dots per inch.</long>
|
||||
</locale>
|
||||
</schema>
|
||||
</schemalist>
|
||||
</gconfschemafile>
|
||||
]]>
|
||||
</programlisting>
|
||||
produces a <filename>org.gnome.font-rendering.gschema.xml</filename> file with the following content:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schemalist>
|
||||
<schema id="org.gnome.font-rendering" path="/desktop/gnome/font_rendering/">
|
||||
<key name="dpi" type="i">
|
||||
<default>96</default>
|
||||
<summary>DPI</summary>
|
||||
<description>The resolution used for converting font sizes to pixel sizes, in dots per inch.</description>
|
||||
</key>
|
||||
</schema>
|
||||
</schemalist>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
</example>
|
||||
|
||||
<para>
|
||||
GSettings schemas are identified at runtime by their id (as specified
|
||||
in the XML source file). It is recommended to use a dotted name as schema
|
||||
id, similar in style to a D-Bus bus name, e.g. "org.gnome.SessionManager".
|
||||
In cases where the settings are general and not specific to one application,
|
||||
the id should not use StudlyCaps, e.g. "org.gnome.font-rendering".
|
||||
The filename used for the XML schema source is immaterial, but
|
||||
schema compiler expects the files to have the extension
|
||||
<filename>.gschema.xml</filename>. It is recommended to simply
|
||||
use the schema id as the filename, followed by this extension,
|
||||
e.g. <filename>org.gnome.SessionManager.gschema.xml</filename>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The XML source file for your GSettings schema needs to get installed
|
||||
into <filename>$datadir/glib-2.0/schemas</filename>, and needs to be
|
||||
compiled into a binary form. At runtime, GSettings looks for compiled
|
||||
schemas in the <filename>glib-2.0/schemas</filename> subdirectories
|
||||
of all <envar>XDG_DATA_DIRS</envar> directories, so if you install
|
||||
your schema in a different location, you need to set the
|
||||
<envar>XDG_DATA_DIRS</envar> environment variable appropriately.
|
||||
</para>
|
||||
<para>
|
||||
Schemas are compiled into binary form by the
|
||||
<link linkend="glib-compile-schemas">glib-compile-schemas</link> utility.
|
||||
GIO provides a <literal>glib_compile_schemas</literal>
|
||||
variable for the schema compiler.
|
||||
</para>
|
||||
<para>
|
||||
You can ignore all of this by using the provided m4 macros. To
|
||||
do this, add to your <filename>configure.ac</filename>:
|
||||
<programlisting>
|
||||
GLIB_GSETTINGS
|
||||
</programlisting>
|
||||
The corresponding <filename>Makefile.am</filename> fragment looks like
|
||||
this:
|
||||
<programlisting>
|
||||
# gsettings_SCHEMAS is a list of all the schemas you want to install
|
||||
gsettings_SCHEMAS = my.app.gschema.xml
|
||||
|
||||
# include the appropriate makefile rules for schema handling
|
||||
@GSETTINGS_RULES@
|
||||
</programlisting>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This is not sufficient on its own. You need to mention what the source
|
||||
of the <filename>my.app.gschema.xml</filename> file is. If the schema
|
||||
file is distributed directly with your project's tarball then a mention
|
||||
in <varname>EXTRA_DIST</varname> is appropriate. If the schema file is
|
||||
generated from another source then you will need the appropriate rule
|
||||
for that, plus probably an item in <varname>EXTRA_DIST</varname> for the
|
||||
source files used by that rule.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
One possible pitfall in doing schema conversion is that the default
|
||||
values in GSettings schemas are parsed by the #GVariant parser.
|
||||
This means that strings need to include quotes in the XML. Also note
|
||||
that the types are now specified as #GVariant type strings.
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<type>string</type>
|
||||
<default>rgb</default>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key name="rgba-order" type="s">
|
||||
<default>'rgb'</default> <!-- note quotes -->
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Another possible complication is that GConf specifies full paths
|
||||
for each key, while a GSettings schema has a 'path' attribute that
|
||||
contains the prefix for all the keys in the schema, and individual
|
||||
keys just have a simple name. So
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key>/schemas/desktop/gnome/font_rendering/antialiasing</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schema id="org.gnome.font" path="/desktop/gnome/font_rendering/">
|
||||
<key name="antialiasing" type="s">
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Default values can be localized in both GConf and GSettings schemas,
|
||||
but GSettings uses gettext for the localization. You can specify
|
||||
the gettext domain to use in the <tag class="attribute">gettext-domain</tag>
|
||||
attribute. Therefore, when converting localized defaults in GConf,
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<key>/schemas/apps/my_app/font_size</key>
|
||||
<locale name="C">
|
||||
<default>18</default>
|
||||
</locale>
|
||||
<locale name="be">
|
||||
<default>24</default>
|
||||
</locale>
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
becomes
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
<schema id="..." gettext-domain="your-domain">
|
||||
...
|
||||
<key name="font-size" type="i">
|
||||
<default l10n="messages" context="font_size">18</default>
|
||||
</key>
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
GSettings uses gettext for translation of default values.
|
||||
The string that is translated is exactly the string that appears
|
||||
inside of the <tag class='starttag'>default</tag> element. This
|
||||
includes the quotation marks that appear around strings.
|
||||
Default values must be marked with the <varname>l10n</varname>
|
||||
attribute in the <tag class='starttag'>default</tag> tag, which
|
||||
should be set as equal to <literal>'messages'</literal> or
|
||||
<literal>'time'</literal> depending on the desired category. An
|
||||
optional translation context can also be specified with the
|
||||
<varname>context</varname> attribute, as in the example. This
|
||||
is usually recommended, since the string "<literal>18</literal>"
|
||||
is not particularly easy to translate without context. The
|
||||
translated version of the default value should be stored in the
|
||||
specified <varname>gettext-domain</varname>. Care must be taken
|
||||
during translation to ensure that all translated values remain
|
||||
syntactically valid; mistakes here will cause runtime errors.
|
||||
</para>
|
||||
<para>
|
||||
GSettings schemas have optional <tag class="starttag">summary</tag> and
|
||||
<tag class="starttag">description</tag> elements for each key which
|
||||
correspond to the <tag class="starttag">short</tag> and
|
||||
<tag class="starttag">long</tag> elements in the GConf schema and
|
||||
will be used in similar ways by a future gsettings-editor, so you
|
||||
should use the same conventions for them: The summary is just a short
|
||||
label with no punctuation, the description can be one or more complete
|
||||
sentences. If multiple paragraphs are desired for the description, the
|
||||
paragraphs should be separated by a completely empty line.
|
||||
</para>
|
||||
<para>
|
||||
Translations for these strings will also be handled
|
||||
via gettext, so you should arrange for these strings to be
|
||||
extracted into your gettext catalog. One way to do that is to use
|
||||
intltool. Since intltool 0.50.1, schema files are
|
||||
supported, so all you have to do is to add your .gschema.xml
|
||||
files to <filename>POTFILES.in</filename> with a line like
|
||||
<programlisting>
|
||||
[type: gettext/gsettings]data/org.foo.MyApp.gschema.xml
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
GSettings is a bit more restrictive about key names than GConf. Key
|
||||
names in GSettings can be at most 32 characters long, and must only
|
||||
consist of lowercase characters, numbers and dashes, with no
|
||||
consecutive dashes. The first character must not be a number or dash,
|
||||
and the last character cannot be '-'.
|
||||
</para>
|
||||
<para>
|
||||
If you are using the GConf backend for GSettings during the
|
||||
transition, you may want to keep your key names the same they
|
||||
were in GConf, so that existing settings in the users GConf
|
||||
database are preserved. You can achieve this by using the
|
||||
<option>--allow-any-name</option> with the
|
||||
<link linkend="glib-compile-schemas">glib-compile-schemas</link> schema
|
||||
compiler. Note that this option is only meant
|
||||
to ease the process of porting your application, allowing parts
|
||||
of your application to continue to access GConf and parts to use
|
||||
GSettings. By the time you have finished porting your application
|
||||
you must ensure that all key names are valid.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section><title>Data conversion</title>
|
||||
<para>
|
||||
GConf comes with a GSettings backend that can be used to
|
||||
facility the transition to the GSettings API until you are
|
||||
ready to make the jump to a different backend (most likely
|
||||
dconf). To use it, you need to set the <envar>GSETTINGS_BACKEND</envar>
|
||||
to 'gconf', e.g. by using
|
||||
<programlisting>
|
||||
g_setenv ("GSETTINGS_BACKEND", "gconf", TRUE);
|
||||
</programlisting>
|
||||
early on in your program. Note that this backend is meant purely
|
||||
as a transition tool, and should not be used in production.
|
||||
</para>
|
||||
<para>
|
||||
GConf also comes with a utility called
|
||||
<command>gsettings-data-convert</command>, which is designed to help
|
||||
with the task of migrating user settings from GConf into another
|
||||
GSettings backend. It can be run manually, but it is designed to be
|
||||
executed automatically, every time a user logs in. It keeps track of
|
||||
the data migrations that it has already done, and it is harmless to
|
||||
run it more than once.
|
||||
</para>
|
||||
<para>
|
||||
To make use of this utility, you must install a keyfile in the
|
||||
directory <filename>/usr/share/GConf/gsettings</filename> which
|
||||
lists the GSettings keys and GConf paths to map to each other, for
|
||||
each schema that you want to migrate user data for.
|
||||
</para>
|
||||
<para>
|
||||
Here is an example:
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
[org.gnome.fonts]
|
||||
antialiasing = /desktop/gnome/font_rendering/antialiasing
|
||||
dpi = /desktop/gnome/font_rendering/dpi
|
||||
hinting = /desktop/gnome/font_rendering/hinting
|
||||
rgba-order = /desktop/gnome/font_rendering/rgba_order
|
||||
|
||||
[apps.myapp:/path/to/myapps/]
|
||||
some-odd-key1 = /apps/myapp/some_ODD-key1
|
||||
]]>
|
||||
</programlisting>
|
||||
The last key demonstrates that it may be necessary to modify the key
|
||||
name to comply with stricter GSettings key name rules. Of course,
|
||||
that means your application must use the new key names when looking
|
||||
up settings in GSettings.
|
||||
</para>
|
||||
<para>
|
||||
The last group in the example also shows how to handle the case
|
||||
of 'relocatable' schemas, which don't have a fixed path. You can
|
||||
specify the path to use in the group name, separated by a colon.
|
||||
</para>
|
||||
<para>
|
||||
There are some limitations: <command>gsettings-data-convert</command>
|
||||
does not do any transformation of the values. And it does not handle
|
||||
complex GConf types other than lists of strings or integers.
|
||||
</para>
|
||||
<para>
|
||||
Don't forget to require GConf 2.31.1 or newer in your configure
|
||||
script if you are making use of the GConf backend or the conversion
|
||||
utility.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If, as an application developer, you are interested in manually
|
||||
ensuring that <command>gsettings-data-convert</command> has been
|
||||
invoked (for example, to deal with the case where the user is
|
||||
logged in during a distribution upgrade or for non-XDG desktop
|
||||
environments which do not run the command as an autostart) you
|
||||
may invoke it manually during your program initialisation. This
|
||||
is not recommended for all application authors -- it is your
|
||||
choice if this use case concerns you enough.
|
||||
</para>
|
||||
<para>
|
||||
Internally, <command>gsettings-data-convert</command> uses a
|
||||
keyfile to track which settings have been migrated. The
|
||||
following code fragment will check that keyfile to see if your
|
||||
data conversion script has been run yet and, if not, will
|
||||
attempt to invoke the tool to run it. You should adapt it to
|
||||
your application as you see fit.
|
||||
</para>
|
||||
<para>
|
||||
<programlisting>
|
||||
<![CDATA[
|
||||
static void
|
||||
ensure_migrated (const gchar *name)
|
||||
{
|
||||
gboolean needed = TRUE;
|
||||
GKeyFile *kf;
|
||||
gchar **list;
|
||||
gsize i, n;
|
||||
|
||||
kf = g_key_file_new ();
|
||||
|
||||
g_key_file_load_from_data_dirs (kf, "gsettings-data-convert",
|
||||
NULL, G_KEY_FILE_NONE, NULL);
|
||||
list = g_key_file_get_string_list (kf, "State", "converted", &n, NULL);
|
||||
|
||||
if (list)
|
||||
{
|
||||
for (i = 0; i < n; i++)
|
||||
if (strcmp (list[i], name) == 0)
|
||||
{
|
||||
needed = FALSE;
|
||||
break;
|
||||
}
|
||||
|
||||
g_strfreev (list);
|
||||
}
|
||||
|
||||
g_key_file_free (kf);
|
||||
|
||||
if (needed)
|
||||
g_spawn_command_line_sync ("gsettings-data-convert",
|
||||
NULL, NULL, NULL, NULL);
|
||||
}
|
||||
|
||||
]]>
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
Although there is the possibility that the
|
||||
<command>gsettings-data-convert</command> script will end up
|
||||
running multiple times concurrently with this approach, it is
|
||||
believed that this is safe.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
633
docs/reference/gio/migrating-gdbus.md
Normal file
633
docs/reference/gio/migrating-gdbus.md
Normal file
@ -0,0 +1,633 @@
|
||||
Title: Migrating to GDBus
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2010 Matthias Clasen
|
||||
SPDX-FileCopyrightText: 2010, 2011 David Zeuthen
|
||||
|
||||
# Migrating to GDBus
|
||||
|
||||
## Conceptual differences
|
||||
|
||||
The central concepts of D-Bus are modelled in a very similar way in
|
||||
dbus-glib and GDBus. Both have objects representing connections, proxies and
|
||||
method invocations. But there are some important differences:
|
||||
|
||||
- dbus-glib uses the libdbus reference implementation, GDBus doesn't.
|
||||
Instead, it relies on GIO streams as transport layer, and has its own
|
||||
implementation for the D-Bus connection setup and authentication. Apart
|
||||
from using streams as transport, avoiding libdbus also lets GDBus avoid
|
||||
some thorny multithreading issues.
|
||||
- dbus-glib uses the GObject type system for method arguments and return
|
||||
values, including a homegrown container specialization mechanism. GDBus
|
||||
relies on the GVariant type system which is explicitly designed to match
|
||||
D-Bus types.
|
||||
- dbus-glib models only D-Bus interfaces and does not provide any types for
|
||||
objects. GDBus models both D-Bus interfaces (via the GDBusInterface,
|
||||
GDBusProxy and GDBusInterfaceSkeleton types) and objects (via the
|
||||
GDBusObject, GDBusObjectSkeleton and GDBusObjectProxy types).
|
||||
- GDBus includes native support for the org.freedesktop.DBus.Properties (via
|
||||
the GDBusProxy type) and org.freedesktop.DBus.ObjectManager D-Bus
|
||||
interfaces, dbus-glib doesn't.
|
||||
- The typical way to export an object in dbus-glib involves generating glue
|
||||
code from XML introspection data using dbus-binding-tool. GDBus provides a
|
||||
similar tool called gdbus-codegen that can also generate Docbook D-Bus
|
||||
interface documentation.
|
||||
- dbus-glib doesn't provide any convenience API for owning and watching bus
|
||||
names, GDBus provides the `g_bus_own_name()` and `g_bus_watch_name()`
|
||||
family of convenience functions.
|
||||
- GDBus provides API to parse, generate and work with Introspection XML,
|
||||
dbus-glib doesn't.
|
||||
- GTestDBus provides API to create isolated unit tests
|
||||
|
||||
## API comparison
|
||||
|
||||
| dbus-glib | GDBus |
|
||||
|-----------|-------|
|
||||
| `DBusGConnection` | `GDBusConnection` |
|
||||
| `DBusGProxy` | `GDBusProxy`, `GDBusInterface` - also see `GDBusObjectProxy` |
|
||||
| `DBusGObject` | `GDBusInterfaceSkeleton`, `GDBusInterface` - also see `GDBusObjectSkeleton` |
|
||||
| `DBusGMethodInvocation` | `GDBusMethodInvocation` |
|
||||
| `dbus_g_bus_get()` | `g_bus_get_sync()`, also see `g_bus_get()` |
|
||||
| `dbus_g_proxy_new_for_name()` | `g_dbus_proxy_new_sync()` and `g_dbus_proxy_new_for_bus_sync()`, also see `g_dbus_proxy_new()` |
|
||||
| `dbus_g_proxy_add_signal()` | not needed, use the generic “g-signal” |
|
||||
| `dbus_g_proxy_connect_signal()` | use `g_signal_connect()` with “g-signal” |
|
||||
| `dbus_g_connection_register_g_object()` | `g_dbus_connection_register_object()` - also see `g_dbus_object_manager_server_export()` |
|
||||
| `dbus_g_connection_unregister_g_object()` | `g_dbus_connection_unregister_object()` - also see `g_dbus_object_manager_server_unexport()` |
|
||||
| `dbus_g_object_type_install_info()` | introspection data is installed while registering an object, see `g_dbus_connection_register_object()` |
|
||||
| `dbus_g_proxy_begin_call()` | `g_dbus_proxy_call()` |
|
||||
| `dbus_g_proxy_end_call()` | `g_dbus_proxy_call_finish()` |
|
||||
| `dbus_g_proxy_call()` | `g_dbus_proxy_call_sync()` |
|
||||
| `dbus_g_error_domain_register()` | `g_dbus_error_register_error_domain()` |
|
||||
| `dbus_g_error_has_name()` | no direct equivalent, see `g_dbus_error_get_remote_error()` |
|
||||
| `dbus_g_method_return()` | `g_dbus_method_invocation_return_value()` |
|
||||
| `dbus_g_method_return_error()` | `g_dbus_method_invocation_return_error()` and variants |
|
||||
| `dbus_g_method_get_sender()` | `g_dbus_method_invocation_get_sender()` |
|
||||
|
||||
## Owning bus names
|
||||
|
||||
Using dbus-glib, you typically call RequestName manually to own a name, like in the following excerpt:
|
||||
|
||||
```c
|
||||
error = NULL;
|
||||
res = dbus_g_proxy_call (system_bus_proxy,
|
||||
"RequestName",
|
||||
&error,
|
||||
G_TYPE_STRING, NAME_TO_CLAIM,
|
||||
G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_UINT, &result,
|
||||
G_TYPE_INVALID);
|
||||
if (!res)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
|
||||
dbus_g_proxy_add_signal (system_bus_proxy, "NameLost",
|
||||
G_TYPE_STRING, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost",
|
||||
G_CALLBACK (on_name_lost), NULL, NULL);
|
||||
|
||||
/* further setup ... */
|
||||
```
|
||||
|
||||
While you can do things this way with GDBus too, using
|
||||
`g_dbus_proxy_call_sync()`, it is much nicer to use the high-level API for
|
||||
this:
|
||||
|
||||
```c
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* further setup ... */
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
|
||||
NAME_TO_CLAIM,
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
```
|
||||
|
||||
Note that `g_bus_own_name()` works asynchronously and requires you to enter
|
||||
your mainloop to await the `on_name_aquired()` callback. Also note that in
|
||||
order to avoid race conditions (e.g. when your service is activated by a
|
||||
method call), you have to export your manager object before acquiring the
|
||||
name. The `on_bus_acquired()` callback is the right place to do such
|
||||
preparations.
|
||||
|
||||
## Creating proxies for well-known names
|
||||
|
||||
dbus-glib lets you create proxy objects for well-known names, like the following example:
|
||||
|
||||
```c
|
||||
proxy = dbus_g_proxy_new_for_name (system_bus_connection,
|
||||
"org.freedesktop.Accounts",
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts");
|
||||
```
|
||||
|
||||
For a DBusGProxy constructed like this, method calls will be sent to the current owner of the name, and that owner can change over time.
|
||||
|
||||
The same can be achieved with GDBusProxy:
|
||||
|
||||
```c
|
||||
error = NULL;
|
||||
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL, /* GDBusInterfaceInfo */
|
||||
"org.freedesktop.Accounts",
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts",
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
```
|
||||
|
||||
For an added layer of safety, you can specify what D-Bus interface the proxy
|
||||
is expected to conform to by using the GDBusInterfaceInfo type.
|
||||
Additionally, GDBusProxy loads, caches and tracks changes to the D-Bus
|
||||
properties on the remote object. It also sets up match rules so D-Bus
|
||||
signals from the remote object are delivered locally.
|
||||
|
||||
The GDBusProxy type normally isn't used directly - instead proxies
|
||||
subclassing GDBusProxy generated by `gdbus-codegen` is used, see the section
|
||||
called “Using gdbus-codegen”.
|
||||
|
||||
## Generating code and docs
|
||||
|
||||
### Using gdbus-codegen
|
||||
|
||||
dbus-glib comes with dbus-binding-tool, which can produce somewhat nice
|
||||
client- and server-side wrappers for a D-Bus interface. With GDBus,
|
||||
gdbus-codegen is used and like its counterpart, it also takes D-Bus
|
||||
Introspection XML as input:
|
||||
|
||||
#### Example D-Bus Introspection XML
|
||||
|
||||
```xml
|
||||
<node>
|
||||
<!-- org.gtk.GDBus.Example.ObjectManager.Animal:
|
||||
@short_description: Example docs generated by gdbus-codegen
|
||||
@since: 2.30
|
||||
|
||||
This D-Bus interface is used to describe a simple animal.
|
||||
-->
|
||||
<interface name="org.gtk.GDBus.Example.ObjectManager.Animal">
|
||||
<!-- Mood: The mood of the animal.
|
||||
@since: 2.30
|
||||
|
||||
Known values for this property include
|
||||
<literal>Happy</literal> and <literal>Sad</literal>. Use the
|
||||
org.gtk.GDBus.Example.ObjectManager.Animal.Poke() method to
|
||||
change this property.
|
||||
|
||||
This property influences how often the animal jumps up and
|
||||
down, see the
|
||||
#org.gtk.GDBus.Example.ObjectManager.Animal::Jumped signal
|
||||
for more details.
|
||||
-->
|
||||
<property name="Mood" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
Poke:
|
||||
@make_sad: Whether to make the animal sad.
|
||||
@make_happy: Whether to make the animal happy.
|
||||
@since: 2.30
|
||||
|
||||
Method used to changing the mood of the animal. See also the
|
||||
#org.gtk.GDBus.Example.ObjectManager.Animal:Mood property.
|
||||
-->
|
||||
<method name="Poke">
|
||||
<arg direction="in" type="b" name="make_sad"/>
|
||||
<arg direction="in" type="b" name="make_happy"/>
|
||||
</method>
|
||||
|
||||
<!--
|
||||
Jumped:
|
||||
@height: Height, in meters, that the animal jumped.
|
||||
@since: 2.30
|
||||
|
||||
Emitted when the animal decides to jump.
|
||||
-->
|
||||
<signal name="Jumped">
|
||||
<arg type="d" name="height"/>
|
||||
</signal>
|
||||
|
||||
<!--
|
||||
Foo:
|
||||
Property with no <quote>since</quote> annotation (should inherit the 2.30 from its containing interface).
|
||||
-->
|
||||
<property name="Foo" type="s" access="read"/>
|
||||
|
||||
<!--
|
||||
Bar:
|
||||
@since: 2.36
|
||||
Property with a later <quote>since</quote> annotation.
|
||||
-->
|
||||
<property name="Bar" type="s" access="read"/>
|
||||
</interface>
|
||||
|
||||
<!-- org.gtk.GDBus.Example.ObjectManager.Cat:
|
||||
@short_description: More example docs generated by gdbus-codegen
|
||||
|
||||
This D-Bus interface is used to describe a cat. Right now there
|
||||
are no properties, methods or signals associated with this
|
||||
interface so it is essentially a <ulink
|
||||
url="http://en.wikipedia.org/wiki/Marker_interface_pattern">Marker
|
||||
Interface</ulink>.
|
||||
|
||||
Note that D-Bus objects implementing this interface also
|
||||
implement the #org.gtk.GDBus.Example.ObjectManager.Animal
|
||||
interface.
|
||||
-->
|
||||
<interface name="org.gtk.GDBus.Example.ObjectManager.Cat">
|
||||
</interface>
|
||||
</node>
|
||||
```
|
||||
|
||||
If this XML is processed like this
|
||||
|
||||
```
|
||||
gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \
|
||||
--generate-c-code generated-code \
|
||||
--c-namespace Example \
|
||||
--c-generate-object-manager \
|
||||
--generate-docbook generated-docs \
|
||||
gdbus-example-objectmanager.xml
|
||||
```
|
||||
|
||||
then two files generated-code.h and generated-code.c are generated.
|
||||
Additionally, two XML files
|
||||
generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal and
|
||||
generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat with Docbook XML are
|
||||
generated.
|
||||
|
||||
While the contents of `generated-code.h` and `generated-code.c` are best described by the `gdbus-codegen` manual page, here's a brief example of how this generated code can be used:
|
||||
|
||||
```c
|
||||
#include "gdbus-object-manager-example/objectmanager-gen.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static GDBusObjectManagerServer *manager = NULL;
|
||||
|
||||
static gboolean
|
||||
on_animal_poke (ExampleAnimal *animal,
|
||||
GDBusMethodInvocation *invocation,
|
||||
gboolean make_sad,
|
||||
gboolean make_happy,
|
||||
gpointer user_data)
|
||||
{
|
||||
if ((make_sad && make_happy) || (!make_sad && !make_happy))
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.Examples.ObjectManager.Error.Failed",
|
||||
"Exactly one of make_sad or make_happy must be TRUE");
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (make_sad)
|
||||
{
|
||||
if (g_strcmp0 (example_animal_get_mood (animal), "Sad") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.Examples.ObjectManager.Error.SadAnimalIsSad",
|
||||
"Sad animal is already sad");
|
||||
goto out;
|
||||
}
|
||||
|
||||
example_animal_set_mood (animal, "Sad");
|
||||
example_animal_complete_poke (animal, invocation);
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (make_happy)
|
||||
{
|
||||
if (g_strcmp0 (example_animal_get_mood (animal), "Happy") == 0)
|
||||
{
|
||||
g_dbus_method_invocation_return_dbus_error (invocation,
|
||||
"org.gtk.GDBus.Examples.ObjectManager.Error.HappyAnimalIsHappy",
|
||||
"Happy animal is already happy");
|
||||
goto out;
|
||||
}
|
||||
|
||||
example_animal_set_mood (animal, "Happy");
|
||||
example_animal_complete_poke (animal, invocation);
|
||||
goto out;
|
||||
}
|
||||
|
||||
g_assert_not_reached ();
|
||||
|
||||
out:
|
||||
return G_DBUS_METHOD_INVOCATION_HANDLED;
|
||||
}
|
||||
|
||||
|
||||
static void
|
||||
on_bus_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
ExampleObjectSkeleton *object;
|
||||
guint n;
|
||||
|
||||
g_print ("Acquired a message bus connection\n");
|
||||
|
||||
/* Create a new org.freedesktop.DBus.ObjectManager rooted at /example/Animals */
|
||||
manager = g_dbus_object_manager_server_new ("/example/Animals");
|
||||
|
||||
for (n = 0; n < 10; n++)
|
||||
{
|
||||
gchar *s;
|
||||
ExampleAnimal *animal;
|
||||
|
||||
/* Create a new D-Bus object at the path /example/Animals/N where N is 000..009 */
|
||||
s = g_strdup_printf ("/example/Animals/%03d", n);
|
||||
object = example_object_skeleton_new (s);
|
||||
g_free (s);
|
||||
|
||||
/* Make the newly created object export the interface
|
||||
* org.gtk.GDBus.Example.ObjectManager.Animal (note
|
||||
* that @object takes its own reference to @animal).
|
||||
*/
|
||||
animal = example_animal_skeleton_new ();
|
||||
example_animal_set_mood (animal, "Happy");
|
||||
example_object_skeleton_set_animal (object, animal);
|
||||
g_object_unref (animal);
|
||||
|
||||
/* Cats are odd animals - so some of our objects implement the
|
||||
* org.gtk.GDBus.Example.ObjectManager.Cat interface in addition
|
||||
* to the .Animal interface
|
||||
*/
|
||||
if (n % 2 == 1)
|
||||
{
|
||||
ExampleCat *cat;
|
||||
cat = example_cat_skeleton_new ();
|
||||
example_object_skeleton_set_cat (object, cat);
|
||||
g_object_unref (cat);
|
||||
}
|
||||
|
||||
/* Handle Poke() D-Bus method invocations on the .Animal interface */
|
||||
g_signal_connect (animal,
|
||||
"handle-poke",
|
||||
G_CALLBACK (on_animal_poke),
|
||||
NULL); /* user_data */
|
||||
|
||||
/* Export the object (@manager takes its own reference to @object) */
|
||||
g_dbus_object_manager_server_export (manager, G_DBUS_OBJECT_SKELETON (object));
|
||||
g_object_unref (object);
|
||||
}
|
||||
|
||||
/* Export all objects */
|
||||
g_dbus_object_manager_server_set_connection (manager, connection);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Acquired the name %s\n", name);
|
||||
}
|
||||
|
||||
static void
|
||||
on_name_lost (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
g_print ("Lost the name %s\n", name);
|
||||
}
|
||||
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
GMainLoop *loop;
|
||||
guint id;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
id = g_bus_own_name (G_BUS_TYPE_SESSION,
|
||||
"org.gtk.GDBus.Examples.ObjectManager",
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT |
|
||||
G_BUS_NAME_OWNER_FLAGS_REPLACE,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
loop,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (id);
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
This, on the other hand, is a client-side application using generated code:
|
||||
|
||||
```c
|
||||
#include "gdbus-object-manager-example/objectmanager-gen.h"
|
||||
|
||||
/* ---------------------------------------------------------------------------------------------------- */
|
||||
|
||||
static void
|
||||
print_objects (GDBusObjectManager *manager)
|
||||
{
|
||||
GList *objects;
|
||||
GList *l;
|
||||
|
||||
g_print ("Object manager at %s\n", g_dbus_object_manager_get_object_path (manager));
|
||||
objects = g_dbus_object_manager_get_objects (manager);
|
||||
for (l = objects; l != NULL; l = l->next)
|
||||
{
|
||||
ExampleObject *object = EXAMPLE_OBJECT (l->data);
|
||||
GList *interfaces;
|
||||
GList *ll;
|
||||
g_print (" - Object at %s\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object)));
|
||||
|
||||
interfaces = g_dbus_object_get_interfaces (G_DBUS_OBJECT (object));
|
||||
for (ll = interfaces; ll != NULL; ll = ll->next)
|
||||
{
|
||||
GDBusInterface *interface = G_DBUS_INTERFACE (ll->data);
|
||||
g_print (" - Interface %s\n", g_dbus_interface_get_info (interface)->name);
|
||||
|
||||
/* Note that @interface is really a GDBusProxy instance - and additionally also
|
||||
* an ExampleAnimal or ExampleCat instance - either of these can be used to
|
||||
* invoke methods on the remote object. For example, the generated function
|
||||
*
|
||||
* void example_animal_call_poke_sync (ExampleAnimal *proxy,
|
||||
* gboolean make_sad,
|
||||
* gboolean make_happy,
|
||||
* GCancellable *cancellable,
|
||||
* GError **error);
|
||||
*
|
||||
* can be used to call the Poke() D-Bus method on the .Animal interface.
|
||||
* Additionally, the generated function
|
||||
*
|
||||
* const gchar *example_animal_get_mood (ExampleAnimal *object);
|
||||
*
|
||||
* can be used to get the value of the :Mood property.
|
||||
*/
|
||||
}
|
||||
g_list_free_full (interfaces, g_object_unref);
|
||||
}
|
||||
g_list_free_full (objects, g_object_unref);
|
||||
}
|
||||
|
||||
static void
|
||||
on_object_added (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar *owner;
|
||||
owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager));
|
||||
g_print ("Added object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner);
|
||||
g_free (owner);
|
||||
}
|
||||
|
||||
static void
|
||||
on_object_removed (GDBusObjectManager *manager,
|
||||
GDBusObject *object,
|
||||
gpointer user_data)
|
||||
{
|
||||
gchar *owner;
|
||||
owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager));
|
||||
g_print ("Removed object at %s (owner %s)\n", g_dbus_object_get_object_path (object), owner);
|
||||
g_free (owner);
|
||||
}
|
||||
|
||||
static void
|
||||
on_notify_name_owner (GObject *object,
|
||||
GParamSpec *pspec,
|
||||
gpointer user_data)
|
||||
{
|
||||
GDBusObjectManagerClient *manager = G_DBUS_OBJECT_MANAGER_CLIENT (object);
|
||||
gchar *name_owner;
|
||||
|
||||
name_owner = g_dbus_object_manager_client_get_name_owner (manager);
|
||||
g_print ("name-owner: %s\n", name_owner);
|
||||
g_free (name_owner);
|
||||
}
|
||||
|
||||
static void
|
||||
on_interface_proxy_properties_changed (GDBusObjectManagerClient *manager,
|
||||
GDBusObjectProxy *object_proxy,
|
||||
GDBusProxy *interface_proxy,
|
||||
GVariant *changed_properties,
|
||||
const gchar *const *invalidated_properties,
|
||||
gpointer user_data)
|
||||
{
|
||||
GVariantIter iter;
|
||||
const gchar *key;
|
||||
GVariant *value;
|
||||
gchar *s;
|
||||
|
||||
g_print ("Properties Changed on %s:\n", g_dbus_object_get_object_path (G_DBUS_OBJECT (object_proxy)));
|
||||
g_variant_iter_init (&iter, changed_properties);
|
||||
while (g_variant_iter_next (&iter, "{&sv}", &key, &value))
|
||||
{
|
||||
s = g_variant_print (value, TRUE);
|
||||
g_print (" %s -> %s\n", key, s);
|
||||
g_variant_unref (value);
|
||||
g_free (s);
|
||||
}
|
||||
}
|
||||
|
||||
gint
|
||||
main (gint argc, gchar *argv[])
|
||||
{
|
||||
GDBusObjectManager *manager;
|
||||
GMainLoop *loop;
|
||||
GError *error;
|
||||
gchar *name_owner;
|
||||
|
||||
manager = NULL;
|
||||
loop = NULL;
|
||||
|
||||
loop = g_main_loop_new (NULL, FALSE);
|
||||
|
||||
error = NULL;
|
||||
manager = example_object_manager_client_new_for_bus_sync (G_BUS_TYPE_SESSION,
|
||||
G_DBUS_OBJECT_MANAGER_CLIENT_FLAGS_NONE,
|
||||
"org.gtk.GDBus.Examples.ObjectManager",
|
||||
"/example/Animals",
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
if (manager == NULL)
|
||||
{
|
||||
g_printerr ("Error getting object manager client: %s", error->message);
|
||||
g_error_free (error);
|
||||
goto out;
|
||||
}
|
||||
|
||||
name_owner = g_dbus_object_manager_client_get_name_owner (G_DBUS_OBJECT_MANAGER_CLIENT (manager));
|
||||
g_print ("name-owner: %s\n", name_owner);
|
||||
g_free (name_owner);
|
||||
|
||||
print_objects (manager);
|
||||
|
||||
g_signal_connect (manager,
|
||||
"notify::name-owner",
|
||||
G_CALLBACK (on_notify_name_owner),
|
||||
NULL);
|
||||
g_signal_connect (manager,
|
||||
"object-added",
|
||||
G_CALLBACK (on_object_added),
|
||||
NULL);
|
||||
g_signal_connect (manager,
|
||||
"object-removed",
|
||||
G_CALLBACK (on_object_removed),
|
||||
NULL);
|
||||
g_signal_connect (manager,
|
||||
"interface-proxy-properties-changed",
|
||||
G_CALLBACK (on_interface_proxy_properties_changed),
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
out:
|
||||
if (manager != NULL)
|
||||
g_object_unref (manager);
|
||||
if (loop != NULL)
|
||||
g_main_loop_unref (loop);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
@ -1,310 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
<!ENTITY % local.common.attrib "xmlns:xi CDATA #FIXED 'http://www.w3.org/2003/XInclude'">
|
||||
<!ENTITY version SYSTEM "version.xml">
|
||||
]>
|
||||
<chapter>
|
||||
<title>Migrating to GDBus</title>
|
||||
|
||||
<section>
|
||||
<title>Conceptual differences</title>
|
||||
|
||||
<para>
|
||||
The central concepts of D-Bus are modelled in a very similar way
|
||||
in dbus-glib and GDBus. Both have objects representing connections,
|
||||
proxies and method invocations. But there are some important
|
||||
differences:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
dbus-glib uses the <ulink
|
||||
url="http://www.freedesktop.org/wiki/Software/dbus#ReferenceImplementation.28dbus-daemonandlibdbus.29">libdbus
|
||||
reference implementation</ulink>, GDBus doesn't. Instead, it
|
||||
relies on GIO streams as transport layer, and has its own
|
||||
implementation for the D-Bus connection setup and
|
||||
authentication. Apart from using streams as transport,
|
||||
avoiding libdbus also lets GDBus avoid some thorny
|
||||
multithreading issues.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
dbus-glib uses the GObject type system for method arguments and
|
||||
return values, including a homegrown container specialization
|
||||
mechanism. GDBus relies on the #GVariant type system which is
|
||||
explicitly designed to match D-Bus types.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
dbus-glib models only D-Bus interfaces and does not provide
|
||||
any types for objects. GDBus models both D-Bus interfaces
|
||||
(via the #GDBusInterface, #GDBusProxy and
|
||||
#GDBusInterfaceSkeleton types) and objects (via the
|
||||
#GDBusObject, #GDBusObjectSkeleton and #GDBusObjectProxy types).
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
GDBus includes native support for the <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-properties">org.freedesktop.DBus.Properties</ulink> (via the #GDBusProxy type) and <ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#standard-interfaces-objectmanager">org.freedesktop.DBus.ObjectManager</ulink> D-Bus interfaces, dbus-glib doesn't.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
The typical way to export an object in dbus-glib involves
|
||||
generating glue code from XML introspection data using
|
||||
<command>dbus-binding-tool</command>. GDBus provides a
|
||||
similar tool called <command><link
|
||||
linkend="gdbus-codegen">gdbus-codegen</link></command> that
|
||||
can also generate Docbook D-Bus interface documentation.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
dbus-glib doesn't provide any convenience API for owning and
|
||||
watching bus names, GDBus provides the g_bus_own_name() and
|
||||
g_bus_watch_name() family of convenience functions.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
GDBus provides API to parse, generate and work with <link
|
||||
linkend="gio-D-Bus-Introspection-Data">Introspection
|
||||
XML</link>, dbus-glib doesn't.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
GTestDBus provides API to create isolated unit tests <link
|
||||
linkend="gio-D-Bus-Test-Scaffolding">GDBus Test Scaffolding</link>.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>API comparison</title>
|
||||
|
||||
<table id="dbus-glib-vs-gdbus">
|
||||
<title>dbus-glib APIs and their GDBus counterparts</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>dbus-glib</entry><entry>GDBus</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>#DBusGConnection</entry><entry>#GDBusConnection</entry></row>
|
||||
<row><entry>#DBusGProxy</entry><entry>#GDBusProxy, #GDBusInterface - also see #GDBusObjectProxy</entry></row>
|
||||
<row><entry>#DBusGObject</entry><entry>#GDBusInterfaceSkeleton, #GDBusInterface - also see #GDBusObjectSkeleton</entry></row>
|
||||
<row><entry>#DBusGMethodInvocation</entry><entry>#GDBusMethodInvocation</entry></row>
|
||||
<row><entry>dbus_g_bus_get()</entry><entry>g_bus_get_sync(), also see
|
||||
g_bus_get()</entry></row>
|
||||
<row><entry>dbus_g_proxy_new_for_name()</entry><entry>g_dbus_proxy_new_sync() and
|
||||
g_dbus_proxy_new_for_bus_sync(), also see g_dbus_proxy_new()</entry></row>
|
||||
<row><entry>dbus_g_proxy_add_signal()</entry><entry>not needed, use the generic #GDBusProxy::g-signal</entry></row>
|
||||
<row><entry>dbus_g_proxy_connect_signal()</entry><entry>use g_signal_connect() with #GDBusProxy::g-signal</entry></row>
|
||||
<row><entry>dbus_g_connection_register_g_object()</entry><entry>g_dbus_connection_register_object() - also see g_dbus_object_manager_server_export()</entry></row>
|
||||
<row><entry>dbus_g_connection_unregister_g_object()</entry><entry>g_dbus_connection_unregister_object() - also see g_dbus_object_manager_server_unexport()</entry></row>
|
||||
<row><entry>dbus_g_object_type_install_info()</entry><entry>introspection data is installed while registering
|
||||
an object, see g_dbus_connection_register_object()</entry></row>
|
||||
<row><entry>dbus_g_proxy_begin_call()</entry><entry>g_dbus_proxy_call()</entry></row>
|
||||
<row><entry>dbus_g_proxy_end_call()</entry><entry>g_dbus_proxy_call_finish()</entry></row>
|
||||
<row><entry>dbus_g_proxy_call()</entry><entry>g_dbus_proxy_call_sync()</entry></row>
|
||||
<row><entry>dbus_g_error_domain_register()</entry><entry>g_dbus_error_register_error_domain()</entry></row>
|
||||
<row><entry>dbus_g_error_has_name()</entry><entry>no direct equivalent, see g_dbus_error_get_remote_error()</entry></row>
|
||||
<row><entry>dbus_g_method_return()</entry><entry>g_dbus_method_invocation_return_value()</entry></row>
|
||||
<row><entry>dbus_g_method_return_error()</entry><entry>g_dbus_method_invocation_return_error() and variants</entry></row>
|
||||
<row><entry>dbus_g_method_get_sender()</entry><entry>g_dbus_method_invocation_get_sender()</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Owning bus names</title>
|
||||
<para>
|
||||
Using dbus-glib, you typically call RequestName manually
|
||||
to own a name, like in the following excerpt:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
error = NULL;
|
||||
res = dbus_g_proxy_call (system_bus_proxy,
|
||||
"RequestName",
|
||||
&error,
|
||||
G_TYPE_STRING, NAME_TO_CLAIM,
|
||||
G_TYPE_UINT, DBUS_NAME_FLAG_ALLOW_REPLACEMENT,
|
||||
G_TYPE_INVALID,
|
||||
G_TYPE_UINT, &result,
|
||||
G_TYPE_INVALID);
|
||||
if (!res)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
goto out;
|
||||
}
|
||||
|
||||
if (result != DBUS_REQUEST_NAME_REPLY_PRIMARY_OWNER)
|
||||
{
|
||||
if (error != NULL)
|
||||
{
|
||||
g_warning ("Failed to acquire %s: %s",
|
||||
NAME_TO_CLAIM, error->message);
|
||||
g_error_free (error);
|
||||
}
|
||||
else
|
||||
{
|
||||
g_warning ("Failed to acquire %s", NAME_TO_CLAIM);
|
||||
}
|
||||
exit (1);
|
||||
}
|
||||
|
||||
dbus_g_proxy_add_signal (system_bus_proxy, "NameLost",
|
||||
G_TYPE_STRING, G_TYPE_INVALID);
|
||||
dbus_g_proxy_connect_signal (system_bus_proxy, "NameLost",
|
||||
G_CALLBACK (on_name_lost), NULL, NULL);
|
||||
|
||||
/* further setup ... */
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
</para>
|
||||
<para>
|
||||
While you can do things this way with GDBus too, using
|
||||
g_dbus_proxy_call_sync(), it is much nicer to use the high-level API
|
||||
for this:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
static void
|
||||
on_name_acquired (GDBusConnection *connection,
|
||||
const gchar *name,
|
||||
gpointer user_data)
|
||||
{
|
||||
/* further setup ... */
|
||||
}
|
||||
|
||||
/* ... */
|
||||
|
||||
owner_id = g_bus_own_name (G_BUS_TYPE_SYSTEM,
|
||||
NAME_TO_CLAIM,
|
||||
G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT,
|
||||
on_bus_acquired,
|
||||
on_name_acquired,
|
||||
on_name_lost,
|
||||
NULL,
|
||||
NULL);
|
||||
|
||||
g_main_loop_run (loop);
|
||||
|
||||
g_bus_unown_name (owner_id);
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
Note that g_bus_own_name() works asynchronously and requires
|
||||
you to enter your mainloop to await the on_name_aquired()
|
||||
callback. Also note that in order to avoid race conditions (e.g.
|
||||
when your service is activated by a method call), you have to export
|
||||
your manager object <emphasis>before</emphasis> acquiring the
|
||||
name. The on_bus_acquired() callback is the right place to do
|
||||
such preparations.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Creating proxies for well-known names</title>
|
||||
<para>
|
||||
dbus-glib lets you create proxy objects for well-known names, like the
|
||||
following example:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
proxy = dbus_g_proxy_new_for_name (system_bus_connection,
|
||||
"org.freedesktop.Accounts",
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts");
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
For a #DBusGProxy constructed like this, method calls will be sent to
|
||||
the current owner of the name, and that owner can change over time.
|
||||
</para>
|
||||
<para>
|
||||
The same can be achieved with #GDBusProxy:
|
||||
<informalexample><programlisting><![CDATA[
|
||||
error = NULL;
|
||||
proxy = g_dbus_proxy_new_for_bus_sync (G_BUS_TYPE_SYSTEM,
|
||||
G_DBUS_PROXY_FLAGS_NONE,
|
||||
NULL, /* GDBusInterfaceInfo */
|
||||
"org.freedesktop.Accounts",
|
||||
"/org/freedesktop/Accounts",
|
||||
"org.freedesktop.Accounts",
|
||||
NULL, /* GCancellable */
|
||||
&error);
|
||||
]]>
|
||||
</programlisting></informalexample>
|
||||
For an added layer of safety, you can specify what D-Bus
|
||||
interface the proxy is expected to conform to by using the
|
||||
#GDBusInterfaceInfo type. Additionally, #GDBusProxy loads,
|
||||
caches and tracks changes to the D-Bus properties on the remote
|
||||
object. It also sets up match rules so D-Bus signals from the
|
||||
remote object are delivered locally.
|
||||
</para>
|
||||
<para>
|
||||
The #GDBusProxy type normally isn't used directly - instead
|
||||
proxies subclassing #GDBusProxy generated by <command><link
|
||||
linkend="gdbus-codegen">gdbus-codegen</link></command> is used, see <xref linkend="gdbus-example-gdbus-codegen"/>
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Generating code and docs</title>
|
||||
|
||||
<section id="gdbus-example-gdbus-codegen">
|
||||
<title>Using gdbus-codegen</title>
|
||||
|
||||
<para>
|
||||
dbus-glib comes with <command>dbus-binding-tool</command>, which
|
||||
can produce somewhat nice client- and server-side wrappers for a D-Bus interface.
|
||||
With GDBus, <command><link
|
||||
linkend="gdbus-codegen">gdbus-codegen</link></command> is used and like
|
||||
its counterpart, it also takes D-Bus Introspection XML as input:
|
||||
</para>
|
||||
<example id="gdbus-example-codegen-input"><title>Example D-Bus Introspection XML</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-object-manager-example/gdbus-example-objectmanager.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager.xml</xi:fallback></xi:include></programlisting></example>
|
||||
<para>
|
||||
If this XML is processed like this
|
||||
<informalexample><programlisting><![CDATA[
|
||||
gdbus-codegen --interface-prefix org.gtk.GDBus.Example.ObjectManager. \
|
||||
--generate-c-code generated-code \
|
||||
--c-namespace Example \
|
||||
--c-generate-object-manager \
|
||||
--generate-docbook generated-docs \
|
||||
gdbus-example-objectmanager.xml
|
||||
]]></programlisting></informalexample>
|
||||
then two files <filename>generated-code.h</filename> and
|
||||
<filename>generated-code.c</filename> are
|
||||
generated. Additionally, two XML files
|
||||
<filename>generated-docs-org.gtk.GDBus.Example.ObjectManager.Animal</filename> and
|
||||
<filename>generated-docs-org.gtk.GDBus.Example.ObjectManager.Cat</filename>
|
||||
with Docbook XML are generated. For an example of what the docs look
|
||||
like see <link
|
||||
linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Animal">the Animal D-Bus interface documentation</link>.
|
||||
and
|
||||
<link
|
||||
linkend="gdbus-interface-org-gtk-GDBus-Example-ObjectManager-Cat">the Cat D-Bus interface documentation</link>.
|
||||
</para>
|
||||
<para>
|
||||
While the contents of <filename>generated-code.h</filename> and
|
||||
<filename>generated-code.c</filename> are best described by the
|
||||
<command><link
|
||||
linkend="gdbus-codegen">gdbus-codegen</link></command> manual
|
||||
page, brief examples of how this generated code can be used can be found in
|
||||
<xref linkend="gdbus-example-codegen-server"/>
|
||||
and <xref
|
||||
linkend="gdbus-example-codegen-client"/>. Additionally, since
|
||||
the generated code has 100% gtk-doc coverage, see
|
||||
#ExampleAnimal, #ExampleCat, #ExampleObject and
|
||||
#ExampleObjectManagerClient pages for documentation.
|
||||
</para>
|
||||
|
||||
<example id="gdbus-example-codegen-server"><title>Server-side application using generated code</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-example-objectmanager-server.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-server.c</xi:fallback></xi:include></programlisting></example>
|
||||
|
||||
<example id="gdbus-example-codegen-client"><title>Client-side application using generated code</title><programlisting><xi:include xmlns:xi="http://www.w3.org/2001/XInclude" parse="text" href="../../../../../gio/tests/gdbus-example-objectmanager-client.c"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: gdbus-example-objectmanager-client.c</xi:fallback></xi:include></programlisting></example>
|
||||
|
||||
</section>
|
||||
|
||||
<!-- All XInclude paths are relative to the html/ directory under the build root directory -->
|
||||
<xi:include href="../../../../gio/tests/gdbus-object-manager-example/objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Animal.xml</xi:fallback></xi:include>
|
||||
<xi:include href="../../../../gio/tests/gdbus-object-manager-example/objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: objectmanager-gen-org.gtk.GDBus.Example.ObjectManager.Cat.xml</xi:fallback></xi:include>
|
||||
<xi:include href="../gdbus-object-manager-example/xml/ExampleAnimal.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleAnimal.xml</xi:fallback></xi:include>
|
||||
<xi:include href="../gdbus-object-manager-example/xml/ExampleCat.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleCat.xml</xi:fallback></xi:include>
|
||||
<xi:include href="../gdbus-object-manager-example/xml/ExampleObject.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleObject.xml</xi:fallback></xi:include>
|
||||
<xi:include href="../gdbus-object-manager-example/xml/ExampleObjectManagerClient.xml"><xi:fallback>FIXME: MISSING XINCLUDE CONTENT: ExampleObjectManagerClient.xml</xi:fallback></xi:include>
|
||||
|
||||
</section>
|
||||
|
||||
</chapter>
|
109
docs/reference/gio/migrating-gnome-vfs.md
Normal file
109
docs/reference/gio/migrating-gnome-vfs.md
Normal file
@ -0,0 +1,109 @@
|
||||
Title: Migrating from GnomeVFS to GIO
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2010 Matthias Clasen
|
||||
|
||||
# Migrating from GnomeVFS to GIO
|
||||
|
||||
## Comparison of GnomeVFS and GIO concepts
|
||||
|
||||
| GnomeVFS | GIO |
|
||||
|----------|-----|
|
||||
| `GnomeVFSURI` | [iface@Gio.File] |
|
||||
| `GnomeVFSFileInfo` | [class@Gio.FileInfo] |
|
||||
| `GnomeVFSResult` | [struct@GLib.Error], with `G_IO_ERROR` values |
|
||||
| `GnomeVFSHandle` & `GnomeVFSAsyncHandle` | [class@Gio.InputStream] or [class@Gio.OutputStream] |
|
||||
| `GnomeVFSDirectoryHandle` | [class@Gio.FileEnumerator] |
|
||||
| MIME type | content type |
|
||||
| `GnomeVFSMonitor` | [class@Gio.FileMonitor] |
|
||||
| `GnomeVFSVolumeMonitor` | [class@Gio.VolumeMonitor] |
|
||||
| `GnomeVFSVolume` | [iface@Gio.Mount] |
|
||||
| `GnomeVFSDrive` | [iface@Gio.Volume] |
|
||||
| - | [iface@Gio.Drive] |
|
||||
| `GnomeVFSContext` | [class@Gio.Cancellable] |
|
||||
| `gnome_vfs_async_cancel()` | [method@Gio.Cancellable.cancel] |
|
||||
|
||||
## Trash handling
|
||||
|
||||
The handling of trashed files has been changed in GIO, compared to
|
||||
gnome-vfs. gnome-vfs has a home-grown trash implementation that predates the
|
||||
freedesktop.org [Desktop Trash
|
||||
Can](http://www.freedesktop.org/wiki/Specifications/trash-spec)
|
||||
specification that is implemented in GIO. The location for storing trashed
|
||||
files has changed from `$HOME/.Trash` to `$HOME/.local/share/Trash` (or more
|
||||
correctly `$XDG_DATA_HOME/Trash`), which means that there is a need for
|
||||
migrating files that have been trashed by gnome-vfs to the new location.
|
||||
|
||||
In gnome-vfs, the `trash://` scheme offering a merged view of all trash
|
||||
directories was implemented in Nautilus, and trash-handling applications had
|
||||
to find and monitor all trash directories themselves. With GIO, the
|
||||
`trash://` implementation has been moved to gvfs and applications can simply
|
||||
monitor that location:
|
||||
|
||||
```c
|
||||
static void
|
||||
file_changed (GFileMonitor *file_monitor,
|
||||
GFile *child,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
switch (event_type)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
g_print ("'%s' removed from trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
g_print ("'%s' added to trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_monitoring_trash (void)
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
|
||||
file = g_file_new_for_uri ("trash://");
|
||||
monitor = g_file_monitor_directory (file, 0, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL);
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
GIO exposes some useful metadata about trashed files. There are
|
||||
`trash::orig-path` and `trash::deletion-date` attributes. The
|
||||
`standard::icon` attribute of the `trash://` itself provides a suitable icon
|
||||
for displaying the trash can on the desktop. If you are using this icon,
|
||||
make sure to monitor this attribute for changes, since the icon may be
|
||||
updated to reflect that state of the trash can.
|
||||
|
||||
Moving a file to the trash is much simpler with GIO. Instead of using
|
||||
`gnome_vfs_find_directory()` with `GNOME_VFS_DIRECTORY_KIND_TRASH` to find
|
||||
out where to move the trashed file, just use the [`method@Gio.File.trash`]
|
||||
method.
|
||||
|
||||
## Operations on multiple files
|
||||
|
||||
gnome-vfs has the dreaded `gnome_vfs_xfer_uri_list()` function which has
|
||||
tons of options and offers the equivalent of `cp`, `mv`, `ln`, `mkdir` and
|
||||
`rm` at the same time.
|
||||
|
||||
GIO offers a much simpler asynchronous task functionality instead, that lets
|
||||
you schedule a function to be called in a separate thread, making sure that
|
||||
updates are scheduled within the main context that created the task, so you
|
||||
can update your user interface. See: [`class@Gio.Task`].
|
||||
|
||||
## Mime monitoring
|
||||
|
||||
gnome-vfs offered a way to monitor the association between mime types and
|
||||
default handlers for changes, with the `GnomeVFSMIMEMonitor` object. GIO
|
||||
does not offer a replacement for this functionality at this time, since we
|
||||
have not found a compelling use case where `GnomeVFSMIMEMonitor` was used.
|
||||
If you think you have such a use case, please [open an issue on the GLib
|
||||
issue tracker](https://gitlab.gnome.org/GNOME/glib/issues/new).
|
@ -1,133 +0,0 @@
|
||||
<chapter>
|
||||
<title>Migrating from GnomeVFS to GIO</title>
|
||||
|
||||
<table id="gnome-vfs-vs-gio">
|
||||
<title>Comparison of GnomeVFS and GIO concepts</title>
|
||||
<tgroup cols="2">
|
||||
<thead>
|
||||
<row><entry>GnomeVFS</entry><entry>GIO</entry></row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row><entry>GnomeVFSURI</entry><entry>GFile</entry></row>
|
||||
<row><entry>GnomeVFSFileInfo</entry><entry>GFileInfo</entry></row>
|
||||
<row><entry>GnomeVFSResult</entry><entry>GError, with G_IO_ERROR values</entry></row>
|
||||
<row><entry>GnomeVFSHandle & GnomeVFSAsyncHandle</entry><entry>GInputStream or GOutputStream</entry></row>
|
||||
<row><entry>GnomeVFSDirectoryHandle</entry><entry>GFileEnumerator</entry></row>
|
||||
<row><entry>mime type</entry><entry>content type</entry></row>
|
||||
<row><entry>GnomeVFSMonitor</entry><entry>GFileMonitor</entry></row>
|
||||
<row><entry>GnomeVFSVolumeMonitor</entry><entry>GVolumeMonitor</entry></row>
|
||||
<row><entry>GnomeVFSVolume</entry><entry>GMount</entry></row>
|
||||
<row><entry>GnomeVFSDrive</entry><entry>GVolume</entry></row>
|
||||
<row><entry>-</entry><entry>GDrive</entry></row>
|
||||
<row><entry>GnomeVFSContext</entry><entry>GCancellable</entry></row>
|
||||
<row><entry>gnome_vfs_async_cancel</entry><entry>g_cancellable_cancel</entry></row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
|
||||
<section>
|
||||
<title>Trash handling</title>
|
||||
|
||||
<para>
|
||||
The handling of trashed files has been changed in GIO, compared
|
||||
to gnome-vfs. gnome-vfs has a home-grown trash implementation that
|
||||
predates the freedesktop.org <ulink url="http://www.freedesktop.org/wiki/Specifications/trash-spec">Desktop Trash Can</ulink> specification
|
||||
that is implemented in GIO. The location for storing trashed files
|
||||
has changed from <filename>$HOME/.Trash</filename> to
|
||||
<filename>$HOME/.local/share/Trash</filename> (or more correctly
|
||||
<filename>$XDG_DATA_HOME/Trash</filename>), which means that
|
||||
there is a need for migrating files that have been trashed by
|
||||
gnome-vfs to the new location.
|
||||
</para>
|
||||
<para>
|
||||
In gnome-vfs, the <filename>trash://</filename> scheme offering a
|
||||
merged view of all trash directories was implemented in nautilus,
|
||||
and trash-handling applications had to find and monitor all trash
|
||||
directories themselves. With GIO, the <filename>trash://</filename>
|
||||
implementation has been moved to gvfs and applications can simply
|
||||
monitor that location:
|
||||
</para>
|
||||
<informalexample><programlisting>
|
||||
static void
|
||||
file_changed (GFileMonitor *file_monitor,
|
||||
GFile *child,
|
||||
GFile *other_file,
|
||||
GFileMonitorEvent event_type,
|
||||
gpointer user_data)
|
||||
{
|
||||
switch (event_type)
|
||||
{
|
||||
case G_FILE_MONITOR_EVENT_DELETED:
|
||||
g_print ("'%s' removed from trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
case G_FILE_MONITOR_EVENT_CREATED:
|
||||
g_print ("'%s' added to trash\n", g_file_get_basename (child));
|
||||
break;
|
||||
default: ;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
start_monitoring_trash (void)
|
||||
{
|
||||
GFile *file;
|
||||
GFileMonitor *monitor;
|
||||
|
||||
file = g_file_new_for_uri ("trash://");
|
||||
monitor = g_file_monitor_directory (file, 0, NULL, NULL);
|
||||
g_object_unref (file);
|
||||
|
||||
g_signal_connect (monitor, "changed", G_CALLBACK (file_changed), NULL);
|
||||
|
||||
/* ... */
|
||||
|
||||
}
|
||||
</programlisting></informalexample>
|
||||
<para>
|
||||
GIO exposes some useful metadata about trashed files. There are
|
||||
trash::orig-path and trash::deletion-date attributes. The
|
||||
standard::icon attribute of the <filename>trash://</filename>
|
||||
itself provides a suitable icon for displaying the trash can on
|
||||
the desktop. If you are using this icon, make sure to monitor
|
||||
this attribute for changes, since the icon may be updated to
|
||||
reflect that state of the trash can.
|
||||
</para>
|
||||
<para>
|
||||
Moving a file to the trash is much simpler with GIO. Instead of
|
||||
using gnome_vfs_find_directory() with %GNOME_VFS_DIRECTORY_KIND_TRASH
|
||||
to find out where to move the trashed file, just use the g_file_trash()
|
||||
function.
|
||||
</para>
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Operations on multiple files</title>
|
||||
|
||||
<para>
|
||||
gnome-vfs has the dreaded gnome_vfs_xfer_uri_list() function which
|
||||
has tons of options and offers the equivalent of cp, mv, ln, mkdir
|
||||
and rm at the same time.
|
||||
</para>
|
||||
<para>
|
||||
GIO offers a much simpler I/O scheduler functionality instead, that
|
||||
lets you schedule a function to be called in a separate thread, or
|
||||
if threads are not available, as an idle in the mainloop.
|
||||
See g_io_scheduler_push_job().
|
||||
</para>
|
||||
|
||||
</section>
|
||||
|
||||
<section>
|
||||
<title>Mime monitoring</title>
|
||||
|
||||
<para>
|
||||
gnome-vfs offered a way to monitor the association between mime types
|
||||
and default handlers for changes, with the #GnomeVFSMIMEMonitor object.
|
||||
GIO does not offer a replacement for this functionality at this time,
|
||||
since we have not found a compelling use case where
|
||||
#GnomeVFSMIMEMonitor was used. If you think you have such a use
|
||||
case, please report it at
|
||||
<ulink url="https://gitlab.gnome.org/GNOME/glib/issues/new">https://gitlab.gnome.org/GNOME/glib/issues/new</ulink>.
|
||||
</para>
|
||||
</section>
|
||||
</chapter>
|
406
docs/reference/gio/overview.md
Normal file
406
docs/reference/gio/overview.md
Normal file
@ -0,0 +1,406 @@
|
||||
Title: Overview
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2007, 2008, 2010, 2011, 2012, 2013 Matthias Clasen
|
||||
SPDX-FileCopyrightText: 2007, 2009 Alexander Larsson
|
||||
SPDX-FileCopyrightText: 2008 A. Walton
|
||||
SPDX-FileCopyrightText: 2010 David Zeuthen
|
||||
SPDX-FileCopyrightText: 2013 Stef Walter
|
||||
SPDX-FileCopyrightText: 2015 Collabora, Ltd.
|
||||
SPDX-FileCopyrightText: 2016 Colin Walters
|
||||
SPDX-FileCopyrightText: 2020 Wouter Bolsterlee
|
||||
SPDX-FileCopyrightText: 2022 Endless OS Foundation, LLC
|
||||
|
||||
# Overview
|
||||
|
||||
GIO is striving to provide a modern, easy-to-use VFS API that sits at the
|
||||
right level in the library stack, as well as other generally useful APIs
|
||||
for desktop applications (such as networking and D-Bus support). The goal
|
||||
is to overcome the shortcomings of GnomeVFS and provide an API that is so
|
||||
good that developers prefer it over raw POSIX calls. Among other things
|
||||
that means using GObject. It also means not cloning the POSIX API, but
|
||||
providing higher-level, document-centric interfaces.
|
||||
|
||||
The abstract file system model of GIO consists of a number of interfaces and
|
||||
base classes for I/O and files:
|
||||
|
||||
[iface@Gio.File]
|
||||
: reference to a file
|
||||
|
||||
[class@Gio.FileInfo]
|
||||
: information about a file or filesystem
|
||||
|
||||
[class@Gio.FileEnumerator]
|
||||
: list files in directories
|
||||
|
||||
[iface@Gio.Drive]
|
||||
: represents a drive
|
||||
|
||||
[iface@Gio.Volume]
|
||||
: represents a file system in an abstract way
|
||||
|
||||
[iface@Gio.Mount]
|
||||
: represents a mounted file system
|
||||
|
||||
Then there is a number of stream classes, similar to the input and output
|
||||
stream hierarchies that can be found in frameworks like Java:
|
||||
|
||||
[class@Gio.InputStream]
|
||||
: read data
|
||||
|
||||
[class@Gio.OutputStream]
|
||||
: write data
|
||||
|
||||
[class@Gio.IOStream]
|
||||
: read and write data
|
||||
|
||||
[iface@Gio.Seekable]
|
||||
: interface optionally implemented by streams to support seeking
|
||||
|
||||
There are interfaces related to applications and the types of files they
|
||||
handle:
|
||||
|
||||
[iface@Gio.AppInfo]
|
||||
: information about an installed application
|
||||
|
||||
[iface@Gio.Icon]
|
||||
: abstract type for file and application icons
|
||||
|
||||
There is a framework for storing and retrieving application settings:
|
||||
|
||||
[class@Gio.Settings]
|
||||
: stores and retrieves application settings
|
||||
|
||||
There is support for network programming, including connectivity monitoring,
|
||||
name resolution, lowlevel socket APIs and highlevel client and server helper
|
||||
classes:
|
||||
|
||||
[class@Gio.Socket]
|
||||
: lowlevel platform independent socket object
|
||||
|
||||
[class@Gio.Resolver]
|
||||
: asynchronous and cancellable DNS resolver
|
||||
|
||||
[class@Gio.SocketClient]
|
||||
: high-level network client helper
|
||||
|
||||
[class@Gio.SocketService]
|
||||
: high-level network server helper
|
||||
|
||||
[class@Gio.SocketConnection]
|
||||
: network connection stream
|
||||
|
||||
[iface@Gio.NetworkMonitor]
|
||||
: network connectivity monitoring
|
||||
|
||||
There is support for connecting to
|
||||
[D-Bus](https://www.freedesktop.org/wiki/Software/dbus/), sending and receiving
|
||||
messages, owning and watching bus names, and making objects available on the bus:
|
||||
|
||||
[class@Gio.DBusConnection]
|
||||
: a D-Bus connection
|
||||
|
||||
[class@Gio.DBusMethodInvocation]
|
||||
: for handling remote calls
|
||||
|
||||
[class@Gio.DBusServer]
|
||||
: helper for accepting connections
|
||||
|
||||
[class@Gio.DBusProxy]
|
||||
: proxy to access D-Bus interfaces on a remote object
|
||||
|
||||
Beyond these, GIO provides facilities for file monitoring, asynchronous I/O
|
||||
and filename completion. In addition to the interfaces, GIO provides
|
||||
implementations for the local case. Implementations for various network file
|
||||
systems are provided by the GVFS package as loadable modules.
|
||||
|
||||
Other design choices which consciously break with the GnomeVFS design are to
|
||||
move backends out-of-process, which minimizes the dependency bloat and makes
|
||||
the whole system more robust. The backends are not included in GIO, but in
|
||||
the separate GVFS package. The GVFS package also contains the GVFS daemon,
|
||||
which spawn further mount daemons for each individual connection.
|
||||
|
||||
![GIO in the GTK library stack](./gvfs-overview.png)
|
||||
|
||||
The GIO model of I/O is stateful: if an application establishes e.g. a SFTP
|
||||
connection to a server, it becomes available to all applications in the
|
||||
session; the user does not have to enter his password over and over again.
|
||||
|
||||
One of the big advantages of putting the VFS in the GLib layer is that GTK
|
||||
can directly use it, e.g. in the filechooser.
|
||||
|
||||
## Writing GIO applications
|
||||
|
||||
The information in the GLib documentation about writing GLib applications is
|
||||
generally applicable when writing GIO applications.
|
||||
|
||||
### Threads
|
||||
|
||||
GDBus has its own private worker thread, so applications using GDBus have at
|
||||
least 3 threads. GIO makes heavy use of the concept of a thread-default main
|
||||
context to execute callbacks of asynchronous methods in the same context in
|
||||
which the operation was started.
|
||||
|
||||
### Asynchronous Programming
|
||||
|
||||
Many GIO functions come in two versions: synchronous and asynchronous,
|
||||
denoted by an `_async` suffix. It is important to use these appropriately:
|
||||
synchronous calls should not be used from within a main loop which is shared
|
||||
with other code, such as one in the application’s main thread. Synchronous
|
||||
calls block until they complete, and I/O operations can take noticeable
|
||||
amounts of time (even on ‘fast’ SSDs). Blocking a main loop iteration while
|
||||
waiting for I/O means that other sources in the main loop will not be
|
||||
dispatched, such as input and redraw handlers for the application’s UI. This
|
||||
can cause the application to ‘freeze’ until I/O completes.
|
||||
|
||||
A few self-contained groups of functions, such as code generated by
|
||||
gdbus-codegen, use a different convention: functions are asynchronous
|
||||
default, and it is the synchronous version which has a `_sync` suffix. Aside
|
||||
from naming differences, they should be treated the same way as functions
|
||||
following the normal convention above.
|
||||
|
||||
The asynchronous (`_async`) versions of functions return control to the
|
||||
caller immediately, after scheduling the I/O in the kernel and adding a
|
||||
callback for it to the main loop. This callback will be invoked when the
|
||||
operation has completed. From the callback, the paired `_finish` function
|
||||
should be called to retrieve the return value of the I/O operation, and any
|
||||
errors which occurred. For more information on using and implementing
|
||||
asynchronous functions, see [iface@Gio.AsyncResult] and [class@Gio.Task].
|
||||
|
||||
By starting multiple asynchronous operations in succession, they will be
|
||||
executed in parallel (up to an arbitrary limit imposed by GIO’s internal
|
||||
worker thread pool).
|
||||
|
||||
The synchronous versions of functions can be used early in application
|
||||
startup when there is no main loop to block, for example to load initial
|
||||
configuration files. They can also be used for I/O on files which are
|
||||
guaranteed to be small and on the local disk. Note that the user’s home
|
||||
directory is not guaranteed to be on the local disk. Security
|
||||
|
||||
When your program needs to carry out some privileged operation (say, create
|
||||
a new user account), there are various ways in which you can go about this:
|
||||
|
||||
- Implement a daemon that offers the privileged operation. A convenient way
|
||||
to do this is as a D-Bus system-bus service. The daemon will probably need
|
||||
ways to check the identity and authorization of the caller before
|
||||
executing the operation.
|
||||
[polkit](https://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html)
|
||||
is a framework that allows this.
|
||||
- Use a small helper that is executed with elevated privileges via pkexec.
|
||||
[`pkexec`](https://www.freedesktop.org/software/polkit/docs/latest/pkexec.1.html)
|
||||
is a small program launcher that is part of polkit.
|
||||
- Use a small helper that is executed with elevated privileges by being suid
|
||||
root.
|
||||
|
||||
None of these approaches is the clear winner, they all have their advantages
|
||||
and disadvantages.
|
||||
|
||||
When writing code that runs with elevated privileges, it is important to
|
||||
follow some basic rules of secure programming. David Wheeler has an
|
||||
excellent book on this topic,
|
||||
[Secure Programming for Linux and Unix HOWTO](https://dwheeler.com/secure-programs/Secure-Programs-HOWTO/index.html).
|
||||
|
||||
When using GIO in code that runs with elevated privileges, you have to be
|
||||
careful. GIO has extension points whose implementations get loaded from
|
||||
modules (executable code in shared objects), which could allow an attacker
|
||||
to sneak his own code into your application by tricking it into loading the
|
||||
code as a module. However, GIO will never load modules from your home
|
||||
directory except when explicitly asked to do so via an environment variable.
|
||||
|
||||
In most cases, your helper program should be so small that you don't need
|
||||
GIO, whose APIs are largely designed to support full-blown desktop
|
||||
applications. If you can't resist the convenience of these APIs, here are
|
||||
some steps you should take:
|
||||
|
||||
- Clear the environment, e.g. using the `clearenv()` function. David Wheeler
|
||||
has a good
|
||||
[explanation](https://dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html)
|
||||
for why it is important to sanitize the environment. See the section on
|
||||
running GIO applications for a list of all environment variables affecting
|
||||
GIO. In particular, `PATH` (used to locate binaries), `GIO_EXTRA_MODULES`
|
||||
(used to locate loadable modules) and `DBUS_{SYSTEM,SESSION}_BUS_ADDRESS`
|
||||
(used to locate the D-Bus system and session bus) are important.
|
||||
- Don't use GVfs, by setting `GIO_USE_VFS=local` in the environment. The
|
||||
reason to avoid GVfs in security-sensitive programs is that it uses many
|
||||
libraries which have not necessarily been audited for security problems.
|
||||
Gvfs is also heavily distributed and relies on a session bus to be
|
||||
present.
|
||||
|
||||
## Compiling GIO applications
|
||||
|
||||
GIO comes with a `gio-2.0.pc` file that you should use together with
|
||||
pkg-config to obtain the necessary information about header files and
|
||||
libraries. See the pkg-config man page or the GLib documentation for more
|
||||
information on how to use pkg-config to compile your application.
|
||||
|
||||
If you are using GIO on UNIX-like systems, you may want to use UNIX-specific
|
||||
GIO interfaces such as `GUnixInputStream`, `GUnixOutputStream`, `GUnixMount`
|
||||
or `GDesktopAppInfo`. To do so, use the `gio-unix-2.0.pc` file instead of
|
||||
`gio-2.0.pc`.
|
||||
|
||||
## Running GIO applications
|
||||
|
||||
GIO inspects a few environment variables in addition to the ones used by GLib.
|
||||
|
||||
- `XDG_DATA_HOME`, `XDG_DATA_DIRS`. GIO uses these environment variables to
|
||||
locate MIME information. For more information, see the
|
||||
[Shared MIME-info Database](https://specifications.freedesktop.org/shared-mime-info-spec/latest/)
|
||||
and the [Base Directory Specification](https://specifications.freedesktop.org/basedir-spec/latest/).
|
||||
- `GVFS_DISABLE_FUSE`. This variable can be set to keep Gvfs from starting
|
||||
the fuse backend, which may be unwanted or unnecessary in certain
|
||||
situations.
|
||||
- `GIO_USE_VFS`. This environment variable can be set to the name of a GVfs
|
||||
implementation to override the default for debugging purposes. The GVfs
|
||||
implementation for local files that is included in GIO has the name
|
||||
"local", the implementation in the gvfs module has the name "gvfs". Most
|
||||
commonly, system software will set this to "local" to avoid having `GFile`
|
||||
APIs perform unnecessary D-Bus calls. The special value help can be used
|
||||
to print a list of available implementations to standard output.
|
||||
|
||||
The following environment variables are only useful for debugging GIO itself
|
||||
or modules that it loads. They should not be set in a production
|
||||
environment.
|
||||
|
||||
- `GIO_USE_FILE_MONITOR`. This variable can be set to the name of a
|
||||
GFileMonitor implementation to override the default for debugging
|
||||
purposes. The GFileMonitor implementation for local files that is included
|
||||
in GIO on Linux has the name "inotify", others that are built are built as
|
||||
modules (depending on the platform) are called "fam" and "fen". The
|
||||
special value help can be used to print a list of available
|
||||
implementations to standard output.
|
||||
- `GIO_USE_VOLUME_MONITOR`. This variable can be set to the name of a
|
||||
GVolumeMonitor implementation to override the default for debugging
|
||||
purposes. The GVolumeMonitor implementation for local files that is
|
||||
included in GIO has the name "unix", the udisks2-based implementation in
|
||||
the gvfs module has the name "udisks2". The special value help can be used
|
||||
to print a list of available implementations to standard output.
|
||||
- `GIO_USE_TLS`. This variable can be set to the name of a GTlsBackend
|
||||
implementation to override the default for debugging purposes. GIO does
|
||||
not include a GTlsBackend implementation, the gnutls-based implementation
|
||||
in the glib-networking module has the name "gnutls". The special value
|
||||
help can be used to print a list of available implementations to standard
|
||||
output.
|
||||
- `GIO_USE_PORTALS`. This variable can be set to override detection of portals
|
||||
and force them to be used to provide various bits of GIO functionality, for
|
||||
testing and debugging. This variable is not intended to be used in production.
|
||||
- `GIO_MODULE_DIR`. When this environment variable is set to a path, GIO
|
||||
will load modules from this alternate directory instead of the directory
|
||||
built into GIO. This is useful when running tests, for example. This
|
||||
environment variable is ignored when running in a setuid program.
|
||||
- `GIO_EXTRA_MODULES`. When this environment variable is set to a path, or
|
||||
a set of paths separated by a colon, GIO will attempt to load additional
|
||||
modules from within the path. This environment variable is ignored when
|
||||
running in a setuid program.
|
||||
- `GSETTINGS_BACKEND`. This variable can be set to the name of a
|
||||
GSettingsBackend implementation to override the default for debugging
|
||||
purposes. The memory-based implementation that is included in GIO has the
|
||||
name "memory", the one in dconf has the name "dconf". The special value
|
||||
help can be used to print a list of available implementations to standard
|
||||
output.
|
||||
- `GSETTINGS_SCHEMA_DIR`. This variable can be set to the names of
|
||||
directories to consider when looking for compiled schemas for GSettings,
|
||||
in addition to the `glib-2.0/schemas` subdirectories of the XDG system
|
||||
data dirs. To specify multiple directories, use `G_SEARCHPATH_SEPARATOR_S`
|
||||
as a separator.
|
||||
- `DBUS_SYSTEM_BUS_ADDRESS`. This variable is consulted to find the address
|
||||
of the D-Bus system bus. For the format of D-Bus addresses, see the
|
||||
[D-Bus specification](https://dbus.freedesktop.org/doc/dbus-specification.html#addresses).
|
||||
Setting this variable overrides platform-specific ways of determining the
|
||||
system bus address.
|
||||
- `DBUS_SESSION_BUS_ADDRESS`. This variable is consulted to find the
|
||||
address of the D-Bus session bus. Setting this variable overrides
|
||||
platform-specific ways of determining the session bus address.
|
||||
- `DBUS_STARTER_BUS_TYPE`. This variable is consulted to find out the
|
||||
'starter' bus for an application that has been started via D-Bus
|
||||
activation. The possible values are 'system' or 'session'.
|
||||
- `G_DBUS_DEBUG`. This variable can be set to a list of debug options,
|
||||
which cause GLib to print out different types of debugging information
|
||||
when using the D-Bus routines.
|
||||
- `transport`: Show IO activity (e.g. reads and writes)
|
||||
- `message`: Show all sent and received D-Bus messages
|
||||
- `payload`: Show payload for all sent and received D-Bus messages (implies
|
||||
message)
|
||||
- `call`: Trace `g_dbus_connection_call()` and
|
||||
`g_dbus_connection_call_sync()` API usage
|
||||
- `signal`: Show when a D-Bus signal is received
|
||||
- `incoming`: Show when an incoming D-Bus method call is received
|
||||
- `return`: Show when a reply is returned via the GDBusMethodInvocation API
|
||||
- `emission`: Trace `g_dbus_connection_emit_signal()` API usage
|
||||
- `authentication`: Show information about connection authentication
|
||||
- `address`: Show information about D-Bus address lookups and autolaunching
|
||||
- `all`: Turn on all debug options
|
||||
- `help`: Print a list of supported options to the standard output
|
||||
- `G_DBUS_COOKIE_SHA1_KEYRING_DIR`. Can be used to override the directory
|
||||
used to store the keyring used in the `DBUS_COOKIE_SHA1` authentication
|
||||
mechanism. Normally the directory used is `.dbus-keyrings` in the user's
|
||||
home directory.
|
||||
- `G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION`. If set, the
|
||||
permissions of the directory used to store the keyring used in the
|
||||
`DBUS_COOKIE_SHA1` authentication mechanism won't be checked. Normally the
|
||||
directory must be readable only by the user.
|
||||
|
||||
## Extending GIO
|
||||
|
||||
A lot of the functionality that is accessible through GIO is implemented in
|
||||
loadable modules, and modules provide a convenient way to extend GIO. In
|
||||
addition to the [`class@Gio.IOModule`] API which supports writing such modules, GIO has a
|
||||
mechanism to define extension points, and register implementations thereof,
|
||||
see [`struct@Gio.IOExtensionPoint`].
|
||||
|
||||
The following extension points are currently defined by GIO:
|
||||
|
||||
- `G_VFS_EXTENSION_POINT_NAME`. Allows to override the functionality of the
|
||||
GVfs class. Implementations of this extension point must be derived from
|
||||
GVfs. GIO uses the implementation with the highest priority that is
|
||||
active, see `g_vfs_is_active()`. GIO implements this extension point for
|
||||
local files, gvfs contains an implementation that supports all the
|
||||
backends in gvfs.
|
||||
- `G_VOLUME_MONITOR_EXTENSION_POINT_NAME`. Allows to add more volume
|
||||
monitors. Implementations of this extension point must be derived from
|
||||
GVolumeMonitor. GIO uses all registered extensions. gvfs contains an
|
||||
implementation that works together with the GVfs implementation in gvfs.
|
||||
- `G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME`. Allows to override the
|
||||
'native' volume monitor. Implementations of this extension point must be
|
||||
derived from GNativeVolumeMonitor. GIO uses the implementation with the
|
||||
highest priority that is supported, as determined by the `is_supported()`
|
||||
vfunc in GVolumeMonitorClass. GIO implements this extension point for
|
||||
local mounts, gvfs contains a udisks2-based implementation.
|
||||
- `G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME`. Allows to override the file
|
||||
monitor implementation for local files. Implementations of this extension
|
||||
point must be derived from GLocalFileMonitor. GIO uses the implementation
|
||||
with the highest priority that is supported, as determined by the
|
||||
`is_supported()` vfunc in GLocalFileMonitorClass. GIO uses this extension
|
||||
point internally, to switch between its fam-based and inotify-based file
|
||||
monitoring implementations.
|
||||
- `G_LOCAL_DIRECTORY_MONITOR_EXTENSION_POINT_NAME`. Allows to override the
|
||||
directory monitor implementation for local files. Implementations of this
|
||||
extension point must be derived from GLocalDirectoryMonitor. GIO uses the
|
||||
implementation with the highest priority that is supported, as determined
|
||||
by the `is_supported()` vfunc in GLocalDirectoryMonitorClass. GIO uses
|
||||
this extension point internally, to switch between its fam-based and
|
||||
inotify-based directory monitoring implementations.
|
||||
- `G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME`. Unix-only. Allows to
|
||||
provide a way to associate default handlers with URI schemes.
|
||||
Implementations of this extension point must implement the
|
||||
GDesktopAppInfoLookup interface. GIO uses the implementation with the
|
||||
highest priority. This extension point has been discontinued in GLib 2.28.
|
||||
It is still available to keep API and ABI stability, but GIO is no longer
|
||||
using it for default handlers. Instead, the mime handler mechanism is
|
||||
used, together with x-scheme-handler pseudo-mimetypes.
|
||||
- `G_SETTINGS_BACKEND_EXTENSION_POINT_NAME`. Allows to provide an
|
||||
alternative storage for GSettings. Implementations of this extension point
|
||||
must derive from the GSettingsBackend type. GIO contains a keyfile-based
|
||||
implementation of this extension point, another one is provided by dconf.
|
||||
- `G_PROXY_EXTENSION_POINT_NAME`. Allows to provide implementations for
|
||||
network proxying. Implementations of this extension point must provide the
|
||||
GProxy interface, and must be named after the network protocol they are
|
||||
proxying. glib-networking contains an implementation of this extension
|
||||
point based on libproxy.
|
||||
- `G_TLS_BACKEND_EXTENSION_POINT_NAME`. Allows to provide implementations
|
||||
for TLS support. Implementations of this extension point must implement
|
||||
the GTlsBackend interface. glib-networking contains an implementation of
|
||||
this extension point.
|
||||
- `G_NETWORK_MONITOR_EXTENSION_POINT_NAME`. Allows to provide
|
||||
implementations for network connectivity monitoring. Implementations of
|
||||
this extension point must implement the GNetworkMonitorInterface
|
||||
interface. GIO contains an implementation of this extension point that is
|
||||
using the netlink interface of the Linux kernel.
|
@ -1,755 +0,0 @@
|
||||
<part>
|
||||
<title>GIO Overview</title>
|
||||
|
||||
<chapter>
|
||||
<title>Introduction</title>
|
||||
|
||||
<para>
|
||||
GIO is striving to provide a modern, easy-to-use VFS API that sits
|
||||
at the right level in the library stack, as well as other generally
|
||||
useful APIs for desktop applications (such as networking and
|
||||
D-Bus support). The goal is to overcome the shortcomings of GnomeVFS
|
||||
and provide an API that is so good that developers prefer it over raw
|
||||
POSIX calls. Among other things that means using GObject. It also means
|
||||
not cloning the POSIX API, but providing higher-level, document-centric
|
||||
interfaces.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The abstract file system model of GIO consists of a number of
|
||||
interfaces and base classes for I/O and files:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GFile</term>
|
||||
<listitem><para>reference to a file</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GFileInfo</term>
|
||||
<listitem><para>information about a file or filesystem</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GFileEnumerator</term>
|
||||
<listitem><para>list files in directories</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GDrive</term>
|
||||
<listitem><para>represents a drive</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GVolume</term>
|
||||
<listitem><para>represents a file system in an abstract way</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GMount</term>
|
||||
<listitem><para>represents a mounted file system</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
Then there is a number of stream classes, similar to the input and
|
||||
output stream hierarchies that can be found in frameworks like Java:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GInputStream</term>
|
||||
<listitem><para>read data</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GOutputStream</term>
|
||||
<listitem><para>write data</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GIOStream</term>
|
||||
<listitem><para>read and write data</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GSeekable</term>
|
||||
<listitem><para>interface optionally implemented by streams to support seeking</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
There are interfaces related to applications and the types
|
||||
of files they handle:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GAppInfo</term>
|
||||
<listitem><para>information about an installed application</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GIcon</term>
|
||||
<listitem><para>abstract type for file and application icons</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
There is a framework for storing and retrieving application settings:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GSettings</term>
|
||||
<listitem><para>stores and retrieves application settings</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
There is support for network programming, including connectivity monitoring,
|
||||
name resolution, lowlevel socket APIs and highlevel client and server
|
||||
helper classes:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GSocket</term>
|
||||
<listitem><para>lowlevel platform independent socket object</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GResolver</term>
|
||||
<listitem><para>asynchronous and cancellable DNS resolver</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GSocketClient</term>
|
||||
<listitem><para>high-level network client helper</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GSocketService</term>
|
||||
<listitem><para>high-level network server helper</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GSocketConnection</term>
|
||||
<listitem><para>network connection stream</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>GNetworkMonitor</term>
|
||||
<listitem><para>network connectivity monitoring</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
There is support for connecting to <ulink url="http://www.freedesktop.org/wiki/Software/dbus">D-Bus</ulink>,
|
||||
sending and receiving messages, owning and watching bus names,
|
||||
and making objects available on the bus:
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>GDBusConnection</term>
|
||||
<listitem><para>a D-Bus connection</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusMethodInvocation</term>
|
||||
<listitem><para>for handling remote calls</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusServer</term>
|
||||
<listitem><para>helper for accepting connections</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
<varlistentry>
|
||||
<term>GDBusProxy</term>
|
||||
<listitem><para>proxy to access D-Bus interfaces on a remote object</para></listitem>
|
||||
</varlistentry>
|
||||
|
||||
</variablelist>
|
||||
Beyond these, GIO provides facilities for file monitoring,
|
||||
asynchronous I/O and filename completion. In addition to the
|
||||
interfaces, GIO provides implementations for the local case.
|
||||
Implementations for various network file systems are provided
|
||||
by the GVFS package as loadable modules.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Other design choices which consciously break with the GnomeVFS
|
||||
design are to move backends out-of-process, which minimizes the
|
||||
dependency bloat and makes the whole system more robust. The backends
|
||||
are not included in GIO, but in the separate GVFS package. The GVFS
|
||||
package also contains the GVFS daemon, which spawn further mount
|
||||
daemons for each individual connection.
|
||||
</para>
|
||||
|
||||
<figure id="gvfs-overview">
|
||||
<title>GIO in the GTK library stack</title>
|
||||
<graphic fileref="gvfs-overview.png" format="PNG"></graphic>
|
||||
</figure>
|
||||
|
||||
<para>
|
||||
The GIO model of I/O is stateful: if an application establishes e.g.
|
||||
a SFTP connection to a server, it becomes available to all applications
|
||||
in the session; the user does not have to enter their password over
|
||||
and over again.
|
||||
</para>
|
||||
<para>
|
||||
One of the big advantages of putting the VFS in the GLib layer
|
||||
is that GTK can directly use it, e.g. in the filechooser.
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>Writing GIO applications</title>
|
||||
|
||||
<para>
|
||||
The information in the GLib <ulink url="http://developer.gnome.org/glib/stable/glib-programming.html">documentation</ulink> about writing GLib
|
||||
applications is generally applicable when writing GIO applications.
|
||||
</para>
|
||||
|
||||
<simplesect><title>Threads</title>
|
||||
|
||||
<para>
|
||||
GDBus has its own private worker thread, so applications using
|
||||
GDBus have at least 3 threads. GIO makes heavy use of the concept
|
||||
of a <link linkend="g-main-context-push-thread-default">thread-default
|
||||
main context</link> to execute callbacks of asynchronous
|
||||
methods in the same context in which the operation was started.
|
||||
</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
<simplesect id="async-programming"><title>Asynchronous Programming</title>
|
||||
|
||||
<para>
|
||||
Many GIO functions come in two versions: synchronous and asynchronous,
|
||||
denoted by an <code>_async</code> suffix. It is important to use these
|
||||
appropriately: synchronous calls should not be used from
|
||||
within a main loop which is shared with other code, such as one in the
|
||||
application’s main thread. Synchronous calls block until they complete,
|
||||
and I/O operations can take noticeable amounts of time (even on ‘fast’
|
||||
SSDs). Blocking a main loop iteration while waiting for I/O means that
|
||||
other sources in the main loop will not be dispatched, such as input and
|
||||
redraw handlers for the application’s UI. This can cause the application
|
||||
to ‘freeze’ until I/O completes.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A few self-contained groups of functions, such as code generated by
|
||||
<link linkend="gdbus-codegen"><application>gdbus-codegen</application></link>,
|
||||
use a different convention: functions are asynchronous default, and it is
|
||||
the <emphasis>synchronous</emphasis> version which has a
|
||||
<code>_sync</code>
|
||||
suffix. Aside from naming differences, they should be treated the same
|
||||
way as functions following the normal convention above.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The asynchronous (<code>_async</code>) versions of functions return
|
||||
control to the caller immediately, after scheduling the I/O in the kernel
|
||||
and adding a callback for it to the main loop. This callback will be
|
||||
invoked when the operation has completed. From the callback, the paired
|
||||
<code>_finish</code> function should be called to retrieve the return
|
||||
value of the I/O operation, and any errors which occurred. For more
|
||||
information on using and implementing asynchronous functions, see
|
||||
<link linkend="GAsyncResult.description"><type>GAsyncResult</type></link>
|
||||
and <link linkend="GTask.description"><type>GTask</type></link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
By starting multiple asynchronous operations in succession, they will be
|
||||
executed in parallel (up to an arbitrary limit imposed by GIO’s internal
|
||||
worker thread pool).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The synchronous versions of functions can be used early in application
|
||||
startup when there is no main loop to block, for example to load initial
|
||||
configuration files. They can also be used for I/O on files which are
|
||||
guaranteed to be small and on the local disk. Note that the user’s home
|
||||
directory is not guaranteed to be on the local disk.
|
||||
</para>
|
||||
</simplesect>
|
||||
|
||||
<simplesect><title>Security</title>
|
||||
|
||||
<para>
|
||||
When your program needs to carry out some privileged operation (say,
|
||||
create a new user account), there are various ways in which you can go
|
||||
about this:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Implement a daemon that offers the privileged operation. A convenient
|
||||
way to do this is as a D-Bus system-bus service. The daemon will probably
|
||||
need ways to check the identity and authorization of the caller before
|
||||
executing the operation. <ulink url="http://www.freedesktop.org/software/polkit/docs/latest/polkit.8.html">polkit</ulink> is a framework that allows this.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Use a small helper that is executed with elevated privileges via
|
||||
pkexec. <ulink url="http://www.freedesktop.org/software/polkit/docs/latest/pkexec.1.html">pkexec</ulink> is a small program launcher that is part of polkit.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Use a small helper that is executed with elevated privileges by
|
||||
being suid root.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
None of these approaches is the clear winner, they all have their
|
||||
advantages and disadvantages.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When writing code that runs with elevated privileges, it is important
|
||||
to follow some basic rules of secure programming. David Wheeler has an
|
||||
excellent book on this topic,
|
||||
<ulink url="http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/index.html">Secure Programming for Linux and Unix HOWTO</ulink>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When using GIO in code that runs with elevated privileges, you have to
|
||||
be careful. GIO has extension points whose implementations get loaded
|
||||
from modules (executable code in shared objects), which could allow
|
||||
an attacker to sneak their own code into your application by tricking it
|
||||
into loading the code as a module. However, GIO will never load modules
|
||||
from your home directory except when explicitly asked to do so via an
|
||||
environment variable.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In most cases, your helper program should be so small that you don't
|
||||
need GIO, whose APIs are largely designed to support full-blown desktop
|
||||
applications. If you can't resist the convenience of these APIs, here
|
||||
are some steps you should take:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Clear the environment, e.g. using the <function>clearenv()</function>
|
||||
function.
|
||||
David Wheeler has a good <ulink url="http://www.dwheeler.com/secure-programs/Secure-Programs-HOWTO/environment-variables.html">explanation</ulink> for why it is
|
||||
important to sanitize the environment.
|
||||
See <xref linkend="running-gio-apps"/>
|
||||
for a list of all environment variables affecting GIO. In particular,
|
||||
<envar>PATH</envar> (used to locate binaries), <envar>GIO_EXTRA_MODULES</envar> (used to locate loadable modules) and <envar>DBUS_{SYSTEM,SESSION}_BUS_ADDRESS</envar> (used to locate the D-Bus system and session bus) are important.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Don't use GVfs, by setting <envar>GIO_USE_VFS=local</envar> in the environment.
|
||||
The reason to avoid GVfs in security-sensitive programs is that it uses
|
||||
many libraries which have not necessarily been audited for security problems.
|
||||
Gvfs is also heavily distributed and relies on a session bus to be present.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
</simplesect>
|
||||
|
||||
</chapter>
|
||||
|
||||
<chapter>
|
||||
<title>Compiling GIO applications</title>
|
||||
|
||||
<para>
|
||||
GIO comes with a <filename>gio-2.0.pc</filename> file that you
|
||||
should use together with <literal>pkg-config</literal> to obtain
|
||||
the necessary information about header files and libraries. See
|
||||
the <literal>pkg-config</literal> man page or the GLib documentation
|
||||
for more information on how to use <literal>pkg-config</literal>
|
||||
to compile your application.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If you are using GIO on UNIX-like systems, you may want to use
|
||||
UNIX-specific GIO interfaces such as #GUnixInputStream,
|
||||
#GUnixOutputStream, #GUnixMount or #GDesktopAppInfo.
|
||||
To do so, use the <filename>gio-unix-2.0.pc</filename> file
|
||||
instead of <filename>gio-2.0.pc</filename>
|
||||
</para>
|
||||
</chapter>
|
||||
|
||||
<chapter id="running-gio-apps">
|
||||
<title>Running GIO applications</title>
|
||||
|
||||
<para>
|
||||
GIO inspects a few environment variables in addition to the
|
||||
ones used by GLib.
|
||||
</para>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>XDG_DATA_HOME</envar>, <envar>XDG_DATA_DIRS</envar></title>
|
||||
|
||||
<para>
|
||||
GIO uses these environment variables to locate MIME information.
|
||||
For more information, see the <ulink url="http://freedesktop.org/Standards/shared-mime-info-spec">Shared MIME-info Database</ulink>
|
||||
and the <ulink url="http://freedesktop.org/Standards/basedir-spec">Base Directory Specification</ulink>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GVFS_DISABLE_FUSE</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to keep #Gvfs from starting the fuse backend,
|
||||
which may be unwanted or unnecessary in certain situations.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_USE_VFS</envar></title>
|
||||
|
||||
<para>
|
||||
This environment variable can be set to the name of a #GVfs
|
||||
implementation to override the default for debugging purposes.
|
||||
The #GVfs implementation for local files that is included in GIO
|
||||
has the name "local", the implementation in the gvfs module has
|
||||
the name "gvfs". Most commonly, system software will set this to "local"
|
||||
to avoid having `GFile` APIs perform unnecessary D-Bus calls.
|
||||
</para><para>
|
||||
The special value <literal>help</literal> can be used to print a list of
|
||||
available implementations to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<para>
|
||||
The following environment variables are only useful for debugging
|
||||
GIO itself or modules that it loads. They should not be set in a
|
||||
production environment.
|
||||
</para>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_USE_FILE_MONITOR</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the name of a #GFileMonitor
|
||||
implementation to override the default for debugging purposes.
|
||||
The #GFileMonitor implementation for local files that is included
|
||||
in GIO on Linux has the name <literal>inotify</literal>, others that are built
|
||||
are built as modules (depending on the platform) are called
|
||||
<literal>kqueue</literal> and <literal>win32filemonitor</literal>.
|
||||
</para><para>
|
||||
The special value <literal>help</literal> can be used to print a list of
|
||||
available implementations to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_USE_VOLUME_MONITOR</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the name of a #GVolumeMonitor
|
||||
implementation to override the default for debugging purposes.
|
||||
The #GVolumeMonitor implementation for local files that is included
|
||||
in GIO has the name "unix", the udisks2-based implementation in the
|
||||
gvfs module has the name "udisks2".
|
||||
</para><para>
|
||||
The special value <literal>help</literal> can be used to print a list of
|
||||
available implementations to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_USE_TLS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the name of a #GTlsBackend
|
||||
implementation to override the default for debugging purposes.
|
||||
GIO does not include a #GTlsBackend implementation, the gnutls-based
|
||||
implementation in the glib-networking module has the name "gnutls".
|
||||
</para><para>
|
||||
The special value <literal>help</literal> can be used to print a list of
|
||||
available implementations to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_USE_PORTALS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to override detection of portals and force them
|
||||
to be used to provide various bits of GIO functionality, for testing and
|
||||
debugging. This variable is not intended to be used in production.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_MODULE_DIR</envar></title>
|
||||
|
||||
<para>
|
||||
When this environment variable is set to a path, GIO will load
|
||||
modules from this alternate directory instead of the directory
|
||||
built into GIO. This is useful when running tests, for example.
|
||||
</para>
|
||||
<para>
|
||||
This environment variable is ignored when running in a setuid program.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GIO_EXTRA_MODULES</envar></title>
|
||||
|
||||
<para>
|
||||
When this environment variable is set to a path, or a set of
|
||||
paths separated by a colon, GIO will attempt to load
|
||||
additional modules from within the path.
|
||||
</para>
|
||||
<para>
|
||||
This environment variable is ignored when running in a setuid program.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GSETTINGS_BACKEND</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the name of a #GSettingsBackend
|
||||
implementation to override the default for debugging purposes.
|
||||
The memory-based implementation that is included in GIO has
|
||||
the name "memory", the one in dconf has the name "dconf".
|
||||
</para><para>
|
||||
The special value <literal>help</literal> can be used to print a list of
|
||||
available implementations to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>GSETTINGS_SCHEMA_DIR</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to the names of directories to consider when looking for compiled schemas for #GSettings,
|
||||
in addition to the <filename>glib-2.0/schemas</filename>
|
||||
subdirectories of the XDG system data dirs. To specify multiple directories, use <constant>G_SEARCHPATH_SEPARATOR_S</constant> as a separator.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>DBUS_SYSTEM_BUS_ADDRESS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable is consulted to find the address of the D-Bus system
|
||||
bus. For the format of D-Bus addresses, see the D-Bus
|
||||
<ulink url="http://dbus.freedesktop.org/doc/dbus-specification.html#addresses">specification</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
Setting this variable overrides platform-specific ways of determining
|
||||
the system bus address.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>DBUS_SESSION_BUS_ADDRESS</envar></title>
|
||||
|
||||
<para>
|
||||
This variable is consulted to find the address of the D-Bus session bus.
|
||||
</para>
|
||||
<para>
|
||||
Setting this variable overrides platform-specific ways of determining
|
||||
the session bus address.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>DBUS_STARTER_BUS_TYPE</envar></title>
|
||||
|
||||
<para>
|
||||
This variable is consulted to find out the 'starter' bus for an
|
||||
application that has been started via D-Bus activation. The possible
|
||||
values are 'system' or 'session'.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_DEBUG</envar></title>
|
||||
|
||||
<para>
|
||||
This variable can be set to a list of debug options, which
|
||||
cause GLib to print out different types of debugging
|
||||
information when using the D-Bus routines.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>transport</term>
|
||||
<listitem><para>Show IO activity (e.g. reads and writes)</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>message</term>
|
||||
<listitem><para>Show all sent and received D-Bus messages</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>payload</term>
|
||||
<listitem><para>Show payload for all sent and received D-Bus messages (implies message)</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>call</term>
|
||||
<listitem><para>Trace g_dbus_connection_call() and g_dbus_connection_call_sync() API usage</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>signal</term>
|
||||
<listitem><para>Show when a D-Bus signal is received</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>incoming</term>
|
||||
<listitem><para>Show when an incoming D-Bus method call is received</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>return</term>
|
||||
<listitem><para>Show when a reply is returned via the #GDBusMethodInvocation API</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>emission</term>
|
||||
<listitem><para>Trace g_dbus_connection_emit_signal() API usage</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>authentication</term>
|
||||
<listitem><para>Show information about connection authentication</para></listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>address</term>
|
||||
<listitem><para>Show information about D-Bus address lookups and autolaunching</para></listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
The special value <literal>all</literal> can be used to turn
|
||||
on all debug options. The special value
|
||||
<literal>help</literal> can be used to print a list of
|
||||
supported options to standard output.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR</envar></title>
|
||||
|
||||
<para>
|
||||
Can be used to override the directory used to store the
|
||||
keyring used in the <literal>DBUS_COOKIE_SHA1</literal>
|
||||
authentication mechanism. Normally the directory used is
|
||||
<filename>.dbus-keyrings</filename> in the user's home
|
||||
directory.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><envar>G_DBUS_COOKIE_SHA1_KEYRING_DIR_IGNORE_PERMISSION</envar></title>
|
||||
|
||||
<para>
|
||||
If set, the permissions of the directory used to store the
|
||||
keyring used in the <literal>DBUS_COOKIE_SHA1</literal>
|
||||
authentication mechanism won't be checked. Normally the
|
||||
directory must be readable only by the user.
|
||||
</para>
|
||||
</formalpara>
|
||||
</chapter>
|
||||
|
||||
<chapter id="extending-gio">
|
||||
<title>Extending GIO</title>
|
||||
|
||||
<para>
|
||||
A lot of the functionality that is accessible through GIO
|
||||
is implemented in loadable modules, and modules provide a convenient
|
||||
way to extend GIO. In addition to the #GIOModule API which supports
|
||||
writing such modules, GIO has a mechanism to define extension points,
|
||||
and register implementations thereof, see #GIOExtensionPoint.
|
||||
</para>
|
||||
<para>
|
||||
The following extension points are currently defined by GIO:
|
||||
</para>
|
||||
|
||||
<formalpara>
|
||||
<title>G_VFS_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to override the functionality of the #GVfs class.
|
||||
Implementations of this extension point must be derived from #GVfs.
|
||||
GIO uses the implementation with the highest priority that is active,
|
||||
see g_vfs_is_active().
|
||||
</para>
|
||||
<para>
|
||||
GIO implements this extension point for local files, gvfs contains
|
||||
an implementation that supports all the backends in gvfs.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_VOLUME_MONITOR_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to add more volume monitors.
|
||||
Implementations of this extension point must be derived from
|
||||
#GVolumeMonitor. GIO uses all registered extensions.
|
||||
</para>
|
||||
<para>
|
||||
gvfs contains an implementation that works together with the #GVfs
|
||||
implementation in gvfs.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_NATIVE_VOLUME_MONITOR_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to override the 'native' volume monitor.
|
||||
Implementations of this extension point must be derived from
|
||||
#GNativeVolumeMonitor. GIO uses the implementation with
|
||||
the highest priority that is supported, as determined by the
|
||||
is_supported() vfunc in #GVolumeMonitorClass.
|
||||
</para>
|
||||
<para>
|
||||
GIO implements this extension point for local mounts,
|
||||
gvfs contains a udisks2-based implementation.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_LOCAL_FILE_MONITOR_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to override the file monitor implementation for
|
||||
local files. Implementations of this extension point must
|
||||
be derived from #GLocalFileMonitor. GIO uses the implementation
|
||||
with the highest priority that is supported, as determined by the
|
||||
is_supported() vfunc in #GLocalFileMonitorClass.
|
||||
</para>
|
||||
<para>
|
||||
GIO uses this extension point internally, to switch between
|
||||
its kqueue-based and inotify-based file monitoring implementations.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_DESKTOP_APP_INFO_LOOKUP_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Unix-only. Allows to provide a way to associate default handlers
|
||||
with URI schemes. Implementations of this extension point must
|
||||
implement the #GDesktopAppInfoLookup interface. GIO uses the
|
||||
implementation with the highest priority.
|
||||
</para>
|
||||
<para>
|
||||
This extension point has been discontinued in GLib 2.28. It is
|
||||
still available to keep API and ABI stability, but GIO is no
|
||||
longer using it for default handlers. Instead, the mime handler
|
||||
mechanism is used, together with x-scheme-handler pseudo-mimetypes.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_SETTINGS_BACKEND_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to provide an alternative storage for #GSettings.
|
||||
Implementations of this extension point must derive from the
|
||||
#GSettingsBackend type. GIO contains a keyfile-based
|
||||
implementation of this extension point, another one is provided
|
||||
by dconf.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_PROXY_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to provide implementations for network proxying.
|
||||
Implementations of this extension point must provide the
|
||||
#GProxy interface, and must be named after the network
|
||||
protocol they are proxying.
|
||||
</para>
|
||||
<para>
|
||||
glib-networking contains an implementation of this extension
|
||||
point based on libproxy.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>G_TLS_BACKEND_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to provide implementations for TLS support.
|
||||
Implementations of this extension point must implement
|
||||
the #GTlsBackend interface.
|
||||
</para>
|
||||
<para>
|
||||
glib-networking contains an implementation of this extension
|
||||
point.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>G_NETWORK_MONITOR_EXTENSION_POINT_NAME</title>
|
||||
|
||||
<para>
|
||||
Allows to provide implementations for network connectivity
|
||||
monitoring.
|
||||
Implementations of this extension point must implement
|
||||
the #GNetworkMonitorInterface interface.
|
||||
</para>
|
||||
<para>
|
||||
GIO contains an implementation of this extension point
|
||||
that is using the netlink interface of the Linux kernel.
|
||||
</para>
|
||||
</formalpara>
|
||||
</chapter>
|
||||
</part>
|
||||
|
9
docs/reference/gio/urlmap.js
Normal file
9
docs/reference/gio/urlmap.js
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// SPDX-FileCopyrightText: 2023 Matthias Clasen
|
||||
var baseURLs = [
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GModule', 'https://docs.gtk.org/gmodule/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk4/' ],
|
||||
];
|
86561
docs/reference/glib/GLib-2.0.gir
Normal file
86561
docs/reference/glib/GLib-2.0.gir
Normal file
File diff suppressed because it is too large
Load Diff
291
docs/reference/glib/auto-cleanup.md
Normal file
291
docs/reference/glib/auto-cleanup.md
Normal file
@ -0,0 +1,291 @@
|
||||
Title: Automatic Cleanup
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2023 Matthias Clasen
|
||||
|
||||
# Automatic Cleanup
|
||||
|
||||
GLib provides a set of macros that wrap the GCC extension for automatic
|
||||
cleanup of variables when they go out of scope.
|
||||
|
||||
These macros can only be used with GCC and GCC-compatible C compilers.
|
||||
|
||||
## Variable declaration
|
||||
|
||||
`g_auto(TypeName)`
|
||||
|
||||
: Helper to declare a variable with automatic cleanup.
|
||||
|
||||
The variable is cleaned up in a way appropriate to its type when the
|
||||
variable goes out of scope. The `TypeName` of the variable must support
|
||||
this.
|
||||
|
||||
The way to clean up the type must have been defined using one of the macros
|
||||
`G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC()` or `G_DEFINE_AUTO_CLEANUP_FREE_FUNC()`.
|
||||
|
||||
This feature is only supported on GCC and clang. This macro is not
|
||||
defined on other compilers and should not be used in programs that
|
||||
are intended to be portable to those compilers.
|
||||
|
||||
This macro meant to be used with stack-allocated structures and
|
||||
non-pointer types. For the (more commonly used) pointer version, see
|
||||
`g_autoptr()`.
|
||||
|
||||
This macro can be used to avoid having to do explicit cleanups of
|
||||
local variables when exiting functions. It often vastly simplifies
|
||||
handling of error conditions, removing the need for various tricks
|
||||
such as `goto out` or repeating of cleanup code. It is also helpful
|
||||
for non-error cases.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
GVariant *
|
||||
my_func(void)
|
||||
{
|
||||
g_auto(GQueue) queue = G_QUEUE_INIT;
|
||||
g_auto(GVariantBuilder) builder;
|
||||
g_auto(GStrv) strv;
|
||||
|
||||
g_variant_builder_init (&builder, G_VARIANT_TYPE_VARDICT);
|
||||
strv = g_strsplit("a:b:c", ":", -1);
|
||||
|
||||
// ...
|
||||
|
||||
if (error_condition)
|
||||
return NULL;
|
||||
|
||||
// ...
|
||||
|
||||
return g_variant_builder_end (&builder);
|
||||
}
|
||||
|
||||
You must initialize the variable in some way — either by use of an
|
||||
initialiser or by ensuring that an `_init` function will be called on
|
||||
it unconditionally before it goes out of scope.
|
||||
|
||||
Since: 2.44
|
||||
|
||||
|
||||
`g_autoptr(TypeName)`
|
||||
: Helper to declare a pointer variable with automatic cleanup.
|
||||
|
||||
The variable is cleaned up in a way appropriate to its type when the
|
||||
variable goes out of scope. The `TypeName` of the variable must support this.
|
||||
The way to clean up the type must have been defined using the macro
|
||||
`G_DEFINE_AUTOPTR_CLEANUP_FUNC()`.
|
||||
|
||||
This feature is only supported on GCC and clang. This macro is not
|
||||
defined on other compilers and should not be used in programs that
|
||||
are intended to be portable to those compilers.
|
||||
|
||||
This is meant to be used to declare pointers to types with cleanup
|
||||
functions. The type of the variable is a pointer to `TypeName`. You
|
||||
must not add your own `*`.
|
||||
|
||||
This macro can be used to avoid having to do explicit cleanups of
|
||||
local variables when exiting functions. It often vastly simplifies
|
||||
handling of error conditions, removing the need for various tricks
|
||||
such as `goto out` or repeating of cleanup code. It is also helpful
|
||||
for non-error cases.
|
||||
|
||||
Consider the following example:
|
||||
|
||||
gboolean
|
||||
check_exists(GVariant *dict)
|
||||
{
|
||||
g_autoptr(GVariant) dirname, basename = NULL;
|
||||
g_autofree gchar *path = NULL;
|
||||
|
||||
dirname = g_variant_lookup_value (dict, "dirname", G_VARIANT_TYPE_STRING);
|
||||
if (dirname == NULL)
|
||||
return FALSE;
|
||||
|
||||
basename = g_variant_lookup_value (dict, "basename", G_VARIANT_TYPE_STRING);
|
||||
if (basename == NULL)
|
||||
return FALSE;
|
||||
|
||||
path = g_build_filename (g_variant_get_string (dirname, NULL),
|
||||
g_variant_get_string (basename, NULL),
|
||||
NULL);
|
||||
|
||||
return g_access (path, R_OK) == 0;
|
||||
}
|
||||
|
||||
You must initialise the variable in some way — either by use of an
|
||||
initialiser or by ensuring that it is assigned to unconditionally
|
||||
before it goes out of scope.
|
||||
|
||||
See also: `g_auto()`, `g_autofree()` and `g_steal_pointer()`.
|
||||
|
||||
Since: 2.44
|
||||
|
||||
|
||||
`g_autofree`
|
||||
|
||||
: Macro to add an attribute to pointer variable to ensure automatic
|
||||
cleanup using `g_free()`.
|
||||
|
||||
This macro differs from `g_autoptr()` in that it is an attribute supplied
|
||||
before the type name, rather than wrapping the type definition. Instead
|
||||
of using a type-specific lookup, this macro always calls `g_free()` directly.
|
||||
|
||||
This means it's useful for any type that is returned from `g_malloc()`.
|
||||
|
||||
Otherwise, this macro has similar constraints as `g_autoptr()`: only
|
||||
supported on GCC and clang, the variable must be initialized, etc.
|
||||
|
||||
gboolean
|
||||
operate_on_malloc_buf (void)
|
||||
{
|
||||
g_autofree guint8* membuf = NULL;
|
||||
|
||||
membuf = g_malloc (8192);
|
||||
|
||||
// Some computation on membuf
|
||||
|
||||
// membuf will be automatically freed here
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
Since: 2.44
|
||||
|
||||
|
||||
`g_autolist(TypeName)`
|
||||
|
||||
: Helper to declare a list variable with automatic deep cleanup.
|
||||
|
||||
The list is deeply freed, in a way appropriate to the specified type, when the
|
||||
variable goes out of scope. The type must support this.
|
||||
|
||||
This feature is only supported on GCC and clang. This macro is not
|
||||
defined on other compilers and should not be used in programs that
|
||||
are intended to be portable to those compilers.
|
||||
|
||||
This is meant to be used to declare lists of a type with a cleanup
|
||||
function. The type of the variable is a `GList *`. You
|
||||
must not add your own `*`.
|
||||
|
||||
This macro can be used to avoid having to do explicit cleanups of
|
||||
local variables when exiting functions. It often vastly simplifies
|
||||
handling of error conditions, removing the need for various tricks
|
||||
such as `goto out` or repeating of cleanup code. It is also helpful
|
||||
for non-error cases.
|
||||
|
||||
See also: `g_autoslist()`, `g_autoptr()` and `g_steal_pointer()`.
|
||||
|
||||
Since: 2.56
|
||||
|
||||
|
||||
`g_autoslist(TypeName)`
|
||||
|
||||
: Helper to declare a singly linked list variable with automatic deep cleanup.
|
||||
|
||||
The list is deeply freed, in a way appropriate to the specified type, when the
|
||||
variable goes out of scope. The type must support this.
|
||||
|
||||
This feature is only supported on GCC and clang. This macro is not
|
||||
defined on other compilers and should not be used in programs that
|
||||
are intended to be portable to those compilers.
|
||||
|
||||
This is meant to be used to declare lists of a type with a cleanup
|
||||
function. The type of the variable is a `GSList *`. You
|
||||
must not add your own `*`.
|
||||
|
||||
This macro can be used to avoid having to do explicit cleanups of
|
||||
local variables when exiting functions. It often vastly simplifies
|
||||
handling of error conditions, removing the need for various tricks
|
||||
such as `goto out` or repeating of cleanup code. It is also helpful
|
||||
for non-error cases.
|
||||
|
||||
See also: `g_autolist()`, `g_autoptr()` and `g_steal_pointer()`.
|
||||
|
||||
Since: 2.56
|
||||
|
||||
|
||||
`g_autoqueue(TypeName)`
|
||||
|
||||
: Helper to declare a double-ended queue variable with automatic deep cleanup.
|
||||
|
||||
The queue is deeply freed, in a way appropriate to the specified type, when the
|
||||
variable goes out of scope. The type must support this.
|
||||
|
||||
This feature is only supported on GCC and clang. This macro is not
|
||||
defined on other compilers and should not be used in programs that
|
||||
are intended to be portable to those compilers.
|
||||
|
||||
This is meant to be used to declare queues of a type with a cleanup
|
||||
function. The type of the variable is a `GQueue *`. You
|
||||
must not add your own `*`.
|
||||
|
||||
This macro can be used to avoid having to do explicit cleanups of
|
||||
local variables when exiting functions. It often vastly simplifies
|
||||
handling of error conditions, removing the need for various tricks
|
||||
such as `goto out` or repeating of cleanup code. It is also helpful
|
||||
for non-error cases.
|
||||
|
||||
See also: `g_autolist()`, `g_autoptr()` and `g_steal_pointer()`.
|
||||
|
||||
Since: 2.62
|
||||
|
||||
|
||||
## Type definition
|
||||
|
||||
`G_DEFINE_AUTOPTR_CLEANUP_FUNC(TypeName, func)`
|
||||
|
||||
: Defines the appropriate cleanup function for a pointer type.
|
||||
|
||||
The function will not be called if the variable to be cleaned up
|
||||
contains `NULL`.
|
||||
|
||||
This will typically be the `_free()` or `_unref()` function for the given
|
||||
type.
|
||||
|
||||
With this definition, it will be possible to use `g_autoptr()` with
|
||||
the given `TypeName`.
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC(GObject, g_object_unref)
|
||||
|
||||
This macro should be used unconditionally; it is a no-op on compilers
|
||||
where cleanup is not supported.
|
||||
|
||||
Since: 2.44
|
||||
|
||||
|
||||
`G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(TypeName, func)`
|
||||
|
||||
: Defines the appropriate cleanup function for a type.
|
||||
|
||||
This will typically be the `_clear()` function for the given type.
|
||||
|
||||
With this definition, it will be possible to use `g_auto()` with
|
||||
the given `TypeName`.
|
||||
|
||||
G_DEFINE_AUTO_CLEANUP_CLEAR_FUNC(GQueue, g_queue_clear)
|
||||
|
||||
This macro should be used unconditionally; it is a no-op on compilers
|
||||
where cleanup is not supported.
|
||||
|
||||
Since: 2.44
|
||||
|
||||
|
||||
`G_DEFINE_AUTO_CLEANUP_FREE_FUNC(TypeName, func, none_value)`
|
||||
|
||||
: Defines the appropriate cleanup function for a type.
|
||||
|
||||
With this definition, it will be possible to use `g_auto()` with the
|
||||
given `TypeName`.
|
||||
|
||||
This function will be rarely used. It is used with pointer-based
|
||||
typedefs and non-pointer types where the value of the variable
|
||||
represents a resource that must be freed. Two examples are `GStrv`
|
||||
and file descriptors.
|
||||
|
||||
`none_value` specifies the "none" value for the type in question. It
|
||||
is probably something like `NULL` or `-1`.If the variable is found to
|
||||
contain this value then the free function will not be called.
|
||||
|
||||
G_DEFINE_AUTO_CLEANUP_FREE_FUNC(GStrv, g_strfreev, NULL)
|
||||
|
||||
This macro should be used unconditionally; it is a no-op on compilers
|
||||
where cleanup is not supported.
|
||||
|
||||
Since: 2.44
|
174
docs/reference/glib/building.md
Normal file
174
docs/reference/glib/building.md
Normal file
@ -0,0 +1,174 @@
|
||||
Title: Building GLib
|
||||
|
||||
# Building GLib
|
||||
|
||||
GLib uses the [Meson build system](https://mesonbuild.com). The normal
|
||||
sequence for compiling and installing the GLib library is thus:
|
||||
|
||||
$ meson setup _build
|
||||
$ meson compile -C _build
|
||||
$ meson install -C _build
|
||||
|
||||
On FreeBSD, you will need something more complex:
|
||||
|
||||
$ env CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib -Wl,--disable-new-dtags" \
|
||||
> meson setup \
|
||||
> -Dxattr=false \
|
||||
> -Dinstalled_tests=true \
|
||||
> -Db_lundef=false \
|
||||
> _build
|
||||
$ meson compile -C _build
|
||||
|
||||
The standard options provided by Meson may be passed to the `meson` command. Please see the Meson documentation or run:
|
||||
|
||||
meson configure --help
|
||||
|
||||
for information about the standard options.
|
||||
|
||||
GLib is compiled with
|
||||
[strict aliasing](https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fstrict-aliasing)
|
||||
disabled. It is strongly recommended that this is not re-enabled by overriding
|
||||
the compiler flags, as GLib has not been tested with strict aliasing and cannot
|
||||
be guaranteed to work.
|
||||
|
||||
## Dependencies
|
||||
|
||||
Before you can compile the GLib library, you need to have various other
|
||||
tools and libraries installed on your system. If you are building from a
|
||||
release archive, you will need a [compliant C
|
||||
toolchain](https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/toolchain-requirements.md),
|
||||
Meson, and pkg-config; the requirements are the same when building from a
|
||||
Git repository clone of GLib.
|
||||
|
||||
- [`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/) is a
|
||||
tool for tracking the compilation flags needed for libraries that are used
|
||||
by the GLib library. (For each library, a small `.pc` text file is
|
||||
installed in a standard location that contains the compilation flags
|
||||
needed for that library along with version number information).
|
||||
|
||||
A UNIX build of GLib requires that the system implements at least the
|
||||
original 1990 version of POSIX. Beyond this, it depends on a number of other
|
||||
libraries.
|
||||
|
||||
- The [GNU libiconv library](http://www.gnu.org/software/libiconv/) is
|
||||
needed to build GLib if your system doesn't have the `iconv()` function
|
||||
for doing conversion between character encodings. Most modern systems
|
||||
should have `iconv()`, however many older systems lack an `iconv()`
|
||||
implementation. On such systems, you must install the libiconv library.
|
||||
This can be found at: http://www.gnu.org/software/libiconv.
|
||||
|
||||
If your system has an `iconv()` implementation but you want to use libiconv
|
||||
instead, make sure it is installed to the default compiler header/library
|
||||
search path (for instance, in `/usr/local/`). The `iconv.h` that libiconv
|
||||
installs hides the system iconv. Meson then detects this, recognizes that the
|
||||
system iconv is unusable and the external one is mandatory, and automatically
|
||||
forces it to be used.
|
||||
|
||||
If you are using the native iconv implementation on Solaris instead of
|
||||
libiconv, you'll need to make sure that you have the converters between
|
||||
locale encodings and UTF-8 installed. At a minimum you'll need the
|
||||
SUNWuiu8 package. You probably should also install the SUNWciu8, SUNWhiu8,
|
||||
SUNWjiu8, and SUNWkiu8 packages.
|
||||
|
||||
The native iconv on Compaq Tru64 doesn't contain support for UTF-8, so
|
||||
you'll need to use GNU libiconv instead. (When using GNU libiconv for
|
||||
GLib, you'll need to use GNU libiconv for GNU gettext as well.) This
|
||||
probably applies to related operating systems as well.
|
||||
|
||||
- Python 3.5 or newer is required. Your system Python must conform to
|
||||
[PEP 394](https://www.python.org/dev/peps/pep-0394/) For FreeBSD, this means
|
||||
that the `lang/python3` port must be installed.
|
||||
|
||||
- The libintl library from the [GNU
|
||||
gettext](http://www.gnu.org/software/gettext) package is needed if your
|
||||
system doesn't have the `gettext()` functionality for handling message
|
||||
translation databases.
|
||||
|
||||
- A thread implementation is needed. The thread support in GLib can be based
|
||||
upon POSIX threads or win32 threads.
|
||||
|
||||
- GRegex uses the [PCRE library](http://www.pcre.org/) for regular
|
||||
expression matching. The system version of PCRE is used, unless not available
|
||||
(which is the case on Android), in which case a fallback subproject is used.
|
||||
|
||||
- The optional extended attribute support in GIO requires the `getxattr()`
|
||||
family of functions that may be provided by the C library or by the
|
||||
standalone libattr library. To build GLib without extended attribute
|
||||
support, use the `-Dxattr=false` option.
|
||||
|
||||
- The optional SELinux support in GIO requires libselinux. To build GLib
|
||||
without SELinux support, use the `-Dselinux=disabled` option.
|
||||
|
||||
- The optional support for DTrace requires the `sys/sdt.h` header, which is
|
||||
provided by SystemTap on Linux. To build GLib without DTrace, use the
|
||||
`-Ddtrace=false` option.
|
||||
|
||||
- The optional support for SystemTap can be disabled with the
|
||||
`-Dsystemtap=false` option. Additionally, you can control the location
|
||||
where GLib installs the SystemTap probes, using the
|
||||
`-Dtapset_install_dir=DIR` option.
|
||||
|
||||
## Extra Configuration Options
|
||||
|
||||
In addition to the normal options, these additional ones are supported when
|
||||
configuring the GLib library:
|
||||
|
||||
`--buildtype`
|
||||
: This is a standard Meson option which specifies how much debugging and
|
||||
optimization to enable. If the build type is `debug`, `G_ENABLE_DEBUG` will be
|
||||
defined and GLib will be built with additional debug code enabled. You can
|
||||
override this behavior using `-Dglib_debug`.
|
||||
|
||||
`-Dforce_posix_threads=true`
|
||||
: Normally, Meson should be able to work out the correct thread implementation
|
||||
to use. This option forces POSIX threads to be used even if the platform
|
||||
provides another threading API (for example, on Windows).
|
||||
|
||||
`-Dbsymbolic_functions=false` and `-Dbsymbolic_functions=true`
|
||||
: By default, GLib uses the `-Bsymbolic-functions` linker flag to avoid
|
||||
intra-library PLT jumps. A side-effect of this is that it is no longer
|
||||
possible to override internal uses of GLib functions with `LD_PRELOAD`.
|
||||
Therefore, it may make sense to turn this feature off in some
|
||||
situations. The `-Dbsymbolic_functions=false` option allows to do that.
|
||||
|
||||
`-Dgtk_doc=false` and `-Dgtk_doc=true`
|
||||
: By default, GLib will detect whether the gtk-doc package is installed.
|
||||
If it is, then it will use it to extract and build the documentation
|
||||
for the GLib library. These options can be used to explicitly control
|
||||
whether gtk-doc should be used or not. If it is not used, the
|
||||
distributed, pre-generated HTML files will be installed instead of
|
||||
building them on your machine.
|
||||
|
||||
`-Dman=false` and `-Dman=true`
|
||||
: By default, GLib will detect whether `xsltproc` and the necessary DocBook
|
||||
stylesheets are installed. If they are, then it will use them to rebuild
|
||||
the included man pages from the XML sources. These options can be used to
|
||||
explicitly control whether man pages should be rebuilt used or not. The
|
||||
distribution includes pre-generated man pages.
|
||||
|
||||
`-Dxattr=false` and `-Dxattr=true`
|
||||
: By default, GLib will detect whether the `getxattr()` family of functions is
|
||||
available. If it is, then extended attribute support will be included in
|
||||
GIO. These options can be used to explicitly control whether extended
|
||||
attribute support should be included or not. `getxattr()` and friends can be
|
||||
provided by glibc or by the standalone libattr library.
|
||||
|
||||
`-Dselinux=auto`, `-Dselinux=enabled` or `-Dselinux=disabled`
|
||||
: By default, GLib will detect if libselinux is available and include SELinux
|
||||
support in GIO if it is. These options can be used to explicitly control
|
||||
whether SELinux support should be included.
|
||||
|
||||
`-Ddtrace=false` and `-Ddtrace=true`
|
||||
: By default, GLib will detect if DTrace support is available, and use it.
|
||||
These options can be used to explicitly control whether DTrace support is
|
||||
compiled into GLib.
|
||||
|
||||
`-Dsystemtap=false` and `-Dsystemtap=true`
|
||||
: This option requires DTrace support. If it is available, then GLib will also
|
||||
check for the presence of SystemTap.
|
||||
|
||||
`-Db_coverage=true` and `-Db_coverage=false`
|
||||
: Enable the generation of coverage reports for the GLib tests. This requires
|
||||
the lcov frontend to gcov from the Linux Test Project. To generate a
|
||||
coverage report, use `ninja coverage-html`. The report is placed in the
|
||||
`meson-logs` directory.
|
@ -1,339 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<refentry id="glib-building">
|
||||
<refmeta>
|
||||
<refentrytitle>Compiling the GLib package</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GLib Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>Compiling the GLib Package</refname>
|
||||
<refpurpose>How to compile GLib itself</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1 id="building">
|
||||
<title>Building the Library on UNIX</title>
|
||||
<para>
|
||||
On UNIX, GLib uses the standard <application>Meson</application> build
|
||||
system. The normal sequence for compiling and installing the GLib library
|
||||
is thus:
|
||||
|
||||
<literallayout>
|
||||
<userinput>meson setup _build</userinput>
|
||||
<userinput>meson compile -C _build</userinput>
|
||||
<userinput>meson install -C _build</userinput>
|
||||
</literallayout>
|
||||
|
||||
On FreeBSD:
|
||||
<literallayout>
|
||||
<userinput>env CPPFLAGS="-I/usr/local/include" LDFLAGS="-L/usr/local/lib -Wl,--disable-new-dtags" meson setup -Dxattr=false -Dinstalled_tests=true -Db_lundef=false _build</userinput>
|
||||
<userinput>meson compile -C _build</userinput>
|
||||
</literallayout>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The standard options provided by <application>Meson</application> may be
|
||||
passed to the <command>meson</command> command. Please see the
|
||||
<application>Meson</application> documentation or run
|
||||
<command>meson configure --help</command> for information about
|
||||
the standard options.
|
||||
</para>
|
||||
<para>
|
||||
GLib is compiled with
|
||||
<ulink url="https://gcc.gnu.org/onlinedocs/gcc/Optimize-Options.html#index-fstrict-aliasing">strict aliasing</ulink>
|
||||
disabled. It is strongly recommended that this is not re-enabled by
|
||||
overriding the compiler flags, as GLib has not been tested with strict
|
||||
aliasing and cannot be guaranteed to work.
|
||||
</para>
|
||||
<para>
|
||||
The GTK documentation contains
|
||||
<ulink url="https://developer.gnome.org/gtk3/stable/gtk-building.html">further details</ulink>
|
||||
about the build process and ways to influence it.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1 id="dependencies">
|
||||
<title>Dependencies</title>
|
||||
<para>
|
||||
Before you can compile the GLib library, you need to have
|
||||
various other tools and libraries installed on your system.
|
||||
If you are building from a release archive, you will need
|
||||
<ulink url="https://gitlab.gnome.org/GNOME/glib/-/blob/main/docs/toolchain-requirements.md">a compliant C toolchain</ulink>,
|
||||
<application>Meson</application>, and <application>pkg-config</application>;
|
||||
the requirements are the same when building from a Git repository clone
|
||||
of GLib.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
<ulink url="https://www.freedesktop.org/wiki/Software/pkg-config/">pkg-config</ulink>
|
||||
is a tool for tracking the compilation flags needed for
|
||||
libraries that are used by the GLib library. (For each
|
||||
library, a small <literal>.pc</literal> text file is
|
||||
installed in a standard location that contains the compilation
|
||||
flags needed for that library along with version number
|
||||
information).
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
A UNIX build of GLib requires that the system implements at
|
||||
least the original 1990 version of POSIX. Beyond this, it
|
||||
depends on a number of other libraries.
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>
|
||||
The <ulink url="http://www.gnu.org/software/libiconv/">GNU
|
||||
libiconv library</ulink> is needed to build GLib if your
|
||||
system doesn't have the <function>iconv()</function>
|
||||
function for doing conversion between character
|
||||
encodings. Most modern systems should have
|
||||
<function>iconv()</function>, however many older systems lack
|
||||
an <function>iconv()</function> implementation. On such systems,
|
||||
you must install the libiconv library. This can be found at:
|
||||
<ulink url="http://www.gnu.org/software/libiconv">http://www.gnu.org/software/libiconv</ulink>.
|
||||
</para>
|
||||
<para>
|
||||
If your system has an <function>iconv()</function> implementation but
|
||||
you want to use libiconv instead, make sure it is installed to the
|
||||
default compiler header/library search path (for instance, in
|
||||
<filename>/usr/local/</filename>). The <filename>iconv.h</filename>
|
||||
that libiconv installs hides the system iconv. Meson then detects
|
||||
this, recognizes that the system iconv is unusable and the external
|
||||
one is mandatory, and automatically forces it to be used.
|
||||
</para>
|
||||
<para>
|
||||
If you are using the native iconv implementation on Solaris
|
||||
instead of libiconv, you'll need to make sure that you have
|
||||
the converters between locale encodings and UTF-8 installed.
|
||||
At a minimum you'll need the SUNWuiu8 package. You probably
|
||||
should also install the SUNWciu8, SUNWhiu8, SUNWjiu8, and
|
||||
SUNWkiu8 packages.
|
||||
</para>
|
||||
<para>
|
||||
The native iconv on Compaq Tru64 doesn't contain support for
|
||||
UTF-8, so you'll need to use GNU libiconv instead. (When
|
||||
using GNU libiconv for GLib, you'll need to use GNU libiconv
|
||||
for GNU gettext as well.) This probably applies to related
|
||||
operating systems as well.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
Python 3.5 or newer is required. Your system Python must
|
||||
conform to <ulink
|
||||
url="https://www.python.org/dev/peps/pep-0394/">PEP 394
|
||||
</ulink>
|
||||
For FreeBSD, this means that the
|
||||
<literal>lang/python3</literal> port must be installed.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The libintl library from the <ulink
|
||||
url="http://www.gnu.org/software/gettext">GNU gettext
|
||||
package</ulink> is needed if your system doesn't have the
|
||||
<function>gettext()</function> functionality for handling
|
||||
message translation databases.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
A thread implementation is needed. The thread support in GLib
|
||||
can be based upon POSIX threads or win32 threads.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
GRegex uses the <ulink url="http://www.pcre.org/">PCRE library</ulink>
|
||||
for regular expression matching. The system version of PCRE is used,
|
||||
unless not available (which is the case on Android), in which case a
|
||||
fallback subproject is used.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The optional extended attribute support in GIO requires the
|
||||
<function>getxattr()</function> family of functions that may be
|
||||
provided by the C library or by the standalone libattr library. To
|
||||
build GLib without extended attribute support, use the
|
||||
<option>-Dxattr=false</option> option.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The optional SELinux support in GIO requires libselinux.
|
||||
To build GLib without SELinux support, use the
|
||||
<option>-Dselinux=disabled</option> option.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The optional support for DTrace requires the
|
||||
<filename>sys/sdt.h</filename> header, which is provided
|
||||
by SystemTap on Linux. To build GLib without DTrace, use
|
||||
the <option>-Ddtrace=false</option> option.
|
||||
</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
The optional support for
|
||||
<ulink url="http://sourceware.org/systemtap/">SystemTap</ulink>
|
||||
can be disabled with the <option>-Dsystemtap=false</option>
|
||||
option. Additionally, you can control the location
|
||||
where GLib installs the SystemTap probes, using the
|
||||
<option>-Dtapset_install_dir=DIR</option> option.
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
|
||||
</refsect1>
|
||||
<refsect1 id="extra-configuration-options">
|
||||
<title>Extra Configuration Options</title>
|
||||
|
||||
<para>
|
||||
In addition to the normal options, these additional ones are supported
|
||||
when configuring the GLib library:
|
||||
</para>
|
||||
|
||||
<formalpara>
|
||||
<title><option>--buildtype</option></title>
|
||||
|
||||
<para>
|
||||
This is a standard <application>Meson</application> option which
|
||||
specifies how much debugging and optimization to enable. If the build
|
||||
type is <literal>debug</literal>,
|
||||
<literal>G_ENABLE_DEBUG</literal> will be defined and GLib will be built
|
||||
with additional debug code enabled. You can override this behavior using
|
||||
<option>-Dglib_debug</option>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dforce_posix_threads=true</option></title>
|
||||
|
||||
<para>
|
||||
Normally, <application>Meson</application> should be able to work out
|
||||
the correct thread implementation to use. This option forces POSIX
|
||||
threads to be used even if the platform provides another threading API
|
||||
(for example, on Windows).
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dbsymbolic_functions=false</option> and
|
||||
<option>-Dbsymbolic_functions=true</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib uses the <option>-Bsymbolic-functions</option>
|
||||
linker flag to avoid intra-library PLT jumps. A side-effect
|
||||
of this is that it is no longer possible to override
|
||||
internal uses of GLib functions with
|
||||
<envar>LD_PRELOAD</envar>. Therefore, it may make
|
||||
sense to turn this feature off in some situations.
|
||||
The <option>-Dbsymbolic_functions=false</option> option allows
|
||||
to do that.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dgtk_doc=false</option> and
|
||||
<option>-Dgtk_doc=true</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib will detect whether the
|
||||
<application>gtk-doc</application> package is installed.
|
||||
If it is, then it will use it to extract and build the
|
||||
documentation for the GLib library. These options
|
||||
can be used to explicitly control whether
|
||||
<application>gtk-doc</application> should be
|
||||
used or not. If it is not used, the distributed,
|
||||
pre-generated HTML files will be installed instead of
|
||||
building them on your machine.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dman=false</option> and
|
||||
<option>-Dman=true</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib will detect whether <application>xsltproc</application>
|
||||
and the necessary DocBook stylesheets are installed.
|
||||
If they are, then it will use them to rebuild the included
|
||||
man pages from the XML sources. These options can be used
|
||||
to explicitly control whether man pages should be rebuilt
|
||||
used or not. The distribution includes pre-generated man
|
||||
pages.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dxattr=false</option> and
|
||||
<option>-Dxattr=true</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib will detect whether the
|
||||
<function>getxattr()</function>
|
||||
family of functions is available. If it is, then extended
|
||||
attribute support will be included in GIO. These options can
|
||||
be used to explicitly control whether extended attribute
|
||||
support should be included or not. <function>getxattr()</function>
|
||||
and friends can be provided by glibc or by the standalone
|
||||
libattr library.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dselinux=auto</option>,
|
||||
<option>-Dselinux=enabled</option> or
|
||||
<option>-Dselinux=disabled</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib will detect if libselinux is available and
|
||||
include SELinux support in GIO if it is. These options can be
|
||||
used to explicitly control whether SELinux support should
|
||||
be included.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Ddtrace=false</option> and
|
||||
<option>-Ddtrace=true</option></title>
|
||||
|
||||
<para>
|
||||
By default, GLib will detect if DTrace support is available, and use it.
|
||||
These options can be used to explicitly control whether DTrace support
|
||||
is compiled into GLib.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Dsystemtap=false</option> and
|
||||
<option>-Dsystemtap=true</option></title>
|
||||
|
||||
<para>
|
||||
This option requires DTrace support. If it is available, then
|
||||
GLib will also check for the presence of SystemTap.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title><option>-Db_coverage=true</option> and
|
||||
<option>-Db_coverage=false</option></title>
|
||||
|
||||
<para>
|
||||
Enable the generation of coverage reports for the GLib tests.
|
||||
This requires the lcov frontend to gcov from the
|
||||
<ulink url="http://ltp.sourceforge.net">Linux Test Project</ulink>.
|
||||
To generate a coverage report, use
|
||||
<command>ninja coverage-html</command>. The report is placed in the
|
||||
<filename>meson-logs</filename> directory.
|
||||
</para>
|
||||
</formalpara>
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
91
docs/reference/glib/character-set.md
Normal file
91
docs/reference/glib/character-set.md
Normal file
@ -0,0 +1,91 @@
|
||||
Title: Character set conversions
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2010, 2012, 2014 Matthias Clasen
|
||||
|
||||
# Character set conversions
|
||||
|
||||
The [`func@GLib.convert`] family of function wraps the functionality of
|
||||
iconv(). In addition to pure character set conversions, GLib has functions
|
||||
to deal with the extra complications of encodings for file names.
|
||||
|
||||
## File Name Encodings
|
||||
|
||||
Historically, UNIX has not had a defined encoding for file names: a file
|
||||
name is valid as long as it does not have path separators in it ("/").
|
||||
However, displaying file names may require conversion: from the character
|
||||
set in which they were created, to the character set in which the
|
||||
application operates. Consider the Spanish file name "Presentación.sxi". If
|
||||
the application which created it uses ISO-8859-1 for its encoding,
|
||||
|
||||
```
|
||||
Character: P r e s e n t a c i ó n . s x i
|
||||
Hex code: 50 72 65 73 65 6e 74 61 63 69 f3 6e 2e 73 78 69
|
||||
```
|
||||
|
||||
However, if the application use UTF-8, the actual file name on disk would
|
||||
look like this:
|
||||
|
||||
```
|
||||
Character: P r e s e n t a c i ó n . s x i
|
||||
Hex code: 50 72 65 73 65 6e 74 61 63 69 c3 b3 6e 2e 73 78 69
|
||||
```
|
||||
|
||||
Glib uses UTF-8 for its strings, and GUI toolkits like GTK that use GLib do
|
||||
the same thing. If you get a file name from the file system, for example,
|
||||
from `readdir()` or from [`method@GLib.Dir.read_name`], and you wish to
|
||||
display the file name to the user, you will need to convert it into UTF-8.
|
||||
The opposite case is when the user types the name of a file they wish to
|
||||
save: the toolkit will give you that string in UTF-8 encoding, and you will
|
||||
need to convert it to the character set used for file names before you can
|
||||
create the file with `open()` or `fopen()`.
|
||||
|
||||
By default, GLib assumes that file names on disk are in UTF-8 encoding. This
|
||||
is a valid assumption for file systems which were created relatively
|
||||
recently: most applications use UTF-8 encoding for their strings, and that
|
||||
is also what they use for the file names they create. However, older file
|
||||
systems may still contain file names created in "older" encodings, such as
|
||||
ISO-8859-1. In this case, for compatibility reasons, you may want to
|
||||
instruct GLib to use that particular encoding for file names rather than
|
||||
UTF-8. You can do this by specifying the encoding for file names in the
|
||||
`G_FILENAME_ENCODING` environment variable. For example, if your installation
|
||||
uses ISO-8859-1 for file names, you can put this in your `~/.profile`:
|
||||
|
||||
export G_FILENAME_ENCODING=ISO-8859-1
|
||||
|
||||
GLib provides the functions [`func@GLib.filename_to_utf8`] and
|
||||
[`func@GLib.filename_from_utf8`] to perform the necessary conversions. These
|
||||
functions convert file names from the encoding specified in
|
||||
`G_FILENAME_ENCODING` to UTF-8 and vice-versa. This diagram illustrates how
|
||||
these functions are used to convert between UTF-8 and the encoding for file
|
||||
names in the file system.
|
||||
|
||||
## Conversion between file name encodings
|
||||
|
||||
![](file-name-encodings.png)
|
||||
|
||||
## Checklist for Application Writers
|
||||
|
||||
This section is a practical summary of the detailed things to do to make
|
||||
sure your applications process file name encodings correctly.
|
||||
|
||||
1. If you get a file name from the file system from a function such as
|
||||
`readdir()` or `gtk_file_chooser_get_filename()`, you do not need to do
|
||||
any conversion to pass that file name to functions like `open()`,
|
||||
`rename()`, or `fopen()` -- those are "raw" file names which the file
|
||||
system understands.
|
||||
2. If you need to display a file name, convert it to UTF-8 first by using
|
||||
[`func@GLib.filename_to_utf8`]. If conversion fails, display a string
|
||||
like "Unknown file name". Do not convert this string back into the
|
||||
encoding used for file names if you wish to pass it to the file system;
|
||||
use the original file name instead.
|
||||
3. For example, the document window of a word processor could display
|
||||
"Unknown file name" in its title bar but still let the user save the
|
||||
file, as it would keep the raw file name internally. This can happen if
|
||||
the user has not set the `G_FILENAME_ENCODING` environment variable even
|
||||
though he has files whose names are not encoded in UTF-8.
|
||||
4. If your user interface lets the user type a file name for saving or
|
||||
renaming, convert it to the encoding used for file names in the file
|
||||
system by using [`func@GLib.filename_from_utf8`]. Pass the converted file
|
||||
name to functions like `fopen()`. If conversion fails, ask the user to
|
||||
enter a different file name. This can happen if the user types Japanese
|
||||
characters when `G_FILENAME_ENCODING` is set to ISO-8859-1, for example.
|
71
docs/reference/glib/compiling.md
Normal file
71
docs/reference/glib/compiling.md
Normal file
@ -0,0 +1,71 @@
|
||||
Title: Compiling GLib Applications
|
||||
|
||||
# Compiling GLib Applications
|
||||
|
||||
To compile a GLib application, you need to tell the compiler where to find
|
||||
the GLib header files and libraries. This is done with the
|
||||
[`pkg-config`](https://www.freedesktop.org/wiki/Software/pkg-config/)
|
||||
utility.
|
||||
|
||||
The following interactive shell session demonstrates how pkg-config is used
|
||||
(the actual output on your system may be different):
|
||||
|
||||
$ pkg-config --cflags glib-2.0
|
||||
-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
|
||||
$ pkg-config --libs glib-2.0
|
||||
-L/usr/lib -lm -lglib-2.0
|
||||
|
||||
See the `pkg-config` website for more information about `pkg-config`.
|
||||
|
||||
If your application uses or GObject features, it must be compiled and linked
|
||||
with the options returned by the following `pkg-config` invocation:
|
||||
|
||||
$ pkg-config --cflags --libs gobject-2.0
|
||||
|
||||
If your application uses modules, it must be compiled and linked with the
|
||||
options returned by one of the following pkg-config invocations:
|
||||
|
||||
$ pkg-config --cflags --libs gmodule-no-export-2.0
|
||||
$ pkg-config --cflags --libs gmodule-2.0
|
||||
|
||||
The difference between the two is that `gmodule-2.0` adds `--export-dynamic`
|
||||
to the linker flags, which is often not needed.
|
||||
|
||||
The simplest way to compile a program is to use the "backticks" feature of
|
||||
the shell. If you enclose a command in backticks (not single quotes), then
|
||||
its output will be substituted into the command line before execution. So to
|
||||
compile a GLib Hello, World, you would type the following:
|
||||
|
||||
$ cc `pkg-config --cflags glib-2.0` hello.c -o hello `pkg-config --libs glib-2.0`
|
||||
|
||||
Deprecated GLib functions are annotated to make the compiler emit warnings
|
||||
when they are used (e.g. with GCC, you need to use the
|
||||
`-Wdeprecated-declarations option`). If these warnings are problematic, they
|
||||
can be turned off by defining the preprocessor symbol
|
||||
`GLIB_DISABLE_DEPRECATION_WARNINGS` by using the commandline option
|
||||
`-DGLIB_DISABLE_DEPRECATION_WARNINGS`
|
||||
|
||||
GLib deprecation annotations are versioned; by defining the macros
|
||||
`GLIB_VERSION_MIN_REQUIRED` and `GLIB_VERSION_MAX_ALLOWED`, you can specify the
|
||||
range of GLib versions whose API you want to use. APIs that were deprecated
|
||||
before or introduced after this range will trigger compiler warnings.
|
||||
|
||||
Since GLib 2.62, the older deprecation mechanism of hiding deprecated
|
||||
interfaces entirely from the compiler by using the preprocessor symbol
|
||||
`G_DISABLE_DEPRECATED` has been removed. All deprecations are now handled
|
||||
using the above mechanism.
|
||||
|
||||
The recommended way of using GLib has always been to only include the
|
||||
toplevel headers `glib.h`, `glib-object.h`, `gio.h`. Starting with 2.32, GLib
|
||||
enforces this by generating an error when individual headers are directly
|
||||
included.
|
||||
|
||||
Still, there are some exceptions; these headers have to be included
|
||||
separately:
|
||||
|
||||
- `gmodule.h`
|
||||
- `glib-unix.h`
|
||||
- `glib/gi18n-lib.h` or `glib/gi18n.h` (see the section on
|
||||
[Internationalization](i18n.html))
|
||||
- `glib/gprintf.h` and `glib/gstdio.h` (we don't want to pull in all of
|
||||
stdio)
|
@ -1,125 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<refentry id="glib-compiling" revision="17 Jan 2002">
|
||||
<refmeta>
|
||||
<refentrytitle>Compiling GLib Applications</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GLib Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>Compiling GLib Applications</refname>
|
||||
<refpurpose>
|
||||
How to compile your GLib application
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Compiling GLib Applications on UNIX</title>
|
||||
|
||||
<para>
|
||||
To compile a GLib application, you need to tell the compiler where to
|
||||
find the GLib header files and libraries. This is done with the
|
||||
<application>pkg-config</application> utility.
|
||||
</para>
|
||||
<para>
|
||||
The following interactive shell session demonstrates how
|
||||
<application>pkg-config</application> is used (the actual output on
|
||||
your system may be different):
|
||||
<programlisting>
|
||||
$ pkg-config --cflags glib-2.0
|
||||
-I/usr/include/glib-2.0 -I/usr/lib/glib-2.0/include
|
||||
$ pkg-config --libs glib-2.0
|
||||
-L/usr/lib -lm -lglib-2.0
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
See the <ulink url="http://www.freedesktop.org/wiki/Software/pkg-config">pkg-config website</ulink>
|
||||
for more information about <application>pkg-config</application>.
|
||||
</para>
|
||||
<para>
|
||||
If your application uses or <structname>GObject</structname>
|
||||
features, it must be compiled and linked with the options returned
|
||||
by the following <application>pkg-config</application> invocation:
|
||||
<programlisting>
|
||||
$ pkg-config --cflags --libs gobject-2.0
|
||||
</programlisting>
|
||||
</para>
|
||||
<para>
|
||||
If your application uses modules, it must be compiled and linked
|
||||
with the options returned by one of the following
|
||||
<application>pkg-config</application> invocations:
|
||||
<programlisting>
|
||||
$ pkg-config --cflags --libs gmodule-no-export-2.0
|
||||
$ pkg-config --cflags --libs gmodule-2.0
|
||||
</programlisting>
|
||||
The difference between the two is that gmodule-2.0 adds
|
||||
<option>--export-dynamic</option> to the linker flags,
|
||||
which is often not needed.
|
||||
</para>
|
||||
<para>
|
||||
The simplest way to compile a program is to use command substitution
|
||||
feature of a shell. A command written in the format
|
||||
<literal>$(command)</literal> gets substituted into the command line
|
||||
before execution. So to compile a GLib Hello, World, you would type
|
||||
the following:
|
||||
<programlisting>
|
||||
$ cc hello.c $(pkg-config --cflags --libs glib-2.0) -o hello
|
||||
</programlisting>
|
||||
</para>
|
||||
<note><para>
|
||||
Note that the name of the file must come before the other options
|
||||
(such as <emphasis>pkg-config</emphasis>), or else you may get an
|
||||
error from the linker.
|
||||
</para></note>
|
||||
|
||||
<para>
|
||||
Deprecated GLib functions are annotated to make the compiler
|
||||
emit warnings when they are used (e.g. with gcc, you need to use
|
||||
the -Wdeprecated-declarations option). If these warnings are
|
||||
problematic, they can be turned off by defining the preprocessor
|
||||
symbol %GLIB_DISABLE_DEPRECATION_WARNINGS by using the commandline
|
||||
option <literal>-DGLIB_DISABLE_DEPRECATION_WARNINGS</literal>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
GLib deprecation annotations are versioned; by defining the
|
||||
macros %GLIB_VERSION_MIN_REQUIRED and %GLIB_VERSION_MAX_ALLOWED,
|
||||
you can specify the range of GLib versions whose API you want
|
||||
to use. APIs that were deprecated before or introduced after
|
||||
this range will trigger compiler warnings.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Since GLib 2.62, the older deprecation mechanism of hiding deprecated interfaces
|
||||
entirely from the compiler by using the preprocessor symbol
|
||||
<literal>G_DISABLE_DEPRECATED</literal> has been removed. All deprecations
|
||||
are now handled using the above mechanism.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The recommended way of using GLib has always been to only include the
|
||||
toplevel headers <filename>glib.h</filename>,
|
||||
<filename>glib-object.h</filename>, <filename>gio.h</filename>.
|
||||
Starting with 2.32, GLib enforces this by generating an error
|
||||
when individual headers are directly included.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Still, there are some exceptions; these headers have to be included
|
||||
separately:
|
||||
<filename>gmodule.h</filename>,
|
||||
<filename>glib-unix.h</filename>,
|
||||
<filename>glib/gi18n-lib.h</filename> or
|
||||
<filename>glib/gi18n.h</filename> (see
|
||||
the <link linkend="glib-I18N">Internationalization section</link>),
|
||||
<filename>glib/gprintf.h</filename> and
|
||||
<filename>glib/gstdio.h</filename>
|
||||
(we don't want to pull in all of stdio).
|
||||
</para>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
281
docs/reference/glib/conversion-macros.md
Normal file
281
docs/reference/glib/conversion-macros.md
Normal file
@ -0,0 +1,281 @@
|
||||
Title: Conversion Macros
|
||||
|
||||
# Conversion Macros
|
||||
|
||||
## Type Conversion
|
||||
|
||||
Many times GLib, GTK, and other libraries allow you to pass "user data" to a
|
||||
callback, in the form of a void pointer. From time to time you want to pass
|
||||
an integer instead of a pointer. You could allocate an integer, with
|
||||
something like:
|
||||
|
||||
```c
|
||||
int *ip = g_new (int, 1);
|
||||
*ip = 42;
|
||||
```
|
||||
|
||||
But this is inconvenient, and it's annoying to have to free the memory at
|
||||
some later time.
|
||||
|
||||
Pointers are always at least 32 bits in size (on all platforms GLib intends
|
||||
to support). Thus you can store at least 32-bit integer values in a pointer
|
||||
value. Naively, you might try this, but it's incorrect:
|
||||
|
||||
```c
|
||||
gpointer p;
|
||||
int i;
|
||||
p = (void*) 42;
|
||||
i = (int) p;
|
||||
```
|
||||
|
||||
Again, that example was not correct, don't copy it.
|
||||
|
||||
The problem is that on some systems you need to do this:
|
||||
|
||||
```c
|
||||
gpointer p;
|
||||
int i;
|
||||
p = (void*) (long) 42;
|
||||
i = (int) (long) p;
|
||||
```
|
||||
|
||||
The GLib macros `GPOINTER_TO_INT()`, `GINT_TO_POINTER()`, etc. take care to
|
||||
do the right thing on every platform.
|
||||
|
||||
**Warning**: You may not store pointers in integers. This is not portable in
|
||||
any way, shape or form. These macros only allow storing integers in
|
||||
pointers, and only preserve 32 bits of the integer; values outside the range
|
||||
of a 32-bit integer will be mangled.
|
||||
|
||||
|
||||
``GINT_TO_POINTER(value)``, ``GPOINTER_TO_INT(value)``
|
||||
: Stuffs an integer into a pointer type, and vice versa. Remember, you may not
|
||||
store pointers in integers. This is not portable in any way, shape or form.
|
||||
These macros only allow storing integers in pointers, and only preserve 32
|
||||
bits of the integer; values outside the range of a 32-bit integer will be
|
||||
mangled.
|
||||
|
||||
``GUINT_TO_POINTER(value)``, ``GPOINTER_TO_UINT(value)``
|
||||
: Stuffs an unsigned integer into a pointer type, and vice versa.
|
||||
|
||||
``GSIZE_TO_POINTER(value)``, ``GPOINTER_TO_SIZE(value)``
|
||||
: Stuffs a `size_t` into a pointer type, and vice versa.
|
||||
|
||||
## Byte Order Conversion
|
||||
|
||||
These macros provide a portable way to determine the host byte order and to
|
||||
convert values between different byte orders.
|
||||
|
||||
The byte order is the order in which bytes are stored to create larger data
|
||||
types such as the #gint and #glong values. The host byte order is the byte
|
||||
order used on the current machine.
|
||||
|
||||
Some processors store the most significant bytes (i.e. the bytes that hold
|
||||
the largest part of the value) first. These are known as big-endian
|
||||
processors. Other processors (notably the x86 family) store the most
|
||||
significant byte last. These are known as little-endian processors.
|
||||
|
||||
Finally, to complicate matters, some other processors store the bytes in a
|
||||
rather curious order known as PDP-endian. For a 4-byte word, the 3rd most
|
||||
significant byte is stored first, then the 4th, then the 1st and finally the
|
||||
2nd.
|
||||
|
||||
Obviously there is a problem when these different processors communicate
|
||||
with each other, for example over networks or by using binary file formats.
|
||||
This is where these macros come in. They are typically used to convert
|
||||
values into a byte order which has been agreed on for use when communicating
|
||||
between different processors. The Internet uses what is known as 'network
|
||||
byte order' as the standard byte order (which is in fact the big-endian byte
|
||||
order).
|
||||
|
||||
Note that the byte order conversion macros may evaluate their arguments
|
||||
multiple times, thus you should not use them with arguments which have
|
||||
side-effects.
|
||||
|
||||
`G_BYTE_ORDER`
|
||||
: The host byte order. This can be either `G_LITTLE_ENDIAN` or `G_BIG_ENDIAN`.
|
||||
|
||||
`G_LITTLE_ENDIAN`
|
||||
: Specifies the little endian byte order.
|
||||
|
||||
`G_BIG_ENDIAN`
|
||||
: Specifies the big endian byte order.
|
||||
|
||||
`G_PDP_ENDIAN`
|
||||
: Specifies the PDP endian byte order.
|
||||
|
||||
### Signed
|
||||
|
||||
`GINT_FROM_BE(value)`
|
||||
: Converts an `int` value from big-endian to host byte order.
|
||||
|
||||
`GINT_FROM_LE(value)`
|
||||
: Converts an `int` value from little-endian to host byte order.
|
||||
|
||||
`GINT_TO_BE(value)`
|
||||
: Converts an `int` value from host byte order to big-endian.
|
||||
|
||||
`GINT_TO_LE(value)`
|
||||
: Converts an `int` value from host byte order to little-endian.
|
||||
|
||||
`GLONG_FROM_BE(value)`
|
||||
: Converts a `long` value from big-endian to the host byte order.
|
||||
|
||||
`GLONG_FROM_LE(value)`
|
||||
: Converts a `long` value from little-endian to host byte order.
|
||||
|
||||
`GLONG_TO_BE(value)`
|
||||
: Converts a `long` value from host byte order to big-endian.
|
||||
|
||||
`GLONG_TO_LE(value)`
|
||||
: Converts a `long` value from host byte order to little-endian.
|
||||
|
||||
`GSSIZE_FROM_BE(value)`
|
||||
: Converts a `ssize_t` value from big-endian to host byte order.
|
||||
|
||||
`GSSIZE_FROM_LE(value)`
|
||||
: Converts a `ssize_t` value from little-endian to host byte order.
|
||||
|
||||
`GSSIZE_TO_BE(value)`
|
||||
: Converts a `ssize_t` value from host byte order to big-endian.
|
||||
|
||||
`GSSIZE_TO_LE(value)`
|
||||
: Converts a `ssize_t` value from host byte order to little-endian.
|
||||
|
||||
`GINT16_FROM_BE(value)`
|
||||
: Converts an `int16_t` value from big-endian to host byte order.
|
||||
|
||||
`GINT16_FROM_LE(value)`
|
||||
: Converts an `int16_t` value from little-endian to host byte order.
|
||||
|
||||
`GINT16_TO_BE(value)`
|
||||
: Converts an `int16_t` value from host byte order to big-endian.
|
||||
|
||||
`GINT16_TO_LE(value)`
|
||||
: Converts an `int16_t` value from host byte order to little-endian.
|
||||
|
||||
`GINT32_FROM_BE(value)`
|
||||
: Converts an `int32_t` value from big-endian to host byte order.
|
||||
|
||||
`GINT32_FROM_LE(value)`
|
||||
: Converts an `int32_t` value from little-endian to host byte order.
|
||||
|
||||
`GINT32_TO_BE(value)`
|
||||
: Converts an `int32_t` value from host byte order to big-endian.
|
||||
|
||||
`GINT32_TO_LE(value)`
|
||||
: Converts an `int32_t` value from host byte order to little-endian.
|
||||
|
||||
`GINT64_FROM_BE(value)`
|
||||
: Converts an `int64_t` value from big-endian to host byte order.
|
||||
|
||||
`GINT64_FROM_LE(value)`
|
||||
: Converts an `int64_t` value from little-endian to host byte order.
|
||||
|
||||
`GINT64_TO_BE(value)`
|
||||
: Converts an `int64_t` value from host byte order to big-endian.
|
||||
|
||||
`GINT64_TO_LE(value)`
|
||||
: Converts an `int64_t` value from host byte order to little-endian.
|
||||
|
||||
### Unsigned
|
||||
|
||||
`GUINT_FROM_BE(value)`
|
||||
: Converts an `unsigned int` value from big-endian to host byte order.
|
||||
|
||||
`GUINT_FROM_LE(value)`
|
||||
: Converts an `unsigned int` value from little-endian to host byte order.
|
||||
|
||||
`GUINT_TO_BE(value)`
|
||||
: Converts an `unsigned int` value from host byte order to big-endian.
|
||||
|
||||
`GUINT_TO_LE(value)`
|
||||
: Converts an `unsigned int` value from host byte order to little-endian.
|
||||
|
||||
`GULONG_FROM_BE(value)`
|
||||
: Converts an `unsigned long` value from big-endian to host byte order.
|
||||
|
||||
`GULONG_FROM_LE(value)`
|
||||
: Converts an `unsigned long` value from little-endian to host byte order.
|
||||
|
||||
`GULONG_TO_BE(value)`
|
||||
: Converts an `unsigned long` value from host byte order to big-endian.
|
||||
|
||||
`GULONG_TO_LE(value)`
|
||||
: Converts an `unsigned long` value from host byte order to little-endian.
|
||||
|
||||
`GSIZE_FROM_BE(value)`
|
||||
: Converts a `size_t` value from big-endian to the host byte order.
|
||||
|
||||
`GSIZE_FROM_LE(value)`
|
||||
: Converts a `size_t` value from little-endian to host byte order.
|
||||
|
||||
`GSIZE_TO_BE(value)`
|
||||
: Converts a `size_t` value from host byte order to big-endian.
|
||||
|
||||
`GSIZE_TO_LE(value)`
|
||||
: Converts a `size_t` value from host byte order to little-endian.
|
||||
|
||||
`GUINT16_FROM_BE(value)`
|
||||
: Converts an `uint16_t` value from big-endian to host byte order.
|
||||
|
||||
`GUINT16_FROM_LE(value)`
|
||||
: Converts an `uint16_t` value from little-endian to host byte order.
|
||||
|
||||
`GUINT16_TO_BE(value)`
|
||||
: Converts an `uint16_t` value from host byte order to big-endian.
|
||||
|
||||
`GUINT16_TO_LE(value)`
|
||||
: Converts an `uint16_t` value from host byte order to little-endian.
|
||||
|
||||
`GUINT32_FROM_BE(value)`
|
||||
: Converts an `uint32_t` value from big-endian to host byte order.
|
||||
|
||||
`GUINT32_FROM_LE(value)`
|
||||
: Converts an `uint32_t` value from little-endian to host byte order.
|
||||
|
||||
`GUINT32_TO_BE(value)`
|
||||
: Converts an `uint32_t` value from host byte order to big-endian.
|
||||
|
||||
`GUINT32_TO_LE(value)`
|
||||
: Converts an `uint32_t` value from host byte order to little-endian.
|
||||
|
||||
`GUINT64_FROM_BE(value)`
|
||||
: Converts an `uint64_t` value from big-endian to host byte order.
|
||||
|
||||
`GUINT64_FROM_LE(value)`
|
||||
: Converts an `uint64_t` value from little-endian to host byte order.
|
||||
|
||||
`GUINT64_TO_BE(value)`
|
||||
: Converts an `uint64_t` value from host byte order to big-endian.
|
||||
|
||||
`GUINT64_TO_LE(value)`
|
||||
: Converts an `uint64_t` value from host byte order to little-endian.
|
||||
|
||||
`GUINT16_SWAP_BE_PDP(value)`
|
||||
: Converts an `uint16_t` value between big-endian and pdp-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT16_SWAP_LE_BE(value)`
|
||||
: Converts an `uint16_t` value between little-endian and big-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT16_SWAP_LE_PDP(value)`
|
||||
: Converts an `uint16_t` value between little-endian and pdp-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT32_SWAP_BE_PDP(value)`
|
||||
: Converts an `uint32_t` value between big-endian and pdp-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT32_SWAP_LE_BE(value)`
|
||||
: Converts an `uint32_t` value between little-endian and big-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT32_SWAP_LE_PDP(value)`
|
||||
: Converts an `uint32_t` value between little-endian and pdp-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
||||
|
||||
`GUINT64_SWAP_LE_BE(value)`
|
||||
: Converts a `uint64_t` value between little-endian and big-endian byte order.
|
||||
The conversion is symmetric so it can be used both ways.
|
88
docs/reference/glib/cross-compiling.md
Normal file
88
docs/reference/glib/cross-compiling.md
Normal file
@ -0,0 +1,88 @@
|
||||
Title: Cross-compiling the GLib package
|
||||
|
||||
# Cross-compiling the GLib Package
|
||||
|
||||
## Building the Library for a different architecture
|
||||
|
||||
Cross-compilation is the process of compiling a program or library on a
|
||||
different architecture or operating system then it will be run upon. GLib is
|
||||
slightly more difficult to cross-compile than many packages because much of
|
||||
GLib is about hiding differences between different systems.
|
||||
|
||||
These notes cover things specific to cross-compiling GLib; for general
|
||||
information about cross-compilation, see the [Meson
|
||||
documentation](http://mesonbuild.com/Cross-compilation.html).
|
||||
|
||||
GLib tries to detect as much information as possible about the target system
|
||||
by compiling and linking programs without actually running anything;
|
||||
however, some information GLib needs is not available this way. This
|
||||
information needs to be provided to meson via a ‘cross file’.
|
||||
|
||||
As an example of using a cross file, to cross compile for the ‘MingW32’
|
||||
Win64 runtime environment on a Linux system, create a file `cross_file.txt`
|
||||
with the following contents:
|
||||
|
||||
```
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
c_args = []
|
||||
c_link_args = []
|
||||
|
||||
[binaries]
|
||||
c = 'x86_64-w64-mingw32-gcc'
|
||||
cpp = 'x86_64-w64-mingw32-g++'
|
||||
ar = 'x86_64-w64-mingw32-ar'
|
||||
ld = 'x86_64-w64-mingw32-ld'
|
||||
objcopy = 'x86_64-w64-mingw32-objcopy'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
|
||||
windres = 'x86_64-w64-mingw32-windres'
|
||||
```
|
||||
|
||||
Then execute the following commands:
|
||||
|
||||
meson setup --cross-file cross_file.txt builddir
|
||||
|
||||
The complete list of cross properties follows. Most of these won't need to
|
||||
be set in most cases.
|
||||
|
||||
## Cross properties
|
||||
|
||||
`have_[function]`
|
||||
: When meson checks if a function is supported, the test can be overridden by
|
||||
setting the `have_function` property to `true` or `false`. For example:
|
||||
|
||||
Checking for function "fsync" : YES
|
||||
|
||||
can be overridden by setting
|
||||
|
||||
have_fsync = false
|
||||
|
||||
`growing_stack=[true/false]`
|
||||
: Whether the stack grows up or down. Most places will want `false`. A few
|
||||
architectures, such as PA-RISC need `true`.
|
||||
|
||||
`have_strlcpy=[true/false]`
|
||||
: Whether you have `strlcpy()` that matches OpenBSD. Defaults to `false`,
|
||||
which is safe, since GLib uses a built-in version in that case.
|
||||
|
||||
`va_val_copy=[true/false]`
|
||||
: Whether `va_list` can be copied as a pointer. If set to `false`, then
|
||||
`memcopy()` will be used. Only matters if you don't have `va_copy()` or
|
||||
`__va_copy()`. (So, doesn't matter for GCC.) Defaults to `true` which is
|
||||
slightly more common than `false`.
|
||||
|
||||
`have_c99_vsnprintf=[true/false]`
|
||||
: Whether you have a `vsnprintf()` with C99 semantics. (C99 semantics means
|
||||
returning the number of bytes that would have been written had the output
|
||||
buffer had enough space.) Defaults to `false`.
|
||||
|
||||
`have_c99_snprintf=[true/false]`
|
||||
: Whether you have a `snprintf()` with C99 semantics. (C99 semantics means
|
||||
returning the number of bytes that would have been written had the output
|
||||
buffer had enough space.) Defaults to `false`.
|
@ -1,147 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<refentry id="glib-cross-compiling" revision="7 Aug 2018">
|
||||
<refmeta>
|
||||
<refentrytitle>Cross-compiling the GLib package</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GLib Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>Cross-compiling the GLib Package</refname>
|
||||
<refpurpose>
|
||||
How to cross-compile GLib
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1 id="cross">
|
||||
<title>Building the Library for a different architecture</title>
|
||||
<para>
|
||||
Cross-compilation is the process of compiling a program or
|
||||
library on a different architecture or operating system then
|
||||
it will be run upon. GLib is slightly more difficult to
|
||||
cross-compile than many packages because much of GLib is
|
||||
about hiding differences between different systems.
|
||||
</para>
|
||||
<para>
|
||||
These notes cover things specific to cross-compiling GLib;
|
||||
for general information about cross-compilation, see the
|
||||
<ulink url="http://mesonbuild.com/Cross-compilation.html">meson</ulink>
|
||||
info pages.
|
||||
</para>
|
||||
<para>
|
||||
GLib tries to detect as much information as possible about
|
||||
the target system by compiling and linking programs without
|
||||
actually running anything; however, some information GLib
|
||||
needs is not available this way. This information needs
|
||||
to be provided to meson via a ‘cross file’.
|
||||
</para>
|
||||
<para>
|
||||
As an example of using a cross file, to cross compile for
|
||||
the ‘MingW32’ Win64 runtime environment on a Linux system,
|
||||
create a file <filename>cross_file.txt</filename> with the following
|
||||
contents:
|
||||
</para>
|
||||
<programlisting>
|
||||
[host_machine]
|
||||
system = 'windows'
|
||||
cpu_family = 'x86_64'
|
||||
cpu = 'x86_64'
|
||||
endian = 'little'
|
||||
|
||||
[properties]
|
||||
c_args = []
|
||||
c_link_args = []
|
||||
|
||||
[binaries]
|
||||
c = 'x86_64-w64-mingw32-gcc'
|
||||
cpp = 'x86_64-w64-mingw32-g++'
|
||||
ar = 'x86_64-w64-mingw32-ar'
|
||||
ld = 'x86_64-w64-mingw32-ld'
|
||||
objcopy = 'x86_64-w64-mingw32-objcopy'
|
||||
strip = 'x86_64-w64-mingw32-strip'
|
||||
pkgconfig = 'x86_64-w64-mingw32-pkg-config'
|
||||
windres = 'x86_64-w64-mingw32-windres'
|
||||
</programlisting>
|
||||
<para>
|
||||
Then execute the following commands:
|
||||
</para>
|
||||
<programlisting>
|
||||
meson --cross-file cross_file.txt builddir
|
||||
</programlisting>
|
||||
<para>
|
||||
The complete list of cross properties follows. Most
|
||||
of these won't need to be set in most cases.
|
||||
</para>
|
||||
</refsect1>
|
||||
<refsect1 id="cross-properties">
|
||||
<title>Cross properties</title>
|
||||
<formalpara>
|
||||
<title>have_[function]</title>
|
||||
|
||||
<para>
|
||||
When meson checks if a function is supported, the test can be
|
||||
overridden by setting the
|
||||
<literal>have_<replaceable>function</replaceable></literal> property
|
||||
to <constant>true</constant> or <constant>false</constant>.
|
||||
For example <programlisting>Checking for function "fsync" : YES</programlisting>
|
||||
can be overridden by setting <programlisting>have_fsync = false</programlisting>
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>growing_stack=[true/false]</title>
|
||||
|
||||
<para>
|
||||
Whether the stack grows up or down. Most places will want
|
||||
<constant>false</constant>.
|
||||
A few architectures, such as PA-RISC need <constant>true</constant>.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>have_strlcpy=[true/false]</title>
|
||||
|
||||
<para>
|
||||
Whether you have <function>strlcpy()</function> that matches
|
||||
OpenBSD. Defaults to <constant>false</constant>, which is safe,
|
||||
since GLib uses a built-in version in that case.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>va_val_copy=[true/false]</title>
|
||||
|
||||
<para>
|
||||
Whether <type>va_list</type> can be copied as a pointer. If set
|
||||
to <constant>false</constant>, then <function>memcopy()</function>
|
||||
will be used. Only matters if you don't have
|
||||
<function>va_copy()</function> or <function>__va_copy()</function>.
|
||||
(So, doesn't matter for GCC.)
|
||||
Defaults to <constant>true</constant> which is slightly more common
|
||||
than <constant>false</constant>.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>have_c99_vsnprintf=[true/false]</title>
|
||||
|
||||
<para>
|
||||
Whether you have a <function>vsnprintf()</function> with C99
|
||||
semantics. (C99 semantics means returning the number of bytes
|
||||
that would have been written had the output buffer had enough
|
||||
space.) Defaults to <constant>false</constant>.
|
||||
</para>
|
||||
</formalpara>
|
||||
<formalpara>
|
||||
<title>have_c99_snprintf=[true/false]</title>
|
||||
|
||||
<para>
|
||||
Whether you have a <function>snprintf()</function> with C99
|
||||
semantics. (C99 semantics means returning the number of bytes
|
||||
that would have been written had the output buffer had enough
|
||||
space.) Defaults to <constant>false</constant>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
</refsect1>
|
||||
|
||||
</refentry>
|
487
docs/reference/glib/error-reporting.md
Normal file
487
docs/reference/glib/error-reporting.md
Normal file
@ -0,0 +1,487 @@
|
||||
Title: Error Reporting
|
||||
|
||||
# Error Reporting
|
||||
|
||||
GLib provides a standard method of reporting errors from a called function
|
||||
to the calling code. (This is the same problem solved by exceptions in other
|
||||
languages.) It's important to understand that this method is both a data
|
||||
type (the [`type@GLib.Error`] struct) and a set of rules. If you use
|
||||
`GError` incorrectly, then your code will not properly interoperate with
|
||||
other code that uses `GError`, and users of your API will probably get
|
||||
confused. In most cases, using `GError` is preferred over numeric error
|
||||
codes, but there are situations where numeric error codes are useful for
|
||||
performance.
|
||||
|
||||
First and foremost: `GError` should only be used to report recoverable
|
||||
runtime errors, never to report programming errors. If the programmer has
|
||||
screwed up, then you should use `g_warning()`, `g_return_if_fail()`,
|
||||
`g_assert()`, `g_error()`, or some similar facility. (Incidentally, remember
|
||||
that the `g_error()` function should only be used for programming errors, it
|
||||
should not be used to print any error reportable via `GError`.)
|
||||
|
||||
Examples of recoverable runtime errors are "file not found" or "failed to
|
||||
parse input." Examples of programming errors are "NULL passed to `strcmp()`"
|
||||
or "attempted to free the same pointer twice." These two kinds of errors are
|
||||
fundamentally different: runtime errors should be handled or reported to the
|
||||
user, programming errors should be eliminated by fixing the bug in the
|
||||
program. This is why most functions in GLib and GTK do not use the `GError`
|
||||
facility.
|
||||
|
||||
Functions that can fail take a return location for a `GError` as their last
|
||||
argument. On error, a new `GError` instance will be allocated and returned
|
||||
to the caller via this argument. For example:
|
||||
|
||||
```c
|
||||
gboolean g_file_get_contents (const char *filename,
|
||||
char **contents,
|
||||
gsize *length,
|
||||
GError **error);
|
||||
```
|
||||
|
||||
If you pass a non-`NULL` value for the `error` argument, it should
|
||||
point to a location where an error can be placed. For example:
|
||||
|
||||
```c
|
||||
char *contents;
|
||||
GError *err = NULL;
|
||||
|
||||
g_file_get_contents ("foo.txt", &contents, NULL, &err);
|
||||
g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
|
||||
if (err != NULL)
|
||||
{
|
||||
// Report error to user, and free error
|
||||
g_assert (contents == NULL);
|
||||
fprintf (stderr, "Unable to read file: %s\n", err->message);
|
||||
g_error_free (err);
|
||||
}
|
||||
else
|
||||
{
|
||||
// Use file contents
|
||||
g_assert (contents != NULL);
|
||||
}
|
||||
```
|
||||
|
||||
Note that `err != NULL` in this example is a reliable indicator of whether
|
||||
`g_file_get_contents()` failed. Additionally, `g_file_get_contents()`
|
||||
returns a boolean which indicates whether it was successful.
|
||||
|
||||
Because `g_file_get_contents()` returns `FALSE` on failure, if you
|
||||
are only interested in whether it failed and don't need to display
|
||||
an error message, you can pass `NULL` for the `error` argument:
|
||||
|
||||
```c
|
||||
if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) // ignore errors
|
||||
// no error occurred
|
||||
;
|
||||
else
|
||||
// error
|
||||
;
|
||||
```
|
||||
|
||||
The `GError` object contains three fields: `domain` indicates the module the
|
||||
error-reporting function is located in, `code` indicates the specific error
|
||||
that occurred, and `message` is a user-readable error message with as many
|
||||
details as possible. Several functions are provided to deal with an error
|
||||
received from a called function: `g_error_matches()` returns `TRUE` if the
|
||||
error matches a given domain and code, `g_propagate_error()` copies an error
|
||||
into an error location (so the calling function will receive it), and
|
||||
`g_clear_error()` clears an error location by freeing the error and
|
||||
resetting the location to `NULL`. To display an error to the user, simply
|
||||
display the `message`, perhaps along with additional context known only to
|
||||
the calling function (the file being opened, or whatever - though in the
|
||||
`g_file_get_contents()` case, the `message` already contains a filename).
|
||||
|
||||
Since error messages may be displayed to the user, they need to be valid
|
||||
UTF-8 (all GTK widgets expect text to be UTF-8). Keep this in mind in
|
||||
particular when formatting error messages with filenames, which are in the
|
||||
'filename encoding', and need to be turned into UTF-8 using
|
||||
`g_filename_to_utf8()`, `g_filename_display_name()` or
|
||||
`g_utf8_make_valid()`.
|
||||
|
||||
Note, however, that many error messages are too technical to display to the
|
||||
user in an application, so prefer to use `g_error_matches()` to categorize
|
||||
errors from called functions, and build an appropriate error message for the
|
||||
context within your application. Error messages from a `GError` are more
|
||||
appropriate to be printed in system logs or on the command line. They are
|
||||
typically translated.
|
||||
|
||||
## Reporting errors
|
||||
|
||||
When implementing a function that can report errors, the basic tool is
|
||||
`g_set_error()`. Typically, if a fatal error occurs you want to
|
||||
`g_set_error()`, then return immediately. `g_set_error()` does nothing if
|
||||
the error location passed to it is `NULL`. Here's an example:
|
||||
|
||||
```c
|
||||
int
|
||||
foo_open_file (GError **error)
|
||||
{
|
||||
int fd;
|
||||
int saved_errno;
|
||||
|
||||
g_return_val_if_fail (error == NULL || *error == NULL, -1);
|
||||
|
||||
fd = open ("file.txt", O_RDONLY);
|
||||
saved_errno = errno;
|
||||
|
||||
if (fd < 0)
|
||||
{
|
||||
g_set_error (error,
|
||||
FOO_ERROR, // error domain
|
||||
FOO_ERROR_BLAH, // error code
|
||||
"Failed to open file: %s", // error message format string
|
||||
g_strerror (saved_errno));
|
||||
return -1;
|
||||
}
|
||||
else
|
||||
return fd;
|
||||
}
|
||||
```
|
||||
|
||||
Things are somewhat more complicated if you yourself call another function
|
||||
that can report a `GError`. If the sub-function indicates fatal errors in
|
||||
some way other than reporting a `GError`, such as by returning `TRUE` on
|
||||
success, you can simply do the following:
|
||||
|
||||
```c
|
||||
gboolean
|
||||
my_function_that_can_fail (GError **err)
|
||||
{
|
||||
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
|
||||
if (!sub_function_that_can_fail (err))
|
||||
{
|
||||
// assert that error was set by the sub-function
|
||||
g_assert (err == NULL || *err != NULL);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// otherwise continue, no error occurred
|
||||
g_assert (err == NULL || *err == NULL);
|
||||
}
|
||||
```
|
||||
|
||||
If the sub-function does not indicate errors other than by reporting a
|
||||
`GError` (or if its return value does not reliably indicate errors) you need
|
||||
to create a temporary `GError` since the passed-in one may be `NULL`.
|
||||
`g_propagate_error()` is intended for use in this case.
|
||||
|
||||
```c
|
||||
gboolean
|
||||
my_function_that_can_fail (GError **err)
|
||||
{
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
|
||||
tmp_error = NULL;
|
||||
sub_function_that_can_fail (&tmp_error);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
// store tmp_error in err, if err != NULL,
|
||||
// otherwise call g_error_free() on tmp_error
|
||||
g_propagate_error (err, tmp_error);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// otherwise continue, no error occurred
|
||||
}
|
||||
```
|
||||
|
||||
Error pileups are always a bug. For example, this code is incorrect:
|
||||
|
||||
```c
|
||||
gboolean
|
||||
my_function_that_can_fail (GError **err)
|
||||
{
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
|
||||
tmp_error = NULL;
|
||||
sub_function_that_can_fail (&tmp_error);
|
||||
other_function_that_can_fail (&tmp_error);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (err, tmp_error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
`tmp_error` should be checked immediately after
|
||||
`sub_function_that_can_fail()`, and either cleared or propagated upward. The
|
||||
rule is: after each error, you must either handle the error, or return it to
|
||||
the calling function.
|
||||
|
||||
Note that passing `NULL` for the error location is the equivalent of
|
||||
handling an error by always doing nothing about it. So the following code is
|
||||
fine, assuming errors in `sub_function_that_can_fail()` are not fatal to
|
||||
`my_function_that_can_fail()`:
|
||||
|
||||
```c
|
||||
gboolean
|
||||
my_function_that_can_fail (GError **err)
|
||||
{
|
||||
GError *tmp_error;
|
||||
|
||||
g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
|
||||
sub_function_that_can_fail (NULL); // ignore errors
|
||||
|
||||
tmp_error = NULL;
|
||||
other_function_that_can_fail (&tmp_error);
|
||||
|
||||
if (tmp_error != NULL)
|
||||
{
|
||||
g_propagate_error (err, tmp_error);
|
||||
return FALSE;
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
Note that passing `NULL` for the error location ignores errors; it's
|
||||
equivalent to:
|
||||
|
||||
```cpp
|
||||
try { sub_function_that_can_fail (); } catch (...) {}
|
||||
```
|
||||
|
||||
in C++. It does not mean to leave errors unhandled; it means to handle them
|
||||
by doing nothing.
|
||||
|
||||
## Error domains
|
||||
|
||||
Error domains and codes are conventionally named as follows:
|
||||
|
||||
- The error domain is called `<NAMESPACE>_<MODULE>_ERROR`, for example
|
||||
`G_SPAWN_ERROR` or `G_THREAD_ERROR`:
|
||||
```c
|
||||
#define G_SPAWN_ERROR g_spawn_error_quark ()
|
||||
|
||||
G_DEFINE_QUARK (g-spawn-error-quark, g_spawn_error)
|
||||
```
|
||||
|
||||
- The quark function for the error domain is called
|
||||
`<namespace>_<module>_error_quark`, for example `g_spawn_error_quark()` or
|
||||
`g_thread_error_quark()`.
|
||||
|
||||
- The error codes are in an enumeration called `<Namespace><Module>Error`;
|
||||
for example, `GThreadError` or `GSpawnError`.
|
||||
|
||||
- Members of the error code enumeration are called
|
||||
`<NAMESPACE>_<MODULE>_ERROR_<CODE>`, for example `G_SPAWN_ERROR_FORK` or
|
||||
`G_THREAD_ERROR_AGAIN`.
|
||||
|
||||
- If there's a "generic" or "unknown" error code for unrecoverable errors it
|
||||
doesn't make sense to distinguish with specific codes, it should be called
|
||||
`<NAMESPACE>_<MODULE>_ERROR_FAILED`, for example `G_SPAWN_ERROR_FAILED`.
|
||||
In the case of error code enumerations that may be extended in future
|
||||
releases, you should generally not handle this error code explicitly, but
|
||||
should instead treat any unrecognized error code as equivalent to
|
||||
`FAILED`.
|
||||
|
||||
## Comparison of `GError` and traditional error handling
|
||||
|
||||
`GError` has several advantages over traditional numeric error codes:
|
||||
importantly, tools like [gobject-introspection](https://gi.readthedocs.org)
|
||||
understand `GError`s and convert them to exceptions in bindings; the message
|
||||
includes more information than just a code; and use of a domain helps
|
||||
prevent misinterpretation of error codes.
|
||||
|
||||
`GError` has disadvantages though: it requires a memory allocation, and
|
||||
formatting the error message string has a performance overhead. This makes
|
||||
it unsuitable for use in retry loops where errors are a common case, rather
|
||||
than being unusual. For example, using `G_IO_ERROR_WOULD_BLOCK` means
|
||||
hitting these overheads in the normal control flow. String formatting
|
||||
overhead can be eliminated by using `g_set_error_literal()` in some cases.
|
||||
|
||||
These performance issues can be compounded if a function wraps the `GError`s
|
||||
returned by the functions it calls: this multiplies the number of
|
||||
allocations and string formatting operations. This can be partially
|
||||
mitigated by using `g_prefix_error()`.
|
||||
|
||||
## Rules for use of `GError`
|
||||
|
||||
Summary of rules for use of `GError`:
|
||||
|
||||
- Do not report programming errors via `GError`.
|
||||
|
||||
- The last argument of a function that returns an error should be a location
|
||||
where a `GError` can be placed (i.e. `GError **error`). If `GError` is
|
||||
used with varargs, the `GError**` should be the last argument before the
|
||||
`...`.
|
||||
|
||||
- The caller may pass `NULL` for the `GError**` if they are not interested
|
||||
in details of the exact error that occurred.
|
||||
|
||||
- If `NULL` is passed for the `GError**` argument, then errors should not be
|
||||
returned to the caller, but your function should still abort and return if
|
||||
an error occurs. That is, control flow should not be affected by whether
|
||||
the caller wants to get a `GError`.
|
||||
|
||||
- If a `GError` is reported, then your function by definition had a fatal
|
||||
failure and did not complete whatever it was supposed to do. If the
|
||||
failure was not fatal, then you handled it and you should not report it.
|
||||
If it was fatal, then you must report it and discontinue whatever you were
|
||||
doing immediately.
|
||||
|
||||
- If a `GError` is reported, out parameters are not guaranteed to be set to
|
||||
any defined value.
|
||||
|
||||
- A `GError*` must be initialized to `NULL` before passing its address to a
|
||||
function that can report errors.
|
||||
|
||||
- `GError` structs must not be stack-allocated.
|
||||
|
||||
- "Piling up" errors is always a bug. That is, if you assign a new `GError`
|
||||
to a `GError*` that is non-`NULL`, thus overwriting the previous error, it
|
||||
indicates that you should have aborted the operation instead of
|
||||
continuing. If you were able to continue, you should have cleared the
|
||||
previous error with `g_clear_error()`. `g_set_error()` will complain if
|
||||
you pile up errors.
|
||||
|
||||
- By convention, if you return a boolean value indicating success then
|
||||
`TRUE` means success and `FALSE` means failure. Avoid creating functions
|
||||
which have a boolean return value and a `GError` parameter, but where the
|
||||
boolean does something other than signal whether the `GError` is set.
|
||||
Among other problems, it requires C callers to allocate a temporary error.
|
||||
Instead, provide a `gboolean *` out parameter. There are functions in
|
||||
GLib itself such as `g_key_file_has_key()` that are hard to use because of
|
||||
this. If `FALSE` is returned, the error must be set to a non-`NULL` value.
|
||||
One exception to this is that in situations that are already considered to
|
||||
be undefined behaviour (such as when a `g_return_val_if_fail()` check
|
||||
fails), the error need not be set. Instead of checking separately whether
|
||||
the error is set, callers should ensure that they do not provoke undefined
|
||||
behaviour, then assume that the error will be set on failure.
|
||||
|
||||
- A `NULL` return value is also frequently used to mean that an error
|
||||
occurred. You should make clear in your documentation whether `NULL` is a
|
||||
valid return value in non-error cases; if `NULL` is a valid value, then
|
||||
users must check whether an error was returned to see if the function
|
||||
succeeded.
|
||||
|
||||
- When implementing a function that can report errors, you may want
|
||||
to add a check at the top of your function that the error return
|
||||
location is either `NULL` or contains a `NULL` error (e.g.
|
||||
`g_return_if_fail (error == NULL || *error == NULL);`).
|
||||
|
||||
## Extended `GError` Domains
|
||||
|
||||
Since GLib 2.68 it is possible to extend the `GError` type. This is
|
||||
done with the `G_DEFINE_EXTENDED_ERROR()` macro. To create an
|
||||
extended `GError` type do something like this in the header file:
|
||||
|
||||
```c
|
||||
typedef enum
|
||||
{
|
||||
MY_ERROR_BAD_REQUEST,
|
||||
} MyError;
|
||||
#define MY_ERROR (my_error_quark ())
|
||||
GQuark my_error_quark (void);
|
||||
int
|
||||
my_error_get_parse_error_id (GError *error);
|
||||
const char *
|
||||
my_error_get_bad_request_details (GError *error);
|
||||
```
|
||||
|
||||
and in the implementation:
|
||||
|
||||
```c
|
||||
typedef struct
|
||||
{
|
||||
int parse_error_id;
|
||||
char *bad_request_details;
|
||||
} MyErrorPrivate;
|
||||
|
||||
static void
|
||||
my_error_private_init (MyErrorPrivate *priv)
|
||||
{
|
||||
priv->parse_error_id = -1;
|
||||
// No need to set priv->bad_request_details to NULL,
|
||||
// the struct is initialized with zeros.
|
||||
}
|
||||
|
||||
static void
|
||||
my_error_private_copy (const MyErrorPrivate *src_priv, MyErrorPrivate *dest_priv)
|
||||
{
|
||||
dest_priv->parse_error_id = src_priv->parse_error_id;
|
||||
dest_priv->bad_request_details = g_strdup (src_priv->bad_request_details);
|
||||
}
|
||||
|
||||
static void
|
||||
my_error_private_clear (MyErrorPrivate *priv)
|
||||
{
|
||||
g_free (priv->bad_request_details);
|
||||
}
|
||||
|
||||
// This defines the my_error_get_private and my_error_quark functions.
|
||||
G_DEFINE_EXTENDED_ERROR (MyError, my_error)
|
||||
|
||||
int
|
||||
my_error_get_parse_error_id (GError *error)
|
||||
{
|
||||
MyErrorPrivate *priv = my_error_get_private (error);
|
||||
g_return_val_if_fail (priv != NULL, -1);
|
||||
return priv->parse_error_id;
|
||||
}
|
||||
|
||||
const char *
|
||||
my_error_get_bad_request_details (GError *error)
|
||||
{
|
||||
MyErrorPrivate *priv = my_error_get_private (error);
|
||||
g_return_val_if_fail (priv != NULL, NULL);
|
||||
g_return_val_if_fail (error->code != MY_ERROR_BAD_REQUEST, NULL);
|
||||
return priv->bad_request_details;
|
||||
}
|
||||
|
||||
static void
|
||||
my_error_set_bad_request (GError **error,
|
||||
const char *reason,
|
||||
int error_id,
|
||||
const char *details)
|
||||
{
|
||||
MyErrorPrivate *priv;
|
||||
g_set_error (error, MY_ERROR, MY_ERROR_BAD_REQUEST, "Invalid request: %s", reason);
|
||||
if (error != NULL && *error != NULL)
|
||||
{
|
||||
priv = my_error_get_private (error);
|
||||
g_return_val_if_fail (priv != NULL, NULL);
|
||||
priv->parse_error_id = error_id;
|
||||
priv->bad_request_details = g_strdup (details);
|
||||
}
|
||||
}
|
||||
```
|
||||
|
||||
An example of use of the error could be:
|
||||
|
||||
```c
|
||||
gboolean
|
||||
send_request (GBytes *request, GError **error)
|
||||
{
|
||||
ParseFailedStatus *failure = validate_request (request);
|
||||
if (failure != NULL)
|
||||
{
|
||||
my_error_set_bad_request (error, failure->reason, failure->error_id, failure->details);
|
||||
parse_failed_status_free (failure);
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
return send_one (request, error);
|
||||
}
|
||||
```
|
||||
|
||||
Please note that if you are a library author and your library exposes an
|
||||
existing error domain, then you can't make this error domain an extended one
|
||||
without breaking ABI. This is because earlier it was possible to create an
|
||||
error with this error domain on the stack and then copy it with
|
||||
`g_error_copy()`. If the new version of your library makes the error domain
|
||||
an extended one, then `g_error_copy()` called by code that allocated the
|
||||
error on the stack will try to copy more data than it used to, which will
|
||||
lead to undefined behavior. You must not stack-allocate errors with an
|
||||
extended error domain, and it is bad practice to stack-allocate any other
|
||||
`GError`s.
|
||||
|
||||
Extended error domains in unloadable plugins/modules are not supported.
|
@ -24,11 +24,7 @@
|
||||
General Public License (GNU LGPL).
|
||||
</para>
|
||||
|
||||
<xi:include href="building.xml" />
|
||||
<xi:include href="cross.xml" />
|
||||
<xi:include href="programming.xml" />
|
||||
<xi:include href="xml/compiling.xml" />
|
||||
<xi:include href="running.xml" />
|
||||
<xi:include href="changes.xml" />
|
||||
<xi:include href="resources.xml" />
|
||||
|
||||
@ -118,8 +114,6 @@
|
||||
<xi:include href="xml/datasets.xml" />
|
||||
<xi:include href="xml/gvarianttype.xml"/>
|
||||
<xi:include href="xml/gvariant.xml"/>
|
||||
<xi:include href="gvariant-varargs.xml"/>
|
||||
<xi:include href="gvariant-text.xml"/>
|
||||
<xi:include href="xml/refcount.xml"/>
|
||||
<xi:include href="xml/rcbox.xml"/>
|
||||
<xi:include href="xml/arcbox.xml"/>
|
||||
|
99
docs/reference/glib/glib.toml.in
Normal file
99
docs/reference/glib/glib.toml.in
Normal file
@ -0,0 +1,99 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# Copyright 2023 Matthias Clasen
|
||||
# Copyright 2023 Philip Withnall
|
||||
|
||||
[library]
|
||||
name = "GLib"
|
||||
version = "@VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/glib/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/glib.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
authors = "GLib Development Team"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "GLib is a general-purpose, portable utility library, which provides many useful data types, macros, type conversions, string utilities, file utilities, a mainloop abstraction, and so on."
|
||||
related = [ "GModule-2.0", "GObject-2.0", "Gio-2.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
[related."GModule-2.0"]
|
||||
name = "GModule"
|
||||
description = "Portable API for dynamically loading modules"
|
||||
docs_url = "https://docs.gtk.org/gmodule/"
|
||||
|
||||
[related."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[related."Gio-2.0"]
|
||||
name = "GIO"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[extra]
|
||||
urlmap_file = "urlmap.js"
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"building.md",
|
||||
"compiling.md",
|
||||
"cross-compiling.md",
|
||||
"running.md",
|
||||
|
||||
"gvariant-format-strings.md",
|
||||
"gvariant-text-format.md",
|
||||
|
||||
"character-set.md",
|
||||
"i18n.md",
|
||||
|
||||
"macros.md",
|
||||
"conversion-macros.md",
|
||||
"auto-cleanup.md",
|
||||
|
||||
"memory-slices.md",
|
||||
"error-reporting.md",
|
||||
"logging.md",
|
||||
"main-loop.md",
|
||||
"reference-counting.md",
|
||||
"testing.md",
|
||||
"threads.md",
|
||||
"markup.md",
|
||||
"goption.md",
|
||||
]
|
||||
content_images = [
|
||||
"file-name-encodings.png",
|
||||
"mainloop-states.gif",
|
||||
"Sorted_binary_tree_breadth-first_traversal.svg",
|
||||
"Sorted_binary_tree_inorder.svg",
|
||||
"Sorted_binary_tree_postorder.svg",
|
||||
"Sorted_binary_tree_preorder.svg",
|
||||
]
|
||||
|
||||
[[object]]
|
||||
pattern = "DEPRECATED_IN_2_*"
|
||||
hidden = true
|
||||
|
||||
[[object]]
|
||||
pattern = "DEPRECATED_MACRO_IN_2_*"
|
||||
hidden = true
|
||||
|
||||
[[object]]
|
||||
pattern = "DEPRECATED_ENUMERATOR_IN_2_*"
|
||||
hidden = true
|
||||
|
||||
[[object]]
|
||||
pattern = "DEPRECATED_TYPE_IN_2_*"
|
||||
hidden = true
|
||||
|
||||
[[object]]
|
||||
name = "test_assert_expected_messages_internal"
|
||||
hidden = true
|
||||
|
||||
[[object]]
|
||||
pattern = "macro__has_*"
|
||||
hidden = true
|
149
docs/reference/glib/goption.md
Normal file
149
docs/reference/glib/goption.md
Normal file
@ -0,0 +1,149 @@
|
||||
Title: Commandline option parser
|
||||
|
||||
# Commandline option parser
|
||||
|
||||
The GOption commandline parser is intended to be a simpler replacement
|
||||
for the popt library. It supports short and long commandline options,
|
||||
as shown in the following example:
|
||||
|
||||
testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2
|
||||
|
||||
The example demonstrates a number of features of the GOption commandline parser:
|
||||
|
||||
- Options can be single letters, prefixed by a single dash.
|
||||
- Multiple short options can be grouped behind a single dash.
|
||||
- Long options are prefixed by two consecutive dashes.
|
||||
- Options can have an extra argument, which can be a number, a string or
|
||||
a filename. For long options, the extra argument can be appended with
|
||||
an equals sign after the option name, which is useful if the extra
|
||||
argument starts with a dash, which would otherwise cause it to be
|
||||
interpreted as another option.
|
||||
- Non-option arguments are returned to the application as rest arguments.
|
||||
- An argument consisting solely of two dashes turns off further parsing,
|
||||
any remaining arguments (even those starting with a dash) are returned
|
||||
to the application as rest arguments.
|
||||
|
||||
Another important feature of GOption is that it can automatically
|
||||
generate nicely formatted help output. Unless it is explicitly turned
|
||||
off with [method@GLib.OptionContext.set_help_enabled], GOption will recognize
|
||||
the `--help`, `-?`, `--help-all` and `--help-groupname` options (where `groupname`
|
||||
is the name of a [struct@GLib.OptionGroup]) and write a text similar to the one shown
|
||||
in the following example to stdout.
|
||||
|
||||
Usage:
|
||||
testtreemodel [OPTION...] - test tree model performance
|
||||
|
||||
Help Options:
|
||||
-h, --help Show help options
|
||||
--help-all Show all help options
|
||||
--help-gtk Show GTK Options
|
||||
|
||||
Application Options:
|
||||
-r, --repeats=N Average over N repetitions
|
||||
-m, --max-size=M Test up to 2^M items
|
||||
--display=DISPLAY X display to use
|
||||
-v, --verbose Be verbose
|
||||
-b, --beep Beep when done
|
||||
--rand Randomize the data
|
||||
|
||||
GOption groups options in [struct@GLib.OptionGroup]s, which makes it easy to
|
||||
incorporate options from multiple sources. The intended use for this is
|
||||
to let applications collect option groups from the libraries it uses,
|
||||
add them to their #GOptionContext, and parse all options by a single call
|
||||
to [method@GLib.OptionContext.parse].
|
||||
|
||||
If an option is declared to be of type string or filename, GOption takes
|
||||
care of converting it to the right encoding; strings are returned in UTF-8,
|
||||
filenames are returned in the GLib filename encoding. Note that this only
|
||||
works if `setlocale()` has been called before [method@GLib.OptionContext.parse]
|
||||
|
||||
Here is a complete example of setting up GOption to parse the example
|
||||
commandline above and produce the example help output.
|
||||
|
||||
```c
|
||||
static gint repeats = 2;
|
||||
static gint max_size = 8;
|
||||
static gboolean verbose = FALSE;
|
||||
static gboolean beep = FALSE;
|
||||
static gboolean randomize = FALSE;
|
||||
|
||||
static GOptionEntry entries[] =
|
||||
{
|
||||
{ "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" },
|
||||
{ "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" },
|
||||
{ "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
|
||||
{ "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL },
|
||||
{ "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL },
|
||||
G_OPTION_ENTRY_NULL
|
||||
};
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
|
||||
context = g_option_context_new ("- test tree model performance");
|
||||
g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
|
||||
g_option_context_add_group (context, gtk_get_option_group (TRUE));
|
||||
if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
{
|
||||
g_print ("option parsing failed: %s\n", error->message);
|
||||
exit (1);
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
}
|
||||
```
|
||||
|
||||
On UNIX systems, the argv that is passed to `main()` has no particular
|
||||
encoding, even to the extent that different parts of it may have different
|
||||
encodings. In general, normal arguments and flags will be in the current
|
||||
locale and filenames should be considered to be opaque byte strings.
|
||||
Proper use of `G_OPTION_ARG_FILENAME` vs `G_OPTION_ARG_STRING` is
|
||||
therefore important.
|
||||
|
||||
Note that on Windows, filenames do have an encoding, but using
|
||||
[struct@GLib.OptionContext] with the argv as passed to `main()` will result
|
||||
in a program that can only accept commandline arguments with characters
|
||||
from the system codepage.This can cause problems when attempting to
|
||||
deal with filenames containing Unicode characters that fall outside
|
||||
of the codepage.
|
||||
|
||||
A solution to this is to use `g_win32_get_command_line()` and
|
||||
[method@GLib.OptionContext.parse_strv] which will properly handle full
|
||||
Unicode filenames. If you are using #GApplication, this is done
|
||||
automatically for you.
|
||||
|
||||
The following example shows how you can use #GOptionContext directly
|
||||
in order to correctly deal with Unicode filenames on Windows:
|
||||
|
||||
```c
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
GError *error = NULL;
|
||||
GOptionContext *context;
|
||||
gchar **args;
|
||||
|
||||
#ifdef G_OS_WIN32
|
||||
args = g_win32_get_command_line ();
|
||||
#else
|
||||
args = g_strdupv (argv);
|
||||
#endif
|
||||
|
||||
// set up context
|
||||
|
||||
if (!g_option_context_parse_strv (context, &args, &error))
|
||||
{
|
||||
// error happened
|
||||
}
|
||||
|
||||
...
|
||||
|
||||
g_strfreev (args);
|
||||
|
||||
...
|
||||
}
|
||||
```
|
503
docs/reference/glib/gvariant-format-strings.md
Normal file
503
docs/reference/glib/gvariant-format-strings.md
Normal file
@ -0,0 +1,503 @@
|
||||
Title: GVariant Format Strings
|
||||
|
||||
# GVariant Format Strings
|
||||
|
||||
## Variable Argument Conversions
|
||||
|
||||
This page attempts to document how to perform variable argument conversions
|
||||
with [struct@GLib.Variant].
|
||||
|
||||
Conversions occur according to format strings. A format string is a two-way
|
||||
mapping between a single `GVariant` value and one or more C values.
|
||||
|
||||
A conversion from C values into a `GVariant` value is made using the
|
||||
[ctor@GLib.Variant.new] function. A conversion from a `GVariant` into C
|
||||
values is made using the [method@GLib.Variant.get] function.
|
||||
|
||||
## Syntax
|
||||
|
||||
This section exhaustively describes all possibilities for GVariant format
|
||||
strings. There are no valid forms of format strings other than those
|
||||
described here. Please note that the format string syntax is likely to
|
||||
expand in the future.
|
||||
|
||||
Valid format strings have one of the following forms:
|
||||
|
||||
- any type string
|
||||
- a type string prefixed with a `@`
|
||||
- `&s`, `&o`, `&g`, `^as`, `^a&s`, `^ao`, `^a&o`, `^ay`, `^&ay`, `^aay` or
|
||||
`^a&ay`.
|
||||
- any format string, prefixed with an `m`
|
||||
- a sequence of zero or more format strings, concatenated and enclosed in
|
||||
parentheses
|
||||
- an opening brace, followed by two format strings, followed by a closing
|
||||
brace (subject to the constraint that the first format string correspond
|
||||
to a type valid for use as the key type of a dictionary)
|
||||
|
||||
## Symbols
|
||||
|
||||
The following table describes the rough meaning of symbols that may appear inside a GVariant format string. Each symbol is described in detail in its own section, including usage examples.
|
||||
|
||||
| Symbol | Meaning |
|
||||
|--------|---------|
|
||||
| `b`, `y`, `n`, `q`, `i`, `u`, `x`, `t`, `h`, `d` | Used for building or deconstructing boolean, byte and numeric types. See [Numeric Types](#numeric-types) below. |
|
||||
| `s`, `o`, `g` | Used for building or deconstructing string types. See [Strings](#strings) below. |
|
||||
| `v` | Used for building or deconstructing variant types. See [Variants](#variants) below. |
|
||||
| `a` | Used for building or deconstructing arrays. See [Arrays](#arrays) below. |
|
||||
| `m` | Used for building or deconstructing maybe types. See [Maybe Types](#maybe-types) below. |
|
||||
| `()` | Used for building or deconstructing tuples. See [Tuples](#tuples) below. |
|
||||
| `{}` | Used for building or deconstructing dictionary entries. See [Dictionaries](#dictionaries) below. |
|
||||
| `@` | Used as a prefix for a `GVariant` type string (not a prefix for a format string, so `@as` is a valid format string but `@^as` is not). Denotes that a pointer to a GVariant should be used in place of the normal C type or types. For `g_variant_new()` this means that you must pass a non-`NULL` `(GVariant *)`; if it is a floating reference, ownership will be taken, as if by using `g_variant_ref_sink()`. For `g_variant_get()` this means that you must pass a pointer to a `(GVariant *)` for the value to be returned by reference or `NULL` to ignore the value. See [`GVariant *`](#gvariant) below. |
|
||||
| `*`, `?`, `r` | Exactly equivalent to `@*`, `@?` and `@r`. Provided only for completeness so that all `GVariant` type strings can be used also as format strings. See [`GVariant *`](#gvariant) below. |
|
||||
| `&` | Used as a prefix for a `GVariant` type string (not a prefix for a format string, so `&s` is a valid format string but `&@s` is not). Denotes that a C pointer to serialised data should be used in place of the normal C type. See [Pointers](#pointers) below. |
|
||||
| `^` | Used as a prefix on some specific types of format strings. See [Convenience Conversions](#convenience-conversions) below. |
|
||||
|
||||
## Numeric Types
|
||||
|
||||
Characters: `b`, `y`, `n`, `q`, `i`, `u`, `x`, `t`, `h`, `d`
|
||||
|
||||
Variable argument conversions from numeric types work in the most obvious
|
||||
way possible. Upon encountering one of these characters, `g_variant_new()`
|
||||
takes the equivalent C type as an argument. `g_variant_get()` takes a pointer
|
||||
to the equivalent C type (or `NULL` to ignore the value).
|
||||
|
||||
The equivalent C types are as follows:
|
||||
|
||||
| Character | Equivalent C type |
|
||||
|-----------|-------------------|
|
||||
| `b` | `gboolean` |
|
||||
| `y` | `guchar` |
|
||||
| `n` | `gint16` |
|
||||
| `q` | `guint16` |
|
||||
| `i` | `gint32` |
|
||||
| `u` | `guint32` |
|
||||
| `x` | `gint64` |
|
||||
| `t` | `guint64` |
|
||||
| `h` | `gint32` |
|
||||
| `d` | `gdouble` |
|
||||
|
||||
Note that in C, small integer types in variable argument lists are promoted
|
||||
up to `int` or `unsigned int` as appropriate, and read back accordingly. `int`
|
||||
is 32 bits on every platform on which GLib is currently supported. This
|
||||
means that you can use C expressions of type `int` with `g_variant_new()` and
|
||||
format characters `b`, `y`, `n`, `q`, `i`, `u` and `h`. Specifically, you
|
||||
can use integer literals with these characters.
|
||||
|
||||
When using the `x` and `t` characters, you must ensure that the value that
|
||||
you provide is 64 bit. This means that you should use a cast or make use of
|
||||
the `G_GINT64_CONSTANT` or `G_GUINT64_CONSTANT` macros.
|
||||
|
||||
No type promotion occurs when using `g_variant_get()` since it operates with
|
||||
pointers. The pointers must always point to a memory region of exactly the
|
||||
correct size.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *value1, *value2, *value3, *value4;
|
||||
|
||||
value1 = g_variant_new ("y", 200);
|
||||
value2 = g_variant_new ("b", TRUE);
|
||||
value3 = g_variant_new ("d", 37.5):
|
||||
value4 = g_variant_new ("x", G_GINT64_CONSTANT (998877665544332211));
|
||||
|
||||
{
|
||||
gdouble floating;
|
||||
gboolean truth;
|
||||
gint64 bignum;
|
||||
|
||||
|
||||
g_variant_get (value1, "y", NULL); /* ignore the value. */
|
||||
g_variant_get (value2, "b", &truth);
|
||||
g_variant_get (value3, "d", &floating);
|
||||
g_variant_get (value4, "x", &bignum);
|
||||
}
|
||||
```
|
||||
|
||||
## Strings
|
||||
|
||||
Characters: `s`, `o`, `g`
|
||||
|
||||
String conversions occur to and from standard nul-terminated C strings. Upon
|
||||
encountering an `s`, `o` or `g` in a format string, `g_variant_new()` takes a
|
||||
`(const gchar *)` and makes a copy of it. `NULL` is not a valid string; use
|
||||
maybe types to encode that. If the `o` or `g` characters are used, care must
|
||||
be taken to ensure that the passed string is a valid D-Bus object path or
|
||||
D-Bus type signature, respectively.
|
||||
|
||||
Upon encountering `s`, `o` or `g`, `g_variant_get()` takes a pointer to a
|
||||
`(gchar *)` (ie: `(gchar **)`) and sets it to a newly-allocated copy of the
|
||||
string. It is appropriate to free this copy using `g_free()`. `NULL` may
|
||||
also be passed to indicate that the value of the string should be ignored
|
||||
(in which case no copy is made).
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *value1, *value2, *value3;
|
||||
|
||||
value1 = g_variant_new ("s", "hello world!");
|
||||
value2 = g_variant_new ("o", "/must/be/a/valid/path");
|
||||
value3 = g_variant_new ("g", "iias");
|
||||
|
||||
#if 0
|
||||
g_variant_new ("s", NULL); /* not valid: NULL is not a string. */
|
||||
#endif
|
||||
|
||||
{
|
||||
gchar *result;
|
||||
|
||||
g_variant_get (value1, "s", &result);
|
||||
g_print ("It was '%s'\n", result);
|
||||
g_free (result);
|
||||
}
|
||||
```
|
||||
|
||||
## Variants
|
||||
|
||||
Characters: `v`
|
||||
|
||||
Upon encountering a `v`, `g_variant_new()` takes a `(GVariant *)`. The value
|
||||
of the `GVariant` is used as the contents of the variant value.
|
||||
|
||||
Upon encountering a `v`, `g_variant_get()` takes a pointer to a `(GVariant
|
||||
*)` (ie: `(GVariant **)`). It is set to a new reference to a `GVariant`
|
||||
instance containing the contents of the variant value. It is appropriate to
|
||||
free this reference using `g_variant_unref()`. `NULL` may also be passed to
|
||||
indicate that the value should be ignored (in which case no new reference is
|
||||
created).
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *x, *y;
|
||||
|
||||
/* the following two lines are equivalent: */
|
||||
x = g_variant_new ("v", y);
|
||||
x = g_variant_new_variant (y);
|
||||
|
||||
/* as are these: */
|
||||
g_variant_get (x, "v", &y);
|
||||
y = g_variant_get_variant (x);
|
||||
```
|
||||
|
||||
## Arrays
|
||||
|
||||
Characters: `a`
|
||||
|
||||
Upon encountering an `a` character followed by a type string,
|
||||
`g_variant_new()` will take a `(GVariantBuilder *)` that has been created as
|
||||
an array builder for an array of the type given in the type string. The
|
||||
builder will have `g_variant_builder_end()` called on it and the result will
|
||||
be used as the value. As a special exception, if the given type string is a
|
||||
definite type, then `NULL` may be given to mean an empty array of that type.
|
||||
|
||||
Upon encountering an `a` character followed by a type string,
|
||||
`g_variant_get()` will take a pointer to a `(GVariantIter *)` (ie:
|
||||
`(GVariantIter **)`). A new heap-allocated iterator is created and returned,
|
||||
initialised for iterating over the elements of the array. This iterator
|
||||
should be freed when you are done with it, using `g_variant_iter_free()`.
|
||||
`NULL` may also be given to indicate that the value of the array should be
|
||||
ignored.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariantBuilder *builder;
|
||||
GVariant *value;
|
||||
|
||||
builder = g_variant_builder_new (G_VARIANT_TYPE ("as"));
|
||||
g_variant_builder_add (builder, "s", "when");
|
||||
g_variant_builder_add (builder, "s", "in");
|
||||
g_variant_builder_add (builder, "s", "the");
|
||||
g_variant_builder_add (builder, "s", "course");
|
||||
value = g_variant_new ("as", builder);
|
||||
g_variant_builder_unref (builder);
|
||||
|
||||
{
|
||||
GVariantIter *iter;
|
||||
gchar *str;
|
||||
|
||||
g_variant_get (value, "as", &iter);
|
||||
while (g_variant_iter_loop (iter, "s", &str))
|
||||
g_print ("%s\n", str);
|
||||
g_variant_iter_free (iter);
|
||||
}
|
||||
|
||||
g_variant_unref (value);
|
||||
```
|
||||
|
||||
## Maybe Types
|
||||
|
||||
Characters: `m`
|
||||
|
||||
Maybe types are handled in two separate ways depending on the format string
|
||||
that follows the `m`. The method that is used currently depends entirely on
|
||||
the character immediately following the `m`.
|
||||
|
||||
The first way is used with format strings starting with `a`, `s`, `o`, `g`,
|
||||
`v`, `@`, `*`, `?`, `r`, `&`, or `^`. In all of these cases, for non-maybe
|
||||
types, `g_variant_new()` takes a pointer to a non-`NULL` value and
|
||||
`g_variant_get()` returns (by reference) a non-`NULL` pointer. When any of
|
||||
these format strings are prefixed with an `m`, the type of arguments that
|
||||
are collected does not change in any way, but `NULL` becomes a permissible
|
||||
value, to indicate the Nothing case.
|
||||
|
||||
Note that the "special exception" introduced in the array section for
|
||||
constructing empty arrays is ignored here. Using a `NULL` pointer with the
|
||||
format string `mas` constructs the Nothing value -- not an empty array.
|
||||
|
||||
The second way is used with all other format strings. For `g_variant_new()`
|
||||
an additional gboolean argument is collected and for `g_variant_get()` an
|
||||
additional `(gboolean *)`. Following this argument, the arguments that are
|
||||
normally collected for the equivalent non-maybe type will be collected.
|
||||
|
||||
If `FALSE` is given to `g_variant_new()` then the Nothing value is
|
||||
constructed and the collected arguments are ignored. Otherwise (if `TRUE`
|
||||
was given), the arguments are used in the normal way to create the Just
|
||||
value.
|
||||
|
||||
If `NULL` is given to `g_variant_get()` then the value is ignored. If a
|
||||
non-`NULL` pointer is given then it is used to return by reference whether
|
||||
the value was Just. In the case that the value was Just, the `gboolean` will
|
||||
be set to `TRUE` and the value will be stored in the arguments in the usual
|
||||
way. In the case that the value was Nothing, the `gboolean` will be set to
|
||||
`FALSE` and the arguments will be collected in the normal way but have their
|
||||
values set to binary zero.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *value1, *value2, *value3, *value4, *value5, *value6;
|
||||
value1 = g_variant_new ("ms", "Hello world");
|
||||
value2 = g_variant_new ("ms", NULL);
|
||||
value3 = g_variant_new ("(m(ii)s)", TRUE, 123, 456, "Done");
|
||||
value4 = g_variant_new ("(m(ii)s)", FALSE, -1, -1, "Done"); /* both '-1' are ignored. */
|
||||
value5 = g_variant_new ("(m@(ii)s)", NULL, "Done");
|
||||
|
||||
{
|
||||
GVariant *contents;
|
||||
const gchar *cstr;
|
||||
gboolean just;
|
||||
gint32 x, y;
|
||||
gchar *str;
|
||||
|
||||
g_variant_get (value1, "ms", &str);
|
||||
if (str != NULL)
|
||||
g_print ("str: %s\n", str);
|
||||
else
|
||||
g_print ("it was null\n");
|
||||
g_free (str);
|
||||
|
||||
|
||||
g_variant_get (value2, "m&s", &cstr);
|
||||
if (cstr != NULL)
|
||||
g_print ("str: %s\n", cstr);
|
||||
else
|
||||
g_print ("it was null\n");
|
||||
/* don't free 'cstr' */
|
||||
|
||||
|
||||
/* NULL passed for the gboolean *, but two 'gint32 *' still collected */
|
||||
g_variant_get (value3, "(m(ii)s)", NULL, NULL, NULL, &str);
|
||||
g_print ("string is %s\n", str);
|
||||
g_free (str);
|
||||
|
||||
/* note: &s used, so g_free() not needed */
|
||||
g_variant_get (value4, "(m(ii)&s)", &just, &x, &y, &cstr);
|
||||
if (just)
|
||||
g_print ("it was (%d, %d)\n", x, y);
|
||||
else
|
||||
g_print ("it was null\n");
|
||||
g_print ("string is %s\n", cstr);
|
||||
/* don't free 'cstr' */
|
||||
|
||||
|
||||
g_variant_get (value5, "(m*s)", &contents, NULL); /* ignore the string. */
|
||||
if (contents != NULL)
|
||||
{
|
||||
g_variant_get (contents, "(ii)", &x, &y);
|
||||
g_print ("it was (%d, %d)\n", x, y);
|
||||
g_variant_unref (contents);
|
||||
}
|
||||
else
|
||||
g_print ("it was null\n");
|
||||
}
|
||||
```
|
||||
|
||||
## Tuples
|
||||
|
||||
Characters: `()`
|
||||
|
||||
Tuples are handled by handling each item in the tuple, in sequence. Each
|
||||
item is handled in the usual way.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *value1, *value2;
|
||||
|
||||
value1 = g_variant_new ("(s(ii))", "Hello", 55, 77);
|
||||
value2 = g_variant_new ("()");
|
||||
|
||||
{
|
||||
gchar *string;
|
||||
gint x, y;
|
||||
|
||||
g_variant_get (value1, "(s(ii))", &string, &x, &y);
|
||||
g_print ("%s, %d, %d\n", string, x, y);
|
||||
g_free (string);
|
||||
|
||||
g_variant_get (value2, "()"); /* do nothing... */
|
||||
}
|
||||
```
|
||||
|
||||
## `GVariant *`
|
||||
|
||||
Characters: `@`, `*`, `?`, `r`
|
||||
|
||||
Upon encountering a `@` in front of a type string, `g_variant_new()` takes a
|
||||
non-`NULL` pointer to a `GVariant` and uses its value directly instead of
|
||||
collecting arguments to create the value. The provided `GVariant` must have
|
||||
a type that matches the type string following the `@`. `*` is the same as
|
||||
`@*` (ie: take a `GVariant` of any type). `?` is the same as `@?` (ie: take
|
||||
a `GVariant` of any basic type). `r` is the same as `@r` (ie: take a
|
||||
`GVariant` of any tuple type).
|
||||
|
||||
Upon encountering a `@` in front of a type string, `g_variant_get()` takes a
|
||||
pointer to a `(GVariant *)` (ie: a `(GVariant **)`) and sets it to a new
|
||||
reference to a `GVariant` containing the value (instead of deconstructing
|
||||
the value into C types in the usual way). `NULL` can be given to ignore the
|
||||
value. `*`, `?` and `r` are handled in a way analogous to what is stated
|
||||
above.
|
||||
|
||||
You can always use `*` as an alternative to `?`, `r` or any use of `@`.
|
||||
Using the other characters where possible is recommended, however, due to
|
||||
the improvements in type safety and code self-documentation.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *value1, *value2;
|
||||
|
||||
value1 = g_variant_new ("(i@ii)", 44, g_variant_new_int32 (55), 66);
|
||||
|
||||
/* note: consumes floating reference count on 'value1' */
|
||||
value2 = g_variant_new ("(@(iii)*)", value1, g_variant_new_string ("foo"));
|
||||
|
||||
{
|
||||
const gchar *string;
|
||||
GVariant *tmp;
|
||||
gsize length;
|
||||
gint x, y, z;
|
||||
|
||||
g_variant_get (value2, "((iii)*)", &x, &y, &z, &tmp);
|
||||
string = g_variant_get_string (tmp, &length);
|
||||
g_print ("it is %d %d %d %s (length=%d)\n", x, y, z, string, (int) length);
|
||||
g_variant_unref (tmp);
|
||||
|
||||
/* quick way to skip all the values in a tuple */
|
||||
g_variant_get (value2, "(rs)", NULL, &string); /* or "(@(iii)s)" */
|
||||
g_print ("i only got the string: %s\n", string);
|
||||
g_free (string);
|
||||
}
|
||||
```
|
||||
|
||||
## Dictionaries
|
||||
|
||||
Characters: `{}`
|
||||
|
||||
Dictionary entries are handled by handling first the key, then the value. Each is handled in the usual way.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariantBuilder *b;
|
||||
GVariant *dict;
|
||||
|
||||
b = g_variant_builder_new (G_VARIANT_TYPE ("a{sv}"));
|
||||
g_variant_builder_add (b, "{sv}", "name", g_variant_new_string ("foo"));
|
||||
g_variant_builder_add (b, "{sv}", "timeout", g_variant_new_int32 (10));
|
||||
dict = g_variant_builder_end (b);
|
||||
```
|
||||
|
||||
To extract data from nested dictionaries you can go through a vardict.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
GVariant *data;
|
||||
gint value = 1;
|
||||
gint max = 3;
|
||||
|
||||
/* type (oa{sa{sv}) */
|
||||
data = g_variant_new_parsed ("(%o, {'brightness': {'value': <%i>, 'max': <%i>}})",
|
||||
"/object/path", value, max);
|
||||
{
|
||||
GVariant *params;
|
||||
GVariant *p_brightness;
|
||||
gchar *obj
|
||||
gint p_max;
|
||||
|
||||
g_variant_get (data, "(o@a{?*})", &obj, ¶ms);
|
||||
g_print ("object_path: %s\n", obj);
|
||||
|
||||
p_brightness = g_variant_lookup_value (params, "brightness", G_VARIANT_TYPE_VARDICT);
|
||||
g_variant_lookup (p_brightness, "max", "i", &p_max);
|
||||
g_print ("max: %d\n", p_max);
|
||||
}
|
||||
```
|
||||
|
||||
## Pointers
|
||||
|
||||
Characters: `&`
|
||||
|
||||
The `&` character is used to indicate that serialised data should be
|
||||
directly exchanged via a pointer.
|
||||
|
||||
Currently, the only use for this character is when it is applied to a string
|
||||
(ie: `&s`, `&o` or `&g`). For `g_variant_new()` this has absolutely no
|
||||
effect. The string is collected and duplicated normally. For
|
||||
`g_variant_get()` it means that instead of creating a newly allocated copy
|
||||
of the string, a pointer to the serialised data is returned. This pointer
|
||||
should not be freed. Validity checks are performed to ensure that the string
|
||||
data will always be properly nul-terminated.
|
||||
|
||||
### Examples
|
||||
|
||||
```c
|
||||
{
|
||||
const gchar *str;
|
||||
GVariant *value;
|
||||
|
||||
value = g_variant_new ("&s", "hello world");
|
||||
g_variant_get (value, "&s", &str);
|
||||
g_print ("string is: %s\n", str);
|
||||
/* no need to free str */
|
||||
}
|
||||
```
|
||||
|
||||
## Convenience Conversions
|
||||
|
||||
Characters: `^`
|
||||
|
||||
The `^` character currently supports conversion to and from bytestrings or
|
||||
to and from arrays of strings or bytestrings. It does not support byte
|
||||
arrays. It has a number of forms.
|
||||
|
||||
In all forms, when used with `g_variant_new()` one pointer value is
|
||||
collected from the variable arguments and passed to a function (as given in
|
||||
the table below). The result of that function is used as the value for this
|
||||
position. When used with `g_variant_get()` one pointer value is produced by
|
||||
using the function (given in the table) and returned by reference.
|
||||
|
||||
| Conversion | Used with `g_variant_new()` | Used with `g_variant_get()` |
|
||||
|------------|----------------------------------------------------------|------------------------------------------------------------|
|
||||
| `^as` | equivalent to [`ctor@GLib.Variant.new_strv`] | equivalent to [`method@GLib.Variant.dup_strv`] |
|
||||
| `^a&s` | | equivalent to [`method@GLib.Variant.get_strv`] |
|
||||
| `^ao` | equivalent to [`ctor@GLib.Variant.new_objv`] | equivalent to [`method@GLib.Variant.dup_objv`] |
|
||||
| `^a&o` | | equivalent to [`method@GLib.Variant.get_objv`] |
|
||||
| `^ay` | equivalent to [`ctor@GLib.Variant.new_bytestring`] | equivalent to [`method@GLib.Variant.dup_bytestring`] |
|
||||
| `^&ay` | | equivalent to [`method@GLib.Variant.get_bytestring`] |
|
||||
| `^aay` | equivalent to [`ctor@GLib.Variant.new_bytestring_array`] | equivalent to [`method@GLib.Variant.dup_bytestring_array`] |
|
||||
| `^a&ay` | | equivalent to [`method@GLib.Variant.get_bytestring_array`] |
|
346
docs/reference/glib/gvariant-text-format.md
Normal file
346
docs/reference/glib/gvariant-text-format.md
Normal file
@ -0,0 +1,346 @@
|
||||
Title: GVariant Text Format
|
||||
|
||||
# GVariant Text Format
|
||||
|
||||
This page attempts to document the `GVariant` text format as produced by
|
||||
[`method@GLib.Variant.print`] and parsed by the [`func@GLib.Variant.parse`]
|
||||
family of functions. In most cases the style closely resembles the
|
||||
formatting of literals in Python but there are some additions and
|
||||
exceptions.
|
||||
|
||||
The functions that deal with `GVariant` text format absolutely always deal
|
||||
in UTF-8. Conceptually, `GVariant` text format is a string of Unicode
|
||||
characters, not bytes. Non-ASCII but otherwise printable Unicode characters
|
||||
are not treated any differently from normal ASCII characters.
|
||||
|
||||
The parser makes two passes. The purpose of the first pass is to determine
|
||||
the type of the value being parsed. The second pass does the actual parsing.
|
||||
Based on the fact that all elements in an array have to have the same type,
|
||||
`GVariant` is able to make some deductions that would not otherwise be
|
||||
possible. As an example:
|
||||
|
||||
[[1, 2, 3], [4, 5, 6]]
|
||||
|
||||
is parsed as an array of arrays of integers (type `aai`), but
|
||||
|
||||
[[1, 2, 3], [4, 5, 6.0]]
|
||||
|
||||
is parsed as an array of arrays of doubles (type `aad`).
|
||||
|
||||
As another example, `GVariant` is able to determine that
|
||||
|
||||
["hello", nothing]
|
||||
|
||||
is an array of maybe strings (type `ams`).
|
||||
|
||||
What the parser accepts as valid input is dependent on context. The API
|
||||
permits for out-of-band type information to be supplied to the parser (which
|
||||
will change its behaviour). This can be seen in the GSettings and GDBus
|
||||
command line utilities where the type information is available from the
|
||||
schema or the remote introspection information. The additional information
|
||||
can cause parses to succeed when they would not otherwise have been able to
|
||||
(by resolving ambiguous type information) or can cause them to fail (due to
|
||||
conflicting type information). Unless stated otherwise, the examples given
|
||||
in this section assume that no out-of-band type data has been given to the
|
||||
parser.
|
||||
|
||||
## Syntax Summary
|
||||
|
||||
The following table describes the rough meaning of symbols that may appear
|
||||
inside GVariant text format. Each symbol is described in detail in its own
|
||||
section, including usage examples.
|
||||
|
||||
| Symbol | Meaning |
|
||||
|--------|---------|
|
||||
| `true`, `false` | [Booleans](#booleans). |
|
||||
| `""`, `''` | String literal. See [Strings](#strings) below. |
|
||||
| numbers | See [Numbers](#numbers) below. |
|
||||
| `()` | [Tuples](#tuples). |
|
||||
| `[]` | [Arrays](#arrays). |
|
||||
| `{}` | [Dictionaries and Dictionary Entries](#dictionaries-and-dictionary-entries). |
|
||||
| `<>` | [Variants](#variants). |
|
||||
| `just`, `nothing` | [Maybe Types](#maybe-types). |
|
||||
| `@` | [Type Annotations](#type-annotations). |
|
||||
| `boolean`, `byte`, `int16`, `uint16`, `int32`, `uint32`, `handle`, `int64`, `uint64`, `double`, `string`, `objectpath`, `signature` | [Type Annotations](#type-annotations) |
|
||||
| `b""`, `b''` | [Bytestrings](#bytestrings). |
|
||||
| `%` | [Positional Parameters](#positional-parameters). |
|
||||
|
||||
## Booleans
|
||||
|
||||
The strings `true` and `false` are parsed as booleans. This is the only way
|
||||
to specify a boolean value.
|
||||
|
||||
## Strings
|
||||
|
||||
Strings literals must be quoted using `""` or `''`. The two are completely
|
||||
equivalent (except for the fact that each one is unable to contain itself
|
||||
unescaped).
|
||||
|
||||
Strings are Unicode strings with no particular encoding. For example, to
|
||||
specify the character `é`, you just write `'é'`. You could also give the
|
||||
Unicode codepoint of that character (`U+E9`) as the escape sequence
|
||||
`'\u00e9'`. Since the strings are pure Unicode, you should not attempt to
|
||||
encode the UTF-8 byte sequence corresponding to the string using escapes; it
|
||||
won't work and you'll end up with the individual characters corresponding to
|
||||
each byte.
|
||||
|
||||
Unicode escapes of the form `\uxxxx` and `\Uxxxxxxxx` are supported, in
|
||||
hexadecimal. The usual control sequence escapes `\a`, `\b`, `\f`, `\n`,
|
||||
`\r`, `\t` and `\v` are supported. Additionally, a `\` before a newline
|
||||
character causes the newline to be ignored. Finally, any other character
|
||||
following `\` is copied literally (for example, `\"` or `\\`) but for
|
||||
forwards compatibility with future additions you should only use this
|
||||
feature when necessary for escaping backslashes or quotes.
|
||||
|
||||
The usual octal and hexadecimal escapes `\0nnn` and `\xnn` are not supported
|
||||
here. Those escapes are used to encode byte values and `GVariant` strings
|
||||
are Unicode.
|
||||
|
||||
Single-character strings are not interpreted as bytes. Bytes must be
|
||||
specified by their numerical value.
|
||||
|
||||
## Numbers
|
||||
|
||||
Numbers are given by default as decimal values. Octal and hex values can be
|
||||
given in the usual way (by prefixing with `0` or `0x`). Note that `GVariant`
|
||||
considers bytes to be unsigned integers and will print them as a two digit
|
||||
hexadecimal number by default.
|
||||
|
||||
Floating point numbers can also be given in the usual ways, including
|
||||
scientific and hexadecimal notations.
|
||||
|
||||
For lack of additional information, integers will be parsed as `int32`
|
||||
values by default. If the number has a point or an `e` in it, then it will
|
||||
be parsed as a double precision floating point number by default. If type
|
||||
information is available (either explicitly or inferred) then that type will
|
||||
be used instead.
|
||||
|
||||
Some examples:
|
||||
|
||||
`5` parses as the `int32` value five.
|
||||
|
||||
`37.5` parses as a floating point value.
|
||||
|
||||
`3.75e1` parses the same as the value above.
|
||||
|
||||
`uint64 7` parses seven as a `uint64`. See [Type Annotations](#type-annotations).
|
||||
|
||||
## Tuples
|
||||
|
||||
Tuples are formed using the same syntax as Python. Here are some examples:
|
||||
|
||||
`()` parses as the empty tuple.
|
||||
|
||||
`(5,)` is a tuple containing a single value.
|
||||
|
||||
`("hello", 42)` is a pair. Note that values of different types are
|
||||
permitted.
|
||||
|
||||
## Arrays
|
||||
|
||||
Arrays are formed using the same syntax as Python uses for lists (which is
|
||||
arguably the term that `GVariant` should have used). Note that, unlike Python
|
||||
lists, `GVariant` arrays are statically typed. This has two implications.
|
||||
|
||||
First, all items in the array must have the same type. Second, the type of
|
||||
the array must be known, even in the case that it is empty. This means that
|
||||
(unless there is some other way to infer it) type information will need to
|
||||
be given explicitly for empty arrays.
|
||||
|
||||
The parser is able to infer some types based on the fact that all items in
|
||||
an array must have the same type. See the examples below:
|
||||
|
||||
`[1]` parses (without additional type information) as a one-item array of
|
||||
signed integers.
|
||||
|
||||
`[1, 2, 3]` parses (similarly) as a three-item array.
|
||||
|
||||
`[1, 2, 3.0]` parses as an array of doubles. This is the most simple case of
|
||||
the type inferencing in action.
|
||||
|
||||
`[(1, 2), (3, 4.0)]` causes the 2 to also be parsed as a double (but the 1
|
||||
and 3 are still integers).
|
||||
|
||||
`["", nothing]` parses as an array of maybe strings. The presence of
|
||||
"nothing" clearly implies that the array elements are nullable.
|
||||
|
||||
`[[], [""]]` will parse properly because the type of the first (empty) array
|
||||
can be inferred to be equal to the type of the second array (both are arrays
|
||||
of strings).
|
||||
|
||||
`[b'hello', []]` looks odd but will parse properly. See
|
||||
[Bytestrings](#bytestrings).
|
||||
|
||||
And some examples of errors:
|
||||
|
||||
`["hello", 42]` fails to parse due to conflicting types.
|
||||
|
||||
`[]` will fail to parse without additional type information.
|
||||
|
||||
## Dictionaries and Dictionary Entries
|
||||
|
||||
Dictionaries and dictionary entries are both specified using the `{}`
|
||||
characters.
|
||||
|
||||
The dictionary syntax is more commonly used. This is what the printer elects
|
||||
to use in the normal case of dictionary entries appearing in an array (AKA
|
||||
"a dictionary"). The separate syntax for dictionary entries is typically
|
||||
only used for when the entries appear on their own, outside of an array
|
||||
(which is valid but unusual). Of course, you are free to use the dictionary
|
||||
entry syntax within arrays but there is no good reason to do so (and the
|
||||
printer itself will never do so). Note that, as with arrays, the type of
|
||||
empty dictionaries must be established (either explicitly or through
|
||||
inference).
|
||||
|
||||
The dictionary syntax is the same as Python's syntax for dictionaries. Some
|
||||
examples:
|
||||
|
||||
`@a{sv} {}` parses as the empty dictionary of everyone's favourite type.
|
||||
|
||||
`@a{sv} []` is the same as above (owing to the fact that dictionaries are
|
||||
really arrays).
|
||||
|
||||
`{1: "one", 2: "two", 3: "three"}` parses as a dictionary mapping integers
|
||||
to strings.
|
||||
|
||||
The dictionary entry syntax looks just like a pair (2-tuple) that uses
|
||||
braces instead of parens. The presence of a comma immediately following the
|
||||
key differentiates it from the dictionary syntax (which features a colon
|
||||
after the first key). Some examples:
|
||||
|
||||
`{1, "one"}` is a free-standing dictionary entry that can be parsed on its
|
||||
own or as part of another container value.
|
||||
|
||||
`[{1, "one"}, {2, "two"}, {3, "three"}]` is exactly equivalent to the
|
||||
dictionary example given above.
|
||||
|
||||
## Variants
|
||||
|
||||
Variants are denoted using angle brackets (aka "XML brackets"), `<>`. They
|
||||
may not be omitted.
|
||||
|
||||
Using `<>` effectively disrupts the type inferencing that occurs between
|
||||
array elements. This can have positive and negative effects.
|
||||
|
||||
`[<"hello">, <42>]` will parse whereas `["hello", 42]` would not.
|
||||
|
||||
`[<['']>, <[]>]` will fail to parse even though `[[''], []]` parses
|
||||
successfully. You would need to specify `[<['']>, <@as []>]`.
|
||||
|
||||
`{"title": <"frobit">, "enabled": <true>, "width": <800>}` is an example of
|
||||
perhaps the most pervasive use of both dictionaries and variants.
|
||||
|
||||
## Maybe Types
|
||||
|
||||
The syntax for specifying maybe types is inspired by Haskell.
|
||||
|
||||
The null case is specified using the keyword nothing and the non-null case
|
||||
is explicitly specified using the keyword just. GVariant allows just to be
|
||||
omitted in every case that it is able to unambiguously determine the
|
||||
intention of the writer. There are two cases where it must be specified:
|
||||
|
||||
- when using nested maybes, in order to specify the just nothing case
|
||||
- to establish the nullability of the type of a value without explicitly
|
||||
specifying its full type
|
||||
|
||||
Some examples:
|
||||
|
||||
`just 'hello'` parses as a non-null nullable string.
|
||||
|
||||
`@ms 'hello'` is the same (demonstrating how just can be dropped if the type is already known).
|
||||
|
||||
`nothing` will not parse without extra type information.
|
||||
|
||||
`@ms nothing` parses as a null nullable string.
|
||||
|
||||
`[just 3, nothing]` is an array of nullable integers
|
||||
|
||||
`[3, nothing]` is the same as the above (demonstrating another place were just can be dropped).
|
||||
|
||||
`[3, just nothing]` parses as an array of maybe maybe integers (type `ammi`).
|
||||
|
||||
## Type Annotations
|
||||
|
||||
Type annotations allow additional type information to be given to the
|
||||
parser. Depending on the context, this type information can change the
|
||||
output of the parser, cause an error when parsing would otherwise have
|
||||
succeeded or resolve an error when parsing would have otherwise failed.
|
||||
|
||||
Type annotations come in two forms: type codes and type keywords.
|
||||
|
||||
Type keywords can be seen as more verbose (and more legible) versions of a
|
||||
common subset of the type codes. The type keywords `boolean`, `byte`,
|
||||
`int16`, `uint16`, `int32`, `uint32`, `handle`, `int64`, `uint64`, `double`,
|
||||
`string`, `objectpath` and literal signature are each exactly equivalent to
|
||||
their corresponding type code.
|
||||
|
||||
Type codes are an `@` ("at" sign) followed by a definite `GVariant` type
|
||||
string. Some examples:
|
||||
|
||||
`uint32 5` causes the number to be parsed unsigned instead of signed (the
|
||||
default).
|
||||
|
||||
`@u 5` is the same
|
||||
|
||||
`objectpath "/org/gnome/xyz"` creates an object path instead of a normal
|
||||
string
|
||||
|
||||
`@au []` specifies the type of the empty array (which would not parse
|
||||
otherwise)
|
||||
|
||||
`@ms ""` indicates that a string value is meant to have a maybe type
|
||||
|
||||
## Bytestrings
|
||||
|
||||
The bytestring syntax is a piece of syntactic sugar meant to complement the
|
||||
bytestring APIs in GVariant. It constructs arrays of non-`NUL` bytes (type
|
||||
`ay`) with a `NUL` terminator at the end. These are normal C strings with no
|
||||
particular encoding enforced, so the bytes may not be valid UTF-8.
|
||||
Bytestrings are a special case of byte arrays; byte arrays (also type 'ay'),
|
||||
in the general case, can contain a `NUL` byte at any position, and need not
|
||||
end with a `NUL` byte.
|
||||
|
||||
Bytestrings are specified with either `b""` or `b''`. As with strings, there
|
||||
is no fundamental difference between the two different types of quotes.
|
||||
|
||||
Bytestrings support the full range of escapes that you would expect (ie:
|
||||
those supported by [`func@GLib.strcompress`]. This includes the normal control
|
||||
sequence escapes (as mentioned in the section on strings) as well as octal
|
||||
and hexadecimal escapes of the forms `\0nnn` and `\xnn`.
|
||||
|
||||
`b'abc'` is equivalent to `[byte 0x61, 0x62, 0x63, 0]`.
|
||||
|
||||
When formatting arrays of bytes, the printer will choose to display the
|
||||
array as a bytestring if it contains a nul character at the end and no other
|
||||
nul bytes within. Otherwise, it is formatted as a normal array.
|
||||
|
||||
## Positional Parameters
|
||||
|
||||
Positional parameters are not a part of the normal `GVariant` text format,
|
||||
but they are mentioned here because they can be used with
|
||||
[`ctor@GLib.Variant.new_parsed`].
|
||||
|
||||
A positional parameter is indicated with a `%` followed by any valid
|
||||
[GVariant Format String](gvariant-format-strings.html). Variable arguments
|
||||
are collected as specified by the format string and the resulting value is
|
||||
inserted at the current position.
|
||||
|
||||
This feature is best explained by example:
|
||||
|
||||
```c
|
||||
char *t = "xyz";
|
||||
gboolean en = false;
|
||||
GVariant *value;
|
||||
|
||||
value = g_variant_new_parsed ("{'title': <%s>, 'enabled': <%b>}", t, en);
|
||||
```
|
||||
|
||||
This constructs a dictionary mapping strings to variants (type `a{sv}`) with
|
||||
two items in it. The key names are parsed from the string and the values for
|
||||
those keys are taken as variable arguments parameters.
|
||||
|
||||
The arguments are always collected in the order that they appear in the
|
||||
string to be parsed. Format strings that collect multiple arguments are
|
||||
permitted, so you may require more varargs parameters than the number of `%`
|
||||
signs that appear. You can also give format strings that collect no
|
||||
arguments, but there's no good reason to do so.
|
@ -1,622 +0,0 @@
|
||||
<?xml version='1.0' encoding='utf-8'?>
|
||||
|
||||
<refentry id='gvariant-text'>
|
||||
<refmeta>
|
||||
<refentrytitle>GVariant Text Format</refentrytitle>
|
||||
</refmeta>
|
||||
<refnamediv>
|
||||
<refname>GVariant Text Format</refname>
|
||||
<refpurpose>textual representation of GVariants</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>GVariant Text Format</title>
|
||||
|
||||
<para>
|
||||
This page attempts to document the GVariant text format as produced by
|
||||
<link linkend='g-variant-print'><function>g_variant_print()</function></link> and parsed by the
|
||||
<link linkend='g-variant-parse'><function>g_variant_parse()</function></link> family of functions. In most
|
||||
cases the style closely resembles the formatting of literals in Python but there are some additions and
|
||||
exceptions.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The functions that deal with GVariant text format absolutely always deal in utf-8. Conceptually, GVariant
|
||||
text format is a string of Unicode characters -- not bytes. Non-ASCII but otherwise printable Unicode
|
||||
characters are not treated any differently from normal ASCII characters.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The parser makes two passes. The purpose of the first pass is to determine the type of the value being
|
||||
parsed. The second pass does the actual parsing. Based on the fact that all elements in an array have to
|
||||
have the same type, GVariant is able to make some deductions that would not otherwise be possible. As an
|
||||
example:
|
||||
|
||||
<informalexample><programlisting>[[1, 2, 3], [4, 5, 6]]</programlisting></informalexample>
|
||||
|
||||
is parsed as an array of arrays of integers (type '<literal>aai</literal>'), but
|
||||
|
||||
<informalexample><programlisting>[[1, 2, 3], [4, 5, 6.0]]</programlisting></informalexample>
|
||||
|
||||
is parsed as an array of arrays of doubles (type '<literal>aad</literal>').
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As another example, GVariant is able to determine that
|
||||
|
||||
<informalexample><programlisting>["hello", nothing]</programlisting></informalexample>
|
||||
|
||||
is an array of maybe strings (type '<literal>ams</literal>').
|
||||
</para>
|
||||
|
||||
<para>
|
||||
What the parser accepts as valid input is dependent on context. The API permits for out-of-band type
|
||||
information to be supplied to the parser (which will change its behaviour). This can be seen in the
|
||||
GSettings and GDBus command line utilities where the type information is available from the schema or the
|
||||
remote introspection information. The additional information can cause parses to succeed when they would not
|
||||
otherwise have been able to (by resolving ambiguous type information) or can cause them to fail (due to
|
||||
conflicting type information). Unless stated otherwise, the examples given in this section assume that no
|
||||
out-of-band type data has been given to the parser.
|
||||
</para>
|
||||
</refsect1>
|
||||
|
||||
<refsect1>
|
||||
<title>Syntax Summary</title>
|
||||
|
||||
<para>
|
||||
The following table describes the rough meaning of symbols that may appear inside GVariant text format.
|
||||
Each symbol is described in detail in its own section, including usage examples.
|
||||
</para>
|
||||
|
||||
<informaltable>
|
||||
<tgroup cols='2'>
|
||||
<colspec colname='col_0'/>
|
||||
<colspec colname='col_1'/>
|
||||
<tbody>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'>Symbol</emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'>Meaning</emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>true</literal></emphasis>,
|
||||
<emphasis role='strong'><literal>false</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-booleans'>Booleans</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>""</literal></emphasis>,
|
||||
<emphasis role='strong'><literal>''</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
String literal. See <link linkend='gvariant-text-strings'>Strings</link> below.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
numbers
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
See <link linkend='gvariant-text-numbers'>Numbers</link> below.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>()</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-tuples'>Tuples</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>[]</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-arrays'>Arrays</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>{}</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-dictionaries'>Dictionaries and Dictionary Entries</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal><></literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-variants'>Variants</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>just</literal></emphasis>,
|
||||
<emphasis role='strong'><literal>nothing</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-maybe-types'>Maybe Types</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>@</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-type-annotations'>Type Annotations</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
type keywords
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<literal>boolean</literal>,
|
||||
<literal>byte</literal>,
|
||||
<literal>int16</literal>,
|
||||
<literal>uint16</literal>,
|
||||
<literal>int32</literal>,
|
||||
<literal>uint32</literal>,
|
||||
<literal>handle</literal>,
|
||||
<literal>int64</literal>,
|
||||
<literal>uint64</literal>,
|
||||
<literal>double</literal>,
|
||||
<literal>string</literal>,
|
||||
<literal>objectpath</literal>,
|
||||
<literal>signature</literal>
|
||||
</para>
|
||||
<para>
|
||||
See <link linkend='gvariant-text-type-annotations'>Type Annotations</link> below.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>b""</literal></emphasis>,
|
||||
<emphasis role='strong'><literal>b''</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-bytestrings'>Bytestrings</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
|
||||
<row rowsep='1'>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<emphasis role='strong'><literal>%</literal></emphasis>
|
||||
</para>
|
||||
</entry>
|
||||
<entry colsep='1' rowsep='1'>
|
||||
<para>
|
||||
<link linkend='gvariant-text-positional'>Positional Parameters</link>.
|
||||
</para>
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</informaltable>
|
||||
|
||||
<refsect2 id='gvariant-text-booleans'>
|
||||
<title>Booleans</title>
|
||||
<para>
|
||||
The strings <literal>true</literal> and <literal>false</literal> are parsed as booleans. This is the only
|
||||
way to specify a boolean value.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-strings'>
|
||||
<title>Strings</title>
|
||||
<para>
|
||||
Strings literals must be quoted using <literal>""</literal> or <literal>''</literal>. The two are
|
||||
completely equivalent (except for the fact that each one is unable to contain itself unescaped).
|
||||
</para>
|
||||
<para>
|
||||
Strings are Unicode strings with no particular encoding. For example, to specify the character
|
||||
<literal>é</literal>, you just write <literal>'é'</literal>. You could also give the Unicode codepoint of
|
||||
that character (U+E9) as the escape sequence <literal>'\u00e9'</literal>. Since the strings are pure
|
||||
Unicode, you should not attempt to encode the utf-8 byte sequence corresponding to the string using escapes;
|
||||
it won't work and you'll end up with the individual characters corresponding to each byte.
|
||||
</para>
|
||||
<para>
|
||||
Unicode escapes of the form <literal>\uxxxx</literal> and <literal>\Uxxxxxxxx</literal> are supported, in
|
||||
hexadecimal. The usual control sequence escapes <literal>\a</literal>, <literal>\b</literal>,
|
||||
<literal>\f</literal>, <literal>\n</literal>, <literal>\r</literal>, <literal>\t</literal> and
|
||||
<literal>\v</literal> are supported. Additionally, a <literal>\</literal> before a newline character causes
|
||||
the newline to be ignored. Finally, any other character following <literal>\</literal> is copied literally
|
||||
(for example, <literal>\"</literal> or <literal>\\</literal>) but for forwards compatibility with future
|
||||
additions you should only use this feature when necessary for escaping backslashes or quotes.
|
||||
</para>
|
||||
<para>
|
||||
The usual octal and hexadecimal escapes <literal>\0nnn</literal> and <literal>\xnn</literal> are not
|
||||
supported here. Those escapes are used to encode byte values and GVariant strings are Unicode.
|
||||
</para>
|
||||
<para>
|
||||
Single-character strings are not interpreted as bytes. Bytes must be specified by their numerical value.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-numbers'>
|
||||
<title>Numbers</title>
|
||||
<para>
|
||||
Numbers are given by default as decimal values. Octal and hex values can be given in the usual way (by
|
||||
prefixing with <literal>0</literal> or <literal>0x</literal>). Note that GVariant considers bytes to be
|
||||
unsigned integers and will print them as a two digit hexadecimal number by default.
|
||||
</para>
|
||||
<para>
|
||||
Floating point numbers can also be given in the usual ways, including scientific and hexadecimal notations.
|
||||
</para>
|
||||
<para>
|
||||
For lack of additional information, integers will be parsed as int32 values by default. If the number has a
|
||||
point or an 'e' in it, then it will be parsed as a double precision floating point number by default. If
|
||||
type information is available (either explicitly or inferred) then that type will be used instead.
|
||||
</para>
|
||||
<para>
|
||||
Some examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>5</literal> parses as the int32 value five.
|
||||
</para>
|
||||
<para>
|
||||
<literal>37.5</literal> parses as a floating point value.
|
||||
</para>
|
||||
<para>
|
||||
<literal>3.75e1</literal> parses the same as the value above.
|
||||
</para>
|
||||
<para>
|
||||
<literal>uint64 7</literal> parses seven as a uint64.
|
||||
See <link linkend='gvariant-text-type-annotations'>Type Annotations</link>.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-tuples'>
|
||||
<title>Tuples</title>
|
||||
<para>
|
||||
Tuples are formed using the same syntax as Python. Here are some examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>()</literal> parses as the empty tuple.
|
||||
</para>
|
||||
<para>
|
||||
<literal>(5,)</literal> is a tuple containing a single value.
|
||||
</para>
|
||||
<para>
|
||||
<literal>("hello", 42)</literal> is a pair. Note that values of different types are permitted.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-arrays'>
|
||||
<title>Arrays</title>
|
||||
<para>
|
||||
Arrays are formed using the same syntax as Python uses for lists (which is arguably the term that GVariant
|
||||
should have used). Note that, unlike Python lists, GVariant arrays are statically typed. This has two
|
||||
implications.
|
||||
</para>
|
||||
<para>
|
||||
First, all items in the array must have the same type. Second, the type of the array must be known, even in
|
||||
the case that it is empty. This means that (unless there is some other way to infer it) type information
|
||||
will need to be given explicitly for empty arrays.
|
||||
</para>
|
||||
<para>
|
||||
The parser is able to infer some types based on the fact that all items in an array must have the same type.
|
||||
See the examples below:
|
||||
</para>
|
||||
<para>
|
||||
<literal>[1]</literal> parses (without additional type information) as a one-item array of signed integers.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[1, 2, 3]</literal> parses (similarly) as a three-item array.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[1, 2, 3.0]</literal> parses as an array of doubles. This is the most simple case of the type
|
||||
inferencing in action.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[(1, 2), (3, 4.0)]</literal> causes the 2 to also be parsed as a double (but the 1 and 3 are still
|
||||
integers).
|
||||
</para>
|
||||
<para>
|
||||
<literal>["", nothing]</literal> parses as an array of maybe strings. The presence of
|
||||
"<literal>nothing</literal>" clearly implies that the array elements are nullable.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[[], [""]]</literal> will parse properly because the type of the first (empty) array can be
|
||||
inferred to be equal to the type of the second array (both are arrays of strings).
|
||||
</para>
|
||||
<para>
|
||||
<literal>[b'hello', []]</literal> looks odd but will parse properly.
|
||||
See <link linkend='gvariant-text-bytestrings'>Bytestrings</link>
|
||||
</para>
|
||||
<para>
|
||||
And some examples of errors:
|
||||
</para>
|
||||
<para>
|
||||
<literal>["hello", 42]</literal> fails to parse due to conflicting types.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[]</literal> will fail to parse without additional type information.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-dictionaries'>
|
||||
<title>Dictionaries and Dictionary Entries</title>
|
||||
<para>
|
||||
Dictionaries and dictionary entries are both specified using the <literal>{}</literal> characters.
|
||||
</para>
|
||||
<para>
|
||||
The dictionary syntax is more commonly used. This is what the printer elects to use in the normal case of
|
||||
dictionary entries appearing in an array (aka "a dictionary"). The separate syntax for dictionary entries
|
||||
is typically only used for when the entries appear on their own, outside of an array (which is valid but
|
||||
unusual). Of course, you are free to use the dictionary entry syntax within arrays but there is no good
|
||||
reason to do so (and the printer itself will never do so). Note that, as with arrays, the type of empty
|
||||
dictionaries must be established (either explicitly or through inference).
|
||||
</para>
|
||||
<para>
|
||||
The dictionary syntax is the same as Python's syntax for dictionaries. Some examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>@a{sv} {}</literal> parses as the empty dictionary of everyone's favourite type.
|
||||
</para>
|
||||
<para>
|
||||
<literal>@a{sv} []</literal> is the same as above (owing to the fact that dictionaries are really arrays).
|
||||
</para>
|
||||
<para>
|
||||
<literal>{1: "one", 2: "two", 3: "three"}</literal> parses as a dictionary mapping integers to strings.
|
||||
</para>
|
||||
<para>
|
||||
The dictionary entry syntax looks just like a pair (2-tuple) that uses braces instead of parens. The
|
||||
presence of a comma immediately following the key differentiates it from the dictionary syntax (which
|
||||
features a colon after the first key). Some examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>{1, "one"}</literal> is a free-standing dictionary entry that can be parsed on its own or as part
|
||||
of another container value.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[{1, "one"}, {2, "two"}, {3, "three"}]</literal> is exactly equivalent to the dictionary example
|
||||
given above.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-variants'>
|
||||
<title>Variants</title>
|
||||
<para>
|
||||
Variants are denoted using angle brackets (aka "XML brackets"), <literal><></literal>. They may not
|
||||
be omitted.
|
||||
</para>
|
||||
<para>
|
||||
Using <literal><></literal> effectively disrupts the type inferencing that occurs between array
|
||||
elements. This can have positive and negative effects.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[<"hello">, <42>]</literal> will parse whereas <literal>["hello", 42]</literal> would
|
||||
not.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[<['']>, <[]>]</literal> will fail to parse even though <literal>[[''], []]</literal>
|
||||
parses successfully. You would need to specify <literal>[<['']>, <@as []>]</literal>.
|
||||
</para>
|
||||
<para>
|
||||
<literal>{"title": <"frobit">, "enabled": <true>, "width": <800>}</literal> is an example of
|
||||
perhaps the most pervasive use of both dictionaries and variants.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-maybe-types'>
|
||||
<title>Maybe Types</title>
|
||||
<para>
|
||||
The syntax for specifying maybe types is inspired by Haskell.
|
||||
</para>
|
||||
<para>
|
||||
The null case is specified using the keyword <literal>nothing</literal> and the non-null case is explicitly
|
||||
specified using the keyword <literal>just</literal>. GVariant allows <literal>just</literal> to be omitted
|
||||
in every case that it is able to unambiguously determine the intention of the writer. There are two cases
|
||||
where it must be specified:
|
||||
</para>
|
||||
<itemizedlist>
|
||||
<listitem>
|
||||
<para>when using nested maybes, in order to specify the <literal>just nothing</literal> case</para>
|
||||
</listitem>
|
||||
<listitem>
|
||||
<para>
|
||||
to establish the nullability of the type of a value without explicitly specifying its full type
|
||||
</para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
<para>
|
||||
Some examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>just 'hello'</literal> parses as a non-null nullable string.
|
||||
</para>
|
||||
<para>
|
||||
<literal>@ms 'hello'</literal> is the same (demonstrating how <literal>just</literal> can be dropped if the type is already
|
||||
known).
|
||||
</para>
|
||||
<para>
|
||||
<literal>nothing</literal> will not parse wtihout extra type information.
|
||||
</para>
|
||||
<para>
|
||||
<literal>@ms nothing</literal> parses as a null nullable string.
|
||||
</para>
|
||||
<para>
|
||||
<literal>[just 3, nothing]</literal> is an array of nullable integers
|
||||
</para>
|
||||
<para>
|
||||
<literal>[3, nothing]</literal> is the same as the above (demonstrating another place were
|
||||
<literal>just</literal> can be dropped).
|
||||
</para>
|
||||
<para>
|
||||
<literal>[3, just nothing]</literal> parses as an array of maybe maybe integers (type
|
||||
<literal>'ammi'</literal>).
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-type-annotations'>
|
||||
<title>Type Annotations</title>
|
||||
<para>
|
||||
Type annotations allow additional type information to be given to the parser. Depending on the context,
|
||||
this type information can change the output of the parser, cause an error when parsing would otherwise have
|
||||
succeeded or resolve an error when parsing would have otherwise failed.
|
||||
</para>
|
||||
<para>
|
||||
Type annotations come in two forms: type codes and type keywords.
|
||||
</para>
|
||||
<para>
|
||||
Type keywords can be seen as more verbose (and more legible) versions of a common subset of the type codes.
|
||||
The type keywords <literal>boolean</literal>, <literal>byte</literal>, <literal>int16</literal>,
|
||||
<literal>uint16</literal>, <literal>int32</literal>, <literal>uint32</literal>, <literal>handle</literal>,
|
||||
<literal>int64</literal>, <literal>uint64</literal>, <literal>double</literal>, <literal>string</literal>,
|
||||
<literal>objectpath</literal> and literal <literal>signature</literal> are each exactly equivalent to their
|
||||
corresponding type code.
|
||||
</para>
|
||||
<para>
|
||||
Type codes are an <literal>@</literal> ("at" sign) followed by a definite GVariant type string. Some
|
||||
examples:
|
||||
</para>
|
||||
<para>
|
||||
<literal>uint32 5</literal> causes the number to be parsed unsigned instead of signed (the default).
|
||||
</para>
|
||||
<para>
|
||||
<literal>@u 5</literal> is the same
|
||||
</para>
|
||||
<para>
|
||||
<literal>objectpath "/org/gnome/xyz"</literal> creates an object path instead of a normal string
|
||||
</para>
|
||||
<para>
|
||||
<literal>@au []</literal> specifies the type of the empty array (which would not parse otherwise)
|
||||
</para>
|
||||
<para>
|
||||
<literal>@ms ""</literal> indicates that a string value is meant to have a maybe type
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-bytestrings'>
|
||||
<title>Bytestrings</title>
|
||||
<para>
|
||||
The bytestring syntax is a piece of syntactic sugar meant to complement the bytestring APIs in GVariant. It
|
||||
constructs arrays of non-nul bytes (type '<literal>ay</literal>') with a nul terminator at the end. These are
|
||||
normal C strings with no particular encoding enforced, so the bytes may not be valid UTF-8.
|
||||
Bytestrings are a special case of byte arrays; byte arrays (also type '<literal>ay</literal>'), in the general
|
||||
case, can contain nul at any position, and need not end with nul.
|
||||
</para>
|
||||
<para>
|
||||
Bytestrings are specified with either <literal>b""</literal> or <literal>b''</literal>. As with strings,
|
||||
there is no fundamental difference between the two different types of quotes.
|
||||
</para>
|
||||
<para>
|
||||
Bytestrings support the full range of escapes that you would expect (ie: those supported by
|
||||
<link linkend='g-strcompress'><function>g_strcompress()</function></link>. This includes the normal control
|
||||
sequence escapes (as mentioned in the section on strings) as well as octal and hexadecimal escapes of the
|
||||
forms <literal>\0nnn</literal> and <literal>\xnn</literal>.
|
||||
</para>
|
||||
<para>
|
||||
<literal>b'abc'</literal> is equivalent to <literal>[byte 0x61, 0x62, 0x63, 0]</literal>.
|
||||
</para>
|
||||
<para>
|
||||
When formatting arrays of bytes, the printer will choose to display the array as a bytestring if it contains
|
||||
a nul character at the end and no other nul bytes within. Otherwise, it is formatted as a normal array.
|
||||
</para>
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id='gvariant-text-positional'>
|
||||
<title>Positional Parameters</title>
|
||||
<para>
|
||||
Positional parameters are not a part of the normal GVariant text format, but they are mentioned here because
|
||||
they can be used with <link linkend='g-variant-new-parsed'><function>g_variant_new_parsed()</function></link>.
|
||||
</para>
|
||||
<para>
|
||||
A positional parameter is indicated with a <literal>%</literal> followed by any valid
|
||||
<link linkend='gvariant-format-strings'>GVariant Format String</link>. Variable arguments are collected as
|
||||
specified by the format string and the resulting value is inserted at the current position.
|
||||
</para>
|
||||
<para>
|
||||
This feature is best explained by example:
|
||||
</para>
|
||||
<informalexample><programlisting><![CDATA[char *t = "xyz";
|
||||
gboolean en = false;
|
||||
GVariant *value;
|
||||
|
||||
value = g_variant_new_parsed ("{'title': <%s>, 'enabled': <%b>}", t, en);]]></programlisting></informalexample>
|
||||
<para>
|
||||
This constructs a dictionary mapping strings to variants (type '<literal>a{sv}</literal>') with two items in
|
||||
it. The key names are parsed from the string and the values for those keys are taken as variable arguments
|
||||
parameters.
|
||||
</para>
|
||||
<para>
|
||||
The arguments are always collected in the order that they appear in the string to be parsed. Format strings
|
||||
that collect multiple arguments are permitted, so you may require more varargs parameters than the number of
|
||||
<literal>%</literal> signs that appear. You can also give format strings that collect no arguments, but
|
||||
there's no good reason to do so.
|
||||
</para>
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
</refentry>
|
File diff suppressed because it is too large
Load Diff
49
docs/reference/glib/i18n.md
Normal file
49
docs/reference/glib/i18n.md
Normal file
@ -0,0 +1,49 @@
|
||||
Title: Internationalization
|
||||
|
||||
# Internationalization
|
||||
|
||||
GLib doesn't force any particular localization method upon its users. But
|
||||
since GLib itself is localized using the `gettext()` mechanism, it seems
|
||||
natural to offer the de-facto standard `gettext()` support macros in an
|
||||
easy-to-use form.
|
||||
|
||||
In order to use these macros in an application, you must include
|
||||
`<glib/gi18n.h>`. For use in a library, you must include `<glib/gi18n-lib.h>`
|
||||
after defining the `GETTEXT_PACKAGE` macro suitably for your library:
|
||||
|
||||
```c
|
||||
#define GETTEXT_PACKAGE "gtk4"
|
||||
#include <glib/gi18n-lib.h>
|
||||
```
|
||||
|
||||
For an application, note that you also have to call `bindtextdomain()`,
|
||||
`bind_textdomain_codeset()`, `textdomain()` and `setlocale()` early on in your
|
||||
`main()` to make `gettext()` work. For example:
|
||||
|
||||
```c
|
||||
#include <glib/gi18n.h>
|
||||
#include <locale.h>
|
||||
|
||||
int
|
||||
main (int argc, char **argv)
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
bindtextdomain (GETTEXT_PACKAGE, DATADIR "/locale");
|
||||
bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
textdomain (GETTEXT_PACKAGE);
|
||||
|
||||
// Rest of your application.
|
||||
}
|
||||
```
|
||||
|
||||
where `DATADIR` is as typically provided by Automake or Meson.
|
||||
|
||||
For a library, you only have to call `bindtextdomain()` and
|
||||
`bind_textdomain_codeset()` in your initialization function. If your library
|
||||
doesn't have an initialization function, you can call the functions before
|
||||
the first translated message.
|
||||
|
||||
The [gettext
|
||||
manual](http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers)
|
||||
covers details of how to integrate gettext into a project’s build system and
|
||||
workflow.
|
137
docs/reference/glib/logging.md
Normal file
137
docs/reference/glib/logging.md
Normal file
@ -0,0 +1,137 @@
|
||||
Title: Message Logging
|
||||
|
||||
# Message Logging
|
||||
|
||||
The `g_return` family of macros (`g_return_if_fail()`,
|
||||
`g_return_val_if_fail()`, `g_return_if_reached()`,
|
||||
`g_return_val_if_reached()`) should only be used for programming errors, a
|
||||
typical use case is checking for invalid parameters at the beginning of a
|
||||
public function. They should not be used if you just mean "if (error)
|
||||
return", they should only be used if you mean "if (bug in program) return".
|
||||
The program behavior is generally considered undefined after one of these
|
||||
checks fails. They are not intended for normal control flow, only to give a
|
||||
perhaps-helpful warning before giving up.
|
||||
|
||||
Structured logging output is supported using `g_log_structured()`. This
|
||||
differs from the traditional `g_log()` API in that log messages are handled
|
||||
as a collection of key–value pairs representing individual pieces of
|
||||
information, rather than as a single string containing all the information
|
||||
in an arbitrary format.
|
||||
|
||||
The convenience macros `g_info()`, `g_message()`, `g_debug()`, `g_warning()`
|
||||
and `g_error()` will use the traditional `g_log()` API unless you define the
|
||||
symbol `G_LOG_USE_STRUCTURED` before including `glib.h`. But note that even
|
||||
messages logged through the traditional `g_log()` API are ultimatively
|
||||
passed to `g_log_structured()`, so that all log messages end up in same
|
||||
destination. If `G_LOG_USE_STRUCTURED` is defined, `g_test_expect_message()`
|
||||
will become ineffective for the wrapper macros `g_warning()` and friends
|
||||
(see [Testing for Messages](#testing-for-messages).)
|
||||
|
||||
The support for structured logging was motivated by the following needs
|
||||
(some of which were supported previously; others weren’t):
|
||||
|
||||
- Support for multiple logging levels.
|
||||
- Structured log support with the ability to add `MESSAGE_ID`s (see
|
||||
`g_log_structured()`).
|
||||
- Moving the responsibility for filtering log messages from the program to
|
||||
the log viewer — instead of libraries and programs installing log handlers
|
||||
(with `g_log_set_handler()`) which filter messages before output, all log
|
||||
messages are outputted, and the log viewer program (such as
|
||||
[`journalctl`](https://www.freedesktop.org/software/systemd/man/journalctl.html))
|
||||
must filter them. This is based on the idea that bugs are sometimes hard
|
||||
to reproduce, so it is better to log everything possible and then use
|
||||
tools to analyse the logs than it is to not be able to reproduce a bug to
|
||||
get additional log data. Code which uses logging in performance-critical
|
||||
sections should compile out the `g_log_structured()` calls in release
|
||||
builds, and compile them in in debugging builds.
|
||||
- A single writer function which handles all log messages in a process, from
|
||||
all libraries and program code; rather than multiple log handlers with
|
||||
poorly defined interactions between them. This allows a program to easily
|
||||
change its logging policy by changing the writer function, for example to
|
||||
log to an additional location or to change what logging output fallbacks
|
||||
are used. The log writer functions provided by GLib are exposed publicly
|
||||
so they can be used from programs’ log writers. This allows log writer
|
||||
policy and implementation to be kept separate.
|
||||
- If a library wants to add standard information to all of its log messages
|
||||
(such as library state) or to redact private data (such as passwords or
|
||||
network credentials), it should use a wrapper function around its
|
||||
`g_log_structured()` calls or implement that in the single log writer
|
||||
function.
|
||||
- If a program wants to pass context data from a `g_log_structured()` call
|
||||
to its log writer function so that, for example, it can use the correct
|
||||
server connection to submit logs to, that user data can be passed as a
|
||||
zero-length `GLogField` to `g_log_structured_array()`.
|
||||
- Color output needed to be supported on the terminal, to make reading
|
||||
through logs easier.
|
||||
|
||||
## Using Structured Logging
|
||||
|
||||
To use structured logging (rather than the old-style logging), either use
|
||||
the `g_log_structured()` and `g_log_structured_array()` functions; or define
|
||||
`G_LOG_USE_STRUCTURED` before including any GLib header, and use the
|
||||
`g_message()`, `g_debug()`, `g_error()` (etc.) macros.
|
||||
|
||||
You do not need to define `G_LOG_USE_STRUCTURED` to use
|
||||
`g_log_structured()`, but it is a good idea to avoid confusion.
|
||||
|
||||
## Log Domains
|
||||
|
||||
Log domains may be used to broadly split up the origins of log messages.
|
||||
Typically, there are one or a few log domains per application or library.
|
||||
`G_LOG_DOMAIN` should be used to define the default log domain for the current
|
||||
compilation unit — it is typically defined at the top of a source file, or
|
||||
in the preprocessor flags for a group of source files.
|
||||
|
||||
Log domains must be unique, and it is recommended that they are the
|
||||
application or library name, optionally followed by a hyphen and a
|
||||
sub-domain name. For example, `bloatpad` or `bloatpad-io`.
|
||||
|
||||
## Debug Message Output
|
||||
|
||||
The default log functions (`g_log_default_handler()` for the old-style API
|
||||
and `g_log_writer_default()` for the structured API) both drop debug and
|
||||
informational messages by default, unless the log domains of those messages
|
||||
are listed in the `G_MESSAGES_DEBUG` environment variable (or it is set to
|
||||
`all`).
|
||||
|
||||
It is recommended that custom log writer functions re-use the
|
||||
`G_MESSAGES_DEBUG` environment variable, rather than inventing a custom one,
|
||||
so that developers can re-use the same debugging techniques and tools across
|
||||
projects. Since GLib 2.68, this can be implemented by dropping messages for
|
||||
which `g_log_writer_default_would_drop()` returns `TRUE`.
|
||||
|
||||
## Testing for Messages
|
||||
|
||||
With the old `g_log()` API, `g_test_expect_message()` and
|
||||
`g_test_assert_expected_messages()` could be used in simple cases to check
|
||||
whether some code under test had emitted a given log message. These
|
||||
functions have been deprecated with the structured logging API, for several
|
||||
reasons:
|
||||
|
||||
- They relied on an internal queue which was too inflexible for many use
|
||||
cases, where messages might be emitted in several orders, some messages
|
||||
might not be emitted deterministically, or messages might be emitted by
|
||||
unrelated log domains.
|
||||
- They do not support structured log fields.
|
||||
- Examining the log output of code is a bad approach to testing it, and
|
||||
while it might be necessary for legacy code which uses `g_log()`, it
|
||||
should be avoided for new code using `g_log_structured()`.
|
||||
|
||||
They will continue to work as before if `g_log()` is in use (and
|
||||
`G_LOG_USE_STRUCTURED` is not defined). They will do nothing if used with
|
||||
the structured logging API.
|
||||
|
||||
Examining the log output of code is discouraged: libraries should not emit
|
||||
to stderr during defined behaviour, and hence this should not be tested. If
|
||||
the log emissions of a library during undefined behaviour need to be tested,
|
||||
they should be limited to asserting that the library aborts and prints a
|
||||
suitable error message before aborting. This should be done with
|
||||
`g_test_trap_assert_stderr()`.
|
||||
|
||||
If it is really necessary to test the structured log messages emitted by a
|
||||
particular piece of code – and the code cannot be restructured to be more
|
||||
suitable to more conventional unit testing – you should write a custom log
|
||||
writer function (see `g_log_set_writer_func()`) which appends all log
|
||||
messages to a queue. When you want to check the log messages, examine and
|
||||
clear the queue, ignoring irrelevant log messages (for example, from log
|
||||
domains other than the one under test).
|
870
docs/reference/glib/macros.md
Normal file
870
docs/reference/glib/macros.md
Normal file
@ -0,0 +1,870 @@
|
||||
Title: Macros
|
||||
|
||||
# Macros
|
||||
|
||||
GLib provides a set of C pre-processor macros and symbols for commonly-used
|
||||
language and platform features.
|
||||
|
||||
## Platform
|
||||
|
||||
`G_OS_WIN32`
|
||||
: This macro is defined only on Windows, so you can bracket Windows-specific
|
||||
code using `#ifdef G_OS_WIN32 ... #endif`.
|
||||
|
||||
`G_OS_UNIX`
|
||||
|
||||
: This macro is defined only on UNIX and UNIX-like systems, so you can bracket
|
||||
UNIX-specific code in `#ifdef G_OS_UNIX ... #endif`. To detect whether to
|
||||
compile features that require a specific kernel or operating system, check
|
||||
for the appropriate OS-specific predefined macros instead, for example:
|
||||
|
||||
- Linux kernel (any libc, including glibc, musl or Android): `#ifdef __linux__`
|
||||
- Linux kernel and GNU user-space: `#if defined(__linux__) && defined(__GLIBC__)`
|
||||
- FreeBSD kernel (any libc, including glibc): `#ifdef __FreeBSD_kernel__`
|
||||
- FreeBSD kernel and user-space: `#ifdef __FreeBSD__`
|
||||
- Apple operating systems (macOS, iOS, tvOS), regardless of whether
|
||||
Cocoa/Carbon toolkits are available: `#ifdef __APPLE__`
|
||||
|
||||
See <https://sourceforge.net/p/predef/wiki/OperatingSystems/> for more.
|
||||
|
||||
|
||||
`G_DIR_SEPARATOR`
|
||||
: The directory separator character. This is `'/'` on UNIX machines and `'\'` under Windows.
|
||||
|
||||
`G_DIR_SEPARATOR_S`
|
||||
: The directory separator as a string. This is `"/"` on UNIX machines and `"\"` under Windows.
|
||||
|
||||
`G_IS_DIR_SEPARATOR(ch)`
|
||||
: Checks whether a character is a directory separator. It returns true for `'/'` on UNIX machines and for `'\'` or `'/'` under Windows. Available since 2.6.
|
||||
|
||||
`G_SEARCHPATH_SEPARATOR`
|
||||
: The search path separator character. This is `':'` on UNIX machines and `';'` under Windows.
|
||||
|
||||
`G_SEARCHPATH_SEPARATOR_S`
|
||||
: The search path separator as a string. This is `":"` on UNIX machines and `";"` under Windows.
|
||||
|
||||
## Values
|
||||
|
||||
`TRUE`
|
||||
: Defines the true value for the `gboolean` type.
|
||||
|
||||
`FALSE`
|
||||
: Defines the false value for the `gboolean` type.
|
||||
|
||||
`NULL`
|
||||
: Defines the standard `NULL` pointer.
|
||||
|
||||
## Maths
|
||||
|
||||
`MIN(a, b)`
|
||||
: Calculates the minimum of `a` and `b`.
|
||||
|
||||
`MAX(a, b)`
|
||||
: Calculates the maximum of `a` and `b`.
|
||||
|
||||
`ABS(value)`
|
||||
|
||||
: Calculates the absolute value of a given numerical value. The absolute value
|
||||
is simply the number with any negative sign taken away.
|
||||
|
||||
For example,
|
||||
|
||||
- `ABS(-10)` is 10.
|
||||
- `ABS(10)` is also 10.
|
||||
|
||||
|
||||
`CLAMP(value, low, high)`
|
||||
|
||||
: Ensures that a value is between the limits set by `low` and `high`. If `low` is
|
||||
greater than `high` the result is undefined.
|
||||
|
||||
For example,
|
||||
|
||||
- `CLAMP(5, 10, 15)` is 10.
|
||||
- `CLAMP(15, 5, 10)` is 10.
|
||||
- `CLAMP(20, 15, 25)` is 20.
|
||||
|
||||
|
||||
`G_APPROX_VALUE(a, b, epsilon)`
|
||||
|
||||
: Evaluates to true if the absolute difference between the given numerical
|
||||
values `a` and `b` is smaller than `epsilon`, and to false otherwise.
|
||||
|
||||
For example,
|
||||
|
||||
- `G_APPROX_VALUE (5, 6, 2)` evaluates to true
|
||||
- `G_APPROX_VALUE (3.14, 3.15, 0.001)` evaluates to false
|
||||
- `G_APPROX_VALUE (n, 0.f, FLT_EPSILON)` evaluates to true if `n` is within
|
||||
the single precision floating point epsilon from zero
|
||||
|
||||
Available since: 2.58
|
||||
|
||||
|
||||
## Structure Access
|
||||
|
||||
`G_STRUCT_MEMBER(member_type, struct_pointer, offset)`
|
||||
: Returns a member of a structure at a given offset, using the given type.
|
||||
|
||||
`G_STRUCT_MEMBER_P(struct_pointer, offset)`
|
||||
: Returns an untyped pointer to a given offset of a struct.
|
||||
|
||||
`G_STRUCT_OFFSET(struct_type, member_name)`
|
||||
: Returns the offset, in bytes, of a member of a struct.
|
||||
Consider using standard C `offsetof()`, available since at least C89
|
||||
and C++98, in new code (but note that `offsetof()` returns a `size_t`
|
||||
rather than a `long`).
|
||||
|
||||
|
||||
## Array Utilties
|
||||
|
||||
`G_N_ELEMENTS(array)`
|
||||
: Determines the number of elements in an array. The array must be
|
||||
declared so the compiler knows its size at compile-time; this
|
||||
macro will not work on an array allocated on the heap, only static
|
||||
arrays or arrays on the stack.
|
||||
|
||||
|
||||
## Miscellaneous Macros
|
||||
|
||||
These macros provide more specialized features which are not needed so often
|
||||
by application programmers.
|
||||
|
||||
`G_STMT_START`
|
||||
: Starts a multi-statement macro block so that it can be used in places
|
||||
where only one statement is expected by the compiler.
|
||||
|
||||
`G_STMT_END`
|
||||
: Ends a multi-statement macro block so that it can be used in places
|
||||
where only one statement is expected by the compiler.
|
||||
|
||||
`G_BEGIN_DECLS`
|
||||
: Used (along with `G_END_DECLS`) to bracket C header files that may be
|
||||
included by C++ sources. If the compiler in use is a C++ compiler, starts
|
||||
an `extern "C"` around the header.
|
||||
|
||||
`G_END_DECLS`
|
||||
: Used (along with `G_BEGIN_DECLS`) to bracket C header files that may be
|
||||
included by C++ sources, or compiled by a C++ compiler. If the compiler
|
||||
in use is a C++ compiler, ends the `extern "C"` block around the header.
|
||||
|
||||
|
||||
`G_VA_COPY(ap1, ap2)`
|
||||
|
||||
: Portable way to copy `va_list` variables.
|
||||
|
||||
In order to use this function, you must include `string.h` yourself,
|
||||
because this macro may use `memmove()` and GLib does not include
|
||||
`string.h` for you.
|
||||
|
||||
Each invocation of `G_VA_COPY (ap1, ap2)` must be matched with a
|
||||
corresponding `va_end (ap1)` call in the same function.
|
||||
|
||||
This is equivalent to standard C `va_copy()`, available since C99
|
||||
and C++11, which should be preferred in new code.
|
||||
|
||||
|
||||
`G_STRINGIFY(macro_or_string)`
|
||||
|
||||
: Accepts a macro or a string and converts it into a string after
|
||||
preprocessor argument expansion. For example, the following code:
|
||||
|
||||
#define AGE 27
|
||||
const gchar *greeting = G_STRINGIFY (AGE) " today!";
|
||||
|
||||
is transformed by the preprocessor into (code equivalent to):
|
||||
|
||||
const gchar *greeting = "27 today!";
|
||||
|
||||
|
||||
`G_PASTE(identifier1, identifier2)`
|
||||
|
||||
: Yields a new preprocessor pasted identifier `identifier1identifier2` from its expanded
|
||||
arguments `identifier1` and `identifier2`. For example,the following code:
|
||||
|
||||
#define GET(traveller,method) G_PASTE(traveller_get_, method) (traveller)
|
||||
const char *name = GET (traveller, name);
|
||||
const char *quest = GET (traveller, quest);
|
||||
Color *favourite = GET (traveller, favourite_colour);
|
||||
|
||||
is transformed by the preprocessor into:
|
||||
|
||||
const char *name = traveller_get_name (traveller);
|
||||
const char *quest = traveller_get_quest (traveller);
|
||||
Color *favourite = traveller_get_favourite_colour (traveller);
|
||||
|
||||
Available since: 2.20
|
||||
|
||||
|
||||
`G_STATIC_ASSERT(expr)`
|
||||
|
||||
: The `G_STATIC_ASSERT()` macro lets the programmer check a condition at
|
||||
compile time. The condition needs to be compile time computable. The
|
||||
macro can be used in any place where a `typedef` is valid.
|
||||
|
||||
A `typedef` is generally allowed in exactly the same places that
|
||||
a variable declaration is allowed. For this reason, you should
|
||||
not use `G_STATIC_ASSERT()` in the middle of blocks of code.
|
||||
|
||||
The macro should only be used once per source code line.
|
||||
|
||||
Since: 2.20
|
||||
|
||||
|
||||
`G_STATIC_ASSERT_EXPR(expr)`
|
||||
|
||||
: The `G_STATIC_ASSERT_EXPR()` macro lets the programmer check a condition
|
||||
at compile time. The condition needs to be compile time computable.
|
||||
|
||||
Unlike `G_STATIC_ASSERT()`, this macro evaluates to an expression
|
||||
and, as such, can be used in the middle of other expressions.
|
||||
Its value should be ignored. This can be accomplished by placing
|
||||
it as the first argument of a comma expression.
|
||||
|
||||
#define ADD_ONE_TO_INT(x) \
|
||||
(G_STATIC_ASSERT_EXPR(sizeof (x) == sizeof (int)), ((x) + 1))
|
||||
|
||||
Since: 2.30
|
||||
|
||||
|
||||
## Compiler
|
||||
|
||||
|
||||
`G_GNUC_EXTENSION`
|
||||
: Expands to `__extension__` when GCC is used as the compiler. This simply
|
||||
tells GCC not to warn about the following non-standard code when compiling
|
||||
with the `-pedantic` option.
|
||||
|
||||
|
||||
`G_GNUC_CONST`
|
||||
|
||||
: Expands to the GNU C `const` function attribute if the compiler is GCC.
|
||||
Declaring a function as `const` enables better optimization of calls to
|
||||
the function. A `const` function doesn't examine any values except its
|
||||
parameters, and has no effects except its return value.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
gchar g_ascii_tolower (gchar c) G_GNUC_CONST;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-const-function-attribute) for more details.
|
||||
|
||||
A function that has pointer arguments and examines the data pointed to
|
||||
must not be declared `const`. Likewise, a function that calls a non-`const`
|
||||
function usually must not be `const`. It doesn't make sense for a `const`
|
||||
function to return `void`.
|
||||
|
||||
|
||||
`G_GNUC_PURE`
|
||||
|
||||
: Expands to the GNU C `pure` function attribute if the compiler is GCC.
|
||||
Declaring a function as `pure` enables better optimization of calls to
|
||||
the function. A `pure` function has no effects except its return value
|
||||
and the return value depends only on the parameters and/or global
|
||||
variables.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
gboolean g_type_check_value (const GValue *value) G_GNUC_PURE;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-pure-function-attribute) for more details.
|
||||
|
||||
|
||||
`G_GNUC_UNUSED`
|
||||
|
||||
: Expands to the GNU C `unused` function attribute if the compiler is gcc.
|
||||
It is used for declaring functions and arguments which may never be used.
|
||||
It avoids possible compiler warnings.
|
||||
|
||||
For functions, place the attribute after the declaration, just before the
|
||||
semicolon. For arguments, place the attribute at the beginning of the
|
||||
argument declaration.
|
||||
|
||||
void my_unused_function (G_GNUC_UNUSED gint unused_argument,
|
||||
gint other_argument) G_GNUC_UNUSED;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-unused-function-attribute) for more details.
|
||||
|
||||
|
||||
`G_GNUC_MALLOC`
|
||||
|
||||
: Expands to the GNU C `malloc` function attribute if the compiler is GCC.
|
||||
|
||||
Declaring a function as `malloc` enables better optimization of the function,
|
||||
but must only be done if the allocation behaviour of the function is fully
|
||||
understood, otherwise miscompilation can result.
|
||||
|
||||
A function can have the `malloc` attribute if it returns a pointer which is
|
||||
guaranteed to not alias with any other pointer valid when the function
|
||||
returns, and moreover no pointers to valid objects occur in any storage
|
||||
addressed by the returned pointer.
|
||||
|
||||
In practice, this means that `G_GNUC_MALLOC` can be used with any function
|
||||
which returns unallocated or zeroed-out memory, but not with functions which
|
||||
return initialised structures containing other pointers, or with functions
|
||||
that reallocate memory. This definition changed in GLib 2.58 to match the
|
||||
stricter definition introduced around GCC 5.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
gpointer g_malloc (gsize n_bytes) G_GNUC_MALLOC G_GNUC_ALLOC_SIZE(1);
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-functions-that-behave-like-malloc)
|
||||
for more details.
|
||||
|
||||
Since: 2.6
|
||||
|
||||
|
||||
`G_GNUC_DEPRECATED`
|
||||
|
||||
: Expands to the GNU C `deprecated` attribute if the compiler is GCC.
|
||||
It can be used to mark `typedef`s, variables and functions as deprecated.
|
||||
When called with the `-Wdeprecated-declarations` option,
|
||||
gcc will generate warnings when deprecated interfaces are used.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
int my_mistake (void) G_GNUC_DEPRECATED;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-deprecated-function-attribute) for more details.
|
||||
|
||||
See also: `G_DEPRECATED`
|
||||
|
||||
Since: 2.2
|
||||
|
||||
|
||||
`G_GNUC_DEPRECATED_FOR(func)`
|
||||
|
||||
: Like `G_GNUC_DEPRECATED`, but names the intended replacement for the
|
||||
deprecated symbol if the version of gcc in use is new enough to support
|
||||
custom deprecation messages.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
int my_mistake (void) G_GNUC_DEPRECATED_FOR(my_replacement);
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-deprecated-function-attribute) for more details.
|
||||
|
||||
Note that if `func` is a macro, it will be expanded in the warning message.
|
||||
You can enclose it in quotes to prevent this. (The quotes will show up
|
||||
in the warning, but it's better than showing the macro expansion.)
|
||||
|
||||
Since: 2.26
|
||||
|
||||
|
||||
`G_GNUC_NORETURN`
|
||||
|
||||
: Expands to the GNU C `noreturn` function attribute if the compiler is GCC.
|
||||
It is used for declaring functions which never return. It enables
|
||||
optimization of the function, and avoids possible compiler warnings.
|
||||
|
||||
Since 2.68, it is recommended that code uses `G_NORETURN` instead of
|
||||
`G_GNUC_NORETURN`, as that works on more platforms and compilers (in
|
||||
particular, MSVC and C++11) than `G_GNUC_NORETURN`, which works with GCC and
|
||||
Clang only. `G_GNUC_NORETURN` continues to work, so has not been deprecated
|
||||
yet.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
void g_abort (void) G_GNUC_NORETURN;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noreturn-function-attribute) for more details.
|
||||
|
||||
|
||||
`G_GNUC_FALLTHROUGH`
|
||||
|
||||
: Expands to the GNU C `fallthrough` statement attribute if the compiler supports it.
|
||||
This allows declaring case statement to explicitly fall through in switch
|
||||
statements. To enable this feature, use `-Wimplicit-fallthrough` during
|
||||
compilation.
|
||||
|
||||
Put the attribute right before the case statement you want to fall through to.
|
||||
|
||||
switch (foo)
|
||||
{
|
||||
case 1:
|
||||
g_message ("it's 1");
|
||||
G_GNUC_FALLTHROUGH;
|
||||
case 2:
|
||||
g_message ("it's either 1 or 2");
|
||||
break;
|
||||
}
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Statement-Attributes.html#index-fallthrough-statement-attribute) for more details.
|
||||
|
||||
Since: 2.60
|
||||
|
||||
|
||||
`G_GNUC_FORMAT(idx)`
|
||||
|
||||
: Expands to the GNU C `format_arg` function attribute if the compiler
|
||||
is GCC. This function attribute specifies that a function takes a
|
||||
format string for a `printf()`, `scanf()`, `strftime()` or `strfmon()`
|
||||
style function and modifies it, so that the result can be passed to
|
||||
a `printf()`, `scanf()`, `strftime()` or `strfmon()` style function
|
||||
(with the remaining arguments to the format function the same as they
|
||||
would have been for the unmodified string).
|
||||
|
||||
Place the attribute after the function declaration, just before the
|
||||
semicolon.
|
||||
|
||||
gchar *g_dgettext (gchar *domain_name, gchar *msgid) G_GNUC_FORMAT (2);
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-Wformat-nonliteral-1) for more details.
|
||||
|
||||
|
||||
`G_GNUC_NULL_TERMINATED`
|
||||
|
||||
: Expands to the GNU C `sentinel` function attribute if the compiler is GCC.
|
||||
This function attribute only applies to variadic functions and instructs
|
||||
the compiler to check that the argument list is terminated with an
|
||||
explicit `NULL`.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
gchar *g_strconcat (const gchar *string1,
|
||||
...) G_GNUC_NULL_TERMINATED;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-sentinel-function-attribute) for more details
|
||||
|
||||
Since: 2.8
|
||||
|
||||
|
||||
`G_GNUC_WARN_UNUSED_RESULT`
|
||||
|
||||
: Expands to the GNU C `warn_unused_result` function attribute if the compiler
|
||||
is GCC. This function attribute makes the compiler emit a warning if the
|
||||
result of a function call is ignored.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
GList *g_list_append (GList *list,
|
||||
gpointer data) G_GNUC_WARN_UNUSED_RESULT;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-warn_005funused_005fresult-function-attribute) for more details.
|
||||
|
||||
Since: 2.10
|
||||
|
||||
|
||||
`G_GNUC_NO_INLINE`
|
||||
|
||||
: Expands to the GNU C `noinline` function attribute if the compiler is GCC.
|
||||
|
||||
Declaring a function as `noinline` prevents the function from being
|
||||
considered for inlining.
|
||||
|
||||
This macro is provided for retro-compatibility and will be eventually
|
||||
deprecated; `G_NO_INLINE` should be used instead.
|
||||
|
||||
The attribute may be placed before the declaration or definition,
|
||||
right before the `static` keyword.
|
||||
|
||||
G_GNUC_NO_INLINE
|
||||
static int
|
||||
do_not_inline_this (void)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-noinline-function-attribute)
|
||||
for more details.
|
||||
|
||||
See also: `G_NO_INLINE`, `G_ALWAYS_INLINE`.
|
||||
|
||||
Since: 2.58
|
||||
|
||||
|
||||
`G_GNUC_NO_INSTRUMENT`
|
||||
|
||||
: Expands to the GNU C `no_instrument_function` function attribute if the
|
||||
compiler is GCC. Functions with this attribute will not be instrumented
|
||||
for profiling, when the compiler is called with the
|
||||
`-finstrument-functions` option.
|
||||
|
||||
Place the attribute after the declaration, just before the semicolon.
|
||||
|
||||
int do_uninteresting_things (void) G_GNUC_NO_INSTRUMENT;
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-no_005finstrument_005ffunction-function-attribute) for more details.
|
||||
|
||||
|
||||
`G_GNUC_MAY_ALIAS`
|
||||
|
||||
: Expands to the GNU C `may_alias` type attribute if the compiler is GCC.
|
||||
Types with this attribute will not be subjected to type-based alias
|
||||
analysis, but are assumed to alias with any other type, just like `char`.
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Type-Attributes.html#index-may_005falias-type-attribute) for details.
|
||||
|
||||
Since: 2.14
|
||||
|
||||
|
||||
`G_GNUC_FUNCTION`
|
||||
|
||||
: Expands to `""` on all modern compilers, and to `__FUNCTION__` on GCC version 2.x. Don't use it.
|
||||
|
||||
Deprecated: 2.16: Use `G_STRFUNC()` instead
|
||||
|
||||
|
||||
`G_GNUC_PRETTY_FUNCTION`
|
||||
|
||||
: Expands to `""` on all modern compilers, and to `__PRETTY_FUNCTION__` on GCC version 2.x. Don't use it.
|
||||
|
||||
Deprecated: 2.16: Use `G_STRFUNC()` instead
|
||||
|
||||
|
||||
`G_GNUC_CHECK_VERSION(major, minor)`
|
||||
|
||||
: Expands to a check for a compiler with `__GNUC__` defined and a version
|
||||
greater than or equal to the major and minor numbers provided. For example,
|
||||
the following would only match on compilers such as GCC 4.8 or newer.
|
||||
|
||||
#if G_GNUC_CHECK_VERSION(4, 8)
|
||||
// ...
|
||||
#endif
|
||||
|
||||
Since: 2.42
|
||||
|
||||
|
||||
`G_GNUC_BEGIN_IGNORE_DEPRECATIONS`
|
||||
|
||||
: Tells GCC (if it is a new enough version) to temporarily stop emitting
|
||||
warnings when functions marked with `G_GNUC_DEPRECATED` or
|
||||
`G_GNUC_DEPRECATED_FOR` are called. This is useful for when you have
|
||||
one deprecated function calling another one, or when you still have
|
||||
regression tests for deprecated functions.
|
||||
|
||||
Use `G_GNUC_END_IGNORE_DEPRECATIONS` to resume warning again. (If you
|
||||
are not compiling with `-Wdeprecated-declarations` then neither macro
|
||||
has any effect.)
|
||||
|
||||
This macro can be used either inside or outside of a function body,
|
||||
but must appear on a line by itself.
|
||||
|
||||
static void
|
||||
test_deprecated_function (void)
|
||||
{
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
g_assert_cmpint (my_mistake (), ==, 42);
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
}
|
||||
|
||||
Both this macro and the corresponding `G_GNUC_END_IGNORE_DEPRECATIONS`
|
||||
are considered statements, so they should not be used around branching
|
||||
or loop conditions; for instance, this use is invalid:
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
if (check == some_deprecated_function ())
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
{
|
||||
do_something ();
|
||||
}
|
||||
|
||||
and you should move the deprecated section outside the condition
|
||||
|
||||
// Solution A
|
||||
some_data_t *res;
|
||||
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
res = some_deprecated_function ();
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
if (check == res)
|
||||
{
|
||||
do_something ();
|
||||
}
|
||||
|
||||
// Solution B
|
||||
G_GNUC_BEGIN_IGNORE_DEPRECATIONS
|
||||
if (check == some_deprecated_function ())
|
||||
{
|
||||
do_something ();
|
||||
}
|
||||
G_GNUC_END_IGNORE_DEPRECATIONS
|
||||
|
||||
Since: 2.32
|
||||
|
||||
|
||||
`G_GNUC_END_IGNORE_DEPRECATIONS`
|
||||
|
||||
: Undoes the effect of `G_GNUC_BEGIN_IGNORE_DEPRECATIONS`, telling
|
||||
GCC to resume outputting warnings again (assuming those warnings
|
||||
had been enabled to begin with).
|
||||
|
||||
This macro can be used either inside or outside of a function body,
|
||||
but must appear on a line by itself.
|
||||
|
||||
Since: 2.32
|
||||
|
||||
|
||||
`G_C_STD_VERSION`
|
||||
|
||||
: The C standard version the code is compiling against, it's normally
|
||||
defined with the same value of `__STDC_VERSION__` for C standard
|
||||
compatible compilers, while it uses the lowest standard version
|
||||
in pure MSVC, given that in such compiler the definition depends on
|
||||
a compilation flag.
|
||||
|
||||
This is granted to be undefined when compiling with a C++ compiler.
|
||||
|
||||
See also: `G_C_STD_CHECK_VERSION` and `G_CXX_STD_VERSION`
|
||||
|
||||
Since: 2.76
|
||||
|
||||
|
||||
`G_C_STD_CHECK_VERSION(version)`
|
||||
|
||||
: Macro to check if the current compiler supports a specified version
|
||||
of the C standard. Such value must be numeric and can be provided both
|
||||
in the short form for the well-known versions (e.g. `90`, `99`...) or in
|
||||
the complete form otherwise (e.g. `199000L`, `199901L`, `205503L`...).
|
||||
|
||||
When a C++ compiler is used, the macro is defined and evaluates to false.
|
||||
|
||||
This value is compared against `G_C_STD_VERSION`.
|
||||
|
||||
#if G_C_STD_CHECK_VERSION(17)
|
||||
// ...
|
||||
#endif
|
||||
|
||||
See also: `G_CXX_STD_CHECK_VERSION`
|
||||
|
||||
Since: 2.76
|
||||
|
||||
|
||||
`G_CXX_STD_VERSION`
|
||||
|
||||
: The C++ standard version the code is compiling against, it's defined
|
||||
with the same value of `__cplusplus` for C++ standard compatible
|
||||
compilers, while it uses `_MSVC_LANG` in MSVC, given that the
|
||||
standard definition depends on a compilation flag in such compiler.
|
||||
|
||||
This is granted to be undefined when not compiling with a C++ compiler.
|
||||
|
||||
See also: `G_CXX_STD_CHECK_VERSION` and `G_C_STD_VERSION`
|
||||
|
||||
Since: 2.76
|
||||
|
||||
|
||||
`G_CXX_STD_CHECK_VERSION(version)`
|
||||
|
||||
: Macro to check if the current compiler supports a specified @version
|
||||
of the C++ standard. Such value must be numeric and can be provided both
|
||||
in the short form for the well-known versions (e.g. `11`, `17`...) or in
|
||||
the complete form otherwise (e.g. `201103L`, `201703L`, `205503L`...).
|
||||
|
||||
When a C compiler is used, the macro evaluates to false.
|
||||
|
||||
This value is compared against `G_CXX_STD_VERSION`.
|
||||
|
||||
#if G_CXX_STD_CHECK_VERSION(20)
|
||||
// ...
|
||||
#endif
|
||||
|
||||
See also: `G_C_STD_CHECK_VERSION`
|
||||
|
||||
Since: 2.76
|
||||
|
||||
|
||||
`G_LIKELY(expr)`
|
||||
|
||||
: Hints the compiler that the expression is likely to evaluate to
|
||||
a true value. The compiler may use this information for optimizations.
|
||||
|
||||
if (G_LIKELY (random () != 1))
|
||||
g_print ("not one");
|
||||
|
||||
Since: 2.2
|
||||
|
||||
|
||||
`G_UNLIKELY(expr)`
|
||||
|
||||
: Hints the compiler that the expression is unlikely to evaluate to
|
||||
a true value. The compiler may use this information for optimizations.
|
||||
|
||||
if (G_UNLIKELY (random () == 1))
|
||||
g_print ("a random one");
|
||||
|
||||
Since: 2.2
|
||||
|
||||
|
||||
`G_ALIGNOF(type)`
|
||||
|
||||
: Evaluates to the minimal alignment required by the platform ABI for values
|
||||
of the given type. The address of a variable or struct member of the given
|
||||
type must always be a multiple of this alignment. For example, most
|
||||
platforms require int variables to be aligned at a 4-byte boundary, so
|
||||
`G_ALIGNOF (int)` is 4 on most platforms.
|
||||
|
||||
Note this is not necessarily the same as the value returned by GCC’s
|
||||
`__alignof__` operator, which returns the preferred alignment for a type.
|
||||
The preferred alignment may be a stricter alignment than the minimal
|
||||
alignment.
|
||||
|
||||
Since: 2.60
|
||||
|
||||
|
||||
`G_SIZEOF_MEMBER(struct_type, member_name)`
|
||||
|
||||
: Evaluates to the size in bytes of `member_name` in the struct definition
|
||||
without having a declared instance of `struct_type`.
|
||||
|
||||
Since: 2.64
|
||||
|
||||
|
||||
`G_NORETURN`
|
||||
|
||||
: Expands to the GNU C or MSVC `noreturn` function attribute depending on
|
||||
the compiler. It is used for declaring functions which never return.
|
||||
Enables optimization of the function, and avoids possible compiler warnings.
|
||||
|
||||
Note that `G_NORETURN` supersedes the previous `G_GNUC_NORETURN` macro, which
|
||||
will eventually be deprecated. `G_NORETURN` supports more platforms.
|
||||
|
||||
Place the attribute before the function declaration as follows:
|
||||
|
||||
G_NORETURN void g_abort (void);
|
||||
|
||||
Since: 2.68
|
||||
|
||||
|
||||
`G_NORETURN_FUNCPTR`
|
||||
|
||||
: Expands to the GNU C or MSVC `noreturn` function attribute depending on
|
||||
the compiler. It is used for declaring function pointers which never return.
|
||||
Enables optimization of the function, and avoids possible compiler warnings.
|
||||
|
||||
Place the attribute before the function declaration as follows:
|
||||
|
||||
G_NORETURN_FUNCPTR void (*funcptr) (void);
|
||||
|
||||
Note that if the function is not a function pointer, you can simply use
|
||||
the `G_NORETURN` macro as follows:
|
||||
|
||||
G_NORETURN void g_abort (void);
|
||||
|
||||
Since: 2.68
|
||||
|
||||
|
||||
`G_ALWAYS_INLINE`
|
||||
|
||||
: Expands to the GNU C `always_inline` or MSVC `__forceinline` function
|
||||
attribute depending on the compiler. It is used for declaring functions
|
||||
as always inlined, ignoring the compiler optimization levels.
|
||||
|
||||
The attribute may be placed before the declaration or definition,
|
||||
right before the `static` keyword.
|
||||
|
||||
G_ALWAYS_INLINE
|
||||
static int
|
||||
do_inline_this (void)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
See the [GNU C documentation](https://gcc.gnu.org/onlinedocs/gcc/Common-Function-Attributes.html#index-always_005finline-function-attribute)
|
||||
and the [MSVC documentation](https://docs.microsoft.com/en-us/visualstudio/misc/inline-inline-forceinline)
|
||||
for more details.
|
||||
|
||||
Since: 2.74
|
||||
|
||||
|
||||
`G_NO_INLINE`
|
||||
|
||||
: Expands to the GNU C or MSVC `noinline` function attribute
|
||||
depending on the compiler. It is used for declaring functions
|
||||
preventing from being considered for inlining.
|
||||
|
||||
Note that `G_NO_INLINE` supersedes the previous `G_GNUC_NO_INLINE`
|
||||
macro, which will eventually be deprecated. `G_NO_INLINE` supports
|
||||
more platforms.
|
||||
|
||||
The attribute may be placed before the declaration or definition,
|
||||
right before the `static` keyword.
|
||||
|
||||
G_NO_INLINE
|
||||
static int
|
||||
do_not_inline_this (void)
|
||||
{
|
||||
// ...
|
||||
}
|
||||
|
||||
Since: 2.74
|
||||
|
||||
|
||||
`G_STRLOC`
|
||||
: Expands to a string identifying the current code position.
|
||||
|
||||
`G_STRFUNC`
|
||||
: Expands to a string identifying the current function. Since: 2.4
|
||||
|
||||
`G_GNUC_INTERNAL`
|
||||
|
||||
: This attribute can be used for marking library functions as being used
|
||||
internally to the library only, which may allow the compiler to handle
|
||||
function calls more efficiently. Note that static functions do not need
|
||||
to be marked as internal in this way. See the GNU C documentation for
|
||||
details.
|
||||
|
||||
When using a compiler that supports the GNU C hidden visibility attribute,
|
||||
this macro expands to `__attribute__((visibility("hidden")))`.
|
||||
When using the Sun Studio compiler, it expands to `__hidden`.
|
||||
|
||||
Note that for portability, the attribute should be placed before the
|
||||
function declaration. While GCC allows the macro after the declaration,
|
||||
Sun Studio does not.
|
||||
|
||||
G_GNUC_INTERNAL
|
||||
void _g_log_fallback_handler (const gchar *log_domain,
|
||||
GLogLevelFlags log_level,
|
||||
const gchar *message,
|
||||
gpointer unused_data);
|
||||
|
||||
Since: 2.6
|
||||
|
||||
|
||||
`G_HAVE_GNUC_VISIBILITY`
|
||||
: Defined to 1 if GCC-style visibility handling is supported.
|
||||
|
||||
|
||||
## Deprecation
|
||||
|
||||
|
||||
`G_DEPRECATED`
|
||||
|
||||
: This macro is similar to `G_GNUC_DEPRECATED`, and can be used to mark
|
||||
functions declarations as deprecated. Unlike `G_GNUC_DEPRECATED`, it is
|
||||
meant to be portable across different compilers and must be placed
|
||||
before the function declaration.
|
||||
|
||||
G_DEPRECATED
|
||||
int my_mistake (void);
|
||||
|
||||
Since: 2.32
|
||||
|
||||
|
||||
`G_DEPRECATED_FOR(f)`
|
||||
|
||||
: This macro is similar to `G_GNUC_DEPRECATED_FOR`, and can be used to mark
|
||||
functions declarations as deprecated. Unlike `G_GNUC_DEPRECATED_FOR`, it
|
||||
is meant to be portable across different compilers and must be placed
|
||||
before the function declaration.
|
||||
|
||||
G_DEPRECATED_FOR(my_replacement)
|
||||
int my_mistake (void);
|
||||
|
||||
Since: 2.32
|
||||
|
||||
|
||||
`G_UNAVAILABLE(major, minor)`
|
||||
|
||||
: This macro can be used to mark a function declaration as unavailable.
|
||||
It must be placed before the function declaration. Use of a function
|
||||
that has been annotated with this macros will produce a compiler warning.
|
||||
|
||||
Since: 2.32
|
||||
|
||||
|
||||
`GLIB_DISABLE_DEPRECATION_WARNINGS`
|
||||
: A macro that should be defined before including the `glib.h` header.
|
||||
If it is defined, no compiler warnings will be produced for uses
|
||||
of deprecated GLib APIs.
|
107
docs/reference/glib/main-loop.md
Normal file
107
docs/reference/glib/main-loop.md
Normal file
@ -0,0 +1,107 @@
|
||||
Title: The Main Event Loop
|
||||
|
||||
# The Main Event Loop
|
||||
|
||||
The main event loop manages all the available sources of events for GLib and
|
||||
GTK applications. These events can come from any number of different types
|
||||
of sources such as file descriptors (plain files, pipes or sockets) and
|
||||
timeouts. New types of event sources can also be added using
|
||||
`g_source_attach()`.
|
||||
|
||||
To allow multiple independent sets of sources to be handled in different
|
||||
threads, each source is associated with a `GMainContext`. A `GMainContext`
|
||||
can only be running in a single thread, but sources can be added to it and
|
||||
removed from it from other threads. All functions which operate on a
|
||||
`GMainContext` or a built-in `GSource` are thread-safe.
|
||||
|
||||
Each event source is assigned a priority. The default priority,
|
||||
`G_PRIORITY_DEFAULT`, is 0. Values less than 0 denote higher priorities.
|
||||
Values greater than 0 denote lower priorities. Events from high priority
|
||||
sources are always processed before events from lower priority sources.
|
||||
|
||||
Idle functions can also be added, and assigned a priority. These will be run
|
||||
whenever no events with a higher priority are ready to be processed.
|
||||
|
||||
The `GMainLoop` data type represents a main event loop. A GMainLoop is
|
||||
created with `g_main_loop_new()`. After adding the initial event sources,
|
||||
`g_main_loop_run()` is called. This continuously checks for new events from
|
||||
each of the event sources and dispatches them. Finally, the processing of an
|
||||
event from one of the sources leads to a call to `g_main_loop_quit()` to
|
||||
exit the main loop, and `g_main_loop_run()` returns.
|
||||
|
||||
It is possible to create new instances of `GMainLoop` recursively. This is
|
||||
often used in GTK applications when showing modal dialog boxes. Note that
|
||||
event sources are associated with a particular `GMainContext`, and will be
|
||||
checked and dispatched for all main loops associated with that GMainContext.
|
||||
|
||||
Libraries may contain wrappers of some of these functions, e.g.
|
||||
`gtk_main()`, `gtk_main_quit()` and `gtk_events_pending()`.
|
||||
|
||||
## Creating new source types
|
||||
|
||||
One of the unusual features of the `GMainLoop` functionality is that new
|
||||
types of event source can be created and used in addition to the builtin
|
||||
type of event source. A new event source type is used for handling GDK
|
||||
events. A new source type is created by "deriving" from the `GSource`
|
||||
structure. The derived type of source is represented by a structure that has
|
||||
the `GSource` structure as a first element, and other elements specific to
|
||||
the new source type. To create an instance of the new source type, call
|
||||
`g_source_new()` passing in the size of the derived structure and a table of
|
||||
functions. These `GSourceFuncs` determine the behavior of the new source
|
||||
type.
|
||||
|
||||
New source types basically interact with the main context in two ways. Their
|
||||
prepare function in `GSourceFuncs` can set a timeout to determine the
|
||||
maximum amount of time that the main loop will sleep before checking the
|
||||
source again. In addition, or as well, the source can add file descriptors
|
||||
to the set that the main context checks using `g_source_add_poll()`.
|
||||
|
||||
## Customizing the main loop iteration
|
||||
|
||||
Single iterations of a `GMainContext` can be run with
|
||||
`g_main_context_iteration()`. In some cases, more detailed control of
|
||||
exactly how the details of the main loop work is desired, for instance, when
|
||||
integrating the `GMainLoop` with an external main loop. In such cases, you
|
||||
can call the component functions of `g_main_context_iteration()` directly.
|
||||
These functions are `g_main_context_prepare()`, `g_main_context_query()`,
|
||||
`g_main_context_check()` and `g_main_context_dispatch()`.
|
||||
|
||||
## State of a Main Context
|
||||
|
||||
The operation of these functions can best be seen in terms of a state
|
||||
diagram, as shown in this image.
|
||||
|
||||
![](mainloop-states.gif)
|
||||
|
||||
On UNIX, the GLib mainloop is incompatible with `fork()`. Any program using
|
||||
the mainloop must either `exec()` or `exit()` from the child without
|
||||
returning to the mainloop.
|
||||
|
||||
## Memory management of sources
|
||||
|
||||
There are two options for memory management of the user data passed to a
|
||||
`GSource` to be passed to its callback on invocation. This data is provided
|
||||
in calls to `g_timeout_add()`, `g_timeout_add_full()`, `g_idle_add()`, etc.
|
||||
and more generally, using `g_source_set_callback()`. This data is typically
|
||||
an object which ‘owns’ the timeout or idle callback, such as a widget or a
|
||||
network protocol implementation. In many cases, it is an error for the
|
||||
callback to be invoked after this owning object has been destroyed, as that
|
||||
results in use of freed memory.
|
||||
|
||||
The first, and preferred, option is to store the source ID returned by
|
||||
functions such as `g_timeout_add()` or `g_source_attach()`, and explicitly
|
||||
remove that source from the main context using `g_source_remove()` when the
|
||||
owning object is finalized. This ensures that the callback can only be
|
||||
invoked while the object is still alive.
|
||||
|
||||
The second option is to hold a strong reference to the object in the
|
||||
callback, and to release it in the callback’s `GDestroyNotify`. This ensures
|
||||
that the object is kept alive until after the source is finalized, which is
|
||||
guaranteed to be after it is invoked for the final time. The
|
||||
`GDestroyNotify` is another callback passed to the ‘full’ variants of
|
||||
`GSource` functions (for example, `g_timeout_add_full()`). It is called when
|
||||
the source is finalized, and is designed for releasing references like this.
|
||||
|
||||
One important caveat of this second approach is that it will keep the object
|
||||
alive indefinitely if the main loop is stopped before the `GSource` is
|
||||
invoked, which may be undesirable.
|
50
docs/reference/glib/markup.md
Normal file
50
docs/reference/glib/markup.md
Normal file
@ -0,0 +1,50 @@
|
||||
Title: Simple XML Subset Parser
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2011, 2014 Matthias Clasen
|
||||
SPDX-FileCopyrightText: 2012 David King
|
||||
|
||||
# Simple XML Subset Parser
|
||||
|
||||
The "GMarkup" parser is intended to parse a simple markup format
|
||||
that's a subset of XML. This is a small, efficient, easy-to-use
|
||||
parser. It should not be used if you expect to interoperate with
|
||||
other applications generating full-scale XML, and must not be used if you
|
||||
expect to parse untrusted input. However, it's very useful for application
|
||||
data files, config files, etc. where you know your application will be the
|
||||
only one writing the file.
|
||||
|
||||
Full-scale XML parsers should be able to parse the subset used by
|
||||
GMarkup, so you can easily migrate to full-scale XML at a later
|
||||
time if the need arises.
|
||||
|
||||
GMarkup is not guaranteed to signal an error on all invalid XML;
|
||||
the parser may accept documents that an XML parser would not.
|
||||
However, XML documents which are not well-formed (which is a
|
||||
weaker condition than being valid. See the
|
||||
[XML specification](http://www.w3.org/TR/REC-xml/)
|
||||
for definitions of these terms.) are not considered valid GMarkup
|
||||
documents.
|
||||
|
||||
## Simplifications to XML
|
||||
|
||||
The simplifications compared to full XML include:
|
||||
|
||||
- Only UTF-8 encoding is allowed
|
||||
- No user-defined entities
|
||||
- Processing instructions, comments and the doctype declaration
|
||||
are "passed through" but are not interpreted in any way
|
||||
- No DTD or validation
|
||||
|
||||
The markup format does support:
|
||||
|
||||
- Elements
|
||||
- Attributes
|
||||
- 5 standard entities: `&` `<` `>` `"` `'`
|
||||
- Character references
|
||||
- Sections marked as CDATA
|
||||
|
||||
## An example parser
|
||||
|
||||
Here is an example for a markup parser:
|
||||
[markup-example.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/markup-example.c)
|
||||
|
58
docs/reference/glib/memory-slices.md
Normal file
58
docs/reference/glib/memory-slices.md
Normal file
@ -0,0 +1,58 @@
|
||||
Title: Memory Slices
|
||||
|
||||
# Memory Slices
|
||||
|
||||
GSlice was a space-efficient and multi-processing scalable way to allocate
|
||||
equal sized pieces of memory. Since GLib 2.76, its implementation has been
|
||||
removed and it calls `g_malloc()` and `g_free()`, because the performance of the
|
||||
system-default allocators has improved on all platforms since GSlice was
|
||||
written.
|
||||
|
||||
The GSlice APIs have not been deprecated, as they are widely in use and doing
|
||||
so would be very disruptive for little benefit.
|
||||
|
||||
New code should be written using [`func@GLib.new`]/[`func@GLib.malloc`] and
|
||||
[`func@GLib.free`]. There is no particular benefit in porting existing code away
|
||||
from `g_slice_new()`/`g_slice_free()` unless it’s being rewritten anyway.
|
||||
|
||||
Here is an example for using the slice allocator:
|
||||
|
||||
```c
|
||||
gchar *mem[10000];
|
||||
gint i;
|
||||
|
||||
// Allocate 10000 blocks.
|
||||
for (i = 0; i < 10000; i++)
|
||||
{
|
||||
mem[i] = g_slice_alloc (50);
|
||||
|
||||
// Fill in the memory with some junk.
|
||||
for (j = 0; j < 50; j++)
|
||||
mem[i][j] = i * j;
|
||||
}
|
||||
|
||||
// Now free all of the blocks.
|
||||
for (i = 0; i < 10000; i++)
|
||||
g_slice_free1 (50, mem[i]);
|
||||
```
|
||||
|
||||
And here is an example for using the using the slice allocator with data
|
||||
structures:
|
||||
|
||||
```c
|
||||
GRealArray *array;
|
||||
|
||||
// Allocate one block, using the g_slice_new() macro.
|
||||
array = g_slice_new (GRealArray);
|
||||
|
||||
// We can now use array just like a normal pointer to a structure.
|
||||
array->data = NULL;
|
||||
array->len = 0;
|
||||
array->alloc = 0;
|
||||
array->zero_terminated = (zero_terminated ? 1 : 0);
|
||||
array->clear = (clear ? 1 : 0);
|
||||
array->elt_size = elt_size;
|
||||
|
||||
// We can free the block, so it can be reused.
|
||||
g_slice_free (GRealArray, array);
|
||||
```
|
@ -71,22 +71,15 @@ if get_option('gtk_doc')
|
||||
'--ignore-headers=' + ' '.join(ignore_headers),
|
||||
],
|
||||
content_files : [
|
||||
'cross.xml',
|
||||
'running.xml',
|
||||
'building.xml',
|
||||
'changes.xml',
|
||||
'compiling.xml',
|
||||
'programming.xml',
|
||||
'resources.xml',
|
||||
'regex-syntax.xml',
|
||||
'glib-gettextize.xml',
|
||||
'gtester.xml',
|
||||
'gtester-report.xml',
|
||||
'gvariant-varargs.xml',
|
||||
'gvariant-text.xml',
|
||||
],
|
||||
expand_content_files : [
|
||||
'compiling.xml',
|
||||
],
|
||||
html_assets : [
|
||||
'file-name-encodings.png',
|
||||
@ -100,7 +93,7 @@ if get_option('gtk_doc')
|
||||
'--html-dir=' + docpath,
|
||||
],
|
||||
install: true,
|
||||
check: true)
|
||||
check: false)
|
||||
endif
|
||||
|
||||
if get_option('man')
|
||||
@ -149,3 +142,43 @@ if get_option('gtk_doc')
|
||||
)
|
||||
endif
|
||||
endif
|
||||
|
||||
# gi-docgen version
|
||||
expand_content_files = [
|
||||
'building.md',
|
||||
'character-set.md',
|
||||
'compiling.md',
|
||||
'cross-compiling.md',
|
||||
'error-reporting.md',
|
||||
'gvariant-format-strings.md',
|
||||
'gvariant-text-format.md',
|
||||
'i18n.md',
|
||||
'logging.md',
|
||||
'main-loop.md',
|
||||
'memory-slices.md',
|
||||
'reference-counting.md',
|
||||
'running.md',
|
||||
'testing.md',
|
||||
'threads.md',
|
||||
'markup.md',
|
||||
'goption.md',
|
||||
]
|
||||
|
||||
glib_gir = meson.current_source_dir() / 'GLib-2.0.gir'
|
||||
glib_toml = configure_file(input: 'glib.toml.in', output: 'glib.toml', configuration: toml_conf)
|
||||
|
||||
custom_target('glib-docs',
|
||||
input: [ glib_toml, glib_gir ],
|
||||
output: 'glib',
|
||||
command: [
|
||||
gidocgen,
|
||||
'generate',
|
||||
gidocgen_common_args,
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'@INPUT1@',
|
||||
],
|
||||
build_by_default: true,
|
||||
depend_files: expand_content_files,
|
||||
)
|
||||
|
164
docs/reference/glib/reference-counting.md
Normal file
164
docs/reference/glib/reference-counting.md
Normal file
@ -0,0 +1,164 @@
|
||||
Title: Reference Counting
|
||||
|
||||
## Reference counting types
|
||||
|
||||
Reference counting is a garbage collection mechanism that is based on
|
||||
assigning a counter to a data type, or any memory area; the counter is
|
||||
increased whenever a new reference to that data type is acquired, and
|
||||
decreased whenever the reference is released. Once the last reference is
|
||||
released, the resources associated to that data type are freed.
|
||||
|
||||
GLib uses reference counting in many of its data types, and provides the
|
||||
`grefcount` and `gatomicrefcount` types to implement safe and atomic
|
||||
reference counting semantics in new data types.
|
||||
|
||||
It is important to note that `grefcount` and `gatomicrefcount` should be
|
||||
considered completely opaque types; you should always use the provided API
|
||||
to increase and decrease the counters, and you should never check their
|
||||
content directly, or compare their content with other values.
|
||||
|
||||
## Reference counted data
|
||||
|
||||
A "reference counted box", or "RcBox", is an opaque wrapper data type that
|
||||
is guaranteed to be as big as the size of a given data type, and which
|
||||
augments the given data type with reference counting semantics for its
|
||||
memory management.
|
||||
|
||||
RcBox is useful if you have a plain old data type, like a structure
|
||||
typically placed on the stack, and you wish to provide additional API to use
|
||||
it on the heap; or if you want to implement a new type to be passed around
|
||||
by reference without necessarily implementing copy/free semantics or your
|
||||
own reference counting.
|
||||
|
||||
The typical use is:
|
||||
|
||||
```c
|
||||
typedef struct {
|
||||
char *name;
|
||||
char *address;
|
||||
char *city;
|
||||
char *state;
|
||||
int age;
|
||||
} Person;
|
||||
|
||||
Person *
|
||||
person_new (void)
|
||||
{
|
||||
return g_rc_box_new0 (Person);
|
||||
}
|
||||
```
|
||||
|
||||
Every time you wish to acquire a reference on the memory, you should call
|
||||
`g_rc_box_acquire()`; similarly, when you wish to release a reference you
|
||||
should call `g_rc_box_release()`:
|
||||
|
||||
```c
|
||||
// Add a Person to the Database; the Database acquires ownership
|
||||
// of the Person instance
|
||||
void
|
||||
add_person_to_database (Database *db, Person *p)
|
||||
{
|
||||
db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p));
|
||||
}
|
||||
|
||||
// Removes a Person from the Database; the reference acquired by
|
||||
// add_person_to_database() is released here
|
||||
void
|
||||
remove_person_from_database (Database *db, Person *p)
|
||||
{
|
||||
db->persons = g_list_remove (db->persons, p);
|
||||
g_rc_box_release (p);
|
||||
}
|
||||
```
|
||||
|
||||
If you have additional memory allocated inside the structure, you can use
|
||||
`g_rc_box_release_full()`, which takes a function pointer, which will be
|
||||
called if the reference released was the last:
|
||||
|
||||
```c
|
||||
void
|
||||
person_clear (Person *p)
|
||||
{
|
||||
g_free (p->name);
|
||||
g_free (p->address);
|
||||
g_free (p->city);
|
||||
g_free (p->state);
|
||||
}
|
||||
|
||||
void
|
||||
remove_person_from_database (Database *db, Person *p)
|
||||
{
|
||||
db->persons = g_list_remove (db->persons, p);
|
||||
g_rc_box_release_full (p, (GDestroyNotify) person_clear);
|
||||
}
|
||||
```
|
||||
|
||||
If you wish to transfer the ownership of a reference counted data
|
||||
type without increasing the reference count, you can use `g_steal_pointer()`:
|
||||
|
||||
```c
|
||||
Person *p = g_rc_box_new (Person);
|
||||
|
||||
// fill_person_details() is defined elsewhere
|
||||
fill_person_details (p);
|
||||
|
||||
// add_person_to_database_no_ref() is defined elsewhere; it adds
|
||||
// a Person to the Database without taking a reference
|
||||
add_person_to_database_no_ref (db, g_steal_pointer (&p));
|
||||
```
|
||||
|
||||
|
||||
## Thread safety
|
||||
|
||||
The reference counting operations on data allocated using
|
||||
`g_rc_box_alloc()`, `g_rc_box_new()`, and `g_rc_box_dup()` are not thread
|
||||
safe; it is your code's responsibility to ensure that references are
|
||||
acquired are released on the same thread.
|
||||
|
||||
If you need thread safe reference counting, you should use the
|
||||
`g_atomic_rc_*` API:
|
||||
|
||||
| Operation | Atomic equivalent |
|
||||
|---------------------------|----------------------------------|
|
||||
| `g_rc_box_alloc()` | `g_atomic_rc_box_alloc()` |
|
||||
| `g_rc_box_new()` | `g_atomic_rc_box_new()` |
|
||||
| `g_rc_box_dup()` | `g_atomic_rc_box_dup()` |
|
||||
| `g_rc_box_acquire()` | `g_atomic_rc_box_acquire()` |
|
||||
| `g_rc_box_release()` | `g_atomic_rc_box_release()` |
|
||||
| `g_rc_box_release_full()` | `g_atomic_rc_box_release_full()` |
|
||||
|
||||
The reference counting operations on data allocated using
|
||||
`g_atomic_rc_box_alloc()`, `g_atomic_rc_box_new()`, and
|
||||
`g_atomic_rc_box_dup()` are guaranteed to be atomic, and thus can be safely
|
||||
be performed by different threads. It is important to note that only the
|
||||
reference acquisition and release are atomic; changes to the content of the
|
||||
data are your responsibility.
|
||||
|
||||
It is a programmer error to mix the atomic and non-atomic reference counting
|
||||
operations.
|
||||
|
||||
## Automatic pointer clean up
|
||||
|
||||
If you want to add `g_autoptr()` support to your plain old data type through
|
||||
reference counting, you can use the `G_DEFINE_AUTOPTR_CLEANUP_FUNC()` and
|
||||
`g_rc_box_release()`:
|
||||
|
||||
```c
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release)
|
||||
```
|
||||
|
||||
If you need to clear the contents of the data, you will need to use an
|
||||
ancillary function that calls `g_rc_box_release_full()`:
|
||||
|
||||
```c
|
||||
static void
|
||||
my_data_struct_release (MyDataStruct *data)
|
||||
{
|
||||
// my_data_struct_clear() is defined elsewhere
|
||||
g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
|
||||
}
|
||||
|
||||
G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
|
||||
```
|
||||
|
||||
The `g_rc_box*` and `g_atomic_rc_box*` APIs were introduced in GLib 2.58.
|
189
docs/reference/glib/running.md
Normal file
189
docs/reference/glib/running.md
Normal file
@ -0,0 +1,189 @@
|
||||
Title: Running GLib Applications
|
||||
|
||||
# Running GLib Applications
|
||||
|
||||
## Environment variables
|
||||
|
||||
The runtime behaviour of GLib applications can be influenced by a number of
|
||||
environment variables.
|
||||
|
||||
Standard variables
|
||||
: GLib reads standard environment variables like `LANG`, `PATH`, `HOME`,
|
||||
`TMPDIR`, `TZ` and `LOGNAME`.
|
||||
|
||||
XDG directories
|
||||
: GLib consults the environment variables `XDG_DATA_HOME`,
|
||||
`XDG_DATA_DIRS`, `XDG_CONFIG_HOME`, `XDG_CONFIG_DIRS`, `XDG_CACHE_HOME` and
|
||||
`XDG_RUNTIME_DIR` for the various XDG directories. For more information, see
|
||||
the [XDG basedir specification](https://specifications.freedesktop.org/basedir-spec/latest/).
|
||||
|
||||
`G_FILENAME_ENCODING`
|
||||
: This environment variable can be set to a comma-separated list of character
|
||||
set names. GLib assumes that filenames are encoded in the first character
|
||||
set from that list rather than in UTF-8. The special token "@locale" can be
|
||||
used to specify the character set for the current locale.
|
||||
|
||||
`G_BROKEN_FILENAMES`
|
||||
: If this environment variable is set, GLib assumes that filenames are in the
|
||||
locale encoding rather than in UTF-8. `G_FILENAME_ENCODING` takes priority
|
||||
over `G_BROKEN_FILENAMES`.
|
||||
|
||||
`G_MESSAGES_PREFIXED`
|
||||
: A list of log levels for which messages should be prefixed by the program
|
||||
name and PID of the application. The default is to prefix everything except
|
||||
`G_LOG_LEVEL_MESSAGE` and `G_LOG_LEVEL_INFO`. The possible values are error,
|
||||
warning, critical, message, info and debug. You can also use the special
|
||||
values all and help. This environment variable only affects the default log
|
||||
handler, `g_log_default_handler()`.
|
||||
|
||||
`G_MESSAGES_DEBUG`
|
||||
: A space-separated list of log domains for which informational and debug
|
||||
messages should be printed. By default, these messages are not printed. You
|
||||
can also use the special value all. This environment variable only affects
|
||||
the default log handler, `g_log_default_handler()`.
|
||||
|
||||
`G_DEBUG`
|
||||
: This environment variable can be set to a list of debug options, which cause
|
||||
GLib to print out different types of debugging information.
|
||||
|
||||
- `fatal-warnings`: Causes GLib to abort the program at the first call to
|
||||
`g_warning()` or `g_critical()`. Use of this flag is not recommended
|
||||
except when debugging.
|
||||
- `fatal-criticals`: Causes GLib to abort the program at the first call
|
||||
to `g_critical()`. This flag can be useful during debugging and
|
||||
testing.
|
||||
- `gc-friendly`: Newly allocated memory that isn't directly initialized,
|
||||
as well as memory being freed will be reset to 0. The point here is to
|
||||
allow memory checkers and similar programs that use Boehm GC alike
|
||||
algorithms to produce more accurate results.
|
||||
- `resident-modules`: All modules loaded by GModule will be made
|
||||
resident. This can be useful for tracking memory leaks in modules which
|
||||
are later unloaded; but it can also hide bugs where code is accessed
|
||||
after the module would have normally been unloaded.
|
||||
- `bind-now-modules`: All modules loaded by GModule will bind their
|
||||
symbols at load time, even when the code uses `G_MODULE_BIND_LAZY`.
|
||||
|
||||
The special value `all` can be used to turn on all debug options. The special
|
||||
value `help` can be used to print all available options.
|
||||
|
||||
`G_SLICE`
|
||||
: This environment variable allowed reconfiguration of the GSlice memory
|
||||
allocator. Since GLib 2.76, GSlice uses the system `malloc()` implementation
|
||||
internally, so this variable is ignored.
|
||||
|
||||
`G_RANDOM_VERSION`
|
||||
: If this environment variable is set to '2.0', the outdated pseudo-random
|
||||
number seeding and generation algorithms from GLib 2.0 are used instead of
|
||||
the newer, better ones. You should only set this variable if you have
|
||||
sequences of numbers that were generated with Glib 2.0 that you need to
|
||||
reproduce exactly.
|
||||
|
||||
`LIBCHARSET_ALIAS_DIR`
|
||||
: Allows to specify a nonstandard location for the `charset.aliases` file
|
||||
that is used by the character set conversion routines. The default
|
||||
location is the `libdir` specified at compilation time.
|
||||
|
||||
`TZDIR`
|
||||
: Allows to specify a nonstandard location for the timezone data files that
|
||||
are used by the `GDateTime` API. The default location is under
|
||||
`/usr/share/zoneinfo`. For more information, also look at the `tzset` manual
|
||||
page.
|
||||
|
||||
`G_ENABLE_DIAGNOSTIC`
|
||||
: If set to a non-zero value, this environment variable enables diagnostic
|
||||
messages, like deprecation messages for GObject properties and signals.
|
||||
|
||||
`G_DEBUGGER`
|
||||
: When running on Windows, if set to a non-empty string, GLib will try to
|
||||
interpret the contents of this environment variable as a command line to a
|
||||
debugger, and run it if the process crashes. The debugger command line
|
||||
should contain `%p` and `%e` substitution tokens, which GLib will replace
|
||||
with the process ID of the crashing process and a handle to an event that
|
||||
the debugger should signal to let GLib know that the debugger successfully
|
||||
attached to the process. If `%e` is absent, or if the debugger is not able
|
||||
to signal events, GLib will resume execution after 60 seconds. If `%p` is
|
||||
absent, the debugger won't know which process to attach to, and GLib will
|
||||
also resume execution after 60 seconds. Additionally, even if `G_DEBUGGER`
|
||||
is not set, GLib would still try to print basic exception information (code
|
||||
and address) into `stderr`. By default the debugger gets a new console
|
||||
allocated for it. Set the `G_DEBUGGER_OLD_CONSOLE` environment variable to
|
||||
any non-empty string to make the debugger inherit the console of the
|
||||
crashing process. Normally this is only used by the GLib testsuite. The
|
||||
exception handler is written with the aim of making it as simple as
|
||||
possible, to minimize the risk of it invoking buggy functions or running
|
||||
buggy code, which would result in exceptions being raised recursively.
|
||||
Because of that it lacks most of the amenities that one would expect of
|
||||
GLib. Namely, it does not support Unicode, so it is highly advisable to
|
||||
only use ASCII characters in `G_DEBUGGER`. See also `G_VEH_CATCH`.
|
||||
|
||||
`G_VEH_CATCH`
|
||||
: Catching some exceptions can break the program, since Windows will
|
||||
sometimes use exceptions for execution flow control and other purposes
|
||||
other than signalling a crash. The `G_VEH_CATCH` environment variable
|
||||
augments Vectored Exception Handling on Windows (see `G_DEBUGGER`),
|
||||
allowing GLib to catch more exceptions. Set this variable to a
|
||||
comma-separated list of hexadecimal exception codes that should
|
||||
additionally be caught. By default GLib will only catch Access Violation,
|
||||
Stack Overflow and Illegal Instruction exceptions.
|
||||
|
||||
## Locale
|
||||
|
||||
A number of interfaces in GLib depend on the current locale in which an
|
||||
application is running. Therefore, most GLib-using applications should call
|
||||
`setlocale (LC_ALL, "")` to set up the current locale.
|
||||
|
||||
On Windows, in a C program there are several locale concepts that not
|
||||
necessarily are synchronized. On one hand, there is the system default ANSI
|
||||
code-page, which determines what encoding is used for file names handled by
|
||||
the C library's functions and the Win32 API. (We are talking about the
|
||||
"narrow" functions here that take character pointers, not the "wide" ones.)
|
||||
|
||||
On the other hand, there is the C library's current locale. The character
|
||||
set (code-page) used by that is not necessarily the same as the system
|
||||
default ANSI code-page. Strings in this character set are returned by
|
||||
functions like `strftime()`.
|
||||
|
||||
## Debugging with GDB
|
||||
|
||||
GLib ships with a set of Python macros for the GDB debugger. These includes
|
||||
pretty printers for lists, hashtables and GObject types. It also has a
|
||||
backtrace filter that makes backtraces with signal emissions easier to read.
|
||||
|
||||
To use this you need a version of GDB that supports Python scripting;
|
||||
anything from 7.0 should be fine. You then need to install GLib in the same
|
||||
prefix as GDB so that the Python GDB autoloaded files get installed in the
|
||||
right place for GDB to pick up.
|
||||
|
||||
General pretty printing should just happen without having to do anything
|
||||
special. To get the signal emission filtered backtrace you must use the
|
||||
"new-backtrace" command instead of the standard one.
|
||||
|
||||
There is also a new command called gforeach that can be used to apply a
|
||||
command on each item in a list. E.g. you can do
|
||||
|
||||
`gforeach i in some_list_variable: print *(GtkWidget *)l`
|
||||
|
||||
Which would print the contents of each widget in a list of widgets.
|
||||
|
||||
## SystemTap
|
||||
|
||||
SystemTap is a dynamic whole-system analysis toolkit. GLib ships with a file
|
||||
`libglib-2.0.so.*.stp` which defines a set of probe points, which you can hook
|
||||
into with custom SystemTap scripts. See the files `libglib-2.0.so.*.stp`,
|
||||
`libgobject-2.0.so.*.stp` and `libgio-2.0.so.*.stp` which are in your shared
|
||||
SystemTap scripts directory.
|
||||
|
||||
## Memory statistics
|
||||
|
||||
`g_mem_profile()` will output a summary `g_malloc()` memory usage, if memory
|
||||
profiling has been enabled by calling:
|
||||
|
||||
```
|
||||
g_mem_set_vtable (glib_mem_profiler_table);
|
||||
```
|
||||
|
||||
upon startup.
|
||||
|
||||
If GLib has been configured with full debugging support, then
|
||||
`g_slice_debug_tree_statistics()` can be called in a debugger to output details
|
||||
about the memory usage of the slice allocator.
|
@ -1,371 +0,0 @@
|
||||
<?xml version="1.0"?>
|
||||
<!DOCTYPE refentry PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<refentry id="glib-running">
|
||||
<refmeta>
|
||||
<refentrytitle>Running GLib Applications</refentrytitle>
|
||||
<manvolnum>3</manvolnum>
|
||||
<refmiscinfo>GLib Library</refmiscinfo>
|
||||
</refmeta>
|
||||
|
||||
<refnamediv>
|
||||
<refname>Running GLib Applications</refname>
|
||||
<refpurpose>
|
||||
How to run and debug your GLib application
|
||||
</refpurpose>
|
||||
</refnamediv>
|
||||
|
||||
<refsect1>
|
||||
<title>Running and debugging GLib Applications</title>
|
||||
|
||||
<refsect2>
|
||||
<title>Environment variables</title>
|
||||
|
||||
<para>
|
||||
The runtime behaviour of GLib applications can be influenced by a
|
||||
number of environment variables.
|
||||
</para>
|
||||
|
||||
<formalpara>
|
||||
<title>Standard variables</title>
|
||||
|
||||
<para>
|
||||
GLib reads standard environment variables like <envar>LANG</envar>,
|
||||
<envar>PATH</envar>, <envar>HOME</envar>, <envar>TMPDIR</envar>,
|
||||
<envar>TZ</envar> and <envar>LOGNAME</envar>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara>
|
||||
<title>XDG directories</title>
|
||||
|
||||
<para>
|
||||
GLib consults the environment variables <envar>XDG_DATA_HOME</envar>,
|
||||
<envar>XDG_DATA_DIRS</envar>, <envar>XDG_CONFIG_HOME</envar>,
|
||||
<envar>XDG_CONFIG_DIRS</envar>, <envar>XDG_CACHE_HOME</envar> and
|
||||
<envar>XDG_RUNTIME_DIR</envar> for the various XDG directories.
|
||||
For more information, see the <ulink url="http://standards.freedesktop.org/basedir-spec/basedir-spec-latest.html">XDG basedir spec</ulink>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_FILENAME_ENCODING">
|
||||
<title><envar>G_FILENAME_ENCODING</envar></title>
|
||||
|
||||
<para>
|
||||
This environment variable can be set to a comma-separated list of character
|
||||
set names. GLib assumes that filenames are encoded in the first character
|
||||
set from that list rather than in UTF-8. The special token "@locale" can be
|
||||
used to specify the character set for the current locale.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_BROKEN_FILENAMES">
|
||||
<title><envar>G_BROKEN_FILENAMES</envar></title>
|
||||
|
||||
<para>
|
||||
If this environment variable is set, GLib assumes that filenames are in
|
||||
the locale encoding rather than in UTF-8. G_FILENAME_ENCODING takes
|
||||
priority over G_BROKEN_FILENAMES.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_MESSAGES_PREFIXED">
|
||||
<title><envar>G_MESSAGES_PREFIXED</envar></title>
|
||||
|
||||
<para>
|
||||
A list of log levels for which messages should be prefixed by the
|
||||
program name and PID of the application. The default is to prefix
|
||||
everything except <literal>G_LOG_LEVEL_MESSAGE</literal> and
|
||||
<literal>G_LOG_LEVEL_INFO</literal>.
|
||||
The possible values are
|
||||
<literal>error</literal>,
|
||||
<literal>warning</literal>,
|
||||
<literal>critical</literal>,
|
||||
<literal>message</literal>,
|
||||
<literal>info</literal> and
|
||||
<literal>debug</literal>.
|
||||
You can also use the special values
|
||||
<literal>all</literal> and
|
||||
<literal>help</literal>.
|
||||
</para>
|
||||
<para>
|
||||
This environment variable only affects the default log handler,
|
||||
g_log_default_handler().
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_MESSAGES_DEBUG">
|
||||
<title><envar>G_MESSAGES_DEBUG</envar></title>
|
||||
|
||||
<para>
|
||||
A space-separated list of log domains for which informational
|
||||
and debug messages should be printed. By default, these
|
||||
messages are not printed.
|
||||
</para>
|
||||
<para>
|
||||
You can also use the special value <literal>all</literal>.
|
||||
</para>
|
||||
<para>
|
||||
This environment variable only affects the default log handler,
|
||||
g_log_default_handler().
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G-DEBUG:CAPS">
|
||||
<title><envar>G_DEBUG</envar></title>
|
||||
|
||||
<para>
|
||||
This environment variable can be set to a list of debug options,
|
||||
which cause GLib to print out different types of debugging information.
|
||||
<variablelist>
|
||||
<varlistentry>
|
||||
<term>fatal-warnings</term>
|
||||
<listitem><para>Causes GLib to abort the program at the first call
|
||||
to g_warning() or g_critical(). Use of this flag is not
|
||||
recommended except when debugging.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>fatal-criticals</term>
|
||||
<listitem><para>Causes GLib to abort the program at the first call
|
||||
to g_critical(). This flag can be useful during debugging and
|
||||
testing.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>gc-friendly</term>
|
||||
<listitem><para>Newly allocated memory that isn't directly initialized,
|
||||
as well as memory being freed will be reset to 0. The point here is
|
||||
to allow memory checkers and similar programs that use Boehm GC alike
|
||||
algorithms to produce more accurate results.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>resident-modules</term>
|
||||
<listitem><para>All modules loaded by GModule will be made resident.
|
||||
This can be useful for tracking memory leaks in modules which are
|
||||
later unloaded; but it can also hide bugs where code is accessed
|
||||
after the module would have normally been unloaded.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
<varlistentry>
|
||||
<term>bind-now-modules</term>
|
||||
<listitem><para>All modules loaded by GModule will bind their symbols
|
||||
at load time, even when the code uses %G_MODULE_BIND_LAZY.</para>
|
||||
</listitem>
|
||||
</varlistentry>
|
||||
</variablelist>
|
||||
The special value <literal>all</literal> can be used to turn on all debug options.
|
||||
The special value <literal>help</literal> can be used to print all available options.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_SLICE">
|
||||
<title><envar>G_SLICE</envar></title>
|
||||
|
||||
<para>
|
||||
This environment variable allowed reconfiguration of the GSlice
|
||||
memory allocator. Since GLib 2.76, GSlice uses the system
|
||||
<literal>malloc()</literal> implementation internally, so this variable is
|
||||
ignored.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_RANDOM_VERSION">
|
||||
<title><envar>G_RANDOM_VERSION</envar></title>
|
||||
|
||||
<para>
|
||||
If this environment variable is set to '2.0', the outdated
|
||||
pseudo-random number seeding and generation algorithms from
|
||||
GLib 2.0 are used instead of the newer, better ones. You should
|
||||
only set this variable if you have sequences of numbers that were
|
||||
generated with Glib 2.0 that you need to reproduce exactly.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="LIBCHARSET_ALIAS_DIR">
|
||||
<title><envar>LIBCHARSET_ALIAS_DIR</envar></title>
|
||||
|
||||
<para>
|
||||
Allows to specify a nonstandard location for the
|
||||
<filename>charset.aliases</filename> file that is used by the
|
||||
character set conversion routines. The default location is the
|
||||
<replaceable>libdir</replaceable> specified at compilation time.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="TZDIR">
|
||||
<title><envar>TZDIR</envar></title>
|
||||
|
||||
<para>
|
||||
Allows to specify a nonstandard location for the timezone data files
|
||||
that are used by the #GDateTime API. The default location is under
|
||||
<filename>/usr/share/zoneinfo</filename>. For more information,
|
||||
also look at the <command>tzset</command> manual page.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_ENABLE_DIAGNOSTIC">
|
||||
<title><envar>G_ENABLE_DIAGNOSTIC</envar></title>
|
||||
|
||||
<para>
|
||||
If set to a non-zero value, this environment variable enables
|
||||
diagnostic messages, like deprecation messages for GObject properties
|
||||
and signals.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_DEBUGGER">
|
||||
<title><envar>G_DEBUGGER</envar></title>
|
||||
|
||||
<para>
|
||||
When running on Windows, if set to a non-empty string, GLib will
|
||||
try to interpret the contents of this environment variable as
|
||||
a command line to a debugger, and run it if the process crashes.
|
||||
The debugger command line should contain <literal>%p</literal> and <literal>%e</literal> substitution
|
||||
tokens, which GLib will replace with the process ID of the crashing
|
||||
process and a handle to an event that the debugger should signal
|
||||
to let GLib know that the debugger successfully attached to the
|
||||
process. If <literal>%e</literal> is absent, or if the debugger is not able to
|
||||
signal events, GLib will resume execution after 60 seconds.
|
||||
If <literal>%p</literal> is absent, the debugger won't know which process to attach to,
|
||||
and GLib will also resume execution after 60 seconds.
|
||||
</para>
|
||||
<para>
|
||||
Additionally, even if <envar>G_DEBUGGER</envar> is not set, GLib would still
|
||||
try to print basic exception information (code and address) into
|
||||
stderr.
|
||||
</para>
|
||||
<para>
|
||||
By default the debugger gets a new console allocated for it.
|
||||
Set the <envar>G_DEBUGGER_OLD_CONSOLE</envar> environment variable to any
|
||||
non-empty string to make the debugger inherit the console of
|
||||
the crashing process. Normally this is only used by the GLib
|
||||
testsuite.
|
||||
</para>
|
||||
<para>
|
||||
The exception handler is written with the aim of making it as
|
||||
simple as possible, to minimize the risk of it invoking
|
||||
buggy functions or running buggy code, which would result
|
||||
in exceptions being raised recursively. Because of that
|
||||
it lacks most of the amenities that one would expect of GLib.
|
||||
Namely, it does not support Unicode, so it is highly advisable
|
||||
to only use ASCII characters in <envar>G_DEBUGGER</envar>.
|
||||
</para>
|
||||
<para>
|
||||
See also <link linkend="G_VEH_CATCH"><envar>G_VEH_CATCH</envar></link>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
<formalpara id="G_VEH_CATCH">
|
||||
<title><envar>G_VEH_CATCH</envar></title>
|
||||
|
||||
<para>
|
||||
Catching some exceptions can break the program, since Windows
|
||||
will sometimes use exceptions for execution flow control and
|
||||
other purposes other than signalling a crash.
|
||||
</para>
|
||||
<para>
|
||||
The <envar>G_VEH_CATCH</envar> environment variable augments
|
||||
<ulink url="https://docs.microsoft.com/en-us/windows/desktop/debug/vectored-exception-handling">Vectored Exception Handling</ulink>
|
||||
on Windows (see <link linkend="G_DEBUGGER"><envar>G_DEBUGGER</envar></link>), allowing GLib to catch more
|
||||
exceptions. Set this variable to a comma-separated list of
|
||||
hexadecimal exception codes that should additionally be caught.
|
||||
</para>
|
||||
<para>
|
||||
By default GLib will only catch Access Violation, Stack Overflow and
|
||||
Illegal Instruction <ulink url="https://docs.microsoft.com/en-us/windows/desktop/api/winnt/ns-winnt-_exception_record">exceptions</ulink>.
|
||||
</para>
|
||||
</formalpara>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2 id="setlocale">
|
||||
<title>Locale</title>
|
||||
|
||||
<para>
|
||||
A number of interfaces in GLib depend on the current locale in which
|
||||
an application is running. Therefore, most GLib-using applications should
|
||||
call <function>setlocale (LC_ALL, "")</function> to set up the current
|
||||
locale.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On Windows, in a C program there are several locale concepts
|
||||
that not necessarily are synchronized. On one hand, there is the
|
||||
system default ANSI code-page, which determines what encoding is used
|
||||
for file names handled by the C library's functions and the Win32
|
||||
API. (We are talking about the "narrow" functions here that take
|
||||
character pointers, not the "wide" ones.)
|
||||
</para>
|
||||
|
||||
<para>
|
||||
On the other hand, there is the C library's current locale. The
|
||||
character set (code-page) used by that is not necessarily the same as
|
||||
the system default ANSI code-page. Strings in this character set are
|
||||
returned by functions like <function>strftime()</function>.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<para>
|
||||
GLib ships with a set of Python macros for the GDB debugger. These includes pretty
|
||||
printers for lists, hashtables and GObject types. It also has a backtrace filter
|
||||
that makes backtraces with signal emissions easier to read.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
To use this you need a version of GDB that supports Python scripting; anything
|
||||
from 7.0 should be fine. You then need to install GLib in the same prefix as
|
||||
GDB so that the Python GDB autoloaded files get installed in the right place
|
||||
for GDB to pick up.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
General pretty printing should just happen without having to do anything special.
|
||||
To get the signal emission filtered backtrace you must use the "new-backtrace" command
|
||||
instead of the standard one.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There is also a new command called gforeach that can be used to apply a command
|
||||
on each item in a list. E.g. you can do
|
||||
<programlisting>
|
||||
gforeach i in some_list_variable: print *(GtkWidget *)l
|
||||
</programlisting>
|
||||
Which would print the contents of each widget in a list of widgets.
|
||||
</para>
|
||||
|
||||
<refsect2>
|
||||
<title>SystemTap</title>
|
||||
|
||||
<para>
|
||||
<ulink url="http://sourceware.org/systemtap/">SystemTap</ulink> is a dynamic whole-system
|
||||
analysis toolkit. GLib ships with a file <filename>libglib-2.0.so.*.stp</filename> which defines a
|
||||
set of probe points, which you can hook into with custom SystemTap scripts.
|
||||
See the files <filename>libglib-2.0.so.*.stp</filename>, <filename>libgobject-2.0.so.*.stp</filename>
|
||||
and <filename>libgio-2.0.so.*.stp</filename> which
|
||||
are in your shared SystemTap scripts directory.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
|
||||
<refsect2>
|
||||
<title>Memory statistics</title>
|
||||
|
||||
<para>
|
||||
g_mem_profile() will output a summary g_malloc() memory usage, if memory
|
||||
profiling has been enabled by calling
|
||||
<literal>g_mem_set_vtable (glib_mem_profiler_table)</literal> upon startup.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If GLib has been configured with <option>--enable-debug=yes</option>,
|
||||
then g_slice_debug_tree_statistics() can be called in a debugger to
|
||||
output details about the memory usage of the slice allocator.
|
||||
</para>
|
||||
|
||||
</refsect2>
|
||||
</refsect1>
|
||||
</refentry>
|
183
docs/reference/glib/testing.md
Normal file
183
docs/reference/glib/testing.md
Normal file
@ -0,0 +1,183 @@
|
||||
Title: Testing Framework
|
||||
|
||||
# Testing Framework
|
||||
|
||||
GLib provides a framework for writing and maintaining unit tests in parallel
|
||||
to the code they are testing. The API is designed according to established
|
||||
concepts found in the other test frameworks (JUnit, NUnit, RUnit), which in
|
||||
turn is based on smalltalk unit testing concepts.
|
||||
|
||||
- Test case: Tests (test methods) are grouped together with their fixture
|
||||
into test cases.
|
||||
- Fixture: A test fixture consists of fixture data and setup and teardown
|
||||
methods to establish the environment for the test functions. We use fresh
|
||||
fixtures, i.e. fixtures are newly set up and torn down around each test
|
||||
invocation to avoid dependencies between tests.
|
||||
- Test suite: Test cases can be grouped into test suites, to allow subsets
|
||||
of the available tests to be run. Test suites can be grouped into other
|
||||
test suites as well.
|
||||
|
||||
The API is designed to handle creation and registration of test suites and
|
||||
test cases implicitly. A simple call like:
|
||||
|
||||
```c
|
||||
g_test_add_func ("/misc/assertions", test_assertions);
|
||||
```
|
||||
|
||||
creates a test suite called "misc" with a single test case named
|
||||
"assertions", which consists of running the `test_assertions` function.
|
||||
|
||||
In addition to the traditional `g_assert_true()`, the test framework
|
||||
provides an extended set of assertions for comparisons:
|
||||
`g_assert_cmpfloat()`, `g_assert_cmpfloat_with_epsilon()`,
|
||||
`g_assert_cmpint()`, `g_assert_cmpuint()`, `g_assert_cmphex()`,
|
||||
`g_assert_cmpstr()`, `g_assert_cmpmem()` and `g_assert_cmpvariant()`. The
|
||||
advantage of these variants over plain `g_assert_true()` is that the
|
||||
assertion messages can be more elaborate, and include the values of the
|
||||
compared entities.
|
||||
|
||||
Note that `g_assert()` should **not** be used in unit tests, since it is a
|
||||
no-op when compiling with `G_DISABLE_ASSERT`. Use `g_assert()` in production
|
||||
code, and `g_assert_true()` in unit tests.
|
||||
|
||||
A full example of creating a test suite with two tests using fixtures:
|
||||
|
||||
```c
|
||||
#include <glib.h>
|
||||
#include <locale.h>
|
||||
|
||||
typedef struct {
|
||||
MyObject *obj;
|
||||
OtherObject *helper;
|
||||
} MyObjectFixture;
|
||||
|
||||
static void
|
||||
my_object_fixture_set_up (MyObjectFixture *fixture,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
fixture->obj = my_object_new ();
|
||||
my_object_set_prop1 (fixture->obj, "some-value");
|
||||
my_object_do_some_complex_setup (fixture->obj, user_data);
|
||||
|
||||
fixture->helper = other_object_new ();
|
||||
}
|
||||
|
||||
static void
|
||||
my_object_fixture_tear_down (MyObjectFixture *fixture,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
g_clear_object (&fixture->helper);
|
||||
g_clear_object (&fixture->obj);
|
||||
}
|
||||
|
||||
static void
|
||||
test_my_object_test1 (MyObjectFixture *fixture,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "initial-value");
|
||||
}
|
||||
|
||||
static void
|
||||
test_my_object_test2 (MyObjectFixture *fixture,
|
||||
gconstpointer user_data)
|
||||
{
|
||||
my_object_do_some_work_using_helper (fixture->obj, fixture->helper);
|
||||
g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "updated-value");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc, char *argv[])
|
||||
{
|
||||
setlocale (LC_ALL, "");
|
||||
|
||||
g_test_init (&argc, &argv, NULL);
|
||||
|
||||
// Define the tests.
|
||||
g_test_add ("/my-object/test1", MyObjectFixture, "some-user-data",
|
||||
my_object_fixture_set_up, test_my_object_test1,
|
||||
my_object_fixture_tear_down);
|
||||
g_test_add ("/my-object/test2", MyObjectFixture, "some-user-data",
|
||||
my_object_fixture_set_up, test_my_object_test2,
|
||||
my_object_fixture_tear_down);
|
||||
|
||||
return g_test_run ();
|
||||
}
|
||||
```
|
||||
|
||||
### Integrating GTest in your project
|
||||
|
||||
#### Using Meson
|
||||
|
||||
If you are using the Meson build system, you will typically use the provided
|
||||
`test()` primitive to call the test binaries, e.g.:
|
||||
|
||||
```
|
||||
test(
|
||||
'foo',
|
||||
executable('foo', 'foo.c', dependencies: deps),
|
||||
env: [
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
],
|
||||
protocol: 'tap',
|
||||
)
|
||||
|
||||
test(
|
||||
'bar',
|
||||
executable('bar', 'bar.c', dependencies: deps),
|
||||
env: [
|
||||
'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
],
|
||||
protocol: 'tap',
|
||||
)
|
||||
```
|
||||
|
||||
#### Using Autotools
|
||||
|
||||
If you are using Autotools, you're strongly encouraged to use the Automake
|
||||
TAP harness; GLib provides template files for easily integrating with it:
|
||||
|
||||
- [`glib-tap.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk)
|
||||
- [`tap-test`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test)
|
||||
- [`tap-driver.sh`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh)
|
||||
|
||||
You can copy these files in your own project's root directory, and then set
|
||||
up your `Makefile.am` file to reference them, for instance:
|
||||
|
||||
```
|
||||
include $(top_srcdir)/glib-tap.mk
|
||||
|
||||
# test binaries
|
||||
test_programs = \
|
||||
foo \
|
||||
bar
|
||||
|
||||
# data distributed in the tarball
|
||||
dist_test_data = \
|
||||
foo.data.txt \
|
||||
bar.data.txt
|
||||
|
||||
# data not distributed in the tarball
|
||||
test_data = \
|
||||
blah.data.txt
|
||||
```
|
||||
|
||||
Make sure to distribute the TAP files, using something like the following in
|
||||
your top-level `Makefile.am`:
|
||||
|
||||
```
|
||||
EXTRA_DIST += \
|
||||
tap-driver.sh \
|
||||
tap-test
|
||||
```
|
||||
|
||||
`glib-tap.mk` will be distributed implicitly due to being included in a
|
||||
`Makefile.am`. All three files should be added to version control.
|
||||
|
||||
If you don't have access to the Autotools TAP harness, you can use the
|
||||
gtester and gtester-report tools, and use the
|
||||
[`glib.mk`](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk)
|
||||
Automake template provided by GLib. Note, however, that since GLib 2.62,
|
||||
gtester and gtester-report have been deprecated in favour of using TAP. The
|
||||
`--tap` argument to tests is enabled by default as of GLib 2.62.
|
91
docs/reference/glib/threads.md
Normal file
91
docs/reference/glib/threads.md
Normal file
@ -0,0 +1,91 @@
|
||||
Title: Threads
|
||||
SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
SPDX-FileCopyrightText: 2010 Allison Lortie
|
||||
SPDX-FileCopyrightText: 2011, 2012, 2014 Matthias Clasen
|
||||
SPDX-FileCopyrightText: 2014 Collabora, Ltd.
|
||||
|
||||
# Threads
|
||||
|
||||
Threads act almost like processes, but unlike processes all threads of one
|
||||
process share the same memory. This is good, as it provides easy
|
||||
communication between the involved threads via this shared memory, and it is
|
||||
bad, because strange things (so called "Heisenbugs") might happen if the
|
||||
program is not carefully designed. In particular, due to the concurrent
|
||||
nature of threads, no assumptions on the order of execution of code running
|
||||
in different threads can be made, unless order is explicitly forced by the
|
||||
programmer through synchronization primitives.
|
||||
|
||||
The aim of the thread-related functions in GLib is to provide a portable
|
||||
means for writing multi-threaded software. There are primitives for mutexes
|
||||
to protect the access to portions of memory (`GMutex`, `GRecMutex` and
|
||||
`GRWLock`). There is a facility to use individual bits for locks
|
||||
(`g_bit_lock()`). There are primitives for condition variables to allow
|
||||
synchronization of threads (`GCond`). There are primitives for
|
||||
thread-private data - data that every thread has a private instance of
|
||||
(`GPrivate`). There are facilities for one-time initialization (`GOnce`,
|
||||
`g_once_init_enter_pointer()`, `g_once_init_enter()`). Finally, there are
|
||||
primitives to create and manage threads (`GThread`).
|
||||
|
||||
The GLib threading system used to be initialized with `g_thread_init()`.
|
||||
This is no longer necessary. Since version 2.32, the GLib threading system
|
||||
is automatically initialized at the start of your program, and all
|
||||
thread-creation functions and synchronization primitives are available right
|
||||
away.
|
||||
|
||||
Note that it is not safe to assume that your program has no threads even if
|
||||
you don't call `g_thread_new()` yourself. GLib and GIO can and will create
|
||||
threads for their own purposes in some cases, such as when using
|
||||
`g_unix_signal_source_new()` or when using GDBus.
|
||||
|
||||
Originally, UNIX did not have threads, and therefore some traditional UNIX
|
||||
APIs are problematic in threaded programs. Some notable examples are
|
||||
|
||||
- C library functions that return data in statically allocated buffers, such
|
||||
as `strtok()` or `strerror()`. For many of these, there are thread-safe
|
||||
variants with a `_r` suffix, or you can look at corresponding GLib APIs
|
||||
(`like g_strsplit()` or `g_strerror()`).
|
||||
- The functions `setenv()` and `unsetenv()` manipulate the process
|
||||
environment in a not thread-safe way, and may interfere with `getenv()`
|
||||
calls in other threads. Note that `getenv()` calls may be hidden behind
|
||||
other APIs. For example, GNU `gettext()` calls `getenv()` under the
|
||||
covers. In general, it is best to treat the environment as readonly. If
|
||||
you absolutely have to modify the environment, do it early in `main()`,
|
||||
when no other threads are around yet.
|
||||
- The `setlocale()` function changes the locale for the entire process,
|
||||
affecting all threads. Temporary changes to the locale are often made to
|
||||
change the behavior of string scanning or formatting functions like
|
||||
`scanf()` or `printf()`. GLib offers a number of string APIs (like
|
||||
`g_ascii_formatd()` or `g_ascii_strtod()`) that can often be used as an
|
||||
alternative. Or you can use the `uselocale()` function to change the
|
||||
locale only for the current thread.
|
||||
- The `fork()` function only takes the calling thread into the child's copy
|
||||
of the process image. If other threads were executing in critical sections
|
||||
they could have left mutexes locked which could easily cause deadlocks in
|
||||
the new child. For this reason, you should call `exit()` or `exec()` as
|
||||
soon as possible in the child and only make signal-safe library calls
|
||||
before that.
|
||||
- The `daemon()` function uses `fork()` in a way contrary to what is
|
||||
described above. It should not be used with GLib programs.
|
||||
|
||||
GLib itself is internally completely thread-safe (all global data is
|
||||
automatically locked), but individual data structure instances are not
|
||||
automatically locked for performance reasons. For example, you must
|
||||
coordinate accesses to the same `GHashTable` from multiple threads. The two
|
||||
notable exceptions from this rule are `GMainLoop` and `GAsyncQueue`, which are
|
||||
thread-safe and need no further application-level locking to be accessed
|
||||
from multiple threads. Most refcounting functions such as `g_object_ref()` are
|
||||
also thread-safe.
|
||||
|
||||
A common use for GThreads is to move a long-running blocking operation out
|
||||
of the main thread and into a worker thread. For GLib functions, such as
|
||||
single GIO operations, this is not necessary, and complicates the code.
|
||||
Instead, the `…_async()` version of the function should be used from the main
|
||||
thread, eliminating the need for locking and synchronisation between
|
||||
multiple threads. If an operation does need to be moved to a worker thread,
|
||||
consider using `g_task_run_in_thread()`, or a `GThreadPool`. `GThreadPool` is
|
||||
often a better choice than `GThread`, as it handles thread reuse and task
|
||||
queueing; `GTask` uses this internally.
|
||||
|
||||
However, if multiple blocking operations need to be performed in sequence,
|
||||
and it is not possible to use `GTask` for them, moving them to a worker thread
|
||||
can clarify the code.
|
9
docs/reference/glib/urlmap.js
Normal file
9
docs/reference/glib/urlmap.js
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// SPDX-FileCopyrightText: 2023 Matthias Clasen
|
||||
var baseURLs = [
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GModule', 'https://docs.gtk.org/gmodule/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk4/' ],
|
||||
];
|
535
docs/reference/gmodule/GModule-2.0.gir
Normal file
535
docs/reference/gmodule/GModule-2.0.gir
Normal file
@ -0,0 +1,535 @@
|
||||
<?xml version="1.0"?>
|
||||
<!-- This file was automatically generated from C sources - DO NOT EDIT!
|
||||
To affect the contents of this file, edit the original C definitions,
|
||||
and/or use gtk-doc annotations. -->
|
||||
<repository version="1.2"
|
||||
xmlns="http://www.gtk.org/introspection/core/1.0"
|
||||
xmlns:c="http://www.gtk.org/introspection/c/1.0"
|
||||
xmlns:glib="http://www.gtk.org/introspection/glib/1.0">
|
||||
<include name="GLib" version="2.0"/>
|
||||
<package name="gmodule-2.0"/>
|
||||
<c:include name="gmodule.h"/>
|
||||
<namespace name="GModule"
|
||||
version="2.0"
|
||||
shared-library="libgmodule-2.0.so.0"
|
||||
c:identifier-prefixes="G"
|
||||
c:symbol-prefixes="g">
|
||||
<record name="Module" c:type="GModule" disguised="1" opaque="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="5">The #GModule struct is an opaque data structure to represent a
|
||||
[dynamically-loaded module][glib-Dynamic-Loading-of-Modules].
|
||||
It should only be accessed via the following functions.</doc>
|
||||
<source-position filename="gmodule.h" line="70"/>
|
||||
<method name="close" c:identifier="g_module_close">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="207">Closes a module.</doc>
|
||||
<source-position filename="gmodule.h" line="110"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="213">%TRUE on success</doc>
|
||||
<type name="gboolean" c:type="gboolean"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<instance-parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="209">a #GModule to close</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</instance-parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<method name="make_resident" c:identifier="g_module_make_resident">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="226">Ensures that a module will never be unloaded.
|
||||
Any future g_module_close() calls on the module will be ignored.</doc>
|
||||
<source-position filename="gmodule.h" line="114"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<type name="none" c:type="void"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<instance-parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="228">a #GModule to make permanently resident</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</instance-parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<method name="name" c:identifier="g_module_name">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="235">Returns the filename that the module was opened with.
|
||||
|
||||
If @module refers to the application itself, "main" is returned.</doc>
|
||||
<source-position filename="gmodule.h" line="128"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="243">the filename of the module</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<instance-parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="237">a #GModule</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</instance-parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<method name="symbol" c:identifier="g_module_symbol">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="299">Gets a symbol pointer from a module, such as one exported
|
||||
by %G_MODULE_EXPORT. Note that a valid symbol can be %NULL.</doc>
|
||||
<source-position filename="gmodule.h" line="122"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="308">%TRUE on success</doc>
|
||||
<type name="gboolean" c:type="gboolean"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<instance-parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="301">a #GModule</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</instance-parameter>
|
||||
<parameter name="symbol_name" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="302">the name of the symbol to find</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
<parameter name="symbol"
|
||||
direction="out"
|
||||
caller-allocates="0"
|
||||
transfer-ownership="full"
|
||||
nullable="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="303">returns the pointer to the symbol value</doc>
|
||||
<type name="gpointer" c:type="gpointer*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</method>
|
||||
<function name="build_path"
|
||||
c:identifier="g_module_build_path"
|
||||
deprecated="1"
|
||||
deprecated-version="2.76">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="179">A portable way to build the filename of a module. The platform-specific
|
||||
prefix and suffix are added to the filename, if needed, and the result
|
||||
is added to the directory, using the correct separator character.
|
||||
|
||||
The directory should specify the directory where the module can be found.
|
||||
It can be %NULL or an empty string to indicate that the module is in a
|
||||
standard platform-specific directory, though this is not recommended
|
||||
since the wrong module may be found.
|
||||
|
||||
For example, calling g_module_build_path() on a Linux system with a
|
||||
@directory of `/lib` and a @module_name of "mylibrary" will return
|
||||
`/lib/libmylibrary.so`. On a Windows system, using `\Windows` as the
|
||||
directory it will return `\Windows\mylibrary.dll`.</doc>
|
||||
<doc-deprecated xml:space="preserve">Use g_module_open() instead with @module_name as the
|
||||
basename of the file_name argument. See %G_MODULE_SUFFIX for why.</doc-deprecated>
|
||||
<source-position filename="gmodule.h" line="142"/>
|
||||
<return-value transfer-ownership="full">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="200">the complete path of the module, including the standard library
|
||||
prefix and suffix. This should be freed when no longer needed</doc>
|
||||
<type name="utf8" c:type="gchar*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="directory"
|
||||
transfer-ownership="none"
|
||||
nullable="1"
|
||||
allow-none="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="181">the directory where the module is. This can be
|
||||
%NULL or the empty string to indicate that the standard platform-specific
|
||||
directories will be used, though that is not recommended</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
<parameter name="module_name" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="184">the name of the module</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</function>
|
||||
<function name="error" c:identifier="g_module_error">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="217">Gets a string describing the last module error.</doc>
|
||||
<source-position filename="gmodule.h" line="118"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="222">a string describing the last module error</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</return-value>
|
||||
</function>
|
||||
<function name="error_quark" c:identifier="g_module_error_quark">
|
||||
<return-value transfer-ownership="none">
|
||||
<type name="GLib.Quark" c:type="GQuark"/>
|
||||
</return-value>
|
||||
</function>
|
||||
<function name="open" c:identifier="g_module_open" introspectable="0">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="247">A thin wrapper function around g_module_open_full()</doc>
|
||||
<source-position filename="gmodule.h" line="100"/>
|
||||
<return-value>
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="256">a #GModule on success, or %NULL on failure</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="file_name"
|
||||
transfer-ownership="none"
|
||||
nullable="1"
|
||||
allow-none="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="249">the name or path to the file containing the module,
|
||||
or %NULL to obtain a #GModule representing the main program itself</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
<parameter name="flags" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="251">the flags used for opening the module. This can be the
|
||||
logical OR of any of the #GModuleFlags.</doc>
|
||||
<type name="ModuleFlags" c:type="GModuleFlags"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</function>
|
||||
<function name="open_full"
|
||||
c:identifier="g_module_open_full"
|
||||
version="2.70"
|
||||
introspectable="0"
|
||||
throws="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="260">Opens a module. If the module has already been opened, its reference count
|
||||
is incremented. If not, the module is searched in the following order:
|
||||
|
||||
1. If @file_name exists as a regular file, it is used as-is; else
|
||||
2. If @file_name doesn't have the correct suffix and/or prefix for the
|
||||
platform, then possible suffixes and prefixes will be added to the
|
||||
basename till a file is found and whatever is found will be used; else
|
||||
3. If @file_name doesn't have the ".la"-suffix, ".la" is appended. Either
|
||||
way, if a matching .la file exists (and is a libtool archive) the
|
||||
libtool archive is parsed to find the actual file name, and that is
|
||||
used.
|
||||
|
||||
At the end of all this, we would have a file path that we can access on
|
||||
disk, and it is opened as a module. If not, @file_name is opened as
|
||||
a module verbatim in the hopes that the system implementation will somehow
|
||||
be able to access it.</doc>
|
||||
<source-position filename="gmodule.h" line="104"/>
|
||||
<return-value>
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="285">a #GModule on success, or %NULL on failure</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="file_name"
|
||||
transfer-ownership="none"
|
||||
nullable="1"
|
||||
allow-none="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="262">the name or path to the file containing the module,
|
||||
or %NULL to obtain a #GModule representing the main program itself</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
<parameter name="flags" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="264">the flags used for opening the module. This can be the
|
||||
logical OR of any of the #GModuleFlags</doc>
|
||||
<type name="ModuleFlags" c:type="GModuleFlags"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</function>
|
||||
<function name="supported" c:identifier="g_module_supported">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="290">Checks if modules are supported on the current platform.</doc>
|
||||
<source-position filename="gmodule.h" line="96"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="295">%TRUE if modules are supported</doc>
|
||||
<type name="gboolean" c:type="gboolean"/>
|
||||
</return-value>
|
||||
</function>
|
||||
</record>
|
||||
<callback name="ModuleCheckInit" c:type="GModuleCheckInit">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="14">Specifies the type of the module initialization function.
|
||||
If a module contains a function named g_module_check_init() it is called
|
||||
automatically when the module is loaded. It is passed the #GModule structure
|
||||
and should return %NULL on success or a string describing the initialization
|
||||
error.</doc>
|
||||
<source-position filename="gmodule.h" line="71"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="24">%NULL on success, or a string describing the initialization error</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="16">the #GModule corresponding to the module which has just been loaded</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</callback>
|
||||
<enumeration name="ModuleError"
|
||||
version="2.70"
|
||||
c:type="GModuleError"
|
||||
glib:error-domain="g-module-error-quark">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="78">Errors returned by g_module_open_full().</doc>
|
||||
<source-position filename="gmodule.h" line="91"/>
|
||||
<member name="failed" value="0" c:identifier="G_MODULE_ERROR_FAILED">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="80">there was an error loading or opening a module file</doc>
|
||||
</member>
|
||||
<member name="check_failed"
|
||||
value="1"
|
||||
c:identifier="G_MODULE_ERROR_CHECK_FAILED">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="81">a module returned an error from its `g_module_check_init()` function</doc>
|
||||
</member>
|
||||
</enumeration>
|
||||
<bitfield name="ModuleFlags" c:type="GModuleFlags">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="49">Flags passed to g_module_open().
|
||||
Note that these flags are not supported on all platforms.</doc>
|
||||
<source-position filename="gmodule.h" line="68"/>
|
||||
<member name="lazy" value="1" c:identifier="G_MODULE_BIND_LAZY">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="51">specifies that symbols are only resolved when
|
||||
needed. The default action is to bind all symbols when the module
|
||||
is loaded.</doc>
|
||||
</member>
|
||||
<member name="local" value="2" c:identifier="G_MODULE_BIND_LOCAL">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="54">specifies that symbols in the module should
|
||||
not be added to the global name space. The default action on most
|
||||
platforms is to place symbols in the module in the global name space,
|
||||
which may cause conflicts with existing symbols.</doc>
|
||||
</member>
|
||||
<member name="mask" value="3" c:identifier="G_MODULE_BIND_MASK">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule.h"
|
||||
line="58">mask for all flags.</doc>
|
||||
</member>
|
||||
</bitfield>
|
||||
<callback name="ModuleUnload" c:type="GModuleUnload">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="28">Specifies the type of the module function called when it is unloaded.
|
||||
If a module contains a function named g_module_unload() it is called
|
||||
automatically when the module is unloaded.
|
||||
It is passed the #GModule structure.</doc>
|
||||
<source-position filename="gmodule.h" line="72"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<type name="none" c:type="void"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="module" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="30">the #GModule about to be unloaded</doc>
|
||||
<type name="Module" c:type="GModule*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</callback>
|
||||
<function name="module_build_path"
|
||||
c:identifier="g_module_build_path"
|
||||
moved-to="Module.build_path"
|
||||
deprecated="1"
|
||||
deprecated-version="2.76">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="179">A portable way to build the filename of a module. The platform-specific
|
||||
prefix and suffix are added to the filename, if needed, and the result
|
||||
is added to the directory, using the correct separator character.
|
||||
|
||||
The directory should specify the directory where the module can be found.
|
||||
It can be %NULL or an empty string to indicate that the module is in a
|
||||
standard platform-specific directory, though this is not recommended
|
||||
since the wrong module may be found.
|
||||
|
||||
For example, calling g_module_build_path() on a Linux system with a
|
||||
@directory of `/lib` and a @module_name of "mylibrary" will return
|
||||
`/lib/libmylibrary.so`. On a Windows system, using `\Windows` as the
|
||||
directory it will return `\Windows\mylibrary.dll`.</doc>
|
||||
<doc-deprecated xml:space="preserve">Use g_module_open() instead with @module_name as the
|
||||
basename of the file_name argument. See %G_MODULE_SUFFIX for why.</doc-deprecated>
|
||||
<source-position filename="gmodule.h" line="142"/>
|
||||
<return-value transfer-ownership="full">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="200">the complete path of the module, including the standard library
|
||||
prefix and suffix. This should be freed when no longer needed</doc>
|
||||
<type name="utf8" c:type="gchar*"/>
|
||||
</return-value>
|
||||
<parameters>
|
||||
<parameter name="directory"
|
||||
transfer-ownership="none"
|
||||
nullable="1"
|
||||
allow-none="1">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="181">the directory where the module is. This can be
|
||||
%NULL or the empty string to indicate that the standard platform-specific
|
||||
directories will be used, though that is not recommended</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
<parameter name="module_name" transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="184">the name of the module</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</parameter>
|
||||
</parameters>
|
||||
</function>
|
||||
<function name="module_error"
|
||||
c:identifier="g_module_error"
|
||||
moved-to="Module.error">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="217">Gets a string describing the last module error.</doc>
|
||||
<source-position filename="gmodule.h" line="118"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="222">a string describing the last module error</doc>
|
||||
<type name="utf8" c:type="const gchar*"/>
|
||||
</return-value>
|
||||
</function>
|
||||
<function name="module_error_quark"
|
||||
c:identifier="g_module_error_quark"
|
||||
moved-to="Module.error_quark">
|
||||
<return-value transfer-ownership="none">
|
||||
<type name="GLib.Quark" c:type="GQuark"/>
|
||||
</return-value>
|
||||
</function>
|
||||
<function name="module_supported"
|
||||
c:identifier="g_module_supported"
|
||||
moved-to="Module.supported">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="290">Checks if modules are supported on the current platform.</doc>
|
||||
<source-position filename="gmodule.h" line="96"/>
|
||||
<return-value transfer-ownership="none">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="295">%TRUE if modules are supported</doc>
|
||||
<type name="gboolean" c:type="gboolean"/>
|
||||
</return-value>
|
||||
</function>
|
||||
<docsection name="modules">
|
||||
<doc xml:space="preserve"
|
||||
filename="gmodule-2.0.c"
|
||||
line="99">These functions provide a portable way to dynamically load object files
|
||||
(commonly known as 'plug-ins'). The current implementation supports all
|
||||
systems that provide an implementation of dlopen() (e.g. Linux/Sun), as
|
||||
well as Windows platforms via DLLs.
|
||||
|
||||
A program which wants to use these functions must be linked to the
|
||||
libraries output by the command `pkg-config --libs gmodule-2.0`.
|
||||
|
||||
To use them you must first determine whether dynamic loading
|
||||
is supported on the platform by calling g_module_supported().
|
||||
If it is, you can open a module with g_module_open(),
|
||||
find the module's symbols (e.g. function names) with g_module_symbol(),
|
||||
and later close the module with g_module_close().
|
||||
g_module_name() will return the file name of a currently opened module.
|
||||
|
||||
If any of the above functions fail, the error status can be found with
|
||||
g_module_error().
|
||||
|
||||
The #GModule implementation features reference counting for opened modules,
|
||||
and supports hook functions within a module which are called when the
|
||||
module is loaded and unloaded (see #GModuleCheckInit and #GModuleUnload).
|
||||
|
||||
If your module introduces static data to common subsystems in the running
|
||||
program, e.g. through calling
|
||||
`g_quark_from_static_string ("my-module-stuff")`,
|
||||
it must ensure that it is never unloaded, by calling g_module_make_resident().
|
||||
|
||||
Example: Calling a function defined in a GModule
|
||||
|[<!-- language="C" -->
|
||||
// the function signature for 'say_hello'
|
||||
typedef void (* SayHelloFunc) (const char *message);
|
||||
|
||||
gboolean
|
||||
just_say_hello (const char *filename, GError **error)
|
||||
{
|
||||
SayHelloFunc say_hello;
|
||||
GModule *module;
|
||||
|
||||
module = g_module_open (filename, G_MODULE_BIND_LAZY);
|
||||
if (!module)
|
||||
{
|
||||
g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
|
||||
"%s", g_module_error ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello))
|
||||
{
|
||||
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
"%s: %s", filename, g_module_error ());
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (say_hello == NULL)
|
||||
{
|
||||
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
"symbol say_hello is NULL");
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// call our function in the module
|
||||
say_hello ("Hello world!");
|
||||
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
return TRUE;
|
||||
}
|
||||
]|</doc>
|
||||
</docsection>
|
||||
</namespace>
|
||||
</repository>
|
49
docs/reference/gmodule/gmodule.toml.in
Normal file
49
docs/reference/gmodule/gmodule.toml.in
Normal file
@ -0,0 +1,49 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# Copyright 2023 Matthias Clasen
|
||||
# Copyright 2023 Philip Withnall
|
||||
|
||||
[library]
|
||||
name = "GModule"
|
||||
version = "@VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/glib/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/glib.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/gmodule/"
|
||||
authors = "GLib Development Team"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "Portable API for dynamically loading modules"
|
||||
dependencies = [ "GLib-2.0", "GObject-2.0", "Gio-2.0" ]
|
||||
devhelp = true
|
||||
search_index = true
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "The base utility library"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
|
||||
[dependencies."GObject-2.0"]
|
||||
name = "GObject"
|
||||
description = "The base type system library"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
|
||||
[dependencies."Gio-2.0"]
|
||||
name = "GIO"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[source-location]
|
||||
base_url = "https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/"
|
||||
|
||||
[extra]
|
||||
urlmap_file = "urlmap.js"
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"modules.md",
|
||||
]
|
||||
content_images = [
|
||||
]
|
23
docs/reference/gmodule/meson.build
Normal file
23
docs/reference/gmodule/meson.build
Normal file
@ -0,0 +1,23 @@
|
||||
expand_content_files = [
|
||||
'modules.md',
|
||||
]
|
||||
|
||||
gmodule_gir = meson.current_source_dir() / 'GModule-2.0.gir'
|
||||
gmodule_toml = configure_file(input: 'gmodule.toml.in', output: 'gmodule.toml', configuration: toml_conf)
|
||||
|
||||
custom_target('gmodule-docs',
|
||||
input: [ gmodule_toml, gmodule_gir ],
|
||||
output: 'gmodule',
|
||||
command: [
|
||||
gidocgen,
|
||||
'generate',
|
||||
gidocgen_common_args,
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'--add-include-path=@0@'.format(meson.current_source_dir() / '../glib'),
|
||||
'@INPUT1@',
|
||||
],
|
||||
build_by_default: true,
|
||||
depend_files: expand_content_files,
|
||||
)
|
92
docs/reference/gmodule/modules.md
Normal file
92
docs/reference/gmodule/modules.md
Normal file
@ -0,0 +1,92 @@
|
||||
Title: Dynamic Loading of Modules
|
||||
|
||||
## Dynamic Loading of Modules
|
||||
|
||||
These functions provide a portable way to dynamically load object files
|
||||
(commonly known as 'plug-ins'). The current implementation supports all
|
||||
systems that provide an implementation of `dlopen()` (e.g. Linux/Sun), as
|
||||
well as Windows platforms via DLLs.
|
||||
|
||||
A program which wants to use these functions must be linked to the libraries
|
||||
output by the command:
|
||||
|
||||
pkg-config --libs gmodule-2.0
|
||||
|
||||
To use them you must first determine whether dynamic loading is supported on
|
||||
the platform by calling [`func@GModule.Module.supported`]. If it is, you can
|
||||
open a module with [`func@GModule.Module.open`], find the module's symbols
|
||||
(e.g. function names) with [`method@GModule.Module.symbol`], and later close
|
||||
the module with [`method@GModule.Module.close`].
|
||||
[`method@GModule.Module.name`] will return the file name of a currently
|
||||
opened module.
|
||||
|
||||
If any of the above functions fail, the error status can be found with
|
||||
[`func@GModule.Module.error`].
|
||||
|
||||
The `GModule` implementation features reference counting for opened modules,
|
||||
and supports hook functions within a module which are called when the module
|
||||
is loaded and unloaded (see [callback@GModule.ModuleCheckInit] and
|
||||
[callback@GModule.ModuleUnload]).
|
||||
|
||||
If your module introduces static data to common subsystems in the running
|
||||
program, e.g. through calling API like:
|
||||
|
||||
```c
|
||||
static GQuark my_module_quark =
|
||||
g_quark_from_static_string ("my-module-stuff");
|
||||
```
|
||||
|
||||
it must ensure that it is never unloaded, by calling
|
||||
[`method@GModule.Module.make_resident`].
|
||||
|
||||
### Calling a function defined in a GModule
|
||||
|
||||
```c
|
||||
// the function signature for 'say_hello'
|
||||
typedef void (* SayHelloFunc) (const char *message);
|
||||
|
||||
gboolean
|
||||
just_say_hello (const char *filename, GError **error)
|
||||
{
|
||||
SayHelloFunc say_hello;
|
||||
GModule *module;
|
||||
|
||||
module = g_module_open (filename, G_MODULE_BIND_LAZY);
|
||||
if (module == NULL)
|
||||
{
|
||||
g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
|
||||
"%s", g_module_error ());
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello))
|
||||
{
|
||||
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
"%s: %s", filename, g_module_error ());
|
||||
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
if (say_hello == NULL)
|
||||
{
|
||||
g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
"symbol say_hello is NULL");
|
||||
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
|
||||
return FALSE;
|
||||
}
|
||||
|
||||
// call our function in the module
|
||||
say_hello ("Hello world!");
|
||||
|
||||
if (!g_module_close (module))
|
||||
g_warning ("%s: %s", filename, g_module_error ());
|
||||
|
||||
return TRUE;
|
||||
}
|
||||
```
|
9
docs/reference/gmodule/urlmap.js
Normal file
9
docs/reference/gmodule/urlmap.js
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// SPDX-FileCopyrightText: 2023 Matthias Clasen
|
||||
var baseURLs = [
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GModule', 'https://docs.gtk.org/gmodule/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk4/' ],
|
||||
];
|
27587
docs/reference/gobject/GObject-2.0.gir
Normal file
27587
docs/reference/gobject/GObject-2.0.gir
Normal file
File diff suppressed because it is too large
Load Diff
113
docs/reference/gobject/boxed.md
Normal file
113
docs/reference/gobject/boxed.md
Normal file
@ -0,0 +1,113 @@
|
||||
Title: Boxed types
|
||||
|
||||
# Boxed types
|
||||
|
||||
A "boxed type" is a generic wrapper mechanism for arbitrary C structures.
|
||||
The only thing the type system needs to know about the structures is how to
|
||||
copy them (a [`callback@GObject.BoxedCopyFunc`]) and how to free them (a
|
||||
[`callback@GObject.BoxedFreeFunc`])—beyond that they are treated as opaque
|
||||
chunks of memory.
|
||||
|
||||
Boxed types are useful for simple value-holder structures like rectangles or
|
||||
points. They can also be used for wrapping structures defined in non-GObject
|
||||
based libraries. They allow arbitrary structures to be handled in a uniform
|
||||
way, allowing uniform copying (or referencing) and freeing (or
|
||||
unreferencing) of them, and uniform representation of the type of the
|
||||
contained structure. In turn, this allows any type which can be boxed to be
|
||||
set as the data in a `GValue`, which allows for polymorphic handling of a much
|
||||
wider range of data types, and hence usage of such types as `GObject` property
|
||||
values.
|
||||
|
||||
All boxed types inherit from the `G_TYPE_BOXED` fundamental type.
|
||||
|
||||
It is very important to note that boxed types are **not** deeply
|
||||
inheritable: you cannot register a boxed type that inherits from another
|
||||
boxed type. This means you cannot create your own custom, parallel type
|
||||
hierarchy and map it to GType using boxed types. If you want to have deeply
|
||||
inheritable types without using GObject, you will need to use
|
||||
`GTypeInstance`.
|
||||
|
||||
## Registering a new boxed type
|
||||
|
||||
The recommended way to register a new boxed type is to use the
|
||||
[`func@GObject.DEFINE_BOXED_TYPE`] macro:
|
||||
|
||||
```c
|
||||
// In the header
|
||||
|
||||
#define EXAMPLE_TYPE_RECTANGLE (example_rectangle_get_type())
|
||||
|
||||
typedef struct {
|
||||
double x, y;
|
||||
double width, height;
|
||||
} ExampleRectangle;
|
||||
|
||||
GType
|
||||
example_rectangle_get_type (void);
|
||||
|
||||
ExampleRectangle *
|
||||
example_rectangle_copy (ExampleRectangle *r);
|
||||
|
||||
void
|
||||
example_rectangle_free (ExampleRectangle *r);
|
||||
|
||||
// In the source
|
||||
G_DEFINE_BOXED_TYPE (ExampleRectangle, example_rectangle,
|
||||
example_rectangle_copy,
|
||||
example_rectangle_free)
|
||||
```
|
||||
|
||||
Just like `G_DEFINE_TYPE` and `G_DEFINE_INTERFACE_TYPE`, the
|
||||
`G_DEFINE_BOXED_TYPE` macro will provide the definition of the `get_type()`
|
||||
function, which will call [`func@GObject.boxed_type_register_static`] with
|
||||
the given type name as well as the `GBoxedCopyFunc` and `GBoxedFreeFunc`
|
||||
functions.
|
||||
|
||||
## Using boxed types
|
||||
|
||||
### Object properties
|
||||
|
||||
In order to use a boxed type with GObject properties you will need to
|
||||
register the property using [`func@GObject.param_spec_boxed`], e.g.
|
||||
|
||||
```c
|
||||
obj_props[PROP_BOUNDS] =
|
||||
g_param_spec_boxed ("bounds", NULL, NULL,
|
||||
EXAMPLE_TYPE_RECTANGLE,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
```
|
||||
|
||||
In the `set_property` implementation you can use `g_value_get_boxed()` to
|
||||
retrieve a pointer to the boxed type:
|
||||
|
||||
```c
|
||||
switch (prop_id)
|
||||
{
|
||||
// ...
|
||||
case PROP_BOUNDS:
|
||||
example_object_set_bounds (self, g_value_get_boxed (value));
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
Similarly, you can use `g_value_set_boxed()` in the implementation of the
|
||||
`get_property` virtual function:
|
||||
|
||||
```c
|
||||
switch (prop_id)
|
||||
{
|
||||
// ...
|
||||
case PROP_BOUNDS:
|
||||
g_value_set_boxed (self, &self->bounds);
|
||||
break;
|
||||
// ...
|
||||
}
|
||||
```
|
||||
|
||||
## Reference counting
|
||||
|
||||
Boxed types are designed so that reference counted types can be boxed. Use
|
||||
the type’s ‘ref’ function as the `GBoxedCopyFunc`, and its ‘unref’ function as
|
||||
the `GBoxedFreeFunc`. For example, for `GBytes`, the `GBoxedCopyFunc` is
|
||||
`g_bytes_ref()`, and the GBoxedFreeFunc is `g_bytes_unref()`.
|
1846
docs/reference/gobject/concepts.md
Normal file
1846
docs/reference/gobject/concepts.md
Normal file
File diff suppressed because it is too large
Load Diff
36
docs/reference/gobject/enum-types.md
Normal file
36
docs/reference/gobject/enum-types.md
Normal file
@ -0,0 +1,36 @@
|
||||
Title: Enumeration types
|
||||
|
||||
# Enumeration types
|
||||
|
||||
The GLib type system provides fundamental types for enumeration and flags
|
||||
types. Enumerations types are collection of identifiers associated with a
|
||||
numeric value; flags types are like enumerations, but allow their values to
|
||||
be combined by bitwise or.
|
||||
|
||||
A registered enumeration or flags type associates a name and a nickname with
|
||||
each allowed value, and the methods [`func@GObject.enum_get_value_by_name`],
|
||||
[`func@GObject.enum_get_value_by_nick`], [`func@GObject.flags_get_value_by_name`] and
|
||||
[`func@GObject.flags_get_value_by_nick`] can look up values by their name or nickname.
|
||||
|
||||
When an enumeration or flags type is registered with the GLib type system,
|
||||
it can be used as value type for object properties, using
|
||||
[`func@GObject.param_spec_enum`] or [`func@GObject.param_spec_flags`].
|
||||
|
||||
GObject ships with a utility called `glib-mkenums`, that can construct
|
||||
suitable type registration functions from C enumeration definitions.
|
||||
|
||||
Example of how to get a string representation of an enum value:
|
||||
|
||||
```c
|
||||
GEnumClass *enum_class;
|
||||
GEnumValue *enum_value;
|
||||
|
||||
enum_class = g_type_class_ref (EXAMPLE_TYPE_ENUM);
|
||||
enum_value = g_enum_get_value (enum_class, EXAMPLE_ENUM_FOO);
|
||||
|
||||
g_print ("Name: %s\n", enum_value->value_name);
|
||||
|
||||
g_type_class_unref (enum_class);
|
||||
```
|
||||
|
||||
Alternatively, you can use [`func@GObject.enum_to_string`].
|
128
docs/reference/gobject/floating-refs.md
Normal file
128
docs/reference/gobject/floating-refs.md
Normal file
@ -0,0 +1,128 @@
|
||||
Title: Floating references
|
||||
|
||||
# Floating references
|
||||
|
||||
**Note**: Floating references are a C convenience API and should not be used
|
||||
in modern GObject code. Language bindings in particular find the concept
|
||||
highly problematic, as floating references are not identifiable through
|
||||
annotations, and neither are deviations from the floating reference
|
||||
behavior, like types that inherit from [class@GObject.InitiallyUnowned] and
|
||||
still return a full reference from [`id@g_object_new`].
|
||||
|
||||
[class@GObject.InitiallyUnowned] is derived from [class@GObject.Object]. The
|
||||
only difference between the two is that the initial reference of a
|
||||
`GInitiallyUnowned` is flagged as a "floating" reference. This means that it
|
||||
is not specifically claimed to be "owned" by any code portion. The main
|
||||
motivation for providing floating references is C convenience. In
|
||||
particular, it allows code to be written as:
|
||||
|
||||
```c
|
||||
container = create_container ();
|
||||
container_add_child (container, create_child());
|
||||
```
|
||||
|
||||
If `container_add_child()` calls [`method@GObject.Object.ref_sink`] on the
|
||||
passed-in child, no reference of the newly created child is leaked. Without
|
||||
floating references, `container_add_child()` can only acquire a reference
|
||||
the new child, so to implement this code without reference leaks, it would
|
||||
have to be written as:
|
||||
|
||||
```c
|
||||
Child *child;
|
||||
container = create_container ();
|
||||
child = create_child ();
|
||||
container_add_child (container, child);
|
||||
g_object_unref (child);
|
||||
```
|
||||
|
||||
The floating reference can be converted into an ordinary reference by
|
||||
calling `g_object_ref_sink()`. For already sunken objects (objects that
|
||||
don't have a floating reference anymore), `g_object_ref_sink()` is
|
||||
equivalent to [`method@GObject.Object.ref`] and returns a new reference.
|
||||
|
||||
Since floating references are useful almost exclusively for C convenience,
|
||||
language bindings that provide automated reference and memory ownership
|
||||
maintenance (such as smart pointers or garbage collection) should not expose
|
||||
floating references in their API. The best practice for handling types that
|
||||
have initially floating references is to immediately sink those references
|
||||
after `g_object_new()` returns, by checking if the `GType` inherits from
|
||||
`GInitiallyUnowned`. For instance:
|
||||
|
||||
```c
|
||||
GObject *res = g_object_new_with_properties (gtype,
|
||||
n_props,
|
||||
prop_names,
|
||||
prop_values);
|
||||
|
||||
// or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED))
|
||||
if (G_IS_INITIALLY_UNOWNED (res))
|
||||
g_object_ref_sink (res);
|
||||
|
||||
return res;
|
||||
```
|
||||
|
||||
Some object implementations may need to save an object's floating state
|
||||
across certain code portions (an example is `GtkMenu` in GTK3), to achieve
|
||||
this, the following sequence can be used:
|
||||
|
||||
```c
|
||||
// save floating state
|
||||
gboolean was_floating = g_object_is_floating (object);
|
||||
g_object_ref_sink (object);
|
||||
// protected code portion
|
||||
|
||||
...
|
||||
|
||||
// restore floating state
|
||||
if (was_floating)
|
||||
g_object_force_floating (object);
|
||||
else
|
||||
g_object_unref (object); // release previously acquired reference
|
||||
```
|
||||
|
||||
## Replacing floating references with annotations
|
||||
|
||||
You should avoid basing your object hierarchy on floating references, as
|
||||
they are hard to understand even in C, and introduce additional limitations
|
||||
when consuming a GObject-based API in other languages.
|
||||
|
||||
One way to express the ownership transfer between ‘container’ and ‘child’
|
||||
instances is to use ownership transfer annotations in your documentation and
|
||||
introspection data. For instance, you can implement this pattern:
|
||||
|
||||
```c
|
||||
container_add_child (container, create_child ());
|
||||
```
|
||||
|
||||
without leaking by having `container_add_child()` defined as:
|
||||
|
||||
```c
|
||||
/**
|
||||
* container_add_child:
|
||||
* @self: a container
|
||||
* @child: (transfer full): the child to add to the container
|
||||
*
|
||||
* ...
|
||||
*/
|
||||
void
|
||||
container_add_child (Container *container,
|
||||
Child *child)
|
||||
{
|
||||
container->children = g_list_append (container->children, child);
|
||||
}
|
||||
```
|
||||
|
||||
The container does not explicitly acquire a reference on the child; instead,
|
||||
the ownership of the child is transferred to the container. The transfer
|
||||
annotation will be used by language bindings to ensure that there are no
|
||||
leaks; and documentation tools will explicitly note that the callee now owns
|
||||
the value passed by the caller.
|
||||
|
||||
## Replacing floating references with weak references
|
||||
|
||||
Another option for replacing floating references is to use weak references
|
||||
in place of strong ones. A ‘container’ can acquire a weak reference on the
|
||||
‘child’ instance by using [`method@GObject.Object.weak_ref`]. Once the
|
||||
child instance loses its last strong reference, the container holding a
|
||||
weak reference is notified, and it can either remove the child from its
|
||||
internal list, or turn a weak reference into a strong one.
|
@ -15,58 +15,6 @@
|
||||
</releaseinfo>
|
||||
</bookinfo>
|
||||
|
||||
<preface>
|
||||
<title>Introduction</title>
|
||||
<para>
|
||||
Most modern programming languages come with their own native object
|
||||
systems and additional fundamental algorithmic language constructs.
|
||||
Just as GLib serves as an implementation of such fundamental
|
||||
types and algorithms (linked lists, hash tables and so forth), the
|
||||
GLib Object System provides the required implementations of a
|
||||
flexible, extensible, and intentionally easy to map (into other
|
||||
languages) object-oriented framework for C.
|
||||
The substantial elements that are provided can be summarized as:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
A generic type system to register arbitrary single-inherited
|
||||
flat and deep derived types as well as interfaces for
|
||||
structured types.
|
||||
It takes care of creation, initialization and memory management
|
||||
of the assorted object and class structures, maintains
|
||||
parent/child relationships and deals with dynamic implementations
|
||||
of such types. That is, their type specific implementations are
|
||||
relocatable/unloadable during runtime.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
A collection of fundamental type implementations, such as integers,
|
||||
doubles, enums and structured types, to name a few.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
A sample fundamental type implementation to base object hierarchies
|
||||
upon - the GObject fundamental type.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
A signal system that allows very flexible user customization of
|
||||
virtual/overridable object methods and can serve as a powerful
|
||||
notification mechanism.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
An extensible parameter/value system, supporting all the provided
|
||||
fundamental types that can be used to generically handle object
|
||||
properties or otherwise parameterized types.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
</preface>
|
||||
|
||||
<part label="I">
|
||||
<title>Concepts</title>
|
||||
|
||||
<xi:include href="tut_intro.xml" />
|
||||
<xi:include href="tut_gtype.xml" />
|
||||
<xi:include href="tut_gobject.xml" />
|
||||
<xi:include href="tut_gsignal.xml" />
|
||||
</part>
|
||||
<reference label="II">
|
||||
<title>API Reference</title>
|
||||
|
||||
@ -95,7 +43,6 @@
|
||||
<xi:include href="gobject-query.xml" />
|
||||
</reference>
|
||||
|
||||
<xi:include href="tut_howto.xml" />
|
||||
<xi:include href="tut_tools.xml" />
|
||||
|
||||
<chapter id="api-index-full">
|
||||
|
61
docs/reference/gobject/gobject.toml.in
Normal file
61
docs/reference/gobject/gobject.toml.in
Normal file
@ -0,0 +1,61 @@
|
||||
# SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
# Copyright 2023 Matthias Clasen
|
||||
# Copyright 2023 Philip Withnall
|
||||
|
||||
[library]
|
||||
name = "GObject"
|
||||
version = "@VERSION@"
|
||||
browse_url = "https://gitlab.gnome.org/GNOME/glib/"
|
||||
repository_url = "https://gitlab.gnome.org/GNOME/glib.git"
|
||||
website_url = "https://www.gtk.org"
|
||||
docs_url = "https://docs.gtk.org/gobject/"
|
||||
authors = "GLib Development Team"
|
||||
license = "LGPL-2.1-or-later"
|
||||
description = "The base type system and object class"
|
||||
devhelp = true
|
||||
search_index = true
|
||||
dependencies = ["GLib-2.0"]
|
||||
|
||||
[dependencies."GLib-2.0"]
|
||||
name = "GLib"
|
||||
description = "The base utility library"
|
||||
docs_url = "https://docs.gtk.org/glib/"
|
||||
|
||||
related = ["GModule-2.0", "Gio-2.0"]
|
||||
|
||||
[related."GModule-2.0"]
|
||||
name = "GModule"
|
||||
description = "Portable API for dynamically loading modules"
|
||||
docs_url = "https://docs.gtk.org/gmodule/"
|
||||
|
||||
[related."Gio-2.0"]
|
||||
name = "GIO"
|
||||
description = "GObject Interfaces and Objects, Networking, IPC, and I/O"
|
||||
docs_url = "https://docs.gtk.org/gio/"
|
||||
|
||||
[theme]
|
||||
name = "basic"
|
||||
show_index_summary = true
|
||||
show_class_hierarchy = true
|
||||
|
||||
[extra]
|
||||
urlmap_file = "urlmap.js"
|
||||
# The same order will be used when generating the index
|
||||
content_files = [
|
||||
"concepts.md",
|
||||
"tutorial.md",
|
||||
"floating-refs.md",
|
||||
"boxed.md",
|
||||
"enum-types.md",
|
||||
"gvalue.md",
|
||||
]
|
||||
content_images = [
|
||||
"images/glue.png",
|
||||
]
|
||||
|
||||
# This is the anonymous union inside GValue; we don't need it
|
||||
# as a type, and including it just generates a dummy union
|
||||
# definition
|
||||
[[object]]
|
||||
name = "_Value__data__union"
|
||||
hidden = true
|
108
docs/reference/gobject/gvalue.md
Normal file
108
docs/reference/gobject/gvalue.md
Normal file
@ -0,0 +1,108 @@
|
||||
Title: Generic value container
|
||||
|
||||
# Generic value container
|
||||
|
||||
The [`struct@GObject.Value`] structure is basically a variable container
|
||||
that consists of a type identifier and a specific value of that type. The
|
||||
type identifier within a `GValue` structure always determines the type of the
|
||||
associated value.
|
||||
|
||||
To create an undefined `GValue` structure, simply create a zero-filled
|
||||
GValue structure. To initialize the `GValue`, use the
|
||||
[`method@GObject.Value.init`] function. A `GValue` cannot be used until it
|
||||
is initialized.
|
||||
|
||||
Once you have finished using a `GValue`, you must call
|
||||
[`method@GObject.Value.unset`] to ensure that all the resources associated
|
||||
with the `GValue` are freed.
|
||||
|
||||
The basic type operations (such as freeing and copying) are determined by
|
||||
the [`struct@GObject.TypeValueTable`] associated with the type ID stored in
|
||||
the `GValue`. Other `GValue` operations (such as converting values between
|
||||
types) are provided by this interface.
|
||||
|
||||
The code in the example program below demonstrates `GValue`'s features:
|
||||
|
||||
```c
|
||||
#include <glib-object.h>
|
||||
|
||||
static void
|
||||
int2string (const GValue *src_value,
|
||||
GValue *dest_value)
|
||||
{
|
||||
if (g_value_get_int (src_value) == 42)
|
||||
g_value_set_static_string (dest_value, "An important number");
|
||||
else
|
||||
g_value_set_static_string (dest_value, "What's that?");
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
// GValues must be initialized
|
||||
GValue a = G_VALUE_INIT;
|
||||
GValue b = G_VALUE_INIT;
|
||||
const char *message;
|
||||
|
||||
// The GValue starts empty
|
||||
g_assert (!G_VALUE_HOLDS_STRING (&a));
|
||||
|
||||
// Put a string in it
|
||||
g_value_init (&a, G_TYPE_STRING);
|
||||
g_assert (G_VALUE_HOLDS_STRING (&a));
|
||||
g_value_set_static_string (&a, "Hello, world!");
|
||||
g_printf ("%s\n", g_value_get_string (&a));
|
||||
|
||||
// Reset it to its pristine state
|
||||
g_value_unset (&a);
|
||||
|
||||
// It can then be reused for another type
|
||||
g_value_init (&a, G_TYPE_INT);
|
||||
g_value_set_int (&a, 42);
|
||||
|
||||
// Attempt to transform it into a GValue of type STRING
|
||||
g_value_init (&b, G_TYPE_STRING);
|
||||
|
||||
// An INT is transformable to a STRING
|
||||
g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING));
|
||||
|
||||
g_value_transform (&a, &b);
|
||||
g_printf ("%s\n", g_value_get_string (&b));
|
||||
|
||||
// Attempt to transform it again using a custom transform function
|
||||
g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string);
|
||||
g_value_transform (&a, &b);
|
||||
g_printf ("%s\n", g_value_get_string (&b));
|
||||
|
||||
g_value_unset (&b);
|
||||
g_value_unset (&a);
|
||||
|
||||
return 0;
|
||||
}
|
||||
```
|
||||
|
||||
For letting a `GValue` own (and memory manage) arbitrary types or pointers,
|
||||
they need to become a [boxed type](boxed.html). The example below shows how
|
||||
the pointer `mystruct` of type `MyStruct` is used as a [boxed type](boxed.html).
|
||||
|
||||
```c
|
||||
typedef struct { ... } MyStruct;
|
||||
G_DEFINE_BOXED_TYPE (MyStruct, my_struct, my_struct_copy, my_struct_free)
|
||||
|
||||
// These two lines normally go in a public header. By GObject convention,
|
||||
// the naming scheme is NAMESPACE_TYPE_NAME:
|
||||
#define MY_TYPE_STRUCT (my_struct_get_type ())
|
||||
GType my_struct_get_type (void);
|
||||
|
||||
void
|
||||
foo (void)
|
||||
{
|
||||
GValue *value = g_new0 (GValue, 1);
|
||||
g_value_init (value, MY_TYPE_STRUCT);
|
||||
g_value_set_boxed (value, mystruct);
|
||||
// [... your code ....]
|
||||
g_value_unset (value);
|
||||
g_free (value);
|
||||
}
|
||||
```
|
@ -38,11 +38,6 @@ if get_option('gtk_doc')
|
||||
'glib-mkenums.xml',
|
||||
'glib-genmarshal.xml',
|
||||
'gobject-query.xml',
|
||||
'tut_gobject.xml',
|
||||
'tut_gsignal.xml',
|
||||
'tut_gtype.xml',
|
||||
'tut_howto.xml',
|
||||
'tut_intro.xml',
|
||||
'tut_tools.xml'
|
||||
],
|
||||
html_assets : [
|
||||
@ -53,7 +48,7 @@ if get_option('gtk_doc')
|
||||
'--extra-dir=' + join_paths('gobject', '..', 'glib', 'html'),
|
||||
],
|
||||
install: true,
|
||||
check: true,
|
||||
check: false,
|
||||
)
|
||||
endif
|
||||
|
||||
@ -68,3 +63,33 @@ if get_option('man')
|
||||
install_dir: man1_dir)
|
||||
endforeach
|
||||
endif
|
||||
|
||||
# gi-docgen version
|
||||
expand_content_files = [
|
||||
'boxed.md',
|
||||
'concepts.md',
|
||||
'enum-types.md',
|
||||
'floating-refs.md',
|
||||
'gvalue.md',
|
||||
'tutorial.md',
|
||||
]
|
||||
|
||||
gobject_gir = meson.current_source_dir() / 'GObject-2.0.gir'
|
||||
gobject_toml = configure_file(input: 'gobject.toml.in', output: 'gobject.toml', configuration: toml_conf)
|
||||
|
||||
custom_target('gobject-docs',
|
||||
input: [ gobject_toml, gobject_gir ],
|
||||
output: 'gobject',
|
||||
command: [
|
||||
gidocgen,
|
||||
'generate',
|
||||
gidocgen_common_args,
|
||||
'--config=@INPUT0@',
|
||||
'--output-dir=@OUTPUT@',
|
||||
'--content-dir=@0@'.format(meson.current_source_dir()),
|
||||
'--add-include-path=@0@'.format(meson.current_source_dir() / '../glib'),
|
||||
'@INPUT1@',
|
||||
],
|
||||
build_by_default: true,
|
||||
depend_files: expand_content_files,
|
||||
)
|
||||
|
@ -1,728 +0,0 @@
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="chapter-gobject">
|
||||
<title>The GObject base class</title>
|
||||
|
||||
<para>
|
||||
The previous chapter discussed the details of GLib's Dynamic Type System.
|
||||
The GObject library also contains an implementation for a base fundamental
|
||||
type named <link linkend="GObject"><type>GObject</type></link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<link linkend="GObject"><type>GObject</type></link> is a fundamental classed instantiatable type. It implements:
|
||||
<itemizedlist>
|
||||
<listitem><para>Memory management with reference counting</para></listitem>
|
||||
<listitem><para>Construction/Destruction of instances</para></listitem>
|
||||
<listitem><para>Generic per-object properties with set/get function pairs</para></listitem>
|
||||
<listitem><para>Easy use of signals</para></listitem>
|
||||
</itemizedlist>
|
||||
All the GNOME libraries which use the GLib type system (like GTK and GStreamer)
|
||||
inherit from <link linkend="GObject"><type>GObject</type></link> which is why it is important to understand
|
||||
the details of how it works.
|
||||
</para>
|
||||
|
||||
<sect1 id="gobject-instantiation">
|
||||
<title>Object instantiation</title>
|
||||
|
||||
<para>
|
||||
The <function><link linkend="g-object-new">g_object_new</link></function>
|
||||
family of functions can be used to instantiate any GType which inherits
|
||||
from the GObject base type. All these functions make sure the class and
|
||||
instance structures have been correctly initialized by GLib's type system
|
||||
and then invoke at one point or another the constructor class method
|
||||
which is used to:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Allocate and clear memory through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>,
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
Initialize the object's instance with the construction properties.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
Although one can expect all class and instance members (except the fields
|
||||
pointing to the parents) to be set to zero, some consider it good practice
|
||||
to explicitly set them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once all construction operations have been completed and constructor
|
||||
properties set, the constructed class method is called.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Objects which inherit from GObject are allowed to override this
|
||||
constructed class method.
|
||||
The example below shows how <type>ViewerFile</type> overrides the parent's construction process:
|
||||
<informalexample><programlisting>
|
||||
#define VIEWER_TYPE_FILE viewer_file_get_type ()
|
||||
G_DECLARE_FINAL_TYPE (ViewerFile, viewer_file, VIEWER, FILE, GObject)
|
||||
|
||||
struct _ViewerFile
|
||||
{
|
||||
GObject parent_instance;
|
||||
|
||||
/* instance members */
|
||||
gchar *filename;
|
||||
guint zoom_level;
|
||||
};
|
||||
|
||||
/* will create viewer_file_get_type and set viewer_file_parent_class */
|
||||
G_DEFINE_TYPE (ViewerFile, viewer_file, G_TYPE_OBJECT)
|
||||
|
||||
static void
|
||||
viewer_file_constructed (GObject *obj)
|
||||
{
|
||||
/* update the object state depending on constructor properties */
|
||||
|
||||
/* Always chain up to the parent constructed function to complete object
|
||||
* initialisation. */
|
||||
G_OBJECT_CLASS (viewer_file_parent_class)->constructed (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
viewer_file_finalize (GObject *obj)
|
||||
{
|
||||
ViewerFile *self = VIEWER_FILE (obj);
|
||||
|
||||
g_free (self->filename);
|
||||
|
||||
/* Always chain up to the parent finalize function to complete object
|
||||
* destruction. */
|
||||
G_OBJECT_CLASS (viewer_file_parent_class)->finalize (obj);
|
||||
}
|
||||
|
||||
static void
|
||||
viewer_file_class_init (ViewerFileClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->constructed = viewer_file_constructed;
|
||||
object_class->finalize = viewer_file_finalize;
|
||||
}
|
||||
|
||||
static void
|
||||
viewer_file_init (ViewerFile *self)
|
||||
{
|
||||
/* initialize the object */
|
||||
}
|
||||
|
||||
</programlisting></informalexample>
|
||||
If the user instantiates an object <type>ViewerFile</type> with:
|
||||
<informalexample><programlisting>
|
||||
ViewerFile *file = g_object_new (VIEWER_TYPE_FILE, NULL);
|
||||
</programlisting></informalexample>
|
||||
If this is the first instantiation of such an object, the
|
||||
<function>viewer_file_class_init</function> function will be invoked
|
||||
after any <function>viewer_file_base_class_init</function> function.
|
||||
This will make sure the class structure of this new object is
|
||||
correctly initialized. Here, <function>viewer_file_class_init</function>
|
||||
is expected to override the object's class methods and setup the
|
||||
class' own methods. In the example above, the <literal>constructed</literal>
|
||||
method is the only overridden method: it is set to
|
||||
<function>viewer_file_constructed</function>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once <function><link linkend="g-object-new">g_object_new</link></function> has obtained a reference to an initialized
|
||||
class structure, it invokes its constructor method to create an instance of the new
|
||||
object, if the constructor has been overridden in <function>viewer_file_class_init</function>.
|
||||
Overridden constructors must chain up to their parent’s constructor. In
|
||||
order to find the parent class and chain up to the parent class
|
||||
constructor, we can use the <literal>viewer_file_parent_class</literal>
|
||||
pointer that has been set up for us by the
|
||||
<link linkend="G-DEFINE-TYPE:CAPS"><literal>G_DEFINE_TYPE</literal></link>
|
||||
macro.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Finally, at one point or another, <function>g_object_constructor</function> is invoked
|
||||
by the last constructor in the chain. This function allocates the object's instance buffer
|
||||
through <function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
which means that the <function>instance_init</function> function is invoked at this point if one
|
||||
was registered. After <function>instance_init</function> returns, the object is fully initialized and should be
|
||||
ready to have its methods called by the user. When
|
||||
<function><link linkend="g-type-create-instance">g_type_create_instance</link></function>
|
||||
returns, <function>g_object_constructor</function> sets the construction properties
|
||||
(i.e. the properties which were given to <function><link linkend="g-object-new">g_object_new</link></function>) and returns
|
||||
to the user's constructor.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process described above might seem a bit complicated, but it can be
|
||||
summarized easily by the table below which lists the functions invoked
|
||||
by <function><link linkend="g-object-new">g_object_new</link></function>
|
||||
and their order of invocation:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<table id="gobject-construction-table">
|
||||
<title><function><link linkend="g-object-new">g_object_new</link></function></title>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="*" colnum="1" align="left"/>
|
||||
<colspec colwidth="*" colnum="2" align="left"/>
|
||||
<colspec colwidth="8*" colnum="3" align="left"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Invocation time</entry>
|
||||
<entry>Function invoked</entry>
|
||||
<entry>Function's parameters</entry>
|
||||
<entry>Remark</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry morerows="3">First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
||||
<entry>target type's <function>base_init</function> function</entry>
|
||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||
<function>base_init</function> is invoked once for each class structure.</entry>
|
||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||
<entry>target type's <function>class_init</function> function</entry>
|
||||
<entry>On target type's class structure</entry>
|
||||
<entry>
|
||||
Here, you should make sure to initialize or override class methods (that is,
|
||||
assign to each class' method its function pointer) and create the signals and
|
||||
the properties associated to your object.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||
<entry>interface's <function>base_init</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry></entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>First call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||
<entry>interface's <function>interface_init</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry></entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry morerows="2">Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry>
|
||||
<entry>target type's class <function>constructor</function> method: <function>GObjectClass->constructor</function></entry>
|
||||
<entry>On object's instance</entry>
|
||||
<entry>
|
||||
If you need to handle construct properties in a custom way, or implement a singleton class, override the constructor
|
||||
method and make sure to chain up to the object's
|
||||
parent class before doing your own initialization.
|
||||
In doubt, do not override the constructor method.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||
<entry>type's <function>instance_init</function> function</entry>
|
||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||
the <function>instance_init</function> provided for each type is invoked once for each instance
|
||||
structure.</entry>
|
||||
<entry>
|
||||
Provide an <function>instance_init</function> function to initialize your object before its construction
|
||||
properties are set. This is the preferred way to initialize a GObject instance.
|
||||
This function is equivalent to C++ constructors.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Each call to <function><link linkend="g-object-new">g_object_new</link></function> for target type</entry-->
|
||||
<entry>target type's class <function>constructed</function> method: <function>GObjectClass->constructed</function></entry>
|
||||
<entry>On object's instance</entry>
|
||||
<entry>
|
||||
If you need to perform object initialization steps after all construct properties have been set.
|
||||
This is the final step in the object initialization process, and is only called if the <function>constructor</function>
|
||||
method returned a new object instance (rather than, for example, an existing singleton).
|
||||
</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Readers should feel concerned about one little twist in the order in
|
||||
which functions are invoked: while, technically, the class' constructor
|
||||
method is called <emphasis>before</emphasis> the GType's <function>instance_init</function>
|
||||
function (since <function><link linkend="g-type-create-instance">g_type_create_instance</link></function> which calls <function>instance_init</function> is called by
|
||||
<function>g_object_constructor</function> which is the top-level class
|
||||
constructor method and to which users are expected to chain to), the
|
||||
user's code which runs in a user-provided constructor will always
|
||||
run <emphasis>after</emphasis> GType's <function>instance_init</function> function since the
|
||||
user-provided constructor <emphasis>must</emphasis> (you've been warned)
|
||||
chain up <emphasis>before</emphasis> doing anything useful.
|
||||
</para>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="gobject-memory">
|
||||
<title>Object memory management</title>
|
||||
|
||||
<para>
|
||||
The memory-management API for GObjects is a bit complicated but the idea behind it
|
||||
is pretty simple: the goal is to provide a flexible model based on reference counting
|
||||
which can be integrated in applications which use or require different memory management
|
||||
models (such as garbage collection). The methods which are used to
|
||||
manipulate this reference count are described below.
|
||||
</para>
|
||||
|
||||
<sect2 id="gobject-memory-refcount">
|
||||
<title>Reference count</title>
|
||||
|
||||
<para>
|
||||
The functions <function><link linkend="g-object-ref">g_object_ref</link></function>/<function><link linkend="g-object-unref">g_object_unref</link></function> respectively
|
||||
increase and decrease the reference count. These functions are
|
||||
thread-safe.
|
||||
<function><link linkend="g-clear-object">g_clear_object</link></function>
|
||||
is a convenience wrapper around <function>g_object_unref</function>
|
||||
which also clears the pointer passed to it.
|
||||
</para>
|
||||
<para>
|
||||
The reference count is initialized to one by
|
||||
<function><link linkend="g-object-new">g_object_new</link></function> which means that the caller
|
||||
is currently the sole owner of the newly-created reference. (If the object is derived from <link linkend="GInitiallyUnowned"><type>GInitiallyUnowned</type></link>, this reference count is <link linkend="floating-ref">floating</link>.)
|
||||
When the reference count reaches zero, that is,
|
||||
when <function><link linkend="g-object-unref">g_object_unref</link></function> is called by the last client holding
|
||||
a reference to the object, the <emphasis>dispose</emphasis> and the
|
||||
<emphasis>finalize</emphasis> class methods are invoked.
|
||||
</para>
|
||||
<para>
|
||||
Finally, after <emphasis>finalize</emphasis> is invoked,
|
||||
<function><link linkend="g-type-free-instance">g_type_free_instance</link></function> is called to free the object instance.
|
||||
Depending on the memory allocation policy decided when the type was registered (through
|
||||
one of the <function>g_type_register_*</function> functions), the object's instance
|
||||
memory will be freed or returned to the object pool for this type.
|
||||
Once the object has been freed, if it was the last instance of the type, the type's class
|
||||
will be destroyed as described in <xref linkend="gtype-instantiatable-classed"/> and
|
||||
<xref linkend="gtype-non-instantiatable-non-classed"/>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The table below summarizes the destruction process of a GObject:
|
||||
<table id="gobject-destruction-table">
|
||||
<title><function><link linkend="g-object-unref">g_object_unref</link></function></title>
|
||||
<tgroup cols="3">
|
||||
<colspec colwidth="*" colnum="1" align="left"/>
|
||||
<colspec colwidth="*" colnum="2" align="left"/>
|
||||
<colspec colwidth="8*" colnum="3" align="left"/>
|
||||
|
||||
<thead>
|
||||
<row>
|
||||
<entry>Invocation time</entry>
|
||||
<entry>Function invoked</entry>
|
||||
<entry>Function's parameters</entry>
|
||||
<entry>Remark</entry>
|
||||
</row>
|
||||
</thead>
|
||||
<tbody>
|
||||
<row>
|
||||
<entry morerows="1">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
||||
of target type
|
||||
</entry>
|
||||
<entry>target type's dispose class function</entry>
|
||||
<entry>GObject instance</entry>
|
||||
<entry>
|
||||
When dispose ends, the object should not hold any reference to any other
|
||||
member object. The object is also expected to be able to answer client
|
||||
method invocations (with possibly an error code but no memory violation)
|
||||
until finalize is executed. dispose can be executed more than once.
|
||||
dispose should chain up to its parent implementation just before returning
|
||||
to the caller.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for an instance
|
||||
of target type
|
||||
</entry-->
|
||||
<entry>target type's finalize class function</entry>
|
||||
<entry>GObject instance</entry>
|
||||
<entry>
|
||||
Finalize is expected to complete the destruction process initiated by
|
||||
dispose. It should complete the object's destruction. finalize will be
|
||||
executed only once.
|
||||
finalize should chain up to its parent implementation just before returning
|
||||
to the caller.
|
||||
The reason why the destruction process is split is two different phases is
|
||||
explained in <xref linkend="gobject-memory-cycles"/>.
|
||||
</entry>
|
||||
</row>
|
||||
<row>
|
||||
<entry morerows="3">Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||
instance of target type
|
||||
</entry>
|
||||
<entry>interface's <function>interface_finalize</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function>for the last
|
||||
instance of target type
|
||||
</entry-->
|
||||
<entry>interface's <function>base_finalize</function> function</entry>
|
||||
<entry>On interface's vtable</entry>
|
||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||
instance of target type
|
||||
</entry-->
|
||||
<entry>target type's <function>class_finalize</function> function</entry>
|
||||
<entry>On target type's class structure</entry>
|
||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||
</row>
|
||||
<row>
|
||||
<!--entry>Last call to <function><link linkend="g-object-unref">g_object_unref</link></function> for the last
|
||||
instance of target type
|
||||
</entry-->
|
||||
<entry>type's <function>base_finalize</function> function</entry>
|
||||
<entry>On the inheritance tree of classes from fundamental type to target type.
|
||||
<function>base_init</function> is invoked once for each class structure.</entry>
|
||||
<entry>Never used in practice. Unlikely you will need it.</entry>
|
||||
</row>
|
||||
</tbody>
|
||||
</tgroup>
|
||||
</table>
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="gobject-memory-weakref">
|
||||
<title>Weak References</title>
|
||||
|
||||
<para>
|
||||
Weak references are used to monitor object finalization:
|
||||
<function><link linkend="g-object-weak-ref">g_object_weak_ref</link></function> adds a monitoring callback which does
|
||||
not hold a reference to the object but which is invoked when the object runs
|
||||
its dispose method. As such, each weak ref can be invoked more than once upon
|
||||
object finalization (since dispose can run more than once during object
|
||||
finalization).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function><link linkend="g-object-weak-unref">g_object_weak_unref</link></function> can be used to remove a monitoring
|
||||
callback from the object.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Weak references are also used to implement <function><link linkend="g-object-add-weak-pointer">g_object_add_weak_pointer</link></function>
|
||||
and <function><link linkend="g-object-remove-weak-pointer">g_object_remove_weak_pointer</link></function>. These functions add a weak reference
|
||||
to the object they are applied to which makes sure to nullify the pointer given by the user
|
||||
when object is finalized.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Similarly, <link linkend="GWeakRef"><type>GWeakRef</type></link> can be
|
||||
used to implement weak references if thread safety is required.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2 id="gobject-memory-cycles">
|
||||
<title>Reference counts and cycles</title>
|
||||
|
||||
<para>
|
||||
GObject's memory management model was designed to be easily integrated in existing code
|
||||
using garbage collection. This is why the destruction process is split in two phases:
|
||||
the first phase, executed in the dispose handler is supposed to release all references
|
||||
to other member objects. The second phase, executed by the finalize handler is supposed
|
||||
to complete the object's destruction process. Object methods should be able to run
|
||||
without program error in-between the two phases.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This two-step destruction process is very useful to break reference counting cycles.
|
||||
While the detection of the cycles is up to the external code, once the cycles have been
|
||||
detected, the external code can invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> which
|
||||
will indeed break any existing cycles since it will run the dispose handler associated
|
||||
to the object and thus release all references to other objects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This explains one of the rules about the dispose handler stated earlier:
|
||||
the dispose handler can be invoked multiple times. Let's say we
|
||||
have a reference count cycle: object A references B which itself references object A.
|
||||
Let's say we have detected the cycle and we want to destroy the two objects. One way to
|
||||
do this would be to invoke <function><link linkend="g-object-run-dispose">g_object_run_dispose</link></function> on one of the
|
||||
objects.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If object A releases all its references to all objects, this means it releases its
|
||||
reference to object B. If object B was not owned by anyone else, this is its last
|
||||
reference count which means this last unref runs B's dispose handler which, in turn,
|
||||
releases B's reference on object A. If this is A's last reference count, this last
|
||||
unref runs A's dispose handler which is running for the second time before
|
||||
A's finalize handler is invoked !
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The above example, which might seem a bit contrived, can really happen if
|
||||
GObjects are being handled by language bindings — hence the rules for
|
||||
object destruction should be closely followed.
|
||||
</para>
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="gobject-properties">
|
||||
<title>Object properties</title>
|
||||
|
||||
<para>
|
||||
One of GObject's nice features is its generic get/set mechanism for object
|
||||
properties. When an object
|
||||
is instantiated, the object's <function>class_init</function> handler should be used to register
|
||||
the object's properties with <function><link linkend="g-object-class-install-properties">g_object_class_install_properties</link></function>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The best way to understand how object properties work is by looking at a real example
|
||||
of how it is used:
|
||||
<informalexample><programlisting>
|
||||
/************************************************/
|
||||
/* Implementation */
|
||||
/************************************************/
|
||||
|
||||
typedef enum
|
||||
{
|
||||
PROP_FILENAME = 1,
|
||||
PROP_ZOOM_LEVEL,
|
||||
N_PROPERTIES
|
||||
} ViewerFileProperty;
|
||||
|
||||
static GParamSpec *obj_properties[N_PROPERTIES] = { NULL, };
|
||||
|
||||
static void
|
||||
viewer_file_set_property (GObject *object,
|
||||
guint property_id,
|
||||
const GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ViewerFile *self = VIEWER_FILE (object);
|
||||
|
||||
switch ((ViewerFileProperty) property_id)
|
||||
{
|
||||
case PROP_FILENAME:
|
||||
g_free (self->filename);
|
||||
self->filename = g_value_dup_string (value);
|
||||
g_print ("filename: %s\n", self->filename);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_LEVEL:
|
||||
self->zoom_level = g_value_get_uint (value);
|
||||
g_print ("zoom level: %u\n", self->zoom_level);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* We don't have any other property... */
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
viewer_file_get_property (GObject *object,
|
||||
guint property_id,
|
||||
GValue *value,
|
||||
GParamSpec *pspec)
|
||||
{
|
||||
ViewerFile *self = VIEWER_FILE (object);
|
||||
|
||||
switch ((ViewerFileProperty) property_id)
|
||||
{
|
||||
case PROP_FILENAME:
|
||||
g_value_set_string (value, self->filename);
|
||||
break;
|
||||
|
||||
case PROP_ZOOM_LEVEL:
|
||||
g_value_set_uint (value, self->zoom_level);
|
||||
break;
|
||||
|
||||
default:
|
||||
/* We don't have any other property... */
|
||||
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, property_id, pspec);
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
viewer_file_class_init (ViewerFileClass *klass)
|
||||
{
|
||||
GObjectClass *object_class = G_OBJECT_CLASS (klass);
|
||||
|
||||
object_class->set_property = viewer_file_set_property;
|
||||
object_class->get_property = viewer_file_get_property;
|
||||
|
||||
obj_properties[PROP_FILENAME] =
|
||||
g_param_spec_string ("filename",
|
||||
"Filename",
|
||||
"Name of the file to load and display from.",
|
||||
NULL /* default value */,
|
||||
G_PARAM_CONSTRUCT_ONLY | G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
obj_properties[PROP_ZOOM_LEVEL] =
|
||||
g_param_spec_uint ("zoom-level",
|
||||
"Zoom level",
|
||||
"Zoom level to view the file at.",
|
||||
0 /* minimum value */,
|
||||
10 /* maximum value */,
|
||||
2 /* default value */,
|
||||
G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS);
|
||||
|
||||
g_object_class_install_properties (object_class,
|
||||
N_PROPERTIES,
|
||||
obj_properties);
|
||||
}
|
||||
|
||||
/************************************************/
|
||||
/* Use */
|
||||
/************************************************/
|
||||
|
||||
ViewerFile *file;
|
||||
GValue val = G_VALUE_INIT;
|
||||
|
||||
file = g_object_new (VIEWER_TYPE_FILE, NULL);
|
||||
|
||||
g_value_init (&val, G_TYPE_UINT);
|
||||
g_value_set_char (&val, 11);
|
||||
|
||||
g_object_set_property (G_OBJECT (file), "zoom-level", &val);
|
||||
|
||||
g_value_unset (&val);
|
||||
</programlisting></informalexample>
|
||||
The client code above looks simple but a lot of things happen under the hood:
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function><link linkend="g-object-set-property">g_object_set_property</link></function> first ensures a property
|
||||
with this name was registered in <emphasis>file</emphasis>'s <function>class_init</function> handler. If so it walks the class hierarchy,
|
||||
from bottom-most most-derived type, to top-most fundamental type to find the class
|
||||
which registered that property. It then tries to convert the user-provided
|
||||
<link linkend="GValue"><type>GValue</type></link>
|
||||
into a <type>GValue</type> whose type is that of the associated property.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the user provides a <type>signed char</type> <type>GValue</type>, as is shown
|
||||
here, and if the object's property was registered as an <type>unsigned int</type>,
|
||||
<function><link linkend="g-value-transform">g_value_transform</link></function> will try to transform the input signed char into
|
||||
an unsigned int. Of course, the success of the transformation depends on the availability
|
||||
of the required transform function. In practice, there will almost always be a transformation
|
||||
<footnote>
|
||||
<para>Its behaviour might not be what you expect but it is up to you to actually avoid
|
||||
relying on these transformations.
|
||||
</para>
|
||||
</footnote>
|
||||
which matches and conversion will be carried out if needed.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
After transformation, the <link linkend="GValue"><type>GValue</type></link> is validated by
|
||||
<function><link linkend="g-param-value-validate">g_param_value_validate</link></function> which makes sure the user's
|
||||
data stored in the <link linkend="GValue"><type>GValue</type></link> matches the characteristics specified by
|
||||
the property's <link linkend="GParamSpec"><type>GParamSpec</type></link>.
|
||||
Here, the <link linkend="GParamSpec"><type>GParamSpec</type></link> we
|
||||
provided in <function>class_init</function> has a validation function which makes sure that the GValue
|
||||
contains a value which respects the minimum and maximum bounds of the
|
||||
<link linkend="GParamSpec"><type>GParamSpec</type></link>. In the example above, the client's GValue does not
|
||||
respect these constraints (it is set to 11, while the maximum is 10). As such, the
|
||||
<function><link linkend="g-object-set-property">g_object_set_property</link></function> function will return with an error.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If the user's GValue had been set to a valid value, <function><link linkend="g-object-set-property">g_object_set_property</link></function>
|
||||
would have proceeded with calling the object's
|
||||
<function>set_property</function> class method. Here, since our
|
||||
implementation of <type>ViewerFile</type> did override this method, execution would jump to
|
||||
<function>viewer_file_set_property</function> after having retrieved from the
|
||||
<link linkend="GParamSpec"><type>GParamSpec</type></link> the <emphasis>param_id</emphasis>
|
||||
<footnote>
|
||||
<para>
|
||||
It should be noted that the param_id used here need only to uniquely identify each
|
||||
<link linkend="GParamSpec"><type>GParamSpec</type></link> within the <type>ViewerFileClass</type> such that the switch
|
||||
used in the set and get methods actually works. Of course, this locally-unique
|
||||
integer is purely an optimization: it would have been possible to use a set of
|
||||
<emphasis>if (strcmp (a, b) == 0) {} else if (strcmp (a, b) == 0) {}</emphasis> statements.
|
||||
</para>
|
||||
</footnote>
|
||||
which had been stored by
|
||||
<function><link linkend="g-object-class-install-property">g_object_class_install_property</link></function>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Once the property has been set by the object's
|
||||
<function>set_property</function> class method, execution
|
||||
returns to <function><link linkend="g-object-set-property">g_object_set_property</link></function> which makes sure that
|
||||
the "notify" signal is emitted on the object's instance with the changed property as
|
||||
parameter unless notifications were frozen by <function><link linkend="g-object-freeze-notify">g_object_freeze_notify</link></function>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function><link linkend="g-object-thaw-notify">g_object_thaw_notify</link></function> can be used to re-enable notification of
|
||||
property modifications through the
|
||||
<link linkend="GObject-notify"><type>“notify”</type></link> signal. It is important to remember that
|
||||
even if properties are changed while property change notification is frozen, the "notify"
|
||||
signal will be emitted once for each of these changed properties as soon as the property
|
||||
change notification is thawed: no property change is lost for the "notify"
|
||||
signal, although multiple notifications for a single property are
|
||||
compressed. Signals can only be delayed by the notification freezing
|
||||
mechanism.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
It sounds like a tedious task to set up GValues every time when one wants to modify a property.
|
||||
In practice one will rarely do this. The functions <function><link linkend="g-object-set-property">g_object_set_property</link></function>
|
||||
and <function><link linkend="g-object-get-property">g_object_get_property</link></function>
|
||||
are meant to be used by language bindings. For application there is an easier way and
|
||||
that is described next.
|
||||
</para>
|
||||
|
||||
<sect2 id="gobject-multi-properties">
|
||||
<title>Accessing multiple properties at once</title>
|
||||
|
||||
<para>
|
||||
It is interesting to note that the <function><link linkend="g-object-set">g_object_set</link></function> and
|
||||
<function><link linkend="g-object-set-valist">g_object_set_valist</link></function> (variadic version) functions can be used to set
|
||||
multiple properties at once. The client code shown above can then be re-written as:
|
||||
<informalexample><programlisting>
|
||||
ViewerFile *file;
|
||||
file = /* */;
|
||||
g_object_set (G_OBJECT (file),
|
||||
"zoom-level", 6,
|
||||
"filename", "~/some-file.txt",
|
||||
NULL);
|
||||
</programlisting></informalexample>
|
||||
This saves us from managing the GValues that we were needing to handle when using
|
||||
<function><link linkend="g-object-set-property">g_object_set_property</link></function>.
|
||||
The code above will trigger one notify signal emission for each property modified.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Equivalent <function>_get</function> versions are also available:
|
||||
<function><link linkend="g-object-get">g_object_get</link></function>
|
||||
and <function><link linkend="g-object-get-valist">g_object_get_valist</link></function> (variadic version) can be used to get numerous
|
||||
properties at once.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
These high level functions have one drawback — they don't provide a return value.
|
||||
One should pay attention to the argument types and ranges when using them.
|
||||
A known source of errors is to pass a different type from what the
|
||||
property expects; for instance, passing an integer when the property
|
||||
expects a floating point value and thus shifting all subsequent parameters
|
||||
by some number of bytes. Also forgetting the terminating
|
||||
<literal>NULL</literal> will lead to undefined behaviour.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This explains how <function><link linkend="g-object-new">g_object_new</link></function>,
|
||||
<function><link linkend="g-object-newv">g_object_newv</link></function> and <function><link linkend="g-object-new-valist">g_object_new_valist</link></function>
|
||||
work: they parse the user-provided variable number of parameters and invoke
|
||||
<function><link linkend="g-object-set">g_object_set</link></function> on the parameters only after the object has been successfully constructed.
|
||||
The "notify" signal will be emitted for each property set.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<!-- @todo tell here about how to pass use handle properties in derived classes -->
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
@ -1,495 +0,0 @@
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="chapter-signal">
|
||||
<title>The GObject messaging system</title>
|
||||
|
||||
<sect1 id="closure">
|
||||
<title>Closures</title>
|
||||
|
||||
<para>
|
||||
Closures are central to the concept of asynchronous signal delivery
|
||||
which is widely used throughout GTK and GNOME applications. A closure is an
|
||||
abstraction, a generic representation of a callback. It is a small structure
|
||||
which contains three objects:
|
||||
<itemizedlist>
|
||||
<listitem><para>a function pointer (the callback itself) whose prototype looks like:
|
||||
<informalexample><programlisting>
|
||||
return_type function_callback (… , gpointer user_data);
|
||||
</programlisting></informalexample>
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
the <parameter>user_data</parameter> pointer which is passed to the callback upon invocation of the closure
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
a function pointer which represents the destructor of the closure: whenever the
|
||||
closure's refcount reaches zero, this function will be called before the closure
|
||||
structure is freed.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The <link linkend="GClosure"><type>GClosure</type></link> structure represents the common functionality of all
|
||||
closure implementations: there exists a different closure implementation for
|
||||
each separate runtime which wants to use the GObject type system.
|
||||
<footnote><para>
|
||||
In practice, closures sit at the boundary of language runtimes: if you are
|
||||
writing Python code and one of your Python callbacks receives a signal from
|
||||
a GTK widget, the C code in GTK needs to execute your Python
|
||||
code. The closure invoked by the GTK object invokes the Python callback:
|
||||
it behaves as a normal C object for GTK and as a normal Python object for
|
||||
Python code.
|
||||
</para></footnote>
|
||||
The GObject library provides a simple <link linkend="GCClosure"><type>GCClosure</type></link> type which
|
||||
is a specific implementation of closures to be used with C/C++ callbacks.
|
||||
</para>
|
||||
<para>
|
||||
A <link linkend="GClosure"><type>GClosure</type></link> provides simple services:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
Invocation (<function><link linkend="g-closure-invoke">g_closure_invoke</link></function>): this is what closures
|
||||
were created for: they hide the details of callback invocation from the
|
||||
callback invoker.</para>
|
||||
</listitem>
|
||||
<listitem><para>
|
||||
Notification: the closure notifies listeners of certain events such as
|
||||
closure invocation, closure invalidation and closure finalization. Listeners
|
||||
can be registered with <function><link linkend="g-closure-add-finalize-notifier">g_closure_add_finalize_notifier</link></function>
|
||||
(finalization notification), <function><link linkend="g-closure-add-invalidate-notifier">g_closure_add_invalidate_notifier</link></function>
|
||||
(invalidation notification) and
|
||||
<function><link linkend="g-closure-add-marshal-guards">g_closure_add_marshal_guards</link></function> (invocation notification).
|
||||
There exist symmetric deregistration functions for finalization and invalidation
|
||||
events (<function><link linkend="g-closure-remove-finalize-notifier">g_closure_remove_finalize_notifier</link></function> and
|
||||
<function><link linkend="g-closure-remove-invalidate-notifier">g_closure_remove_invalidate_notifier</link></function>) but not for the invocation
|
||||
process.
|
||||
<footnote><para>
|
||||
Closures are reference counted and notify listeners of their destruction in a two-stage
|
||||
process: the invalidation notifiers are invoked before the finalization notifiers.
|
||||
</para></footnote></para>
|
||||
</listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<sect2>
|
||||
<title>C Closures</title>
|
||||
|
||||
<para>
|
||||
If you are using C or C++
|
||||
to connect a callback to a given event, you will either use simple <link linkend="GCClosure"><type>GCClosure</type></link>s
|
||||
which have a pretty minimal API or the even simpler <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
||||
functions (which will be presented a bit later).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function><link linkend="g-cclosure-new">g_cclosure_new</link></function> will create a new closure which can invoke the
|
||||
user-provided callback_func with the user-provided
|
||||
<parameter>user_data</parameter> as its last parameter. When the closure
|
||||
is finalized (second stage of the destruction process), it will invoke
|
||||
the <parameter>destroy_data</parameter> function if the user has
|
||||
supplied one.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
<function><link linkend="g-cclosure-new-swap">g_cclosure_new_swap</link></function> will create a new closure which can invoke the
|
||||
user-provided <parameter>callback_func</parameter> with the
|
||||
user-provided <parameter>user_data</parameter> as its first parameter
|
||||
(instead of being the
|
||||
last parameter as with <function><link linkend="g-cclosure-new">g_cclosure_new</link></function>). When the closure
|
||||
is finalized (second stage of the destruction process), it will invoke
|
||||
the <parameter>destroy_data</parameter> function if the user has
|
||||
supplied one.
|
||||
</para>
|
||||
</sect2>
|
||||
|
||||
<sect2>
|
||||
<title>Non-C closures (for the fearless)</title>
|
||||
|
||||
<para>
|
||||
As was explained above, closures hide the details of callback invocation. In C,
|
||||
callback invocation is just like function invocation: it is a matter of creating
|
||||
the correct stack frame for the called function and executing a <emphasis>call</emphasis>
|
||||
assembly instruction.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
C closure marshallers transform the array of GValues which represent
|
||||
the parameters to the target function into a C-style function parameter list, invoke
|
||||
the user-supplied C function with this new parameter list, get the return value of the
|
||||
function, transform it into a GValue and return this GValue to the marshaller caller.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A generic C closure marshaller is available as
|
||||
<link linkend="g-cclosure-marshal-generic"><function>g_cclosure_marshal_generic</function></link>
|
||||
which implements marshalling for all function types using libffi. Custom
|
||||
marshallers for different types are not needed apart from performance
|
||||
critical code where the libffi-based marshaller may be too slow.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
An example of a custom marshaller is given below, illustrating how
|
||||
<type>GValue</type>s can be converted to a C function call. The
|
||||
marshaller is for a C function which takes an integer as its first
|
||||
parameter and returns void.
|
||||
<informalexample><programlisting>
|
||||
g_cclosure_marshal_VOID__INT (GClosure *closure,
|
||||
GValue *return_value,
|
||||
guint n_param_values,
|
||||
const GValue *param_values,
|
||||
gpointer invocation_hint,
|
||||
gpointer marshal_data)
|
||||
{
|
||||
typedef void (*GMarshalFunc_VOID__INT) (gpointer data1,
|
||||
gint arg_1,
|
||||
gpointer data2);
|
||||
register GMarshalFunc_VOID__INT callback;
|
||||
register GCClosure *cc = (GCClosure*) closure;
|
||||
register gpointer data1, data2;
|
||||
|
||||
g_return_if_fail (n_param_values == 2);
|
||||
|
||||
data1 = g_value_peek_pointer (param_values + 0);
|
||||
data2 = closure->data;
|
||||
|
||||
callback = (GMarshalFunc_VOID__INT) (marshal_data ? marshal_data : cc->callback);
|
||||
|
||||
callback (data1,
|
||||
g_marshal_value_peek_int (param_values + 1),
|
||||
data2);
|
||||
}
|
||||
</programlisting></informalexample>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
There exist other kinds of marshallers, for example there is a generic
|
||||
Python marshaller which is used by all Python closures (a Python closure
|
||||
is used to invoke a callback written in Python). This Python marshaller
|
||||
transforms the input GValue list representing the function parameters
|
||||
into a Python tuple which is the equivalent structure in Python.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
</sect1>
|
||||
|
||||
<sect1 id="signal">
|
||||
<title>Signals</title>
|
||||
|
||||
<para>
|
||||
GObject's signals have nothing to do with standard UNIX signals: they connect
|
||||
arbitrary application-specific events with any number of listeners.
|
||||
For example, in GTK, every user event (keystroke or mouse move) is received
|
||||
from the windowing system and generates a GTK event in the form of a signal emission
|
||||
on the widget object instance.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Each signal is registered in the type system together with the type on which
|
||||
it can be emitted: users of the type are said to <emphasis>connect</emphasis>
|
||||
to the signal on a given type instance when they register a closure to be
|
||||
invoked upon the signal emission. The closure will be called synchronously on emission.
|
||||
Users can also emit the signal by themselves or stop the emission of the signal from
|
||||
within one of the closures connected to the signal.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
When a signal is emitted on a given type instance, all the closures
|
||||
connected to this signal on this type instance will be invoked. All the closures
|
||||
connected to such a signal represent callbacks whose signature looks like:
|
||||
<informalexample><programlisting>
|
||||
return_type function_callback (gpointer instance, …, gpointer user_data);
|
||||
</programlisting></informalexample>
|
||||
</para>
|
||||
|
||||
<sect2 id="signal-registration">
|
||||
<title>Signal registration</title>
|
||||
|
||||
<para>
|
||||
To register a new signal on an existing type, we can use any of <function><link linkend="g-signal-newv">g_signal_newv</link></function>,
|
||||
<function><link linkend="g-signal-new-valist">g_signal_new_valist</link></function> or <function><link linkend="g-signal-new">g_signal_new</link></function> functions:
|
||||
<informalexample><programlisting>
|
||||
guint g_signal_newv (const gchar *signal_name,
|
||||
GType itype,
|
||||
GSignalFlags signal_flags,
|
||||
GClosure *class_closure,
|
||||
GSignalAccumulator accumulator,
|
||||
gpointer accu_data,
|
||||
GSignalCMarshaller c_marshaller,
|
||||
GType return_type,
|
||||
guint n_params,
|
||||
GType *param_types);
|
||||
</programlisting></informalexample>
|
||||
The number of parameters to these functions is a bit intimidating but they are relatively
|
||||
simple:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
<parameter>signal_name</parameter>: is a string which can be used to uniquely identify a given signal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>itype</parameter>: is the instance type on which this signal can be emitted.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>signal_flags</parameter>: partly defines the order in which closures which were connected to the
|
||||
signal are invoked.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>class_closure</parameter>: this is the default closure for the signal: if it is not NULL upon
|
||||
the signal emission, it will be invoked upon this emission of the signal. The
|
||||
moment where this closure is invoked compared to other closures connected to that
|
||||
signal depends partly on the signal_flags.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>accumulator</parameter>: this is a function pointer which is invoked after each closure
|
||||
has been invoked. If it returns FALSE, signal emission is stopped. If it returns
|
||||
TRUE, signal emission proceeds normally. It is also used to compute the return
|
||||
value of the signal based on the return value of all the invoked closures.
|
||||
For example, an accumulator could ignore
|
||||
<literal>NULL</literal> returns from closures; or it
|
||||
could build a list of the values returned by the
|
||||
closures.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>accu_data</parameter>: this pointer will be passed down to each invocation of the
|
||||
accumulator during emission.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>c_marshaller</parameter>: this is the default C marshaller for any closure which is connected to
|
||||
this signal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>return_type</parameter>: this is the type of the return value of the signal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>n_params</parameter>: this is the number of parameters this signal takes.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>param_types</parameter>: this is an array of GTypes which indicate the type of each parameter
|
||||
of the signal. The length of this array is indicated by n_params.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As you can see from the above definition, a signal is basically a description
|
||||
of the closures which can be connected to this signal and a description of the
|
||||
order in which the closures connected to this signal will be invoked.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="signal-connection">
|
||||
<title>Signal connection</title>
|
||||
|
||||
<para>
|
||||
If you want to connect to a signal with a closure, you have three possibilities:
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
You can register a class closure at signal registration: this is a
|
||||
system-wide operation. i.e.: the class closure will be invoked during each emission
|
||||
of a given signal on <emphasis>any</emphasis> of the instances of the type which supports that signal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
You can use <function><link linkend="g-signal-override-class-closure">g_signal_override_class_closure</link></function> which
|
||||
overrides the class closure of a given type. It is possible to call this function
|
||||
only on a derived type of the type on which the signal was registered.
|
||||
This function is of use only to language bindings.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
You can register a closure with the <function><link linkend="g-signal-connect">g_signal_connect</link></function>
|
||||
family of functions. This is an instance-specific operation: the closure
|
||||
will be invoked only during emission of a given signal on a given instance.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
It is also possible to connect a different kind of callback on a given signal:
|
||||
emission hooks are invoked whenever a given signal is emitted whatever the instance on
|
||||
which it is emitted. Emission hooks are used for example to get all mouse_clicked
|
||||
emissions in an application to be able to emit the small mouse click sound.
|
||||
Emission hooks are connected with <function><link linkend="g-signal-add-emission-hook">g_signal_add_emission_hook</link></function>
|
||||
and removed with <function><link linkend="g-signal-remove-emission-hook">g_signal_remove_emission_hook</link></function>.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
<sect2 id="signal-emission">
|
||||
<title>Signal emission</title>
|
||||
|
||||
<para>
|
||||
Signal emission is done through the use of the <function><link linkend="g-signal-emit">g_signal_emit</link></function> family
|
||||
of functions.
|
||||
<informalexample><programlisting>
|
||||
void g_signal_emitv (const GValue *instance_and_params,
|
||||
guint signal_id,
|
||||
GQuark detail,
|
||||
GValue *return_value);
|
||||
</programlisting></informalexample>
|
||||
<itemizedlist>
|
||||
<listitem><para>
|
||||
The <parameter>instance_and_params</parameter> array of GValues contains the list of input
|
||||
parameters to the signal. The first element of the array is the
|
||||
instance pointer on which to invoke the signal. The following elements of
|
||||
the array contain the list of parameters to the signal.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>signal_id</parameter> identifies the signal to invoke.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>detail</parameter> identifies the specific detail of the signal to invoke. A detail is a kind of
|
||||
magic token/argument which is passed around during signal emission and which is used
|
||||
by closures connected to the signal to filter out unwanted signal emissions. In most
|
||||
cases, you can safely set this value to zero. See <xref linkend="signal-detail"/> for
|
||||
more details about this parameter.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<parameter>return_value</parameter> holds the return value of the last closure invoked during emission if
|
||||
no accumulator was specified. If an accumulator was specified during signal creation,
|
||||
this accumulator is used to calculate the return value as a function of the return
|
||||
values of all the closures invoked during emission.
|
||||
If no closure is invoked during
|
||||
emission, the <parameter>return_value</parameter> is nonetheless initialized to zero/null.
|
||||
</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Signal emission is done synchronously and can be decomposed in 5 steps:
|
||||
<orderedlist>
|
||||
<listitem><para>
|
||||
<literal>RUN_FIRST</literal>: if the
|
||||
<link linkend="G-SIGNAL-RUN-FIRST:CAPS"><literal>G_SIGNAL_RUN_FIRST</literal></link> flag was used
|
||||
during signal registration and if there exists a class closure for this signal,
|
||||
the class closure is invoked.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<literal>EMISSION_HOOK</literal>: if any emission hook was added to
|
||||
the signal, they are invoked from first to last added. Accumulate return values.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<literal>HANDLER_RUN_FIRST</literal>: if any closure were connected
|
||||
with the <function><link linkend="g-signal-connect">g_signal_connect</link></function> family of
|
||||
functions, and if they are not blocked (with the <function><link linkend="g-signal-handler-block">g_signal_handler_block</link></function>
|
||||
family of functions) they are run here, from first to last connected.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<literal>RUN_LAST</literal>: if the <literal>G_SIGNAL_RUN_LAST</literal>
|
||||
flag was set during registration and if a class closure
|
||||
was set, it is invoked here.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<literal>HANDLER_RUN_LAST</literal>: if any closure were connected
|
||||
with the <function>g_signal_connect_after</function> family of
|
||||
functions, if they were not invoked during <literal>HANDLER_RUN_FIRST</literal> and if they
|
||||
are not blocked, they are run here, from first to last connected.
|
||||
</para></listitem>
|
||||
<listitem><para>
|
||||
<literal>RUN_CLEANUP</literal>: if the <literal>G_SIGNAL_RUN_CLEANUP</literal> flag
|
||||
was set during registration and if a class closure was set,
|
||||
it is invoked here. Signal emission is completed here.
|
||||
</para></listitem>
|
||||
</orderedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If, at any point during emission (except in <literal>RUN_CLEANUP</literal> or
|
||||
<literal>EMISSION_HOOK</literal> state), one of the closures stops the signal emission with
|
||||
<function><link linkend="g-signal-stop-emission">g_signal_stop_emission</link></function>,
|
||||
emission jumps to <literal>RUN_CLEANUP</literal> state.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If, at any point during emission, one of the closures or emission hook
|
||||
emits the same signal on the same instance, emission is restarted from
|
||||
the <literal>RUN_FIRST</literal> state.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The accumulator function is invoked in all states, after invocation
|
||||
of each closure (except in <literal>RUN_EMISSION_HOOK</literal> and
|
||||
<literal>RUN_CLEANUP</literal>). It accumulates
|
||||
the closure return value into the signal return value and returns TRUE or
|
||||
FALSE. If, at any point, it does not return TRUE, emission jumps
|
||||
to <literal>RUN_CLEANUP</literal> state.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If no accumulator function was provided, the value returned by the last handler
|
||||
run will be returned by <function><link linkend="g-signal-emit">g_signal_emit</link></function>.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
|
||||
<sect2 id="signal-detail">
|
||||
<title>The <emphasis>detail</emphasis> argument</title>
|
||||
|
||||
<para>All the functions related to signal emission or signal connection have a parameter
|
||||
named the <emphasis>detail</emphasis>. Sometimes, this parameter is hidden by the API
|
||||
but it is always there, in one form or another.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Of the three main connection functions,
|
||||
only one has an explicit detail parameter as a <link linkend="GQuark"><type>GQuark</type></link>:
|
||||
<link linkend="g-signal-connect-closure-by-id"><function>g_signal_connect_closure_by_id</function></link>.
|
||||
<footnote>
|
||||
<para>A GQuark is an integer which uniquely represents a string. It is possible to transform
|
||||
back and forth between the integer and string representations with the functions
|
||||
<function><link linkend="g-quark-from-string">g_quark_from_string</link></function> and <function><link linkend="g-quark-to-string">g_quark_to_string</link></function>.
|
||||
</para>
|
||||
</footnote>
|
||||
</para>
|
||||
<para>
|
||||
The two other functions,
|
||||
<link linkend="g-signal-connect-closure"><function>g_signal_connect_closure</function></link> and
|
||||
<link linkend="g-signal-connect-data"><function>g_signal_connect_data</function></link>
|
||||
hide the detail parameter in the signal name identification.
|
||||
Their <parameter>detailed_signal</parameter> parameter is a
|
||||
string which identifies the name of the signal to connect to.
|
||||
The format of this string should match
|
||||
<emphasis>signal_name::detail_name</emphasis>. For example,
|
||||
connecting to the signal named
|
||||
<emphasis>notify::cursor_position</emphasis> will actually
|
||||
connect to the signal named <emphasis>notify</emphasis> with the
|
||||
<emphasis>cursor_position</emphasis> detail.
|
||||
Internally, the detail string is transformed to a GQuark if it is present.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Of the four main signal emission functions, one hides it in its
|
||||
signal name parameter:
|
||||
<link linkend="g-signal-connect"><function>g_signal_connect</function></link>.
|
||||
The other three have an explicit detail parameter as a
|
||||
<link linkend="GQuark"><type>GQuark</type></link> again:
|
||||
<link linkend="g-signal-emit"><function>g_signal_emit</function></link>,
|
||||
<link linkend="g-signal-emitv"><function>g_signal_emitv</function></link> and
|
||||
<link linkend="g-signal-emit-valist"><function>g_signal_emit_valist</function></link>.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
If a detail is provided by the user to the emission function, it is used during emission to match
|
||||
against the closures which also provide a detail.
|
||||
If a closure's detail does not match the detail provided by the user, it
|
||||
will not be invoked (even though it is connected to a signal which is
|
||||
being emitted).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
This completely optional filtering mechanism is mainly used as an optimization for signals
|
||||
which are often emitted for many different reasons: the clients can filter out which events they are
|
||||
interested in before the closure's marshalling code runs. For example, this is used extensively
|
||||
by the <link linkend="GObject-notify"><structfield>notify</structfield></link> signal of GObject: whenever a property is modified on a GObject,
|
||||
instead of just emitting the <emphasis>notify</emphasis> signal, GObject associates as a detail to this
|
||||
signal emission the name of the property modified. This allows clients who wish to be notified of changes
|
||||
to only one property to filter most events before receiving them.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
As a simple rule, users can and should set the detail parameter to zero: this will disable completely
|
||||
this optional filtering for that signal.
|
||||
</para>
|
||||
|
||||
</sect2>
|
||||
|
||||
</sect1>
|
||||
</chapter>
|
||||
|
File diff suppressed because it is too large
Load Diff
File diff suppressed because it is too large
Load Diff
@ -1,185 +0,0 @@
|
||||
<?xml version='1.0' encoding="UTF-8"?>
|
||||
<!DOCTYPE chapter PUBLIC "-//OASIS//DTD DocBook XML V4.5//EN"
|
||||
"http://www.oasis-open.org/docbook/xml/4.5/docbookx.dtd" [
|
||||
]>
|
||||
<chapter id="chapter-intro">
|
||||
<title>Background</title>
|
||||
|
||||
<para>
|
||||
GObject, and its lower-level type system, GType, are used by GTK and most GNOME libraries to
|
||||
provide:
|
||||
<itemizedlist>
|
||||
<listitem><para>object-oriented C-based APIs and</para></listitem>
|
||||
<listitem><para>automatic transparent API bindings to other compiled
|
||||
or interpreted languages.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A lot of programmers are used to working with compiled-only or dynamically interpreted-only
|
||||
languages and do not understand the challenges associated with cross-language interoperability.
|
||||
This introduction tries to provide an insight into these challenges and briefly describes
|
||||
the solution chosen by GLib.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The following chapters go into greater detail into how GType and GObject work and
|
||||
how you can use them as a C programmer. It is useful to keep in mind that
|
||||
allowing access to C objects from other interpreted languages was one of the major design
|
||||
goals: this can often explain the sometimes rather convoluted APIs and features present
|
||||
in this library.
|
||||
</para>
|
||||
|
||||
<sect1>
|
||||
<title>Data types and programming</title>
|
||||
|
||||
<para>
|
||||
One could say
|
||||
that a programming language is merely a way to create data types and manipulate them. Most languages
|
||||
provide a number of language-native types and a few primitives to create more complex types based
|
||||
on these primitive types.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
In C, the language provides types such as <emphasis>char</emphasis>, <emphasis>long</emphasis>,
|
||||
<emphasis>pointer</emphasis>. During compilation of C code, the compiler maps these
|
||||
language types to the compiler's target architecture machine types. If you are using a C interpreter
|
||||
(assuming one exists), the interpreter (the program which interprets
|
||||
the source code and executes it) maps the language types to the machine types of the target machine at
|
||||
runtime, during the program execution (or just before execution if it uses a Just In Time compiler engine).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Perl and Python are interpreted languages which do not really provide type definitions similar
|
||||
to those used by C. Perl and Python programmers manipulate variables and the type of the variables
|
||||
is decided only upon the first assignment or upon the first use which forces a type on the variable.
|
||||
The interpreter also often provides a lot of automatic conversions from one type to the other. For example,
|
||||
in Perl, a variable which holds an integer can be automatically converted to a string given the
|
||||
required context:
|
||||
<informalexample><programlisting>
|
||||
my $tmp = 10;
|
||||
print "this is an integer converted to a string:" . $tmp . "\n";
|
||||
</programlisting></informalexample>
|
||||
Of course, it is also often possible to explicitly specify conversions when the default conversions provided
|
||||
by the language are not intuitive.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
<sect1>
|
||||
<title>Exporting a C API</title>
|
||||
|
||||
<para>
|
||||
C APIs are defined by a set of functions and global variables which are usually exported from a
|
||||
binary. C functions have an arbitrary number of arguments and one return value. Each function is thus
|
||||
uniquely identified by the function name and the set of C types which describe the function arguments
|
||||
and return value. The global variables exported by the API are similarly identified by their name and
|
||||
their type.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
A C API is thus merely defined by a set of names to which a set of types are associated. If you know the
|
||||
function calling convention and the mapping of the C types to the machine types used by the platform you
|
||||
are on, you can resolve the name of each function to find where the code associated to this function
|
||||
is located in memory, and then construct a valid argument list for the function. Finally, all you have to
|
||||
do is trigger a call to the target C function with the argument list.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
For the sake of discussion, here is a sample C function and the associated 32 bit x86
|
||||
assembly code generated by GCC on a Linux computer:
|
||||
<informalexample><programlisting>
|
||||
static void
|
||||
function_foo (int foo)
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
main (int argc,
|
||||
char *argv[])
|
||||
{
|
||||
function_foo (10);
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
push $0xa
|
||||
call 0x80482f4 <function_foo>
|
||||
</programlisting></informalexample>
|
||||
The assembly code shown above is pretty straightforward: the first instruction pushes
|
||||
the hexadecimal value 0xa (decimal value 10) as a 32-bit integer on the stack and calls
|
||||
<function>function_foo</function>. As you can see, C function calls are implemented by
|
||||
GCC as native function calls (this is probably the fastest implementation possible).
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Now, let's say we want to call the C function <function>function_foo</function> from
|
||||
a Python program. To do this, the Python interpreter needs to:
|
||||
<itemizedlist>
|
||||
<listitem><para>Find where the function is located. This probably means finding the binary generated by the C compiler
|
||||
which exports this function.</para></listitem>
|
||||
<listitem><para>Load the code of the function in executable memory.</para></listitem>
|
||||
<listitem><para>Convert the Python parameters to C-compatible parameters before calling
|
||||
the function.</para></listitem>
|
||||
<listitem><para>Call the function with the right calling convention.</para></listitem>
|
||||
<listitem><para>Convert the return values of the C function to Python-compatible
|
||||
variables to return them to the Python code.</para></listitem>
|
||||
</itemizedlist>
|
||||
</para>
|
||||
|
||||
<para>
|
||||
The process described above is pretty complex and there are a lot of ways to make it entirely automatic
|
||||
and transparent to C and Python programmers:
|
||||
<itemizedlist>
|
||||
<listitem><para>The first solution is to write by hand a lot of glue code, once for each function exported or imported,
|
||||
which does the Python-to-C parameter conversion and the C-to-Python return value conversion. This glue code is then
|
||||
linked with the interpreter which allows Python programs to call Python functions which delegate work to
|
||||
C functions.</para></listitem>
|
||||
<listitem><para>Another, nicer solution is to automatically generate the glue code, once for each function exported or
|
||||
imported, with a special compiler which
|
||||
reads the original function signature.</para></listitem>
|
||||
<listitem><para>The solution used by GLib is to use the GType library which holds at runtime a description of
|
||||
all the objects manipulated by the programmer. This so-called <emphasis>dynamic type</emphasis>
|
||||
<footnote>
|
||||
<para>
|
||||
There are numerous different implementations of dynamic type systems: all C++
|
||||
compilers have one, Java and .NET have one too. A dynamic type system allows you
|
||||
to get information about every instantiated object at runtime. It can be implemented
|
||||
by a process-specific database: every new object created registers the characteristics
|
||||
of its associated type in the type system. It can also be implemented by introspection
|
||||
interfaces. The common point between all these different type systems and implementations
|
||||
is that they all allow you to query for object metadata at runtime.
|
||||
</para>
|
||||
</footnote>
|
||||
library is then used by special generic glue code to automatically convert function parameters and
|
||||
function calling conventions between different runtime domains.</para></listitem>
|
||||
</itemizedlist>
|
||||
The greatest advantage of the solution implemented by GType is that the glue code sitting at the runtime domain
|
||||
boundaries is written once: the figure below states this more clearly.
|
||||
<figure>
|
||||
<mediaobject>
|
||||
<imageobject> <!-- this is for HTML output -->
|
||||
<imagedata fileref="glue.png" format="PNG" align="center"/>
|
||||
</imageobject>
|
||||
<imageobject> <!-- this is for PDF output -->
|
||||
<imagedata fileref="glue.jpg" format="JPG" align="center"/>
|
||||
</imageobject>
|
||||
</mediaobject>
|
||||
</figure>
|
||||
|
||||
Currently, there exist at least Python and Perl generic glue code which makes it possible to use
|
||||
C objects written with GType directly in Python or Perl, with a minimum amount of work: there
|
||||
is no need to generate huge amounts of glue code either automatically or by hand.
|
||||
</para>
|
||||
|
||||
<para>
|
||||
Although that goal was arguably laudable, its pursuit has had a major influence on
|
||||
the whole GType/GObject library. C programmers are likely to be puzzled at the complexity
|
||||
of the features exposed in the following chapters if they forget that the GType/GObject library
|
||||
was not only designed to offer OO-like features to C programmers but also transparent
|
||||
cross-language interoperability.
|
||||
</para>
|
||||
|
||||
</sect1>
|
||||
|
||||
</chapter>
|
1288
docs/reference/gobject/tutorial.md
Normal file
1288
docs/reference/gobject/tutorial.md
Normal file
File diff suppressed because it is too large
Load Diff
9
docs/reference/gobject/urlmap.js
Normal file
9
docs/reference/gobject/urlmap.js
Normal file
@ -0,0 +1,9 @@
|
||||
// SPDX-License-Identifier: LGPL-2.1-or-later
|
||||
// SPDX-FileCopyrightText: 2023 Matthias Clasen
|
||||
var baseURLs = [
|
||||
[ 'GLib', 'https://docs.gtk.org/glib/' ],
|
||||
[ 'GModule', 'https://docs.gtk.org/gmodule/' ],
|
||||
[ 'GObject', 'https://docs.gtk.org/gobject/' ],
|
||||
[ 'Gio', 'https://docs.gtk.org/gio/' ],
|
||||
[ 'Gtk', 'https://docs.gtk.org/gtk4/' ],
|
||||
];
|
@ -53,6 +53,25 @@ if get_option('gtk_doc')
|
||||
endif
|
||||
endif
|
||||
|
||||
subdir('gio')
|
||||
subdir('glib')
|
||||
subdir('gobject')
|
||||
# gi-docgen version
|
||||
if get_option('gtk_doc')
|
||||
gidocgen_dep = dependency('gi-docgen', version: '>= 2023.1',
|
||||
fallback: ['gi-docgen', 'dummy_dep'],
|
||||
required: true)
|
||||
|
||||
toml_conf = configuration_data()
|
||||
toml_conf.set('VERSION', meson.project_version())
|
||||
|
||||
gidocgen = find_program('gi-docgen', required: true)
|
||||
|
||||
gidocgen_common_args = [
|
||||
'--quiet',
|
||||
'--no-namespace-dir',
|
||||
'--fatal-warnings',
|
||||
]
|
||||
|
||||
subdir('glib')
|
||||
subdir('gmodule')
|
||||
subdir('gobject')
|
||||
subdir('gio')
|
||||
endif
|
||||
|
96
glib/docs.c
96
glib/docs.c
@ -1063,48 +1063,6 @@
|
||||
|
||||
/* Type conversion {{{1 */
|
||||
|
||||
/**
|
||||
* SECTION:type_conversion
|
||||
* @title: Type Conversion Macros
|
||||
* @short_description: portably storing integers in pointer variables
|
||||
*
|
||||
* Many times GLib, GTK, and other libraries allow you to pass "user
|
||||
* data" to a callback, in the form of a void pointer. From time to time
|
||||
* you want to pass an integer instead of a pointer. You could allocate
|
||||
* an integer, with something like:
|
||||
* |[<!-- language="C" -->
|
||||
* int *ip = g_new (int, 1);
|
||||
* *ip = 42;
|
||||
* ]|
|
||||
* But this is inconvenient, and it's annoying to have to free the
|
||||
* memory at some later time.
|
||||
*
|
||||
* Pointers are always at least 32 bits in size (on all platforms GLib
|
||||
* intends to support). Thus you can store at least 32-bit integer values
|
||||
* in a pointer value. Naively, you might try this, but it's incorrect:
|
||||
* |[<!-- language="C" -->
|
||||
* gpointer p;
|
||||
* int i;
|
||||
* p = (void*) 42;
|
||||
* i = (int) p;
|
||||
* ]|
|
||||
* Again, that example was not correct, don't copy it.
|
||||
* The problem is that on some systems you need to do this:
|
||||
* |[<!-- language="C" -->
|
||||
* gpointer p;
|
||||
* int i;
|
||||
* p = (void*) (long) 42;
|
||||
* i = (int) (long) p;
|
||||
* ]|
|
||||
* The GLib macros GPOINTER_TO_INT(), GINT_TO_POINTER(), etc. take care
|
||||
* to do the right thing on every platform.
|
||||
*
|
||||
* Warning: You may not store pointers in integers. This is not
|
||||
* portable in any way, shape or form. These macros only allow storing
|
||||
* integers in pointers, and only preserve 32 bits of the integer; values
|
||||
* outside the range of a 32-bit integer will be mangled.
|
||||
*/
|
||||
|
||||
/**
|
||||
* GINT_TO_POINTER:
|
||||
* @i: integer to stuff into a pointer
|
||||
@ -1162,41 +1120,6 @@
|
||||
|
||||
/* Byte order {{{1 */
|
||||
|
||||
/**
|
||||
* SECTION:byte_order
|
||||
* @title: Byte Order Macros
|
||||
* @short_description: a portable way to convert between different byte orders
|
||||
*
|
||||
* These macros provide a portable way to determine the host byte order
|
||||
* and to convert values between different byte orders.
|
||||
*
|
||||
* The byte order is the order in which bytes are stored to create larger
|
||||
* data types such as the #gint and #glong values.
|
||||
* The host byte order is the byte order used on the current machine.
|
||||
*
|
||||
* Some processors store the most significant bytes (i.e. the bytes that
|
||||
* hold the largest part of the value) first. These are known as big-endian
|
||||
* processors. Other processors (notably the x86 family) store the most
|
||||
* significant byte last. These are known as little-endian processors.
|
||||
*
|
||||
* Finally, to complicate matters, some other processors store the bytes in
|
||||
* a rather curious order known as PDP-endian. For a 4-byte word, the 3rd
|
||||
* most significant byte is stored first, then the 4th, then the 1st and
|
||||
* finally the 2nd.
|
||||
*
|
||||
* Obviously there is a problem when these different processors communicate
|
||||
* with each other, for example over networks or by using binary file formats.
|
||||
* This is where these macros come in. They are typically used to convert
|
||||
* values into a byte order which has been agreed on for use when
|
||||
* communicating between different processors. The Internet uses what is
|
||||
* known as 'network byte order' as the standard byte order (which is in
|
||||
* fact the big-endian byte order).
|
||||
*
|
||||
* Note that the byte order conversion macros may evaluate their arguments
|
||||
* multiple times, thus you should not use them with arguments which have
|
||||
* side-effects.
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_BYTE_ORDER:
|
||||
*
|
||||
@ -1986,16 +1909,8 @@
|
||||
*
|
||||
* Multiplying the base 2 exponent by this number yields the base 10 exponent.
|
||||
*/
|
||||
|
||||
/* Macros {{{1 */
|
||||
|
||||
/**
|
||||
* SECTION:macros
|
||||
* @title: Standard Macros
|
||||
* @short_description: commonly-used macros
|
||||
*
|
||||
* These macros provide a few commonly-used features.
|
||||
*/
|
||||
/* Macros {{{1 */
|
||||
|
||||
/**
|
||||
* G_OS_WIN32:
|
||||
@ -2201,15 +2116,6 @@
|
||||
|
||||
/* Miscellaneous Macros {{{1 */
|
||||
|
||||
/**
|
||||
* SECTION:macros_misc
|
||||
* @title: Miscellaneous Macros
|
||||
* @short_description: specialized macros which are not used often
|
||||
*
|
||||
* These macros provide more specialized features which are not
|
||||
* needed so often by application programmers.
|
||||
*/
|
||||
|
||||
/**
|
||||
* G_STMT_START:
|
||||
*
|
||||
|
125
glib/garcbox.c
125
glib/garcbox.c
@ -35,131 +35,6 @@
|
||||
|
||||
#define G_ARC_BOX(p) (GArcBox *) (((char *) (p)) - G_ARC_BOX_SIZE)
|
||||
|
||||
/**
|
||||
* SECTION:arcbox
|
||||
* @Title: Atomically reference counted data
|
||||
* @Short_description: Allocated memory with atomic reference counting semantics
|
||||
*
|
||||
* An "atomically reference counted box", or "ArcBox", is an opaque wrapper
|
||||
* data type that is guaranteed to be as big as the size of a given data type,
|
||||
* and which augments the given data type with thread safe reference counting
|
||||
* semantics for its memory management.
|
||||
*
|
||||
* ArcBox is useful if you have a plain old data type, like a structure
|
||||
* typically placed on the stack, and you wish to provide additional API
|
||||
* to use it on the heap; or if you want to implement a new type to be
|
||||
* passed around by reference without necessarily implementing copy/free
|
||||
* semantics or your own reference counting.
|
||||
*
|
||||
* The typical use is:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* typedef struct {
|
||||
* char *name;
|
||||
* char *address;
|
||||
* char *city;
|
||||
* char *state;
|
||||
* int age;
|
||||
* } Person;
|
||||
*
|
||||
* Person *
|
||||
* person_new (void)
|
||||
* {
|
||||
* return g_atomic_rc_box_new0 (Person);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Every time you wish to acquire a reference on the memory, you should
|
||||
* call g_atomic_rc_box_acquire(); similarly, when you wish to release a reference
|
||||
* you should call g_atomic_rc_box_release():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* // Add a Person to the Database; the Database acquires ownership
|
||||
* // of the Person instance
|
||||
* void
|
||||
* add_person_to_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_prepend (db->persons, g_atomic_rc_box_acquire (p));
|
||||
* }
|
||||
*
|
||||
* // Removes a Person from the Database; the reference acquired by
|
||||
* // add_person_to_database() is released here
|
||||
* void
|
||||
* remove_person_from_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_remove (db->persons, p);
|
||||
* g_atomic_rc_box_release (p);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* If you have additional memory allocated inside the structure, you can
|
||||
* use g_atomic_rc_box_release_full(), which takes a function pointer, which
|
||||
* will be called if the reference released was the last:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* void
|
||||
* person_clear (Person *p)
|
||||
* {
|
||||
* g_free (p->name);
|
||||
* g_free (p->address);
|
||||
* g_free (p->city);
|
||||
* g_free (p->state);
|
||||
* }
|
||||
*
|
||||
* void
|
||||
* remove_person_from_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_remove (db->persons, p);
|
||||
* g_atomic_rc_box_release_full (p, (GDestroyNotify) person_clear);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* If you wish to transfer the ownership of a reference counted data
|
||||
* type without increasing the reference count, you can use g_steal_pointer():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* Person *p = g_atomic_rc_box_new (Person);
|
||||
*
|
||||
* fill_person_details (p);
|
||||
*
|
||||
* add_person_to_database (db, g_steal_pointer (&p));
|
||||
* ]|
|
||||
*
|
||||
* ## Thread safety
|
||||
*
|
||||
* The reference counting operations on data allocated using g_atomic_rc_box_alloc(),
|
||||
* g_atomic_rc_box_new(), and g_atomic_rc_box_dup() are guaranteed to be atomic, and thus
|
||||
* can be safely be performed by different threads. It is important to note that
|
||||
* only the reference acquisition and release are atomic; changes to the content
|
||||
* of the data are your responsibility.
|
||||
*
|
||||
* ## Automatic pointer clean up
|
||||
*
|
||||
* If you want to add g_autoptr() support to your plain old data type through
|
||||
* reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and
|
||||
* g_atomic_rc_box_release():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_atomic_rc_box_release)
|
||||
* ]|
|
||||
*
|
||||
* If you need to clear the contents of the data, you will need to use an
|
||||
* ancillary function that calls g_rc_box_release_full():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* static void
|
||||
* my_data_struct_release (MyDataStruct *data)
|
||||
* {
|
||||
* // my_data_struct_clear() is defined elsewhere
|
||||
* g_atomic_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
|
||||
* }
|
||||
*
|
||||
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
|
||||
* ]|
|
||||
*
|
||||
* Since: 2.58
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_atomic_rc_box_alloc:
|
||||
* @block_size: the size of the allocation, must be greater than 0
|
||||
|
@ -56,105 +56,6 @@
|
||||
|
||||
#include "glibintl.h"
|
||||
|
||||
/**
|
||||
* SECTION:conversions
|
||||
* @title: Character Set Conversion
|
||||
* @short_description: convert strings between different character sets
|
||||
*
|
||||
* The g_convert() family of function wraps the functionality of iconv().
|
||||
* In addition to pure character set conversions, GLib has functions to
|
||||
* deal with the extra complications of encodings for file names.
|
||||
*
|
||||
* ## File Name Encodings
|
||||
*
|
||||
* Historically, UNIX has not had a defined encoding for file names:
|
||||
* a file name is valid as long as it does not have path separators
|
||||
* in it ("/"). However, displaying file names may require conversion:
|
||||
* from the character set in which they were created, to the character
|
||||
* set in which the application operates. Consider the Spanish file name
|
||||
* "Presentación.sxi". If the application which created it uses
|
||||
* ISO-8859-1 for its encoding,
|
||||
* |[
|
||||
* Character: P r e s e n t a c i ó n . s x i
|
||||
* Hex code: 50 72 65 73 65 6e 74 61 63 69 f3 6e 2e 73 78 69
|
||||
* ]|
|
||||
* However, if the application use UTF-8, the actual file name on
|
||||
* disk would look like this:
|
||||
* |[
|
||||
* Character: P r e s e n t a c i ó n . s x i
|
||||
* Hex code: 50 72 65 73 65 6e 74 61 63 69 c3 b3 6e 2e 73 78 69
|
||||
* ]|
|
||||
* GLib uses UTF-8 for its strings, and GUI toolkits like GTK that use
|
||||
* GLib do the same thing. If you get a file name from the file system,
|
||||
* for example, from readdir() or from g_dir_read_name(), and you wish
|
||||
* to display the file name to the user, you will need to convert it
|
||||
* into UTF-8. The opposite case is when the user types the name of a
|
||||
* file they wish to save: the toolkit will give you that string in
|
||||
* UTF-8 encoding, and you will need to convert it to the character
|
||||
* set used for file names before you can create the file with open()
|
||||
* or fopen().
|
||||
*
|
||||
* By default, GLib assumes that file names on disk are in UTF-8
|
||||
* encoding. This is a valid assumption for file systems which
|
||||
* were created relatively recently: most applications use UTF-8
|
||||
* encoding for their strings, and that is also what they use for
|
||||
* the file names they create. However, older file systems may
|
||||
* still contain file names created in "older" encodings, such as
|
||||
* ISO-8859-1. In this case, for compatibility reasons, you may want
|
||||
* to instruct GLib to use that particular encoding for file names
|
||||
* rather than UTF-8. You can do this by specifying the encoding for
|
||||
* file names in the [`G_FILENAME_ENCODING`][G_FILENAME_ENCODING]
|
||||
* environment variable. For example, if your installation uses
|
||||
* ISO-8859-1 for file names, you can put this in your `~/.profile`:
|
||||
* |[
|
||||
* export G_FILENAME_ENCODING=ISO-8859-1
|
||||
* ]|
|
||||
* GLib provides the functions g_filename_to_utf8() and
|
||||
* g_filename_from_utf8() to perform the necessary conversions.
|
||||
* These functions convert file names from the encoding specified
|
||||
* in `G_FILENAME_ENCODING` to UTF-8 and vice-versa. This
|
||||
* [diagram][file-name-encodings-diagram] illustrates how
|
||||
* these functions are used to convert between UTF-8 and the
|
||||
* encoding for file names in the file system.
|
||||
*
|
||||
* ## Conversion between file name encodings # {#file-name-encodings-diagram)
|
||||
*
|
||||
* ![](file-name-encodings.png)
|
||||
*
|
||||
* ## Checklist for Application Writers
|
||||
*
|
||||
* This section is a practical summary of the detailed
|
||||
* things to do to make sure your applications process file
|
||||
* name encodings correctly.
|
||||
*
|
||||
* 1. If you get a file name from the file system from a function
|
||||
* such as readdir() or gtk_file_chooser_get_filename(), you do
|
||||
* not need to do any conversion to pass that file name to
|
||||
* functions like open(), rename(), or fopen() -- those are "raw"
|
||||
* file names which the file system understands.
|
||||
*
|
||||
* 2. If you need to display a file name, convert it to UTF-8 first
|
||||
* by using g_filename_to_utf8(). If conversion fails, display a
|
||||
* string like "Unknown file name". Do not convert this string back
|
||||
* into the encoding used for file names if you wish to pass it to
|
||||
* the file system; use the original file name instead.
|
||||
*
|
||||
* For example, the document window of a word processor could display
|
||||
* "Unknown file name" in its title bar but still let the user save
|
||||
* the file, as it would keep the raw file name internally. This
|
||||
* can happen if the user has not set the `G_FILENAME_ENCODING`
|
||||
* environment variable even though they have files whose names are
|
||||
* not encoded in UTF-8.
|
||||
*
|
||||
* 3. If your user interface lets the user type a file name for saving
|
||||
* or renaming, convert it to the encoding used for file names in
|
||||
* the file system by using g_filename_from_utf8(). Pass the converted
|
||||
* file name to functions like fopen(). If conversion fails, ask the
|
||||
* user to enter a different file name. This can happen if the user
|
||||
* types Japanese characters when `G_FILENAME_ENCODING` is set to
|
||||
* `ISO-8859-1`, for example.
|
||||
*/
|
||||
|
||||
/* We try to terminate strings in unknown charsets with this many zero bytes
|
||||
* to ensure that multibyte strings really are nul-terminated when we return
|
||||
* them from g_convert() and friends.
|
||||
|
475
glib/gerror.c
475
glib/gerror.c
@ -24,481 +24,6 @@
|
||||
* GLib at ftp://ftp.gtk.org/pub/gtk/.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:error_reporting
|
||||
* @Title: Error Reporting
|
||||
* @Short_description: a system for reporting errors
|
||||
*
|
||||
* GLib provides a standard method of reporting errors from a called
|
||||
* function to the calling code. (This is the same problem solved by
|
||||
* exceptions in other languages.) It's important to understand that
|
||||
* this method is both a data type (the #GError struct) and a [set of
|
||||
* rules][gerror-rules]. If you use #GError incorrectly, then your code will not
|
||||
* properly interoperate with other code that uses #GError, and users
|
||||
* of your API will probably get confused. In most cases, [using #GError is
|
||||
* preferred over numeric error codes][gerror-comparison], but there are
|
||||
* situations where numeric error codes are useful for performance.
|
||||
*
|
||||
* First and foremost: #GError should only be used to report recoverable
|
||||
* runtime errors, never to report programming errors. If the programmer
|
||||
* has screwed up, then you should use g_warning(), g_return_if_fail(),
|
||||
* g_assert(), g_error(), or some similar facility. (Incidentally,
|
||||
* remember that the g_error() function should only be used for
|
||||
* programming errors, it should not be used to print any error
|
||||
* reportable via #GError.)
|
||||
*
|
||||
* Examples of recoverable runtime errors are "file not found" or
|
||||
* "failed to parse input." Examples of programming errors are "NULL
|
||||
* passed to strcmp()" or "attempted to free the same pointer twice."
|
||||
* These two kinds of errors are fundamentally different: runtime errors
|
||||
* should be handled or reported to the user, programming errors should
|
||||
* be eliminated by fixing the bug in the program. This is why most
|
||||
* functions in GLib and GTK do not use the #GError facility.
|
||||
*
|
||||
* Functions that can fail take a return location for a #GError as their
|
||||
* last argument. On error, a new #GError instance will be allocated and
|
||||
* returned to the caller via this argument. For example:
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean g_file_get_contents (const gchar *filename,
|
||||
* gchar **contents,
|
||||
* gsize *length,
|
||||
* GError **error);
|
||||
* ]|
|
||||
* If you pass a non-%NULL value for the `error` argument, it should
|
||||
* point to a location where an error can be placed. For example:
|
||||
* |[<!-- language="C" -->
|
||||
* gchar *contents;
|
||||
* GError *err = NULL;
|
||||
*
|
||||
* g_file_get_contents ("foo.txt", &contents, NULL, &err);
|
||||
* g_assert ((contents == NULL && err != NULL) || (contents != NULL && err == NULL));
|
||||
* if (err != NULL)
|
||||
* {
|
||||
* // Report error to user, and free error
|
||||
* g_assert (contents == NULL);
|
||||
* fprintf (stderr, "Unable to read file: %s\n", err->message);
|
||||
* g_error_free (err);
|
||||
* }
|
||||
* else
|
||||
* {
|
||||
* // Use file contents
|
||||
* g_assert (contents != NULL);
|
||||
* }
|
||||
* ]|
|
||||
* Note that `err != NULL` in this example is a reliable indicator
|
||||
* of whether g_file_get_contents() failed. Additionally,
|
||||
* g_file_get_contents() returns a boolean which
|
||||
* indicates whether it was successful.
|
||||
*
|
||||
* Because g_file_get_contents() returns %FALSE on failure, if you
|
||||
* are only interested in whether it failed and don't need to display
|
||||
* an error message, you can pass %NULL for the @error argument:
|
||||
* |[<!-- language="C" -->
|
||||
* if (g_file_get_contents ("foo.txt", &contents, NULL, NULL)) // ignore errors
|
||||
* // no error occurred
|
||||
* ;
|
||||
* else
|
||||
* // error
|
||||
* ;
|
||||
* ]|
|
||||
*
|
||||
* The #GError object contains three fields: @domain indicates the module
|
||||
* the error-reporting function is located in, @code indicates the specific
|
||||
* error that occurred, and @message is a user-readable error message with
|
||||
* as many details as possible. Several functions are provided to deal
|
||||
* with an error received from a called function: g_error_matches()
|
||||
* returns %TRUE if the error matches a given domain and code,
|
||||
* g_propagate_error() copies an error into an error location (so the
|
||||
* calling function will receive it), and g_clear_error() clears an
|
||||
* error location by freeing the error and resetting the location to
|
||||
* %NULL. To display an error to the user, simply display the @message,
|
||||
* perhaps along with additional context known only to the calling
|
||||
* function (the file being opened, or whatever - though in the
|
||||
* g_file_get_contents() case, the @message already contains a filename).
|
||||
*
|
||||
* Since error messages may be displayed to the user, they need to be valid
|
||||
* UTF-8 (all GTK widgets expect text to be UTF-8). Keep this in mind in
|
||||
* particular when formatting error messages with filenames, which are in
|
||||
* the 'filename encoding', and need to be turned into UTF-8 using
|
||||
* g_filename_to_utf8(), g_filename_display_name() or g_utf8_make_valid().
|
||||
*
|
||||
* Note, however, that many error messages are too technical to display to the
|
||||
* user in an application, so prefer to use g_error_matches() to categorize errors
|
||||
* from called functions, and build an appropriate error message for the context
|
||||
* within your application. Error messages from a #GError are more appropriate
|
||||
* to be printed in system logs or on the command line. They are typically
|
||||
* translated.
|
||||
*
|
||||
* When implementing a function that can report errors, the basic
|
||||
* tool is g_set_error(). Typically, if a fatal error occurs you
|
||||
* want to g_set_error(), then return immediately. g_set_error()
|
||||
* does nothing if the error location passed to it is %NULL.
|
||||
* Here's an example:
|
||||
* |[<!-- language="C" -->
|
||||
* gint
|
||||
* foo_open_file (GError **error)
|
||||
* {
|
||||
* gint fd;
|
||||
* int saved_errno;
|
||||
*
|
||||
* g_return_val_if_fail (error == NULL || *error == NULL, -1);
|
||||
*
|
||||
* fd = open ("file.txt", O_RDONLY);
|
||||
* saved_errno = errno;
|
||||
*
|
||||
* if (fd < 0)
|
||||
* {
|
||||
* g_set_error (error,
|
||||
* FOO_ERROR, // error domain
|
||||
* FOO_ERROR_BLAH, // error code
|
||||
* "Failed to open file: %s", // error message format string
|
||||
* g_strerror (saved_errno));
|
||||
* return -1;
|
||||
* }
|
||||
* else
|
||||
* return fd;
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Things are somewhat more complicated if you yourself call another
|
||||
* function that can report a #GError. If the sub-function indicates
|
||||
* fatal errors in some way other than reporting a #GError, such as
|
||||
* by returning %TRUE on success, you can simply do the following:
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean
|
||||
* my_function_that_can_fail (GError **err)
|
||||
* {
|
||||
* g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
*
|
||||
* if (!sub_function_that_can_fail (err))
|
||||
* {
|
||||
* // assert that error was set by the sub-function
|
||||
* g_assert (err == NULL || *err != NULL);
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* // otherwise continue, no error occurred
|
||||
* g_assert (err == NULL || *err == NULL);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* If the sub-function does not indicate errors other than by
|
||||
* reporting a #GError (or if its return value does not reliably indicate
|
||||
* errors) you need to create a temporary #GError
|
||||
* since the passed-in one may be %NULL. g_propagate_error() is
|
||||
* intended for use in this case.
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean
|
||||
* my_function_that_can_fail (GError **err)
|
||||
* {
|
||||
* GError *tmp_error;
|
||||
*
|
||||
* g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
*
|
||||
* tmp_error = NULL;
|
||||
* sub_function_that_can_fail (&tmp_error);
|
||||
*
|
||||
* if (tmp_error != NULL)
|
||||
* {
|
||||
* // store tmp_error in err, if err != NULL,
|
||||
* // otherwise call g_error_free() on tmp_error
|
||||
* g_propagate_error (err, tmp_error);
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* // otherwise continue, no error occurred
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Error pileups are always a bug. For example, this code is incorrect:
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean
|
||||
* my_function_that_can_fail (GError **err)
|
||||
* {
|
||||
* GError *tmp_error;
|
||||
*
|
||||
* g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
*
|
||||
* tmp_error = NULL;
|
||||
* sub_function_that_can_fail (&tmp_error);
|
||||
* other_function_that_can_fail (&tmp_error);
|
||||
*
|
||||
* if (tmp_error != NULL)
|
||||
* {
|
||||
* g_propagate_error (err, tmp_error);
|
||||
* return FALSE;
|
||||
* }
|
||||
* }
|
||||
* ]|
|
||||
* @tmp_error should be checked immediately after sub_function_that_can_fail(),
|
||||
* and either cleared or propagated upward. The rule is: after each error,
|
||||
* you must either handle the error, or return it to the calling function.
|
||||
*
|
||||
* Note that passing %NULL for the error location is the equivalent
|
||||
* of handling an error by always doing nothing about it. So the
|
||||
* following code is fine, assuming errors in sub_function_that_can_fail()
|
||||
* are not fatal to my_function_that_can_fail():
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean
|
||||
* my_function_that_can_fail (GError **err)
|
||||
* {
|
||||
* GError *tmp_error;
|
||||
*
|
||||
* g_return_val_if_fail (err == NULL || *err == NULL, FALSE);
|
||||
*
|
||||
* sub_function_that_can_fail (NULL); // ignore errors
|
||||
*
|
||||
* tmp_error = NULL;
|
||||
* other_function_that_can_fail (&tmp_error);
|
||||
*
|
||||
* if (tmp_error != NULL)
|
||||
* {
|
||||
* g_propagate_error (err, tmp_error);
|
||||
* return FALSE;
|
||||
* }
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Note that passing %NULL for the error location ignores errors;
|
||||
* it's equivalent to
|
||||
* `try { sub_function_that_can_fail (); } catch (...) {}`
|
||||
* in C++. It does not mean to leave errors unhandled; it means
|
||||
* to handle them by doing nothing.
|
||||
*
|
||||
* Error domains and codes are conventionally named as follows:
|
||||
*
|
||||
* - The error domain is called <NAMESPACE>_<MODULE>_ERROR,
|
||||
* for example %G_SPAWN_ERROR or %G_THREAD_ERROR:
|
||||
* |[<!-- language="C" -->
|
||||
* #define G_SPAWN_ERROR g_spawn_error_quark ()
|
||||
*
|
||||
* G_DEFINE_QUARK (g-spawn-error-quark, g_spawn_error)
|
||||
* ]|
|
||||
*
|
||||
* - The quark function for the error domain is called
|
||||
* <namespace>_<module>_error_quark,
|
||||
* for example g_spawn_error_quark() or g_thread_error_quark().
|
||||
*
|
||||
* - The error codes are in an enumeration called
|
||||
* <Namespace><Module>Error;
|
||||
* for example, #GThreadError or #GSpawnError.
|
||||
*
|
||||
* - Members of the error code enumeration are called
|
||||
* <NAMESPACE>_<MODULE>_ERROR_<CODE>,
|
||||
* for example %G_SPAWN_ERROR_FORK or %G_THREAD_ERROR_AGAIN.
|
||||
*
|
||||
* - If there's a "generic" or "unknown" error code for unrecoverable
|
||||
* errors it doesn't make sense to distinguish with specific codes,
|
||||
* it should be called <NAMESPACE>_<MODULE>_ERROR_FAILED,
|
||||
* for example %G_SPAWN_ERROR_FAILED. In the case of error code
|
||||
* enumerations that may be extended in future releases, you should
|
||||
* generally not handle this error code explicitly, but should
|
||||
* instead treat any unrecognized error code as equivalent to
|
||||
* FAILED.
|
||||
*
|
||||
* ## Comparison of #GError and traditional error handling # {#gerror-comparison}
|
||||
*
|
||||
* #GError has several advantages over traditional numeric error codes:
|
||||
* importantly, tools like
|
||||
* [gobject-introspection](https://developer.gnome.org/gi/stable/) understand
|
||||
* #GErrors and convert them to exceptions in bindings; the message includes
|
||||
* more information than just a code; and use of a domain helps prevent
|
||||
* misinterpretation of error codes.
|
||||
*
|
||||
* #GError has disadvantages though: it requires a memory allocation, and
|
||||
* formatting the error message string has a performance overhead. This makes it
|
||||
* unsuitable for use in retry loops where errors are a common case, rather than
|
||||
* being unusual. For example, using %G_IO_ERROR_WOULD_BLOCK means hitting these
|
||||
* overheads in the normal control flow. String formatting overhead can be
|
||||
* eliminated by using g_set_error_literal() in some cases.
|
||||
*
|
||||
* These performance issues can be compounded if a function wraps the #GErrors
|
||||
* returned by the functions it calls: this multiplies the number of allocations
|
||||
* and string formatting operations. This can be partially mitigated by using
|
||||
* g_prefix_error().
|
||||
*
|
||||
* ## Rules for use of #GError # {#gerror-rules}
|
||||
*
|
||||
* Summary of rules for use of #GError:
|
||||
*
|
||||
* - Do not report programming errors via #GError.
|
||||
*
|
||||
* - The last argument of a function that returns an error should
|
||||
* be a location where a #GError can be placed (i.e. `GError **error`).
|
||||
* If #GError is used with varargs, the `GError**` should be the last
|
||||
* argument before the `...`.
|
||||
*
|
||||
* - The caller may pass %NULL for the `GError**` if they are not interested
|
||||
* in details of the exact error that occurred.
|
||||
*
|
||||
* - If %NULL is passed for the `GError**` argument, then errors should
|
||||
* not be returned to the caller, but your function should still
|
||||
* abort and return if an error occurs. That is, control flow should
|
||||
* not be affected by whether the caller wants to get a #GError.
|
||||
*
|
||||
* - If a #GError is reported, then your function by definition had a
|
||||
* fatal failure and did not complete whatever it was supposed to do.
|
||||
* If the failure was not fatal, then you handled it and you should not
|
||||
* report it. If it was fatal, then you must report it and discontinue
|
||||
* whatever you were doing immediately.
|
||||
*
|
||||
* - If a #GError is reported, out parameters are not guaranteed to
|
||||
* be set to any defined value.
|
||||
*
|
||||
* - A `GError*` must be initialized to %NULL before passing its address
|
||||
* to a function that can report errors.
|
||||
*
|
||||
* - #GError structs must not be stack-allocated.
|
||||
*
|
||||
* - "Piling up" errors is always a bug. That is, if you assign a
|
||||
* new #GError to a `GError*` that is non-%NULL, thus overwriting
|
||||
* the previous error, it indicates that you should have aborted
|
||||
* the operation instead of continuing. If you were able to continue,
|
||||
* you should have cleared the previous error with g_clear_error().
|
||||
* g_set_error() will complain if you pile up errors.
|
||||
*
|
||||
* - By convention, if you return a boolean value indicating success
|
||||
* then %TRUE means success and %FALSE means failure. Avoid creating
|
||||
* functions which have a boolean return value and a #GError parameter,
|
||||
* but where the boolean does something other than signal whether the
|
||||
* #GError is set. Among other problems, it requires C callers to allocate
|
||||
* a temporary error. Instead, provide a `gboolean *` out parameter.
|
||||
* There are functions in GLib itself such as g_key_file_has_key() that
|
||||
* are hard to use because of this. If %FALSE is returned, the error must
|
||||
* be set to a non-%NULL value. One exception to this is that in situations
|
||||
* that are already considered to be undefined behaviour (such as when a
|
||||
* g_return_val_if_fail() check fails), the error need not be set.
|
||||
* Instead of checking separately whether the error is set, callers
|
||||
* should ensure that they do not provoke undefined behaviour, then
|
||||
* assume that the error will be set on failure.
|
||||
*
|
||||
* - A %NULL return value is also frequently used to mean that an error
|
||||
* occurred. You should make clear in your documentation whether %NULL
|
||||
* is a valid return value in non-error cases; if %NULL is a valid value,
|
||||
* then users must check whether an error was returned to see if the
|
||||
* function succeeded.
|
||||
*
|
||||
* - When implementing a function that can report errors, you may want
|
||||
* to add a check at the top of your function that the error return
|
||||
* location is either %NULL or contains a %NULL error (e.g.
|
||||
* `g_return_if_fail (error == NULL || *error == NULL);`).
|
||||
*
|
||||
* ## Extended #GError Domains # {#gerror-extended-domains}
|
||||
*
|
||||
* Since GLib 2.68 it is possible to extend the #GError type. This is
|
||||
* done with the G_DEFINE_EXTENDED_ERROR() macro. To create an
|
||||
* extended #GError type do something like this in the header file:
|
||||
* |[<!-- language="C" -->
|
||||
* typedef enum
|
||||
* {
|
||||
* MY_ERROR_BAD_REQUEST,
|
||||
* } MyError;
|
||||
* #define MY_ERROR (my_error_quark ())
|
||||
* GQuark my_error_quark (void);
|
||||
* int
|
||||
* my_error_get_parse_error_id (GError *error);
|
||||
* const char *
|
||||
* my_error_get_bad_request_details (GError *error);
|
||||
* ]|
|
||||
* and in implementation:
|
||||
* |[<!-- language="C" -->
|
||||
* typedef struct
|
||||
* {
|
||||
* int parse_error_id;
|
||||
* char *bad_request_details;
|
||||
* } MyErrorPrivate;
|
||||
*
|
||||
* static void
|
||||
* my_error_private_init (MyErrorPrivate *priv)
|
||||
* {
|
||||
* priv->parse_error_id = -1;
|
||||
* // No need to set priv->bad_request_details to NULL,
|
||||
* // the struct is initialized with zeros.
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_error_private_copy (const MyErrorPrivate *src_priv, MyErrorPrivate *dest_priv)
|
||||
* {
|
||||
* dest_priv->parse_error_id = src_priv->parse_error_id;
|
||||
* dest_priv->bad_request_details = g_strdup (src_priv->bad_request_details);
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_error_private_clear (MyErrorPrivate *priv)
|
||||
* {
|
||||
* g_free (priv->bad_request_details);
|
||||
* }
|
||||
*
|
||||
* // This defines the my_error_get_private and my_error_quark functions.
|
||||
* G_DEFINE_EXTENDED_ERROR (MyError, my_error)
|
||||
*
|
||||
* int
|
||||
* my_error_get_parse_error_id (GError *error)
|
||||
* {
|
||||
* MyErrorPrivate *priv = my_error_get_private (error);
|
||||
* g_return_val_if_fail (priv != NULL, -1);
|
||||
* return priv->parse_error_id;
|
||||
* }
|
||||
*
|
||||
* const char *
|
||||
* my_error_get_bad_request_details (GError *error)
|
||||
* {
|
||||
* MyErrorPrivate *priv = my_error_get_private (error);
|
||||
* g_return_val_if_fail (priv != NULL, NULL);
|
||||
* g_return_val_if_fail (error->code != MY_ERROR_BAD_REQUEST, NULL);
|
||||
* return priv->bad_request_details;
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_error_set_bad_request (GError **error,
|
||||
* const char *reason,
|
||||
* int error_id,
|
||||
* const char *details)
|
||||
* {
|
||||
* MyErrorPrivate *priv;
|
||||
* g_set_error (error, MY_ERROR, MY_ERROR_BAD_REQUEST, "Invalid request: %s", reason);
|
||||
* if (error != NULL && *error != NULL)
|
||||
* {
|
||||
* priv = my_error_get_private (error);
|
||||
* g_return_val_if_fail (priv != NULL, NULL);
|
||||
* priv->parse_error_id = error_id;
|
||||
* priv->bad_request_details = g_strdup (details);
|
||||
* }
|
||||
* }
|
||||
* ]|
|
||||
* An example of use of the error could be:
|
||||
* |[<!-- language="C" -->
|
||||
* gboolean
|
||||
* send_request (GBytes *request, GError **error)
|
||||
* {
|
||||
* ParseFailedStatus *failure = validate_request (request);
|
||||
* if (failure != NULL)
|
||||
* {
|
||||
* my_error_set_bad_request (error, failure->reason, failure->error_id, failure->details);
|
||||
* parse_failed_status_free (failure);
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* return send_one (request, error);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Please note that if you are a library author and your library
|
||||
* exposes an existing error domain, then you can't make this error
|
||||
* domain an extended one without breaking ABI. This is because
|
||||
* earlier it was possible to create an error with this error domain
|
||||
* on the stack and then copy it with g_error_copy(). If the new
|
||||
* version of your library makes the error domain an extended one,
|
||||
* then g_error_copy() called by code that allocated the error on the
|
||||
* stack will try to copy more data than it used to, which will lead
|
||||
* to undefined behavior. You must not stack-allocate errors with an
|
||||
* extended error domain, and it is bad practice to stack-allocate any
|
||||
* other #GErrors.
|
||||
*
|
||||
* Extended error domains in unloadable plugins/modules are not
|
||||
* supported.
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "gvalgrind.h"
|
||||
|
@ -462,57 +462,6 @@ g_dngettext (const gchar *domain,
|
||||
return dngettext (domain, msgid, msgid_plural, n);
|
||||
}
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:i18n
|
||||
* @title: Internationalization
|
||||
* @short_description: gettext support macros
|
||||
* @see_also: the gettext manual
|
||||
*
|
||||
* GLib doesn't force any particular localization method upon its users.
|
||||
* But since GLib itself is localized using the gettext() mechanism, it seems
|
||||
* natural to offer the de-facto standard gettext() support macros in an
|
||||
* easy-to-use form.
|
||||
*
|
||||
* In order to use these macros in an application, you must include
|
||||
* `<glib/gi18n.h>`. For use in a library, you must include
|
||||
* `<glib/gi18n-lib.h>`
|
||||
* after defining the %GETTEXT_PACKAGE macro suitably for your library:
|
||||
* |[<!-- language="C" -->
|
||||
* #define GETTEXT_PACKAGE "gtk20"
|
||||
* #include <glib/gi18n-lib.h>
|
||||
* ]|
|
||||
* For an application, note that you also have to call bindtextdomain(),
|
||||
* bind_textdomain_codeset(), textdomain() and setlocale() early on in your
|
||||
* main() to make gettext() work. For example:
|
||||
* |[<!-- language="C" -->
|
||||
* #include <glib/gi18n.h>
|
||||
* #include <locale.h>
|
||||
*
|
||||
* int
|
||||
* main (int argc, char **argv)
|
||||
* {
|
||||
* setlocale (LC_ALL, "");
|
||||
* bindtextdomain (GETTEXT_PACKAGE, DATADIR "/locale");
|
||||
* bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
|
||||
* textdomain (GETTEXT_PACKAGE);
|
||||
*
|
||||
* // Rest of your application.
|
||||
* }
|
||||
* ]|
|
||||
* where `DATADIR` is as typically provided by automake or Meson.
|
||||
*
|
||||
* For a library, you only have to call bindtextdomain() and
|
||||
* bind_textdomain_codeset() in your initialization function. If your library
|
||||
* doesn't have an initialization function, you can call the functions before
|
||||
* the first translated message.
|
||||
*
|
||||
* The
|
||||
* [gettext manual](http://www.gnu.org/software/gettext/manual/gettext.html#Maintainers)
|
||||
* covers details of how to integrate gettext into a project’s build system and
|
||||
* workflow.
|
||||
*/
|
||||
|
||||
/**
|
||||
* _:
|
||||
* @String: the string to be translated
|
||||
|
128
glib/gmain.c
128
glib/gmain.c
@ -127,134 +127,6 @@
|
||||
#include "glib-init.h"
|
||||
#include "glib-private.h"
|
||||
|
||||
/**
|
||||
* SECTION:main
|
||||
* @title: The Main Event Loop
|
||||
* @short_description: manages all available sources of events
|
||||
*
|
||||
* The main event loop manages all the available sources of events for
|
||||
* GLib and GTK applications. These events can come from any number of
|
||||
* different types of sources such as file descriptors (plain files,
|
||||
* pipes or sockets) and timeouts. New types of event sources can also
|
||||
* be added using g_source_attach().
|
||||
*
|
||||
* To allow multiple independent sets of sources to be handled in
|
||||
* different threads, each source is associated with a #GMainContext.
|
||||
* A #GMainContext can only be running in a single thread, but
|
||||
* sources can be added to it and removed from it from other threads. All
|
||||
* functions which operate on a #GMainContext or a built-in #GSource are
|
||||
* thread-safe.
|
||||
*
|
||||
* Each event source is assigned a priority. The default priority,
|
||||
* %G_PRIORITY_DEFAULT, is 0. Values less than 0 denote higher priorities.
|
||||
* Values greater than 0 denote lower priorities. Events from high priority
|
||||
* sources are always processed before events from lower priority sources: if
|
||||
* several sources are ready to dispatch, the ones with equal-highest priority
|
||||
* will be dispatched on the current #GMainContext iteration, and the rest wait
|
||||
* until a subsequent #GMainContext iteration when they have the highest
|
||||
* priority of the sources which are ready for dispatch.
|
||||
*
|
||||
* Idle functions can also be added, and assigned a priority. These will
|
||||
* be run whenever no events with a higher priority are ready to be dispatched.
|
||||
*
|
||||
* The #GMainLoop data type represents a main event loop. A GMainLoop is
|
||||
* created with g_main_loop_new(). After adding the initial event sources,
|
||||
* g_main_loop_run() is called. This continuously checks for new events from
|
||||
* each of the event sources and dispatches them. Finally, the processing of
|
||||
* an event from one of the sources leads to a call to g_main_loop_quit() to
|
||||
* exit the main loop, and g_main_loop_run() returns.
|
||||
*
|
||||
* It is possible to create new instances of #GMainLoop recursively.
|
||||
* This is often used in GTK applications when showing modal dialog
|
||||
* boxes. Note that event sources are associated with a particular
|
||||
* #GMainContext, and will be checked and dispatched for all main
|
||||
* loops associated with that GMainContext.
|
||||
*
|
||||
* GTK contains wrappers of some of these functions, e.g. gtk_main(),
|
||||
* gtk_main_quit() and gtk_events_pending().
|
||||
*
|
||||
* ## Creating new source types
|
||||
*
|
||||
* One of the unusual features of the #GMainLoop functionality
|
||||
* is that new types of event source can be created and used in
|
||||
* addition to the builtin type of event source. A new event source
|
||||
* type is used for handling GDK events. A new source type is created
|
||||
* by "deriving" from the #GSource structure. The derived type of
|
||||
* source is represented by a structure that has the #GSource structure
|
||||
* as a first element, and other elements specific to the new source
|
||||
* type. To create an instance of the new source type, call
|
||||
* g_source_new() passing in the size of the derived structure and
|
||||
* a table of functions. These #GSourceFuncs determine the behavior of
|
||||
* the new source type.
|
||||
*
|
||||
* New source types basically interact with the main context
|
||||
* in two ways. Their prepare function in #GSourceFuncs can set a timeout
|
||||
* to determine the maximum amount of time that the main loop will sleep
|
||||
* before checking the source again. In addition, or as well, the source
|
||||
* can add file descriptors to the set that the main context checks using
|
||||
* g_source_add_poll().
|
||||
*
|
||||
* ## Customizing the main loop iteration
|
||||
*
|
||||
* Single iterations of a #GMainContext can be run with
|
||||
* g_main_context_iteration(). In some cases, more detailed control
|
||||
* of exactly how the details of the main loop work is desired, for
|
||||
* instance, when integrating the #GMainLoop with an external main loop.
|
||||
* In such cases, you can call the component functions of
|
||||
* g_main_context_iteration() directly. These functions are
|
||||
* g_main_context_prepare(), g_main_context_query(),
|
||||
* g_main_context_check() and g_main_context_dispatch().
|
||||
*
|
||||
* If the event loop thread releases #GMainContext ownership until the results
|
||||
* required by g_main_context_check() are ready you must create a context with
|
||||
* the flag %G_MAIN_CONTEXT_FLAGS_OWNERLESS_POLLING or else you'll lose
|
||||
* g_source_attach() notifications. This happens for instance when you integrate
|
||||
* the GLib event loop into implementations that follow the proactor pattern
|
||||
* (i.e. in these contexts the `poll()` implementation will reclaim the thread for
|
||||
* other tasks until the results are ready). One example of the proactor pattern
|
||||
* is the Boost.Asio library.
|
||||
*
|
||||
* ## State of a Main Context # {#mainloop-states}
|
||||
*
|
||||
* The operation of these functions can best be seen in terms
|
||||
* of a state diagram, as shown in this image.
|
||||
*
|
||||
* ![](mainloop-states.gif)
|
||||
*
|
||||
* On UNIX, the GLib mainloop is incompatible with fork(). Any program
|
||||
* using the mainloop must either exec() or exit() from the child
|
||||
* without returning to the mainloop.
|
||||
*
|
||||
* ## Memory management of sources # {#mainloop-memory-management}
|
||||
*
|
||||
* There are two options for memory management of the user data passed to a
|
||||
* #GSource to be passed to its callback on invocation. This data is provided
|
||||
* in calls to g_timeout_add(), g_timeout_add_full(), g_idle_add(), etc. and
|
||||
* more generally, using g_source_set_callback(). This data is typically an
|
||||
* object which ‘owns’ the timeout or idle callback, such as a widget or a
|
||||
* network protocol implementation. In many cases, it is an error for the
|
||||
* callback to be invoked after this owning object has been destroyed, as that
|
||||
* results in use of freed memory.
|
||||
*
|
||||
* The first, and preferred, option is to store the source ID returned by
|
||||
* functions such as g_timeout_add() or g_source_attach(), and explicitly
|
||||
* remove that source from the main context using g_source_remove() when the
|
||||
* owning object is finalized. This ensures that the callback can only be
|
||||
* invoked while the object is still alive.
|
||||
*
|
||||
* The second option is to hold a strong reference to the object in the
|
||||
* callback, and to release it in the callback’s #GDestroyNotify. This ensures
|
||||
* that the object is kept alive until after the source is finalized, which is
|
||||
* guaranteed to be after it is invoked for the final time. The #GDestroyNotify
|
||||
* is another callback passed to the ‘full’ variants of #GSource functions (for
|
||||
* example, g_timeout_add_full()). It is called when the source is finalized,
|
||||
* and is designed for releasing references like this.
|
||||
*
|
||||
* One important caveat of this second approach is that it will keep the object
|
||||
* alive indefinitely if the main loop is stopped before the #GSource is
|
||||
* invoked, which may be undesirable.
|
||||
*/
|
||||
|
||||
/* Types */
|
||||
|
||||
typedef struct _GIdleSource GIdleSource;
|
||||
|
@ -38,60 +38,6 @@
|
||||
#include "glibintl.h"
|
||||
#include "gthread.h"
|
||||
|
||||
/**
|
||||
* SECTION:markup
|
||||
* @Title: Simple XML Subset Parser
|
||||
* @Short_description: parses a subset of XML
|
||||
* @See_also: [XML Specification](http://www.w3.org/TR/REC-xml/)
|
||||
*
|
||||
* The "GMarkup" parser is intended to parse a simple markup format
|
||||
* that's a subset of XML. This is a small, efficient, easy-to-use
|
||||
* parser. It should not be used if you expect to interoperate with
|
||||
* other applications generating full-scale XML, and must not be used if you
|
||||
* expect to parse untrusted input. However, it's very
|
||||
* useful for application data files, config files, etc. where you
|
||||
* know your application will be the only one writing the file.
|
||||
* Full-scale XML parsers should be able to parse the subset used by
|
||||
* GMarkup, so you can easily migrate to full-scale XML at a later
|
||||
* time if the need arises.
|
||||
*
|
||||
* GMarkup is not guaranteed to signal an error on all invalid XML;
|
||||
* the parser may accept documents that an XML parser would not.
|
||||
* However, XML documents which are not well-formed (which is a
|
||||
* weaker condition than being valid. See the
|
||||
* [XML specification](http://www.w3.org/TR/REC-xml/)
|
||||
* for definitions of these terms.) are not considered valid GMarkup
|
||||
* documents.
|
||||
*
|
||||
* Simplifications to XML include:
|
||||
*
|
||||
* - Only UTF-8 encoding is allowed
|
||||
*
|
||||
* - No user-defined entities
|
||||
*
|
||||
* - Processing instructions, comments and the doctype declaration
|
||||
* are "passed through" but are not interpreted in any way
|
||||
*
|
||||
* - No DTD or validation
|
||||
*
|
||||
* The markup format does support:
|
||||
*
|
||||
* - Elements
|
||||
*
|
||||
* - Attributes
|
||||
*
|
||||
* - 5 standard entities: & < > " '
|
||||
*
|
||||
* - Character references
|
||||
*
|
||||
* - Sections marked as CDATA
|
||||
|
||||
* ## An example parser # {#example}
|
||||
*
|
||||
* Here is an example for a markup parser:
|
||||
* [markup-example.c](https://gitlab.gnome.org/GNOME/glib/-/blob/HEAD/glib/tests/markup-example.c)
|
||||
*/
|
||||
|
||||
G_DEFINE_QUARK (g-markup-error-quark, g_markup_error)
|
||||
|
||||
typedef enum
|
||||
|
140
glib/gmessages.c
140
glib/gmessages.c
@ -28,146 +28,6 @@
|
||||
* MT safe
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:messages
|
||||
* @Title: Message Output and Debugging Functions
|
||||
* @Short_description: functions to output messages and help debug applications
|
||||
*
|
||||
* These functions provide support for outputting messages.
|
||||
*
|
||||
* The g_return family of macros (g_return_if_fail(),
|
||||
* g_return_val_if_fail(), g_return_if_reached(),
|
||||
* g_return_val_if_reached()) should only be used for programming
|
||||
* errors, a typical use case is checking for invalid parameters at
|
||||
* the beginning of a public function. They should not be used if
|
||||
* you just mean "if (error) return", they should only be used if
|
||||
* you mean "if (bug in program) return". The program behavior is
|
||||
* generally considered undefined after one of these checks fails.
|
||||
* They are not intended for normal control flow, only to give a
|
||||
* perhaps-helpful warning before giving up.
|
||||
*
|
||||
* Structured logging output is supported using g_log_structured(). This differs
|
||||
* from the traditional g_log() API in that log messages are handled as a
|
||||
* collection of key–value pairs representing individual pieces of information,
|
||||
* rather than as a single string containing all the information in an arbitrary
|
||||
* format.
|
||||
*
|
||||
* The convenience macros g_info(), g_message(), g_debug(), g_warning() and g_error()
|
||||
* will use the traditional g_log() API unless you define the symbol
|
||||
* %G_LOG_USE_STRUCTURED before including `glib.h`. But note that even messages
|
||||
* logged through the traditional g_log() API are ultimatively passed to
|
||||
* g_log_structured(), so that all log messages end up in same destination.
|
||||
* If %G_LOG_USE_STRUCTURED is defined, g_test_expect_message() will become
|
||||
* ineffective for the wrapper macros g_warning() and friends (see
|
||||
* [Testing for Messages][testing-for-messages]).
|
||||
*
|
||||
* The support for structured logging was motivated by the following needs (some
|
||||
* of which were supported previously; others weren’t):
|
||||
* * Support for multiple logging levels.
|
||||
* * Structured log support with the ability to add `MESSAGE_ID`s (see
|
||||
* g_log_structured()).
|
||||
* * Moving the responsibility for filtering log messages from the program to
|
||||
* the log viewer — instead of libraries and programs installing log handlers
|
||||
* (with g_log_set_handler()) which filter messages before output, all log
|
||||
* messages are outputted, and the log viewer program (such as `journalctl`)
|
||||
* must filter them. This is based on the idea that bugs are sometimes hard
|
||||
* to reproduce, so it is better to log everything possible and then use
|
||||
* tools to analyse the logs than it is to not be able to reproduce a bug to
|
||||
* get additional log data. Code which uses logging in performance-critical
|
||||
* sections should compile out the g_log_structured() calls in
|
||||
* release builds, and compile them in in debugging builds.
|
||||
* * A single writer function which handles all log messages in a process, from
|
||||
* all libraries and program code; rather than multiple log handlers with
|
||||
* poorly defined interactions between them. This allows a program to easily
|
||||
* change its logging policy by changing the writer function, for example to
|
||||
* log to an additional location or to change what logging output fallbacks
|
||||
* are used. The log writer functions provided by GLib are exposed publicly
|
||||
* so they can be used from programs’ log writers. This allows log writer
|
||||
* policy and implementation to be kept separate.
|
||||
* * If a library wants to add standard information to all of its log messages
|
||||
* (such as library state) or to redact private data (such as passwords or
|
||||
* network credentials), it should use a wrapper function around its
|
||||
* g_log_structured() calls or implement that in the single log writer
|
||||
* function.
|
||||
* * If a program wants to pass context data from a g_log_structured() call to
|
||||
* its log writer function so that, for example, it can use the correct
|
||||
* server connection to submit logs to, that user data can be passed as a
|
||||
* zero-length #GLogField to g_log_structured_array().
|
||||
* * Color output needed to be supported on the terminal, to make reading
|
||||
* through logs easier.
|
||||
*
|
||||
* ## Using Structured Logging ## {#using-structured-logging}
|
||||
*
|
||||
* To use structured logging (rather than the old-style logging), either use
|
||||
* the g_log_structured() and g_log_structured_array() functions; or define
|
||||
* `G_LOG_USE_STRUCTURED` before including any GLib header, and use the
|
||||
* g_message(), g_debug(), g_error() (etc.) macros.
|
||||
*
|
||||
* You do not need to define `G_LOG_USE_STRUCTURED` to use g_log_structured(),
|
||||
* but it is a good idea to avoid confusion.
|
||||
*
|
||||
* ## Log Domains ## {#log-domains}
|
||||
*
|
||||
* Log domains may be used to broadly split up the origins of log messages.
|
||||
* Typically, there are one or a few log domains per application or library.
|
||||
* %G_LOG_DOMAIN should be used to define the default log domain for the current
|
||||
* compilation unit — it is typically defined at the top of a source file, or in
|
||||
* the preprocessor flags for a group of source files.
|
||||
*
|
||||
* Log domains must be unique, and it is recommended that they are the
|
||||
* application or library name, optionally followed by a hyphen and a sub-domain
|
||||
* name. For example, `bloatpad` or `bloatpad-io`.
|
||||
*
|
||||
* ## Debug Message Output ## {#debug-message-output}
|
||||
*
|
||||
* The default log functions (g_log_default_handler() for the old-style API and
|
||||
* g_log_writer_default() for the structured API) both drop debug and
|
||||
* informational messages by default, unless the log domains of those messages
|
||||
* are listed in the `G_MESSAGES_DEBUG` environment variable (or it is set to
|
||||
* `all`).
|
||||
*
|
||||
* It is recommended that custom log writer functions re-use the
|
||||
* `G_MESSAGES_DEBUG` environment variable, rather than inventing a custom one,
|
||||
* so that developers can re-use the same debugging techniques and tools across
|
||||
* projects. Since GLib 2.68, this can be implemented by dropping messages
|
||||
* for which g_log_writer_default_would_drop() returns %TRUE.
|
||||
*
|
||||
* ## Testing for Messages ## {#testing-for-messages}
|
||||
*
|
||||
* With the old g_log() API, g_test_expect_message() and
|
||||
* g_test_assert_expected_messages() could be used in simple cases to check
|
||||
* whether some code under test had emitted a given log message. These
|
||||
* functions have been deprecated with the structured logging API, for several
|
||||
* reasons:
|
||||
* * They relied on an internal queue which was too inflexible for many use
|
||||
* cases, where messages might be emitted in several orders, some
|
||||
* messages might not be emitted deterministically, or messages might be
|
||||
* emitted by unrelated log domains.
|
||||
* * They do not support structured log fields.
|
||||
* * Examining the log output of code is a bad approach to testing it, and
|
||||
* while it might be necessary for legacy code which uses g_log(), it should
|
||||
* be avoided for new code using g_log_structured().
|
||||
*
|
||||
* They will continue to work as before if g_log() is in use (and
|
||||
* %G_LOG_USE_STRUCTURED is not defined). They will do nothing if used with the
|
||||
* structured logging API.
|
||||
*
|
||||
* Examining the log output of code is discouraged: libraries should not emit to
|
||||
* `stderr` during defined behaviour, and hence this should not be tested. If
|
||||
* the log emissions of a library during undefined behaviour need to be tested,
|
||||
* they should be limited to asserting that the library aborts and prints a
|
||||
* suitable error message before aborting. This should be done with
|
||||
* g_test_trap_assert_stderr().
|
||||
*
|
||||
* If it is really necessary to test the structured log messages emitted by a
|
||||
* particular piece of code – and the code cannot be restructured to be more
|
||||
* suitable to more conventional unit testing – you should write a custom log
|
||||
* writer function (see g_log_set_writer_func()) which appends all log messages
|
||||
* to a queue. When you want to check the log messages, examine and clear the
|
||||
* queue, ignoring irrelevant log messages (for example, from log domains other
|
||||
* than the one under test).
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <stdlib.h>
|
||||
|
160
glib/goption.c
160
glib/goption.c
@ -19,166 +19,6 @@
|
||||
* along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:goptioncontext
|
||||
* @Short_description: parses commandline options
|
||||
* @Title: Commandline option parser
|
||||
*
|
||||
* The GOption commandline parser is intended to be a simpler replacement
|
||||
* for the popt library. It supports short and long commandline options,
|
||||
* as shown in the following example:
|
||||
*
|
||||
* `testtreemodel -r 1 --max-size 20 --rand --display=:1.0 -vb -- file1 file2`
|
||||
*
|
||||
* The example demonstrates a number of features of the GOption
|
||||
* commandline parser:
|
||||
*
|
||||
* - Options can be single letters, prefixed by a single dash.
|
||||
*
|
||||
* - Multiple short options can be grouped behind a single dash.
|
||||
*
|
||||
* - Long options are prefixed by two consecutive dashes.
|
||||
*
|
||||
* - Options can have an extra argument, which can be a number, a string or
|
||||
* a filename. For long options, the extra argument can be appended with
|
||||
* an equals sign after the option name, which is useful if the extra
|
||||
* argument starts with a dash, which would otherwise cause it to be
|
||||
* interpreted as another option.
|
||||
*
|
||||
* - Non-option arguments are returned to the application as rest arguments.
|
||||
*
|
||||
* - An argument consisting solely of two dashes turns off further parsing,
|
||||
* any remaining arguments (even those starting with a dash) are returned
|
||||
* to the application as rest arguments.
|
||||
*
|
||||
* Another important feature of GOption is that it can automatically
|
||||
* generate nicely formatted help output. Unless it is explicitly turned
|
||||
* off with g_option_context_set_help_enabled(), GOption will recognize
|
||||
* the `--help`, `-?`, `--help-all` and `--help-groupname` options
|
||||
* (where `groupname` is the name of a #GOptionGroup) and write a text
|
||||
* similar to the one shown in the following example to stdout.
|
||||
*
|
||||
* |[
|
||||
* Usage:
|
||||
* testtreemodel [OPTION...] - test tree model performance
|
||||
*
|
||||
* Help Options:
|
||||
* -h, --help Show help options
|
||||
* --help-all Show all help options
|
||||
* --help-gtk Show GTK Options
|
||||
*
|
||||
* Application Options:
|
||||
* -r, --repeats=N Average over N repetitions
|
||||
* -m, --max-size=M Test up to 2^M items
|
||||
* --display=DISPLAY X display to use
|
||||
* -v, --verbose Be verbose
|
||||
* -b, --beep Beep when done
|
||||
* --rand Randomize the data
|
||||
* ]|
|
||||
*
|
||||
* GOption groups options in #GOptionGroups, which makes it easy to
|
||||
* incorporate options from multiple sources. The intended use for this is
|
||||
* to let applications collect option groups from the libraries it uses,
|
||||
* add them to their #GOptionContext, and parse all options by a single call
|
||||
* to g_option_context_parse(). See gtk_get_option_group() for an example.
|
||||
*
|
||||
* If an option is declared to be of type string or filename, GOption takes
|
||||
* care of converting it to the right encoding; strings are returned in
|
||||
* UTF-8, filenames are returned in the GLib filename encoding. Note that
|
||||
* this only works if setlocale() has been called before
|
||||
* g_option_context_parse().
|
||||
*
|
||||
* Here is a complete example of setting up GOption to parse the example
|
||||
* commandline above and produce the example help output.
|
||||
* |[<!-- language="C" -->
|
||||
* static gint repeats = 2;
|
||||
* static gint max_size = 8;
|
||||
* static gboolean verbose = FALSE;
|
||||
* static gboolean beep = FALSE;
|
||||
* static gboolean randomize = FALSE;
|
||||
*
|
||||
* static GOptionEntry entries[] =
|
||||
* {
|
||||
* { "repeats", 'r', 0, G_OPTION_ARG_INT, &repeats, "Average over N repetitions", "N" },
|
||||
* { "max-size", 'm', 0, G_OPTION_ARG_INT, &max_size, "Test up to 2^M items", "M" },
|
||||
* { "verbose", 'v', 0, G_OPTION_ARG_NONE, &verbose, "Be verbose", NULL },
|
||||
* { "beep", 'b', 0, G_OPTION_ARG_NONE, &beep, "Beep when done", NULL },
|
||||
* { "rand", 0, 0, G_OPTION_ARG_NONE, &randomize, "Randomize the data", NULL },
|
||||
* G_OPTION_ENTRY_NULL
|
||||
* };
|
||||
*
|
||||
* int
|
||||
* main (int argc, char *argv[])
|
||||
* {
|
||||
* GError *error = NULL;
|
||||
* GOptionContext *context;
|
||||
*
|
||||
* context = g_option_context_new ("- test tree model performance");
|
||||
* g_option_context_add_main_entries (context, entries, GETTEXT_PACKAGE);
|
||||
* g_option_context_add_group (context, gtk_get_option_group (TRUE));
|
||||
* if (!g_option_context_parse (context, &argc, &argv, &error))
|
||||
* {
|
||||
* g_print ("option parsing failed: %s\n", error->message);
|
||||
* exit (1);
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* On UNIX systems, the argv that is passed to main() has no particular
|
||||
* encoding, even to the extent that different parts of it may have
|
||||
* different encodings. In general, normal arguments and flags will be
|
||||
* in the current locale and filenames should be considered to be opaque
|
||||
* byte strings. Proper use of %G_OPTION_ARG_FILENAME vs
|
||||
* %G_OPTION_ARG_STRING is therefore important.
|
||||
*
|
||||
* Note that on Windows, filenames do have an encoding, but using
|
||||
* #GOptionContext with the argv as passed to main() will result in a
|
||||
* program that can only accept commandline arguments with characters
|
||||
* from the system codepage. This can cause problems when attempting to
|
||||
* deal with filenames containing Unicode characters that fall outside
|
||||
* of the codepage.
|
||||
*
|
||||
* A solution to this is to use g_win32_get_command_line() and
|
||||
* g_option_context_parse_strv() which will properly handle full Unicode
|
||||
* filenames. If you are using #GApplication, this is done
|
||||
* automatically for you.
|
||||
*
|
||||
* The following example shows how you can use #GOptionContext directly
|
||||
* in order to correctly deal with Unicode filenames on Windows:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* int
|
||||
* main (int argc, char **argv)
|
||||
* {
|
||||
* GError *error = NULL;
|
||||
* GOptionContext *context;
|
||||
* gchar **args;
|
||||
*
|
||||
* #ifdef G_OS_WIN32
|
||||
* args = g_win32_get_command_line ();
|
||||
* #else
|
||||
* args = g_strdupv (argv);
|
||||
* #endif
|
||||
*
|
||||
* // set up context
|
||||
*
|
||||
* if (!g_option_context_parse_strv (context, &args, &error))
|
||||
* {
|
||||
* // error happened
|
||||
* }
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* g_strfreev (args);
|
||||
*
|
||||
* ...
|
||||
* }
|
||||
* ]|
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include <string.h>
|
||||
|
130
glib/grcbox.c
130
glib/grcbox.c
@ -34,136 +34,6 @@
|
||||
|
||||
#include <string.h>
|
||||
|
||||
/**
|
||||
* SECTION:rcbox
|
||||
* @Title: Reference counted data
|
||||
* @Short_description: Allocated memory with reference counting semantics
|
||||
*
|
||||
* A "reference counted box", or "RcBox", is an opaque wrapper data type
|
||||
* that is guaranteed to be as big as the size of a given data type, and
|
||||
* which augments the given data type with reference counting semantics
|
||||
* for its memory management.
|
||||
*
|
||||
* RcBox is useful if you have a plain old data type, like a structure
|
||||
* typically placed on the stack, and you wish to provide additional API
|
||||
* to use it on the heap; or if you want to implement a new type to be
|
||||
* passed around by reference without necessarily implementing copy/free
|
||||
* semantics or your own reference counting.
|
||||
*
|
||||
* The typical use is:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* typedef struct {
|
||||
* char *name;
|
||||
* char *address;
|
||||
* char *city;
|
||||
* char *state;
|
||||
* int age;
|
||||
* } Person;
|
||||
*
|
||||
* Person *
|
||||
* person_new (void)
|
||||
* {
|
||||
* return g_rc_box_new0 (Person);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* Every time you wish to acquire a reference on the memory, you should
|
||||
* call g_rc_box_acquire(); similarly, when you wish to release a reference
|
||||
* you should call g_rc_box_release():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* // Add a Person to the Database; the Database acquires ownership
|
||||
* // of the Person instance
|
||||
* void
|
||||
* add_person_to_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_prepend (db->persons, g_rc_box_acquire (p));
|
||||
* }
|
||||
*
|
||||
* // Removes a Person from the Database; the reference acquired by
|
||||
* // add_person_to_database() is released here
|
||||
* void
|
||||
* remove_person_from_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_remove (db->persons, p);
|
||||
* g_rc_box_release (p);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* If you have additional memory allocated inside the structure, you can
|
||||
* use g_rc_box_release_full(), which takes a function pointer, which
|
||||
* will be called if the reference released was the last:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* void
|
||||
* person_clear (Person *p)
|
||||
* {
|
||||
* g_free (p->name);
|
||||
* g_free (p->address);
|
||||
* g_free (p->city);
|
||||
* g_free (p->state);
|
||||
* }
|
||||
*
|
||||
* void
|
||||
* remove_person_from_database (Database *db, Person *p)
|
||||
* {
|
||||
* db->persons = g_list_remove (db->persons, p);
|
||||
* g_rc_box_release_full (p, (GDestroyNotify) person_clear);
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* If you wish to transfer the ownership of a reference counted data
|
||||
* type without increasing the reference count, you can use g_steal_pointer():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* Person *p = g_rc_box_new (Person);
|
||||
*
|
||||
* // fill_person_details() is defined elsewhere
|
||||
* fill_person_details (p);
|
||||
*
|
||||
* // add_person_to_database_no_ref() is defined elsewhere; it adds
|
||||
* // a Person to the Database without taking a reference
|
||||
* add_person_to_database_no_ref (db, g_steal_pointer (&p));
|
||||
* ]|
|
||||
*
|
||||
* ## Thread safety
|
||||
*
|
||||
* The reference counting operations on data allocated using g_rc_box_alloc(),
|
||||
* g_rc_box_new(), and g_rc_box_dup() are not thread safe; it is your code's
|
||||
* responsibility to ensure that references are acquired are released on the
|
||||
* same thread.
|
||||
*
|
||||
* If you need thread safe reference counting, see the [atomic reference counted
|
||||
* data][arcbox] API.
|
||||
*
|
||||
* ## Automatic pointer clean up
|
||||
*
|
||||
* If you want to add g_autoptr() support to your plain old data type through
|
||||
* reference counting, you can use the G_DEFINE_AUTOPTR_CLEANUP_FUNC() and
|
||||
* g_rc_box_release():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, g_rc_box_release)
|
||||
* ]|
|
||||
*
|
||||
* If you need to clear the contents of the data, you will need to use an
|
||||
* ancillary function that calls g_rc_box_release_full():
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* static void
|
||||
* my_data_struct_release (MyDataStruct *data)
|
||||
* {
|
||||
* // my_data_struct_clear() is defined elsewhere
|
||||
* g_rc_box_release_full (data, (GDestroyNotify) my_data_struct_clear);
|
||||
* }
|
||||
*
|
||||
* G_DEFINE_AUTOPTR_CLEANUP_FUNC (MyDataStruct, my_data_struct_release)
|
||||
* ]|
|
||||
*
|
||||
* Since: 2.58
|
||||
*/
|
||||
|
||||
/* We use the same alignment as GTypeInstance and GNU libc's malloc */
|
||||
#define ALIGN_STRUCT(offset) ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
|
||||
|
||||
|
@ -18,29 +18,6 @@
|
||||
* License along with this library; if not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
/**
|
||||
* SECTION:refcount
|
||||
* @Title: Reference counting
|
||||
* @Short_description: Reference counting types and functions
|
||||
*
|
||||
* Reference counting is a garbage collection mechanism that is based on
|
||||
* assigning a counter to a data type, or any memory area; the counter is
|
||||
* increased whenever a new reference to that data type is acquired, and
|
||||
* decreased whenever the reference is released. Once the last reference
|
||||
* is released, the resources associated to that data type are freed.
|
||||
*
|
||||
* GLib uses reference counting in many of its data types, and provides
|
||||
* the #grefcount and #gatomicrefcount types to implement safe and atomic
|
||||
* reference counting semantics in new data types.
|
||||
*
|
||||
* It is important to note that #grefcount and #gatomicrefcount should be
|
||||
* considered completely opaque types; you should always use the provided
|
||||
* API to increase and decrease the counters, and you should never check
|
||||
* their content directly, or compare their content with other values.
|
||||
*
|
||||
* Since: 2.58
|
||||
*/
|
||||
|
||||
#include "config.h"
|
||||
|
||||
#include "grefcount.h"
|
||||
|
@ -30,65 +30,6 @@
|
||||
#include "glib_trace.h"
|
||||
#include "gprintf.h"
|
||||
|
||||
/**
|
||||
* SECTION:memory_slices
|
||||
* @title: Memory Slices
|
||||
* @short_description: efficient way to allocate groups of equal-sized
|
||||
* chunks of memory
|
||||
*
|
||||
* GSlice was a space-efficient and multi-processing scalable way to allocate
|
||||
* equal sized pieces of memory. Since GLib 2.76, its implementation has been
|
||||
* removed and it calls g_malloc() and g_free_sized(), because the performance
|
||||
* of the system-default allocators has improved on all platforms since GSlice
|
||||
* was written.
|
||||
*
|
||||
* The GSlice APIs have not been deprecated, as they are widely in use and doing
|
||||
* so would be very disruptive for little benefit.
|
||||
*
|
||||
* New code should be written using g_new()/g_malloc() and g_free_sized() or
|
||||
* g_free(). There is no particular benefit in porting existing code away from
|
||||
* g_slice_new()/g_slice_free() unless it’s being rewritten anyway.
|
||||
*
|
||||
* Here is an example for using the slice allocator:
|
||||
* |[<!-- language="C" -->
|
||||
* gchar *mem[10000];
|
||||
* gint i;
|
||||
*
|
||||
* // Allocate 10000 blocks.
|
||||
* for (i = 0; i < 10000; i++)
|
||||
* {
|
||||
* mem[i] = g_slice_alloc (50);
|
||||
*
|
||||
* // Fill in the memory with some junk.
|
||||
* for (j = 0; j < 50; j++)
|
||||
* mem[i][j] = i * j;
|
||||
* }
|
||||
*
|
||||
* // Now free all of the blocks.
|
||||
* for (i = 0; i < 10000; i++)
|
||||
* g_slice_free1 (50, mem[i]);
|
||||
* ]|
|
||||
*
|
||||
* And here is an example for using the using the slice allocator
|
||||
* with data structures:
|
||||
* |[<!-- language="C" -->
|
||||
* GRealArray *array;
|
||||
*
|
||||
* // Allocate one block, using the g_slice_new() macro.
|
||||
* array = g_slice_new (GRealArray);
|
||||
*
|
||||
* // We can now use array just like a normal pointer to a structure.
|
||||
* array->data = NULL;
|
||||
* array->len = 0;
|
||||
* array->alloc = 0;
|
||||
* array->zero_terminated = (zero_terminated ? 1 : 0);
|
||||
* array->clear = (clear ? 1 : 0);
|
||||
* array->elt_size = elt_size;
|
||||
*
|
||||
* // We can free the block, so it can be reused.
|
||||
* g_slice_free (GRealArray, array);
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/* --- auxiliary functions --- */
|
||||
void
|
||||
|
@ -67,193 +67,6 @@
|
||||
* See https://gitlab.gnome.org/GNOME/glib/-/issues/2885 */
|
||||
#define TAP_SUBTEST_PREFIX "# " /* a 4-space indented line */
|
||||
|
||||
/**
|
||||
* SECTION:testing
|
||||
* @title: Testing
|
||||
* @short_description: a test framework
|
||||
*
|
||||
* GLib provides a framework for writing and maintaining unit tests
|
||||
* in parallel to the code they are testing. The API is designed according
|
||||
* to established concepts found in the other test frameworks (JUnit, NUnit,
|
||||
* RUnit), which in turn is based on smalltalk unit testing concepts.
|
||||
*
|
||||
* - Test case: Tests (test methods) are grouped together with their
|
||||
* fixture into test cases.
|
||||
*
|
||||
* - Fixture: A test fixture consists of fixture data and setup and
|
||||
* teardown methods to establish the environment for the test
|
||||
* functions. We use fresh fixtures, i.e. fixtures are newly set
|
||||
* up and torn down around each test invocation to avoid dependencies
|
||||
* between tests.
|
||||
*
|
||||
* - Test suite: Test cases can be grouped into test suites, to allow
|
||||
* subsets of the available tests to be run. Test suites can be
|
||||
* grouped into other test suites as well.
|
||||
*
|
||||
* The API is designed to handle creation and registration of test suites
|
||||
* and test cases implicitly. A simple call like
|
||||
* |[<!-- language="C" -->
|
||||
* g_test_init (&argc, &argv, G_TEST_OPTION_ISOLATE_DIRS, NULL);
|
||||
*
|
||||
* g_test_add_func ("/misc/assertions", test_assertions);
|
||||
* ]|
|
||||
* creates a test suite called "misc" with a single test case named
|
||||
* "assertions", which consists of running the test_assertions function.
|
||||
*
|
||||
* g_test_init() should be called before calling any other test functions.
|
||||
*
|
||||
* In addition to the traditional g_assert_true(), the test framework provides
|
||||
* an extended set of assertions for comparisons: g_assert_cmpfloat(),
|
||||
* g_assert_cmpfloat_with_epsilon(), g_assert_cmpint(), g_assert_cmpuint(),
|
||||
* g_assert_cmphex(), g_assert_cmpstr(), g_assert_cmpmem() and
|
||||
* g_assert_cmpvariant(). The
|
||||
* advantage of these variants over plain g_assert_true() is that the assertion
|
||||
* messages can be more elaborate, and include the values of the compared
|
||||
* entities.
|
||||
*
|
||||
* Note that g_assert() should not be used in unit tests, since it is a no-op
|
||||
* when compiling with `G_DISABLE_ASSERT`. Use g_assert() in production code,
|
||||
* and g_assert_true() in unit tests.
|
||||
*
|
||||
* A full example of creating a test suite with two tests using fixtures:
|
||||
* |[<!-- language="C" -->
|
||||
* #include <glib.h>
|
||||
* #include <locale.h>
|
||||
*
|
||||
* typedef struct {
|
||||
* MyObject *obj;
|
||||
* OtherObject *helper;
|
||||
* } MyObjectFixture;
|
||||
*
|
||||
* static void
|
||||
* my_object_fixture_set_up (MyObjectFixture *fixture,
|
||||
* gconstpointer user_data)
|
||||
* {
|
||||
* fixture->obj = my_object_new ();
|
||||
* my_object_set_prop1 (fixture->obj, "some-value");
|
||||
* my_object_do_some_complex_setup (fixture->obj, user_data);
|
||||
*
|
||||
* fixture->helper = other_object_new ();
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* my_object_fixture_tear_down (MyObjectFixture *fixture,
|
||||
* gconstpointer user_data)
|
||||
* {
|
||||
* g_clear_object (&fixture->helper);
|
||||
* g_clear_object (&fixture->obj);
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* test_my_object_test1 (MyObjectFixture *fixture,
|
||||
* gconstpointer user_data)
|
||||
* {
|
||||
* g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "initial-value");
|
||||
* }
|
||||
*
|
||||
* static void
|
||||
* test_my_object_test2 (MyObjectFixture *fixture,
|
||||
* gconstpointer user_data)
|
||||
* {
|
||||
* my_object_do_some_work_using_helper (fixture->obj, fixture->helper);
|
||||
* g_assert_cmpstr (my_object_get_property (fixture->obj), ==, "updated-value");
|
||||
* }
|
||||
*
|
||||
* int
|
||||
* main (int argc, char *argv[])
|
||||
* {
|
||||
* setlocale (LC_ALL, "");
|
||||
*
|
||||
* g_test_init (&argc, &argv, NULL);
|
||||
*
|
||||
* // Define the tests.
|
||||
* g_test_add ("/my-object/test1", MyObjectFixture, "some-user-data",
|
||||
* my_object_fixture_set_up, test_my_object_test1,
|
||||
* my_object_fixture_tear_down);
|
||||
* g_test_add ("/my-object/test2", MyObjectFixture, "some-user-data",
|
||||
* my_object_fixture_set_up, test_my_object_test2,
|
||||
* my_object_fixture_tear_down);
|
||||
*
|
||||
* return g_test_run ();
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* ## Integrating GTest in your project
|
||||
*
|
||||
* If you are using the [Meson](http://mesonbuild.com) build system, you will
|
||||
* typically use the provided `test()` primitive to call the test binaries,
|
||||
* e.g.:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* test(
|
||||
* 'foo',
|
||||
* executable('foo', 'foo.c', dependencies: deps),
|
||||
* env: [
|
||||
* 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
* 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
* ],
|
||||
* )
|
||||
*
|
||||
* test(
|
||||
* 'bar',
|
||||
* executable('bar', 'bar.c', dependencies: deps),
|
||||
* env: [
|
||||
* 'G_TEST_SRCDIR=@0@'.format(meson.current_source_dir()),
|
||||
* 'G_TEST_BUILDDIR=@0@'.format(meson.current_build_dir()),
|
||||
* ],
|
||||
* )
|
||||
* ]|
|
||||
*
|
||||
* If you are using Autotools, you're strongly encouraged to use the Automake
|
||||
* [TAP](https://testanything.org/) harness; GLib provides template files for
|
||||
* easily integrating with it:
|
||||
*
|
||||
* - [glib-tap.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib-tap.mk)
|
||||
* - [tap-test](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-test)
|
||||
* - [tap-driver.sh](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/tap-driver.sh)
|
||||
*
|
||||
* You can copy these files in your own project's root directory, and then
|
||||
* set up your `Makefile.am` file to reference them, for instance:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* include $(top_srcdir)/glib-tap.mk
|
||||
*
|
||||
* # test binaries
|
||||
* test_programs = \
|
||||
* foo \
|
||||
* bar
|
||||
*
|
||||
* # data distributed in the tarball
|
||||
* dist_test_data = \
|
||||
* foo.data.txt \
|
||||
* bar.data.txt
|
||||
*
|
||||
* # data not distributed in the tarball
|
||||
* test_data = \
|
||||
* blah.data.txt
|
||||
* ]|
|
||||
*
|
||||
* Make sure to distribute the TAP files, using something like the following
|
||||
* in your top-level `Makefile.am`:
|
||||
*
|
||||
* |[<!-- language="plain" -->
|
||||
* EXTRA_DIST += \
|
||||
* tap-driver.sh \
|
||||
* tap-test
|
||||
* ]|
|
||||
*
|
||||
* `glib-tap.mk` will be distributed implicitly due to being included in a
|
||||
* `Makefile.am`. All three files should be added to version control.
|
||||
*
|
||||
* If you don't have access to the Autotools TAP harness, you can use the
|
||||
* [gtester][gtester] and [gtester-report][gtester-report] tools, and use
|
||||
* the [glib.mk](https://gitlab.gnome.org/GNOME/glib/blob/glib-2-58/glib.mk)
|
||||
* Automake template provided by GLib. Note, however, that since GLib 2.62,
|
||||
* [gtester][gtester] and [gtester-report][gtester-report] have been deprecated
|
||||
* in favour of using TAP. The `--tap` argument to tests is enabled by default
|
||||
* as of GLib 2.62.
|
||||
*/
|
||||
|
||||
/**
|
||||
* g_test_initialized:
|
||||
*
|
||||
|
@ -62,105 +62,6 @@
|
||||
#include "glib_trace.h"
|
||||
#include "gtrace-private.h"
|
||||
|
||||
/**
|
||||
* SECTION:threads
|
||||
* @title: Threads
|
||||
* @short_description: portable support for threads, mutexes, locks,
|
||||
* conditions and thread private data
|
||||
* @see_also: #GThreadPool, #GAsyncQueue
|
||||
*
|
||||
* Threads act almost like processes, but unlike processes all threads
|
||||
* of one process share the same memory. This is good, as it provides
|
||||
* easy communication between the involved threads via this shared
|
||||
* memory, and it is bad, because strange things (so called
|
||||
* "Heisenbugs") might happen if the program is not carefully designed.
|
||||
* In particular, due to the concurrent nature of threads, no
|
||||
* assumptions on the order of execution of code running in different
|
||||
* threads can be made, unless order is explicitly forced by the
|
||||
* programmer through synchronization primitives.
|
||||
*
|
||||
* The aim of the thread-related functions in GLib is to provide a
|
||||
* portable means for writing multi-threaded software. There are
|
||||
* primitives for mutexes to protect the access to portions of memory
|
||||
* (#GMutex, #GRecMutex and #GRWLock). There is a facility to use
|
||||
* individual bits for locks (g_bit_lock()). There are primitives
|
||||
* for condition variables to allow synchronization of threads (#GCond).
|
||||
* There are primitives for thread-private data - data that every
|
||||
* thread has a private instance of (#GPrivate). There are facilities
|
||||
* for one-time initialization (#GOnce, g_once_init_enter_pointer(),
|
||||
* g_once_init_enter()). Finally,
|
||||
* there are primitives to create and manage threads (#GThread).
|
||||
*
|
||||
* The GLib threading system used to be initialized with g_thread_init().
|
||||
* This is no longer necessary. Since version 2.32, the GLib threading
|
||||
* system is automatically initialized at the start of your program,
|
||||
* and all thread-creation functions and synchronization primitives
|
||||
* are available right away.
|
||||
*
|
||||
* Note that it is not safe to assume that your program has no threads
|
||||
* even if you don't call g_thread_new() yourself. GLib and GIO can
|
||||
* and will create threads for their own purposes in some cases, such
|
||||
* as when using g_unix_signal_source_new() or when using GDBus.
|
||||
*
|
||||
* Originally, UNIX did not have threads, and therefore some traditional
|
||||
* UNIX APIs are problematic in threaded programs. Some notable examples
|
||||
* are
|
||||
*
|
||||
* - C library functions that return data in statically allocated
|
||||
* buffers, such as strtok() or strerror(). For many of these,
|
||||
* there are thread-safe variants with a _r suffix, or you can
|
||||
* look at corresponding GLib APIs (like g_strsplit() or g_strerror()).
|
||||
*
|
||||
* - The functions setenv() and unsetenv() manipulate the process
|
||||
* environment in a not thread-safe way, and may interfere with getenv()
|
||||
* calls in other threads. Note that getenv() calls may be hidden behind
|
||||
* other APIs. For example, GNU gettext() calls getenv() under the
|
||||
* covers. In general, it is best to treat the environment as readonly.
|
||||
* If you absolutely have to modify the environment, do it early in
|
||||
* main(), when no other threads are around yet.
|
||||
*
|
||||
* - The setlocale() function changes the locale for the entire process,
|
||||
* affecting all threads. Temporary changes to the locale are often made
|
||||
* to change the behavior of string scanning or formatting functions
|
||||
* like scanf() or printf(). GLib offers a number of string APIs
|
||||
* (like g_ascii_formatd() or g_ascii_strtod()) that can often be
|
||||
* used as an alternative. Or you can use the uselocale() function
|
||||
* to change the locale only for the current thread.
|
||||
*
|
||||
* - The fork() function only takes the calling thread into the child's
|
||||
* copy of the process image. If other threads were executing in critical
|
||||
* sections they could have left mutexes locked which could easily
|
||||
* cause deadlocks in the new child. For this reason, you should
|
||||
* call exit() or exec() as soon as possible in the child and only
|
||||
* make signal-safe library calls before that.
|
||||
*
|
||||
* - The daemon() function uses fork() in a way contrary to what is
|
||||
* described above. It should not be used with GLib programs.
|
||||
*
|
||||
* GLib itself is internally completely thread-safe (all global data is
|
||||
* automatically locked), but individual data structure instances are
|
||||
* not automatically locked for performance reasons. For example,
|
||||
* you must coordinate accesses to the same #GHashTable from multiple
|
||||
* threads. The two notable exceptions from this rule are #GMainLoop
|
||||
* and #GAsyncQueue, which are thread-safe and need no further
|
||||
* application-level locking to be accessed from multiple threads.
|
||||
* Most refcounting functions such as g_object_ref() are also thread-safe.
|
||||
*
|
||||
* A common use for #GThreads is to move a long-running blocking operation out
|
||||
* of the main thread and into a worker thread. For GLib functions, such as
|
||||
* single GIO operations, this is not necessary, and complicates the code.
|
||||
* Instead, the `…_async()` version of the function should be used from the main
|
||||
* thread, eliminating the need for locking and synchronisation between multiple
|
||||
* threads. If an operation does need to be moved to a worker thread, consider
|
||||
* using g_task_run_in_thread(), or a #GThreadPool. #GThreadPool is often a
|
||||
* better choice than #GThread, as it handles thread reuse and task queueing;
|
||||
* #GTask uses this internally.
|
||||
*
|
||||
* However, if multiple blocking operations need to be performed in sequence,
|
||||
* and it is not possible to use #GTask for them, moving them to a worker thread
|
||||
* can clarify the code.
|
||||
*/
|
||||
|
||||
/* G_LOCK Documentation {{{1 ---------------------------------------------- */
|
||||
|
||||
/**
|
||||
|
@ -52,84 +52,6 @@
|
||||
#include "gmoduleconf.h"
|
||||
#include "gstdio.h"
|
||||
|
||||
/**
|
||||
* SECTION:modules
|
||||
* @title: Dynamic Loading of Modules
|
||||
* @short_description: portable method for dynamically loading 'plug-ins'
|
||||
*
|
||||
* These functions provide a portable way to dynamically load object files
|
||||
* (commonly known as 'plug-ins'). The current implementation supports all
|
||||
* systems that provide an implementation of dlopen() (e.g. Linux/Sun), as
|
||||
* well as Windows platforms via DLLs.
|
||||
*
|
||||
* A program which wants to use these functions must be linked to the
|
||||
* libraries output by the command `pkg-config --libs gmodule-2.0`.
|
||||
*
|
||||
* To use them you must first determine whether dynamic loading
|
||||
* is supported on the platform by calling g_module_supported().
|
||||
* If it is, you can open a module with g_module_open(),
|
||||
* find the module's symbols (e.g. function names) with g_module_symbol(),
|
||||
* and later close the module with g_module_close().
|
||||
* g_module_name() will return the file name of a currently opened module.
|
||||
*
|
||||
* If any of the above functions fail, the error status can be found with
|
||||
* g_module_error().
|
||||
*
|
||||
* The #GModule implementation features reference counting for opened modules,
|
||||
* and supports hook functions within a module which are called when the
|
||||
* module is loaded and unloaded (see #GModuleCheckInit and #GModuleUnload).
|
||||
*
|
||||
* If your module introduces static data to common subsystems in the running
|
||||
* program, e.g. through calling
|
||||
* `g_quark_from_static_string ("my-module-stuff")`,
|
||||
* it must ensure that it is never unloaded, by calling g_module_make_resident().
|
||||
*
|
||||
* Example: Calling a function defined in a GModule
|
||||
* |[<!-- language="C" -->
|
||||
* // the function signature for 'say_hello'
|
||||
* typedef void (* SayHelloFunc) (const char *message);
|
||||
*
|
||||
* gboolean
|
||||
* just_say_hello (const char *filename, GError **error)
|
||||
* {
|
||||
* SayHelloFunc say_hello;
|
||||
* GModule *module;
|
||||
*
|
||||
* module = g_module_open (filename, G_MODULE_BIND_LAZY);
|
||||
* if (!module)
|
||||
* {
|
||||
* g_set_error (error, FOO_ERROR, FOO_ERROR_BLAH,
|
||||
* "%s", g_module_error ());
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* if (!g_module_symbol (module, "say_hello", (gpointer *)&say_hello))
|
||||
* {
|
||||
* g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
* "%s: %s", filename, g_module_error ());
|
||||
* if (!g_module_close (module))
|
||||
* g_warning ("%s: %s", filename, g_module_error ());
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* if (say_hello == NULL)
|
||||
* {
|
||||
* g_set_error (error, SAY_ERROR, SAY_ERROR_OPEN,
|
||||
* "symbol say_hello is NULL");
|
||||
* if (!g_module_close (module))
|
||||
* g_warning ("%s: %s", filename, g_module_error ());
|
||||
* return FALSE;
|
||||
* }
|
||||
*
|
||||
* // call our function in the module
|
||||
* say_hello ("Hello world!");
|
||||
*
|
||||
* if (!g_module_close (module))
|
||||
* g_warning ("%s: %s", filename, g_module_error ());
|
||||
* return TRUE;
|
||||
* }
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/**
|
||||
* GModule:
|
||||
|
@ -33,35 +33,6 @@
|
||||
#include "gvaluearray.h"
|
||||
#include "gvaluecollector.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:gboxed
|
||||
* @short_description: A mechanism to wrap opaque C structures registered
|
||||
* by the type system
|
||||
* @see_also: #GParamSpecBoxed, g_param_spec_boxed()
|
||||
* @title: Boxed Types
|
||||
*
|
||||
* #GBoxed is a generic wrapper mechanism for arbitrary C structures.
|
||||
*
|
||||
* The only thing the type system needs to know about the structures is how to
|
||||
* copy them (a #GBoxedCopyFunc) and how to free them (a #GBoxedFreeFunc);
|
||||
* beyond that, they are treated as opaque chunks of memory.
|
||||
*
|
||||
* Boxed types are useful for simple value-holder structures like rectangles or
|
||||
* points. They can also be used for wrapping structures defined in non-#GObject
|
||||
* based libraries. They allow arbitrary structures to be handled in a uniform
|
||||
* way, allowing uniform copying (or referencing) and freeing (or unreferencing)
|
||||
* of them, and uniform representation of the type of the contained structure.
|
||||
* In turn, this allows any type which can be boxed to be set as the data in a
|
||||
* #GValue, which allows for polymorphic handling of a much wider range of data
|
||||
* types, and hence usage of such types as #GObject property values.
|
||||
*
|
||||
* #GBoxed is designed so that reference counted types can be boxed. Use the
|
||||
* type’s ‘ref’ function as the #GBoxedCopyFunc, and its ‘unref’ function as the
|
||||
* #GBoxedFreeFunc. For example, for #GBytes, the #GBoxedCopyFunc is
|
||||
* g_bytes_ref(), and the #GBoxedFreeFunc is g_bytes_unref().
|
||||
*/
|
||||
|
||||
static inline void /* keep this function in sync with gvalue.c */
|
||||
value_meminit (GValue *value,
|
||||
GType value_type)
|
||||
|
@ -31,43 +31,6 @@
|
||||
#include "gvaluecollector.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:enumerations_flags
|
||||
* @short_description: Enumeration and flags types
|
||||
* @title: Enumeration and Flag Types
|
||||
* @see_also:#GParamSpecEnum, #GParamSpecFlags, g_param_spec_enum(),
|
||||
* g_param_spec_flags()
|
||||
*
|
||||
* The GLib type system provides fundamental types for enumeration and
|
||||
* flags types. (Flags types are like enumerations, but allow their
|
||||
* values to be combined by bitwise or). A registered enumeration or
|
||||
* flags type associates a name and a nickname with each allowed
|
||||
* value, and the methods g_enum_get_value_by_name(),
|
||||
* g_enum_get_value_by_nick(), g_flags_get_value_by_name() and
|
||||
* g_flags_get_value_by_nick() can look up values by their name or
|
||||
* nickname. When an enumeration or flags type is registered with the
|
||||
* GLib type system, it can be used as value type for object
|
||||
* properties, using g_param_spec_enum() or g_param_spec_flags().
|
||||
*
|
||||
* GObject ships with a utility called [glib-mkenums][glib-mkenums],
|
||||
* that can construct suitable type registration functions from C enumeration
|
||||
* definitions.
|
||||
*
|
||||
* Example of how to get a string representation of an enum value:
|
||||
* |[<!-- language="C" -->
|
||||
* GEnumClass *enum_class;
|
||||
* GEnumValue *enum_value;
|
||||
*
|
||||
* enum_class = g_type_class_ref (MAMAN_TYPE_MY_ENUM);
|
||||
* enum_value = g_enum_get_value (enum_class, MAMAN_MY_ENUM_FOO);
|
||||
*
|
||||
* g_print ("Name: %s\n", enum_value->value_name);
|
||||
*
|
||||
* g_type_class_unref (enum_class);
|
||||
* ]|
|
||||
*/
|
||||
|
||||
|
||||
/* --- prototypes --- */
|
||||
static void g_enum_class_init (GEnumClass *class,
|
||||
gpointer class_data);
|
||||
|
@ -54,86 +54,6 @@
|
||||
* GObjects and their methods, see the [GType conventions][gtype-conventions].
|
||||
* For the high-level concepts behind GObject, read [Instantiatable classed types:
|
||||
* Objects][gtype-instantiatable-classed].
|
||||
*
|
||||
* ## Floating references # {#floating-ref}
|
||||
*
|
||||
* **Note**: Floating references are a C convenience API and should not be
|
||||
* used in modern GObject code. Language bindings in particular find the
|
||||
* concept highly problematic, as floating references are not identifiable
|
||||
* through annotations, and neither are deviations from the floating reference
|
||||
* behavior, like types that inherit from #GInitiallyUnowned and still return
|
||||
* a full reference from g_object_new().
|
||||
*
|
||||
* GInitiallyUnowned is derived from GObject. The only difference between
|
||||
* the two is that the initial reference of a GInitiallyUnowned is flagged
|
||||
* as a "floating" reference. This means that it is not specifically
|
||||
* claimed to be "owned" by any code portion. The main motivation for
|
||||
* providing floating references is C convenience. In particular, it
|
||||
* allows code to be written as:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* container = create_container ();
|
||||
* container_add_child (container, create_child());
|
||||
* ]|
|
||||
*
|
||||
* If container_add_child() calls g_object_ref_sink() on the passed-in child,
|
||||
* no reference of the newly created child is leaked. Without floating
|
||||
* references, container_add_child() can only g_object_ref() the new child,
|
||||
* so to implement this code without reference leaks, it would have to be
|
||||
* written as:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* Child *child;
|
||||
* container = create_container ();
|
||||
* child = create_child ();
|
||||
* container_add_child (container, child);
|
||||
* g_object_unref (child);
|
||||
* ]|
|
||||
*
|
||||
* The floating reference can be converted into an ordinary reference by
|
||||
* calling g_object_ref_sink(). For already sunken objects (objects that
|
||||
* don't have a floating reference anymore), g_object_ref_sink() is equivalent
|
||||
* to g_object_ref() and returns a new reference.
|
||||
*
|
||||
* Since floating references are useful almost exclusively for C convenience,
|
||||
* language bindings that provide automated reference and memory ownership
|
||||
* maintenance (such as smart pointers or garbage collection) should not
|
||||
* expose floating references in their API. The best practice for handling
|
||||
* types that have initially floating references is to immediately sink those
|
||||
* references after g_object_new() returns, by checking if the #GType
|
||||
* inherits from #GInitiallyUnowned. For instance:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* GObject *res = g_object_new_with_properties (gtype,
|
||||
* n_props,
|
||||
* prop_names,
|
||||
* prop_values);
|
||||
*
|
||||
* // or: if (g_type_is_a (gtype, G_TYPE_INITIALLY_UNOWNED))
|
||||
* if (G_IS_INITIALLY_UNOWNED (res))
|
||||
* g_object_ref_sink (res);
|
||||
*
|
||||
* return res;
|
||||
* ]|
|
||||
*
|
||||
* Some object implementations may need to save an objects floating state
|
||||
* across certain code portions (an example is #GtkMenu), to achieve this,
|
||||
* the following sequence can be used:
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* // save floating state
|
||||
* gboolean was_floating = g_object_is_floating (object);
|
||||
* g_object_ref_sink (object);
|
||||
* // protected code portion
|
||||
*
|
||||
* ...
|
||||
*
|
||||
* // restore floating state
|
||||
* if (was_floating)
|
||||
* g_object_force_floating (object);
|
||||
* else
|
||||
* g_object_unref (object); // release previously acquired reference
|
||||
* ]|
|
||||
*/
|
||||
|
||||
/* --- macros --- */
|
||||
|
116
gobject/gvalue.c
116
gobject/gvalue.c
@ -31,122 +31,6 @@
|
||||
#include "gtype-private.h"
|
||||
|
||||
|
||||
/**
|
||||
* SECTION:generic_values
|
||||
* @short_description: A polymorphic type that can hold values of any
|
||||
* other type
|
||||
* @see_also: The fundamental types which all support #GValue
|
||||
* operations and thus can be used as a type initializer for
|
||||
* g_value_init() are defined by a separate interface. See the
|
||||
* [standard values API][gobject-Standard-Parameter-and-Value-Types]
|
||||
* for details
|
||||
* @title: Generic values
|
||||
*
|
||||
* The #GValue structure is basically a variable container that consists
|
||||
* of a type identifier and a specific value of that type.
|
||||
*
|
||||
* The type identifier within a #GValue structure always determines the
|
||||
* type of the associated value.
|
||||
*
|
||||
* To create an undefined #GValue structure, simply create a zero-filled
|
||||
* #GValue structure. To initialize the #GValue, use the g_value_init()
|
||||
* function. A #GValue cannot be used until it is initialized. Before
|
||||
* destruction you must always use g_value_unset() to make sure allocated
|
||||
* memory is freed.
|
||||
*
|
||||
* The basic type operations (such as freeing and copying) are determined
|
||||
* by the #GTypeValueTable associated with the type ID stored in the #GValue.
|
||||
* Other #GValue operations (such as converting values between types) are
|
||||
* provided by this interface.
|
||||
*
|
||||
* The code in the example program below demonstrates #GValue's
|
||||
* features.
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* #include <glib-object.h>
|
||||
*
|
||||
* static void
|
||||
* int2string (const GValue *src_value,
|
||||
* GValue *dest_value)
|
||||
* {
|
||||
* if (g_value_get_int (src_value) == 42)
|
||||
* g_value_set_static_string (dest_value, "An important number");
|
||||
* else
|
||||
* g_value_set_static_string (dest_value, "What's that?");
|
||||
* }
|
||||
*
|
||||
* int
|
||||
* main (int argc,
|
||||
* char *argv[])
|
||||
* {
|
||||
* // GValues must be initialized
|
||||
* GValue a = G_VALUE_INIT;
|
||||
* GValue b = G_VALUE_INIT;
|
||||
* const gchar *message;
|
||||
*
|
||||
* // The GValue starts empty
|
||||
* g_assert (!G_VALUE_HOLDS_STRING (&a));
|
||||
*
|
||||
* // Put a string in it
|
||||
* g_value_init (&a, G_TYPE_STRING);
|
||||
* g_assert (G_VALUE_HOLDS_STRING (&a));
|
||||
* g_value_set_static_string (&a, "Hello, world!");
|
||||
* g_printf ("%s\n", g_value_get_string (&a));
|
||||
*
|
||||
* // Reset it to its pristine state
|
||||
* g_value_unset (&a);
|
||||
*
|
||||
* // It can then be reused for another type
|
||||
* g_value_init (&a, G_TYPE_INT);
|
||||
* g_value_set_int (&a, 42);
|
||||
*
|
||||
* // Attempt to transform it into a GValue of type STRING
|
||||
* g_value_init (&b, G_TYPE_STRING);
|
||||
*
|
||||
* // An INT is transformable to a STRING
|
||||
* g_assert (g_value_type_transformable (G_TYPE_INT, G_TYPE_STRING));
|
||||
*
|
||||
* g_value_transform (&a, &b);
|
||||
* g_printf ("%s\n", g_value_get_string (&b));
|
||||
*
|
||||
* // Attempt to transform it again using a custom transform function
|
||||
* g_value_register_transform_func (G_TYPE_INT, G_TYPE_STRING, int2string);
|
||||
* g_value_transform (&a, &b);
|
||||
* g_printf ("%s\n", g_value_get_string (&b));
|
||||
* return 0;
|
||||
* }
|
||||
* ]|
|
||||
*
|
||||
* See also [gobject-Standard-Parameter-and-Value-Types] for more information on
|
||||
* validation of #GValue.
|
||||
*
|
||||
* For letting a #GValue own (and memory manage) arbitrary types or pointers,
|
||||
* they need to become a [boxed type][gboxed]. The example below shows how
|
||||
* the pointer `mystruct` of type `MyStruct` is used as a [boxed type][gboxed].
|
||||
*
|
||||
* |[<!-- language="C" -->
|
||||
* typedef struct { ... } MyStruct;
|
||||
* G_DEFINE_BOXED_TYPE (MyStruct, my_struct, my_struct_copy, my_struct_free)
|
||||
*
|
||||
* // These two lines normally go in a public header. By GObject convention,
|
||||
* // the naming scheme is NAMESPACE_TYPE_NAME:
|
||||
* #define MY_TYPE_STRUCT (my_struct_get_type ())
|
||||
* GType my_struct_get_type (void);
|
||||
*
|
||||
* void
|
||||
* foo ()
|
||||
* {
|
||||
* GValue *value = g_new0 (GValue, 1);
|
||||
* g_value_init (value, MY_TYPE_STRUCT);
|
||||
* g_value_set_boxed (value, mystruct);
|
||||
* // [... your code ....]
|
||||
* g_value_unset (value);
|
||||
* g_free (value);
|
||||
* }
|
||||
* ]|
|
||||
*/
|
||||
|
||||
|
||||
/* --- typedefs & structures --- */
|
||||
typedef struct {
|
||||
GType src_type;
|
||||
|
5
subprojects/gi-docgen.wrap
Normal file
5
subprojects/gi-docgen.wrap
Normal file
@ -0,0 +1,5 @@
|
||||
[wrap-git]
|
||||
directory=gi-docgen
|
||||
url=https://gitlab.gnome.org/GNOME/gi-docgen.git
|
||||
revision=2023.1
|
||||
depth=1
|
Loading…
Reference in New Issue
Block a user