mirror of
https://gitlab.gnome.org/GNOME/glib.git
synced 2025-06-03 19:30:07 +02: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/
|
- _ccache/
|
||||||
|
|
||||||
variables:
|
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"
|
COVERITY_IMAGE: "registry.gitlab.gnome.org/gnome/glib/coverity:v7"
|
||||||
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v14"
|
DEBIAN_IMAGE: "registry.gitlab.gnome.org/gnome/glib/debian-stable:v15"
|
||||||
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v10"
|
MINGW_IMAGE: "registry.gitlab.gnome.org/gnome/glib/mingw:v11"
|
||||||
MESON_TEST_TIMEOUT_MULTIPLIER: 4
|
MESON_TEST_TIMEOUT_MULTIPLIER: 4
|
||||||
G_MESSAGES_DEBUG: all
|
G_MESSAGES_DEBUG: all
|
||||||
MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings"
|
MESON_COMMON_OPTIONS: "--buildtype debug --wrap-mode=nodownload --fatal-meson-warnings"
|
||||||
@ -61,6 +61,7 @@ variables:
|
|||||||
extends: .only-default
|
extends: .only-default
|
||||||
before_script:
|
before_script:
|
||||||
- rm -rf subprojects/gvdb
|
- rm -rf subprojects/gvdb
|
||||||
|
- git config --global --add safe.directory $(pwd)
|
||||||
- git submodule update --init --depth 1
|
- git submodule update --init --depth 1
|
||||||
variables:
|
variables:
|
||||||
GIT_SUBMODULE_STRATEGY: "none"
|
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 \
|
RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
||||||
bindfs \
|
bindfs \
|
||||||
@ -16,6 +16,7 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
|||||||
gdb \
|
gdb \
|
||||||
g++ \
|
g++ \
|
||||||
gettext \
|
gettext \
|
||||||
|
gi-docgen \
|
||||||
git \
|
git \
|
||||||
libc6-dev \
|
libc6-dev \
|
||||||
gtk-doc-tools \
|
gtk-doc-tools \
|
||||||
@ -37,6 +38,7 @@ RUN apt-get update -qq && apt-get install --no-install-recommends -qq -y \
|
|||||||
python3-pip \
|
python3-pip \
|
||||||
python3-setuptools \
|
python3-setuptools \
|
||||||
python3-wheel \
|
python3-wheel \
|
||||||
|
reuse \
|
||||||
shared-mime-info \
|
shared-mime-info \
|
||||||
shellcheck \
|
shellcheck \
|
||||||
systemtap-sdt-dev \
|
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
|
ENV LANG=C.UTF-8 LANGUAGE=C.UTF-8 LC_ALL=C.UTF-8
|
||||||
|
|
||||||
RUN pip3 install meson==0.60.3
|
RUN pip3 install --break-system-packages meson==0.60.3
|
||||||
|
|
||||||
# FIXME: Once we use Debian Bookworm, we can just install the `reuse` package
|
|
||||||
RUN pip3 install reuse==1.0.0
|
|
||||||
|
|
||||||
ARG HOST_USER_ID=5555
|
ARG HOST_USER_ID=5555
|
||||||
ENV HOST_USER_ID ${HOST_USER_ID}
|
ENV HOST_USER_ID ${HOST_USER_ID}
|
||||||
|
@ -1,4 +1,4 @@
|
|||||||
FROM fedora:34
|
FROM fedora:37
|
||||||
|
|
||||||
RUN dnf -y update \
|
RUN dnf -y update \
|
||||||
&& dnf -y install \
|
&& dnf -y install \
|
||||||
@ -15,6 +15,7 @@ RUN dnf -y update \
|
|||||||
gcc-c++ \
|
gcc-c++ \
|
||||||
gdb \
|
gdb \
|
||||||
gettext \
|
gettext \
|
||||||
|
gi-docgen \
|
||||||
git \
|
git \
|
||||||
glibc-devel \
|
glibc-devel \
|
||||||
glibc-headers \
|
glibc-headers \
|
||||||
|
@ -1,72 +1,17 @@
|
|||||||
FROM fedora:34
|
FROM registry.gitlab.gnome.org/gnome/glib/fedora:v21
|
||||||
|
|
||||||
|
USER root
|
||||||
|
|
||||||
RUN dnf -y install \
|
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 \
|
||||||
mingw64-gcc-c++ \
|
mingw64-gcc-c++ \
|
||||||
mingw64-gettext \
|
mingw64-gettext \
|
||||||
mingw64-libffi \
|
mingw64-libffi \
|
||||||
mingw64-zlib \
|
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
|
&& dnf clean all
|
||||||
|
|
||||||
WORKDIR /opt
|
WORKDIR /opt
|
||||||
COPY cross_file_mingw64.txt /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
|
USER user
|
||||||
WORKDIR /home/user
|
WORKDIR /home/user
|
||||||
|
|
||||||
COPY cache-subprojects.sh .
|
|
||||||
RUN ./cache-subprojects.sh
|
|
||||||
|
|
||||||
ENV LANG C.UTF-8
|
|
||||||
|
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>
|
</releaseinfo>
|
||||||
</bookinfo>
|
</bookinfo>
|
||||||
|
|
||||||
<xi:include href="xml/overview.xml"/>
|
|
||||||
|
|
||||||
<part>
|
<part>
|
||||||
<title>API Reference</title>
|
<title>API Reference</title>
|
||||||
<chapter id="file_ops">
|
<chapter id="file_ops">
|
||||||
@ -270,9 +268,6 @@
|
|||||||
<part id="migrating">
|
<part id="migrating">
|
||||||
<title>Migrating to GIO</title>
|
<title>Migrating to GIO</title>
|
||||||
<xi:include href="xml/migrating-posix.xml"/>
|
<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>
|
</part>
|
||||||
|
|
||||||
<chapter id="gio-hierarchy">
|
<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 = [
|
content_files = [
|
||||||
'overview.xml',
|
|
||||||
'migrating-posix.xml',
|
'migrating-posix.xml',
|
||||||
'migrating-gnome-vfs.xml',
|
|
||||||
'migrating-gconf.xml',
|
|
||||||
'migrating-gdbus.xml',
|
|
||||||
'gio-querymodules.xml',
|
'gio-querymodules.xml',
|
||||||
'glib-compile-schemas.xml',
|
'glib-compile-schemas.xml',
|
||||||
'glib-compile-resources.xml',
|
'glib-compile-resources.xml',
|
||||||
@ -198,11 +194,7 @@ if get_option('gtk_doc')
|
|||||||
],
|
],
|
||||||
content_files : content_files,
|
content_files : content_files,
|
||||||
expand_content_files : [
|
expand_content_files : [
|
||||||
'overview.xml',
|
|
||||||
'migrating-posix.xml',
|
'migrating-posix.xml',
|
||||||
'migrating-gnome-vfs.xml',
|
|
||||||
'migrating-gconf.xml',
|
|
||||||
'migrating-gdbus.xml',
|
|
||||||
'gdbus-codegen.xml',
|
'gdbus-codegen.xml',
|
||||||
],
|
],
|
||||||
html_assets : [
|
html_assets : [
|
||||||
@ -216,7 +208,7 @@ if get_option('gtk_doc')
|
|||||||
'--extra-dir=' + join_paths('gio', '..', 'gobject', 'html'),
|
'--extra-dir=' + join_paths('gio', '..', 'gobject', 'html'),
|
||||||
],
|
],
|
||||||
install: true,
|
install: true,
|
||||||
check: true,
|
check: false,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -234,3 +226,32 @@ if get_option('man')
|
|||||||
install_dir: man1_dir)
|
install_dir: man1_dir)
|
||||||
endforeach
|
endforeach
|
||||||
endif
|
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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
## 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).
|
General Public License (GNU LGPL).
|
||||||
</para>
|
</para>
|
||||||
|
|
||||||
<xi:include href="building.xml" />
|
|
||||||
<xi:include href="cross.xml" />
|
|
||||||
<xi:include href="programming.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="changes.xml" />
|
||||||
<xi:include href="resources.xml" />
|
<xi:include href="resources.xml" />
|
||||||
|
|
||||||
@ -118,8 +114,6 @@
|
|||||||
<xi:include href="xml/datasets.xml" />
|
<xi:include href="xml/datasets.xml" />
|
||||||
<xi:include href="xml/gvarianttype.xml"/>
|
<xi:include href="xml/gvarianttype.xml"/>
|
||||||
<xi:include href="xml/gvariant.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/refcount.xml"/>
|
||||||
<xi:include href="xml/rcbox.xml"/>
|
<xi:include href="xml/rcbox.xml"/>
|
||||||
<xi:include href="xml/arcbox.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.
|
||||||
|
|
||||||
|

|
||||||
|
|
||||||
|
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),
|
'--ignore-headers=' + ' '.join(ignore_headers),
|
||||||
],
|
],
|
||||||
content_files : [
|
content_files : [
|
||||||
'cross.xml',
|
|
||||||
'running.xml',
|
|
||||||
'building.xml',
|
|
||||||
'changes.xml',
|
'changes.xml',
|
||||||
'compiling.xml',
|
|
||||||
'programming.xml',
|
'programming.xml',
|
||||||
'resources.xml',
|
'resources.xml',
|
||||||
'regex-syntax.xml',
|
'regex-syntax.xml',
|
||||||
'glib-gettextize.xml',
|
'glib-gettextize.xml',
|
||||||
'gtester.xml',
|
'gtester.xml',
|
||||||
'gtester-report.xml',
|
'gtester-report.xml',
|
||||||
'gvariant-varargs.xml',
|
|
||||||
'gvariant-text.xml',
|
|
||||||
],
|
],
|
||||||
expand_content_files : [
|
expand_content_files : [
|
||||||
'compiling.xml',
|
|
||||||
],
|
],
|
||||||
html_assets : [
|
html_assets : [
|
||||||
'file-name-encodings.png',
|
'file-name-encodings.png',
|
||||||
@ -100,7 +93,7 @@ if get_option('gtk_doc')
|
|||||||
'--html-dir=' + docpath,
|
'--html-dir=' + docpath,
|
||||||
],
|
],
|
||||||
install: true,
|
install: true,
|
||||||
check: true)
|
check: false)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
if get_option('man')
|
if get_option('man')
|
||||||
@ -149,3 +142,43 @@ if get_option('gtk_doc')
|
|||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
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>
|
</releaseinfo>
|
||||||
</bookinfo>
|
</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">
|
<reference label="II">
|
||||||
<title>API Reference</title>
|
<title>API Reference</title>
|
||||||
|
|
||||||
@ -95,7 +43,6 @@
|
|||||||
<xi:include href="gobject-query.xml" />
|
<xi:include href="gobject-query.xml" />
|
||||||
</reference>
|
</reference>
|
||||||
|
|
||||||
<xi:include href="tut_howto.xml" />
|
|
||||||
<xi:include href="tut_tools.xml" />
|
<xi:include href="tut_tools.xml" />
|
||||||
|
|
||||||
<chapter id="api-index-full">
|
<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-mkenums.xml',
|
||||||
'glib-genmarshal.xml',
|
'glib-genmarshal.xml',
|
||||||
'gobject-query.xml',
|
'gobject-query.xml',
|
||||||
'tut_gobject.xml',
|
|
||||||
'tut_gsignal.xml',
|
|
||||||
'tut_gtype.xml',
|
|
||||||
'tut_howto.xml',
|
|
||||||
'tut_intro.xml',
|
|
||||||
'tut_tools.xml'
|
'tut_tools.xml'
|
||||||
],
|
],
|
||||||
html_assets : [
|
html_assets : [
|
||||||
@ -53,7 +48,7 @@ if get_option('gtk_doc')
|
|||||||
'--extra-dir=' + join_paths('gobject', '..', 'glib', 'html'),
|
'--extra-dir=' + join_paths('gobject', '..', 'glib', 'html'),
|
||||||
],
|
],
|
||||||
install: true,
|
install: true,
|
||||||
check: true,
|
check: false,
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
@ -68,3 +63,33 @@ if get_option('man')
|
|||||||
install_dir: man1_dir)
|
install_dir: man1_dir)
|
||||||
endforeach
|
endforeach
|
||||||
endif
|
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
|
||||||
endif
|
endif
|
||||||
|
|
||||||
subdir('gio')
|
# 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('glib')
|
||||||
|
subdir('gmodule')
|
||||||
subdir('gobject')
|
subdir('gobject')
|
||||||
|
subdir('gio')
|
||||||
|
endif
|
||||||
|
94
glib/docs.c
94
glib/docs.c
@ -1063,48 +1063,6 @@
|
|||||||
|
|
||||||
/* Type conversion {{{1 */
|
/* 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:
|
* GINT_TO_POINTER:
|
||||||
* @i: integer to stuff into a pointer
|
* @i: integer to stuff into a pointer
|
||||||
@ -1162,41 +1120,6 @@
|
|||||||
|
|
||||||
/* Byte order {{{1 */
|
/* 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:
|
* G_BYTE_ORDER:
|
||||||
*
|
*
|
||||||
@ -1989,14 +1912,6 @@
|
|||||||
|
|
||||||
/* Macros {{{1 */
|
/* Macros {{{1 */
|
||||||
|
|
||||||
/**
|
|
||||||
* SECTION:macros
|
|
||||||
* @title: Standard Macros
|
|
||||||
* @short_description: commonly-used macros
|
|
||||||
*
|
|
||||||
* These macros provide a few commonly-used features.
|
|
||||||
*/
|
|
||||||
|
|
||||||
/**
|
/**
|
||||||
* G_OS_WIN32:
|
* G_OS_WIN32:
|
||||||
*
|
*
|
||||||
@ -2201,15 +2116,6 @@
|
|||||||
|
|
||||||
/* Miscellaneous Macros {{{1 */
|
/* 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:
|
* 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)
|
#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:
|
* g_atomic_rc_box_alloc:
|
||||||
* @block_size: the size of the allocation, must be greater than 0
|
* @block_size: the size of the allocation, must be greater than 0
|
||||||
|
@ -56,105 +56,6 @@
|
|||||||
|
|
||||||
#include "glibintl.h"
|
#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)
|
|
||||||
*
|
|
||||||
* 
|
|
||||||
*
|
|
||||||
* ## 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
|
/* 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
|
* to ensure that multibyte strings really are nul-terminated when we return
|
||||||
* them from g_convert() and friends.
|
* 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/.
|
* 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 "config.h"
|
||||||
|
|
||||||
#include "gvalgrind.h"
|
#include "gvalgrind.h"
|
||||||
|
@ -462,57 +462,6 @@ g_dngettext (const gchar *domain,
|
|||||||
return dngettext (domain, msgid, msgid_plural, n);
|
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
|
* @String: the string to be translated
|
||||||
|
128
glib/gmain.c
128
glib/gmain.c
@ -127,134 +127,6 @@
|
|||||||
#include "glib-init.h"
|
#include "glib-init.h"
|
||||||
#include "glib-private.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.
|
|
||||||
*
|
|
||||||
* 
|
|
||||||
*
|
|
||||||
* 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 */
|
/* Types */
|
||||||
|
|
||||||
typedef struct _GIdleSource GIdleSource;
|
typedef struct _GIdleSource GIdleSource;
|
||||||
|
@ -38,60 +38,6 @@
|
|||||||
#include "glibintl.h"
|
#include "glibintl.h"
|
||||||
#include "gthread.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)
|
G_DEFINE_QUARK (g-markup-error-quark, g_markup_error)
|
||||||
|
|
||||||
typedef enum
|
typedef enum
|
||||||
|
140
glib/gmessages.c
140
glib/gmessages.c
@ -28,146 +28,6 @@
|
|||||||
* MT safe
|
* 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 "config.h"
|
||||||
|
|
||||||
#include <stdlib.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/>.
|
* 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 "config.h"
|
||||||
|
|
||||||
#include <string.h>
|
#include <string.h>
|
||||||
|
130
glib/grcbox.c
130
glib/grcbox.c
@ -34,136 +34,6 @@
|
|||||||
|
|
||||||
#include <string.h>
|
#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 */
|
/* We use the same alignment as GTypeInstance and GNU libc's malloc */
|
||||||
#define ALIGN_STRUCT(offset) ((offset + (STRUCT_ALIGNMENT - 1)) & -STRUCT_ALIGNMENT)
|
#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/>.
|
* 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 "config.h"
|
||||||
|
|
||||||
#include "grefcount.h"
|
#include "grefcount.h"
|
||||||
|
@ -30,65 +30,6 @@
|
|||||||
#include "glib_trace.h"
|
#include "glib_trace.h"
|
||||||
#include "gprintf.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 --- */
|
/* --- auxiliary functions --- */
|
||||||
void
|
void
|
||||||
|
@ -67,193 +67,6 @@
|
|||||||
* See https://gitlab.gnome.org/GNOME/glib/-/issues/2885 */
|
* See https://gitlab.gnome.org/GNOME/glib/-/issues/2885 */
|
||||||
#define TAP_SUBTEST_PREFIX "# " /* a 4-space indented line */
|
#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:
|
* g_test_initialized:
|
||||||
*
|
*
|
||||||
|
@ -62,105 +62,6 @@
|
|||||||
#include "glib_trace.h"
|
#include "glib_trace.h"
|
||||||
#include "gtrace-private.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 ---------------------------------------------- */
|
/* G_LOCK Documentation {{{1 ---------------------------------------------- */
|
||||||
|
|
||||||
/**
|
/**
|
||||||
|
@ -52,84 +52,6 @@
|
|||||||
#include "gmoduleconf.h"
|
#include "gmoduleconf.h"
|
||||||
#include "gstdio.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:
|
* GModule:
|
||||||
|
@ -33,35 +33,6 @@
|
|||||||
#include "gvaluearray.h"
|
#include "gvaluearray.h"
|
||||||
#include "gvaluecollector.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 */
|
static inline void /* keep this function in sync with gvalue.c */
|
||||||
value_meminit (GValue *value,
|
value_meminit (GValue *value,
|
||||||
GType value_type)
|
GType value_type)
|
||||||
|
@ -31,43 +31,6 @@
|
|||||||
#include "gvaluecollector.h"
|
#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 --- */
|
/* --- prototypes --- */
|
||||||
static void g_enum_class_init (GEnumClass *class,
|
static void g_enum_class_init (GEnumClass *class,
|
||||||
gpointer class_data);
|
gpointer class_data);
|
||||||
|
@ -54,86 +54,6 @@
|
|||||||
* GObjects and their methods, see the [GType conventions][gtype-conventions].
|
* GObjects and their methods, see the [GType conventions][gtype-conventions].
|
||||||
* For the high-level concepts behind GObject, read [Instantiatable classed types:
|
* For the high-level concepts behind GObject, read [Instantiatable classed types:
|
||||||
* Objects][gtype-instantiatable-classed].
|
* 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 --- */
|
/* --- macros --- */
|
||||||
|
116
gobject/gvalue.c
116
gobject/gvalue.c
@ -31,122 +31,6 @@
|
|||||||
#include "gtype-private.h"
|
#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 --- */
|
/* --- typedefs & structures --- */
|
||||||
typedef struct {
|
typedef struct {
|
||||||
GType src_type;
|
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…
x
Reference in New Issue
Block a user