<?xml version="1.0" encoding="utf-8"?>
<feed xmlns="http://www.w3.org/2005/Atom"><title>halting problem - gnome</title><link href="https://www.bassi.io/" rel="alternate"></link><link href="https://www.bassi.io/feeds/gnome.atom.xml" rel="self"></link><id>https://www.bassi.io/</id><updated>2026-03-17T17:45:00+00:00</updated><entry><title>Let’s talk about Moonforge</title><link href="https://www.bassi.io/articles/2026/03/17/lets-talk-about-moonforge/" rel="alternate"></link><published>2026-03-17T17:45:00+00:00</published><updated>2026-03-17T17:44:31+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2026-03-17:/articles/2026/03/17/lets-talk-about-moonforge/</id><summary type="html">&lt;p&gt;In which I talk a bit about what I&amp;#8217;ve been doing at Igalia in&amp;nbsp;2025&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last week, Igalia finally &lt;a href="https://www.igalia.com/2026/03/09/Introducing-Moonforge-A-Yocto-Based-Linux-OS.html"&gt;announced Moonforge&lt;/a&gt;, a project we&amp;#8217;ve been working on for basically all of 2025. It&amp;#8217;s been quite the rollercoaster, and the announcement hit various news outlets, so I guess now is as good a time as any to talk a bit about what Moonforge is, its goal, and its&amp;nbsp;constraints.&lt;/p&gt;
&lt;p&gt;Of course, as soon as somebody announces a new Linux-based &lt;span class="caps"&gt;OS&lt;/span&gt;, folks immediately think it&amp;#8217;s a new general purpose Linux distribution, as that&amp;#8217;s the &lt;a href="https://www.youtube.com/watch?v=cUbIkNUFs-4"&gt;square shaped hole&lt;/a&gt; where everything &lt;span class="caps"&gt;OS&lt;/span&gt;-related ends up. So, first things first, let&amp;#8217;s get a couple of things out of the way about &lt;a href="https://moonforgelinux.org"&gt;Moonforge&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Moonforge is &lt;strong&gt;not&lt;/strong&gt; a general purpose Linux&amp;nbsp;distribution&lt;/li&gt;
&lt;li&gt;Moonforge is &lt;strong&gt;not&lt;/strong&gt; an embedded Linux&amp;nbsp;distribution&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;What is&amp;nbsp;Moonforge&lt;/h3&gt;
&lt;p&gt;Moonforge is a set of feature-based, well-maintained layers for &lt;a href="https://yoctoproject.org"&gt;Yocto&lt;/a&gt;, that allows you to assemble your own &lt;span class="caps"&gt;OS&lt;/span&gt; for embedded devices, or single-application environments, with specific emphasys on immutable, read-only root file system &lt;span class="caps"&gt;OS&lt;/span&gt; images that are easy to deploy and update, through tight integration with &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt;&amp;nbsp;pipelines.&lt;/p&gt;
&lt;h3&gt;Why?&lt;/h3&gt;
&lt;p&gt;Creating a whole new &lt;span class="caps"&gt;OS&lt;/span&gt; image out of whole cloth is not as hard as it used to be; on the desktop (and devices where you control the hardware), you can reasonably &lt;a href="https://store.steampowered.com/steamos/"&gt;get away&lt;/a&gt; with using existing Linux distributions, filing off the serial numbers, and removing any extant packaging mechanism; or you can rely on the &lt;a href="https://universal-blue.org/"&gt;containerised tech stack&lt;/a&gt;, and boot into&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;When it comes to embedded platforms, on the other hand, you&amp;#8217;re still very much working on bespoke, artisanal, locally sourced, organic operating systems. A good number of device manufacturers coalesced their &lt;a href="https://en.wikipedia.org/wiki/Board_support_package"&gt;BSPs&lt;/a&gt; around the &lt;a href="https://www.yoctoproject.org/"&gt;Yocto Project&lt;/a&gt; and &lt;a href="https://www.openembedded.org/wiki/Main_Page"&gt;OpenEmbedded&lt;/a&gt;, which simplifies adaptations, but you&amp;#8217;re still supposed to build the thing mostly as a one&amp;nbsp;off.&lt;/p&gt;
&lt;p&gt;While Yocto has improved leaps and bounds over the past 15 years, putting together an &lt;span class="caps"&gt;OS&lt;/span&gt; image, especially when it comes to bundling features while keeping the overall size of the base image down, is still an exercise in artisanal&amp;nbsp;knowledge.&lt;/p&gt;
&lt;h3&gt;A little detour:&amp;nbsp;Poky&lt;/h3&gt;
&lt;p&gt;Twenty years ago, I moved to London to work for this little consultancy called OpenedHand. One of the projects that OpenedHand was working on was taking OpenEmbedded and providing a good set of defaults and layers, in order to create a &amp;#8220;reference distribution&amp;#8221; that would help people getting started with their own project. That reference was called &lt;a href="https://web.archive.org/web/20070402231645/http://projects.o-hand.com/poky"&gt;Poky&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;We had a beaver mascot before it was&amp;nbsp;cool&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/poky-beaver.jpeg"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;These days, Poky exists as part of the Yocto Project, and it&amp;#8217;s still the reference distribution for it, but since it&amp;#8217;s part of Yocto, it has to abide to the basic constraint of the project: you still need to set up your &lt;span class="caps"&gt;OS&lt;/span&gt; using shell scripts and copy-pasting layers and recipes inside your own repository. The Yocto project is working on &lt;a href="https://github.com/kanavin/bitbake/commits/akanavin/bitbake-setup"&gt;a setup tool&lt;/a&gt; to
simplify those steps, but there are&amp;nbsp;alternatives…&lt;/p&gt;
&lt;h3&gt;Another little detour:&amp;nbsp;Kas&lt;/h3&gt;
&lt;p&gt;One alternative is &lt;a href="https://kas.readthedocs.io/en/latest/"&gt;kas&lt;/a&gt;, a tool that allows you to generate the &lt;code&gt;local.conf&lt;/code&gt; configuration file used by bitbake through various &lt;span class="caps"&gt;YAML&lt;/span&gt; fragments exported by each layer you&amp;#8217;re interested in, as well as additional fragments that can be used to set up customised&amp;nbsp;environments.&lt;/p&gt;
&lt;p&gt;Another feature of kas is that it can spin up the build environment inside a container, which simplifies enourmously its set up time. It avoids unadvertedly contaminating the build, and it makes it very easy to run the build on &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; pipelines that already rely on&amp;nbsp;containers.&lt;/p&gt;
&lt;h3&gt;What Moonforge&amp;nbsp;provides&lt;/h3&gt;
&lt;p&gt;Moonforge lets you create a new &lt;span class="caps"&gt;OS&lt;/span&gt; in minutes, selecting a series of features you care about from various &lt;a href="https://moonforgelinux.org/docs/layers/"&gt;available layers&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Each layer provides a single feature,&amp;nbsp;like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;support for a specific architecture or device (&lt;span class="caps"&gt;QEMU&lt;/span&gt; x86_64,&amp;nbsp;RaspberryPi)&lt;/li&gt;
&lt;li&gt;containerisation (through Docker or&amp;nbsp;Podman)&lt;/li&gt;
&lt;li&gt;A/B updates (through &lt;span class="caps"&gt;RAUC&lt;/span&gt;, systemd-sysupdate, and&amp;nbsp;more)&lt;/li&gt;
&lt;li&gt;graphical session, using&amp;nbsp;Weston&lt;/li&gt;
&lt;li&gt;a &lt;a href="https://webkit.org/wpe/"&gt;&lt;span class="caps"&gt;WPE&lt;/span&gt;&lt;/a&gt;&amp;nbsp;environment&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every layer comes with its own kas fragment, which describes what the layer needs to add to the project configuration in order to&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;Since every layer is isolated, we can reason about their dependencies and interactions, and we can combine them into a final, custom&amp;nbsp;product.&lt;/p&gt;
&lt;p&gt;Through various tools, including kas, we can set up a Moonforge project that generates and validates &lt;span class="caps"&gt;OS&lt;/span&gt; images as the result of a &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; pipeline on platforms like GitLab, GitHub, and BitBucket; &lt;span class="caps"&gt;OS&lt;/span&gt; updates are also generated as part of that pipeline, just as comprehensive &lt;span class="caps"&gt;CVE&lt;/span&gt; reports and Software Bill of Materials (&lt;span class="caps"&gt;SBOM&lt;/span&gt;) through custom Yocto&amp;nbsp;recipes.&lt;/p&gt;
&lt;p&gt;More importantly, Moonforge can act both as a reference when it comes to hardware enablement and support for BSPs; and as a reference when building applications that need to interact with specific features coming from a&amp;nbsp;board.&lt;/p&gt;
&lt;p&gt;While this is the beginning of the project, it&amp;#8217;s already fairly usable; we are planning a lot more in this space, so keep an eye out on &lt;a href="https://github.com/moonforgelinux"&gt;the repository&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Trying Moonforge&amp;nbsp;out&lt;/h3&gt;
&lt;p&gt;If you want to check out Moonforge, I will point you in the direction of its &lt;a href="https://moonforgelinux.org/docs/tutorials/"&gt;tutorials&lt;/a&gt;, as well as the &lt;a href="https://github.com/moonforgelinux/meta-derivative/"&gt;meta-derivative&lt;/a&gt; repository, which should give you a good overview on how Moonforge works, and how you can use&amp;nbsp;it.&lt;/p&gt;</content><category term="gnome"></category><category term="work"></category><category term="igalia"></category><category term="yocto"></category><category term="development"></category></entry><entry><title>Governance in GNOME</title><link href="https://www.bassi.io/articles/2025/08/03/governance-in-gnome/" rel="alternate"></link><published>2025-08-03T20:48:00+01:00</published><updated>2025-08-03T20:48:33+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2025-08-03:/articles/2025/08/03/governance-in-gnome/</id><summary type="html">&lt;p&gt;In which I talk about introducing a formal technical governance in the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;project&lt;/p&gt;</summary><content type="html">&lt;h2&gt;How do things happen in &lt;span class="caps"&gt;GNOME&lt;/span&gt;?&lt;/h2&gt;
&lt;p&gt;Things happen in &lt;span class="caps"&gt;GNOME&lt;/span&gt;? Could have fooled me,&amp;nbsp;right?&lt;/p&gt;
&lt;p&gt;Of course, things happen in &lt;span class="caps"&gt;GNOME&lt;/span&gt;. After all, we have been releasing every
six months, on the dot, for nearly 25 years. Assuming we&amp;#8217;re not constantly
re-releasing the same source files, then we have to come to the conclusion
that things change inside each project that makes &lt;span class="caps"&gt;GNOME&lt;/span&gt;, and thus things
happen that involve more than one&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;So let&amp;#8217;s roll back a&amp;nbsp;bit.&lt;/p&gt;
&lt;h2&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8217;s original&amp;nbsp;sin&lt;/h2&gt;
&lt;p&gt;We all know Havoc Pennington&amp;#8217;s &lt;a href="https://ometer.com/preferences.html"&gt;essay on
preferences&lt;/a&gt;; it&amp;#8217;s one of &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8217;s
foundational texts, we refer to it pretty much constantly both inside and
outside the contributors community. It has guided our decisions and taste
for over 20 years. As far as foundational text goes, though, it applies to
design philosophy, not to project&amp;nbsp;governance.&lt;/p&gt;
&lt;p&gt;When talking about the inception and technical direction of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; project
there are really two foundational texts that describe the goals of &lt;span class="caps"&gt;GNOME&lt;/span&gt;, as
well as the mechanisms that are employed to achieve those&amp;nbsp;goals.&lt;/p&gt;
&lt;p&gt;The first one is, of course, Miguel&amp;#8217;s announcement of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; project
itself, sent to the &lt;span class="caps"&gt;GTK&lt;/span&gt;, Guile, and (for good measure) the &lt;span class="caps"&gt;KDE&lt;/span&gt; mailing&amp;nbsp;lists:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;We will try to reuse the existing code for &lt;span class="caps"&gt;GNU&lt;/span&gt; programs as
much as possible, while adhering to the guidelines of the project.
Putting nice and consistent user interfaces over all-time
favorites will be one of the projects.
    &amp;#8212; Miguel de Icaza, &lt;a href="https://mail.gnome.org/archives/gtk-list/1997-August/msg00123.html"&gt;&amp;#8220;The &lt;span class="caps"&gt;GNOME&lt;/span&gt; Desktop project.&amp;#8221; announcement&amp;nbsp;email&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Once again, everyone related to the &lt;span class="caps"&gt;GNOME&lt;/span&gt; project is (or should be) familiar
with this&amp;nbsp;text.&lt;/p&gt;
&lt;p&gt;The second foundational text is not as familiar, outside of the core group
of people that were around at the time. I am referring to Derek Glidden&amp;#8217;s
description of the differences between &lt;span class="caps"&gt;GNOME&lt;/span&gt; and &lt;span class="caps"&gt;KDE&lt;/span&gt;, written five years
after the inception of the project. I isolated a small fragment of&amp;nbsp;it:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Development strategies are generally determined by whatever light show happens
to be going on at the moment, when one of the developers will leap up and scream
“I &lt;span class="caps"&gt;WANT&lt;/span&gt; &lt;span class="caps"&gt;IT&lt;/span&gt; &lt;span class="caps"&gt;TO&lt;/span&gt; &lt;span class="caps"&gt;LOOK&lt;/span&gt; &lt;span class="caps"&gt;JUST&lt;/span&gt; &lt;span class="caps"&gt;LIKE&lt;/span&gt; &lt;span class="caps"&gt;THAT&lt;/span&gt;” and then straight-arm his laptop against the
wall in an hallucinogenic frenzy before vomiting copiously, passing out and
falling face-down in the middle of the dance floor.
    &amp;#8212; Derek Glidden, &lt;a href="https://www.bassi.io/~ebassi/GNOMEvKDE.md.html"&gt;&amp;#8220;&lt;span class="caps"&gt;GNOME&lt;/span&gt; vs &lt;span class="caps"&gt;KDE&lt;/span&gt;&amp;#8221;&lt;/a&gt;&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;What both texts have in common is subtle, but explains the origin of the
project. You may not notice it immediately, but once you see it you can&amp;#8217;t
unsee it: it&amp;#8217;s the over-reliance on personal projects and taste, to be
sublimated into a shared vision. A &amp;#8220;bottom up&amp;#8221; approach, with &amp;#8220;nice and
consistent user interfaces&amp;#8221; bolted on top of &amp;#8220;all-time favorites&amp;#8221;, with zero
indication of how those nice and consistent UIs would work on extant code
bases, all driven by somebody&amp;#8217;s with a vision—drug induced or otherwise—that
decides to lead the project towards its&amp;nbsp;implementation.&lt;/p&gt;
&lt;p&gt;It&amp;#8217;s been nearly 30 years, but &lt;span class="caps"&gt;GNOME&lt;/span&gt; still works that&amp;nbsp;way.&lt;/p&gt;
&lt;p&gt;Sure, we&amp;#8217;ve had a &lt;span class="caps"&gt;HIG&lt;/span&gt; for 25 years, and the shared development resources
that the project provides tend to mask this, to the point that everyone
outside the project assumes that all people with access to the &lt;span class="caps"&gt;GNOME&lt;/span&gt; commit
bit work on the whole project, as a single unit. If you are here, listening
(or reading) to this, you know it&amp;#8217;s not true. In fact, it is so comically
removed from the lived experience of everyone involved in the project that
we generally joke about&amp;nbsp;it.&lt;/p&gt;
&lt;h2&gt;Herding cats and vectors&amp;nbsp;sum&lt;/h2&gt;
&lt;p&gt;During my first &lt;span class="caps"&gt;GUADEC&lt;/span&gt;, back in 2005, I saw a great slide from Seth Nickell,
one of the original &lt;span class="caps"&gt;GNOME&lt;/span&gt; designers. It showed &lt;span class="caps"&gt;GNOME&lt;/span&gt; contributors
represented as a jumble of vectors going in all directions, cancelling each
component out; and the occasional movement in the project was the result of
somebody pulling/pushing harder in their&amp;nbsp;direction.&lt;/p&gt;
&lt;p&gt;Of course, this is not the exclusive province of &lt;span class="caps"&gt;GNOME&lt;/span&gt;: you could take most
complex free and open source software projects and draw a similar diagram. I
contend, though, that when it comes to &lt;span class="caps"&gt;GNOME&lt;/span&gt; this is not emergent behaviour
but it&amp;#8217;s baked into the project from its very inception: a loosey-goosey
collection of cats, herded together by whoever shows up with &amp;#8220;a vision&amp;#8221;,
but, also, a collection of loosely coupled projects. Over the years we tried
to put a rest to the notion that &lt;span class="caps"&gt;GNOME&lt;/span&gt; is a box of &lt;span class="caps"&gt;LEGO&lt;/span&gt;, meant to be
assembled together by distributors and users in the way they most like it;
while our software stack has graduated from the &amp;#8220;thrown together at the last
minute&amp;#8221; quality of its first decade, our community is still very much
following that very same model; the only way it &lt;strong&gt;seems&lt;/strong&gt; to work is because
we have a few people maintaining a lot of&amp;nbsp;components.&lt;/p&gt;
&lt;h2&gt;On&amp;nbsp;maintainers&lt;/h2&gt;
&lt;p&gt;I am a software nerd, and one of the side effects of this terminal condition
is that I like optimisation problems. Optimising software is inherently
boring, though, so I end up trying to optimise processes and people. The
fundamental truth of process optimisation, just like software, is to avoid
unnecessary work—which, in some cases, means optimising away the people&amp;nbsp;involved.&lt;/p&gt;
&lt;p&gt;I am afraid I will have to be blunt, here, so I am going to ask for your
forgiveness in&amp;nbsp;advance.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s say you are a maintainer inside a community of maintainers. Dealing
with people is hard, and the lord forbid you talk to other people about what
you&amp;#8217;re doing, what they are doing, and what you can do together, so you only
have a few options&amp;nbsp;available.&lt;/p&gt;
&lt;p&gt;The first one is: you carve out your niche. You start, or take over, a
project, or an aspect of a project, and you try very hard to make yourself
indispensable, so that everything ends up passing through you, and everyone
has to defer to your taste, opinion, or&amp;nbsp;edict.&lt;/p&gt;
&lt;p&gt;Another option: &lt;span class="caps"&gt;API&lt;/span&gt; design is opinionated, and reflects the thoughts of the
person behind it. By designing platform &lt;span class="caps"&gt;API&lt;/span&gt;, you try to replicate your
toughts, taste, and opinions into the minds of the people using it, like the
eggs of parasitic wasp; because if everybody thinks like you, then there
won&amp;#8217;t be conflicts, and you won&amp;#8217;t have to deal with details, like &amp;#8220;how to
make this application work&amp;#8221;, or &amp;#8220;how to share functionality&amp;#8221;; or, you know,
having to develop a theory of mind for relating to other&amp;nbsp;people.&lt;/p&gt;
&lt;p&gt;Another option: you try to reimplement the entirety of a platform by
yourself. You start a bunch of projects, which require starting a bunch of
dependencies, which require refactoring a bunch of libraries, which ends up
cascading into half of the stack. Of course, since you&amp;#8217;re by yourself, you
end up with a consistent approach to everything. Everything is as it ought
to be: fast, lean, efficient, a reflection of your taste, commitment, and
&lt;em&gt;ethos&lt;/em&gt;. You made everyone else redundant, which means people depend on you,
but also nobody is interested in helping you out, because you are now taken
for granted, on the one hand, and nobody is able to get a word edgewise into
what you made on the&amp;nbsp;other.&lt;/p&gt;
&lt;p&gt;I purposefully did not name names, even though we can all recognise somebody
in these examples. For instance, I recognise myself. I have been all of
these examples, at one point or another over the past 20&amp;nbsp;years.&lt;/p&gt;
&lt;h2&gt;Painting a target on your&amp;nbsp;back&lt;/h2&gt;
&lt;p&gt;But if this is what it looks like from within a project, what it looks like
from the outside is even&amp;nbsp;worse.&lt;/p&gt;
&lt;p&gt;Once you start dragging other people, you raise your visibility; people
start learning your name, because you appear in the issue tracker, on
Matrix/&lt;span class="caps"&gt;IRC&lt;/span&gt;, on Discourse and Planet &lt;span class="caps"&gt;GNOME&lt;/span&gt;. Youtubers and journalists start
asking you questions about the project. Randos on web forums start
associating you to everything &lt;span class="caps"&gt;GNOME&lt;/span&gt; does, or does not; to features, design,
and bugs. You become responsible for every decision, whether you are or not,
and this leads to being the embodiment of all evil the project does. You&amp;#8217;ll
get hate mail, you&amp;#8217;ll be harrassed, your words will be used against you and
the project for ever and&amp;nbsp;ever.&lt;/p&gt;
&lt;h2&gt;Burnout and&amp;nbsp;you&lt;/h2&gt;
&lt;p&gt;Of course, that ends up burning people out; it would be absurd if it didn&amp;#8217;t.
Even in the best case possible, you&amp;#8217;ll end up burning out just by reaching
empathy fatigue, because everyone has access to you, and everyone has their
own problems and bugs and features and wouldn&amp;#8217;t it be great to solve every
problem in the world? This is similar to working for non profits as opposed
to the typical corporate burnout: you get into a feedback loop where you
don&amp;#8217;t want to distance yourself from the work you do because the work you do
gives meaning to yourself and to the people that use it; and yet working on
it hurts you. It also empowers bad faith actors to hound you down to the
ends of the earth, until you realise that turning sand into computers was a
terrible mistake, and we should have torched the first personal computer
down on&amp;nbsp;sight.&lt;/p&gt;
&lt;h2&gt;Governance&lt;/h2&gt;
&lt;p&gt;We want to have structure, so that people know what to expect and how to
navigate the decision making process inside the project; we also want to
avoid having a sacrificial lamb that takes on all the problems in the world
on their shoulders until we burn them down to a cinder and they have to
leave. We&amp;#8217;re 28 years too late to have a benevolent dictator, self-appointed
or otherwise, and we don&amp;#8217;t want to have a public consultation every time we
want to deal with a systemic feature. What do we&amp;nbsp;do?&lt;/p&gt;
&lt;h3&gt;Examples&lt;/h3&gt;
&lt;p&gt;What do other projects have to teach us about governance? We are not the
only complex free software project in existence, and it would be an appaling
measure of narcissism to believe that we&amp;#8217;re special in any way, shape or&amp;nbsp;form.&lt;/p&gt;
&lt;h3&gt;Python&lt;/h3&gt;
&lt;p&gt;We should all know what a &lt;a href="https://peps.python.org"&gt;Python &lt;span class="caps"&gt;PEP&lt;/span&gt;&lt;/a&gt; is, but if
you are not familiar with the process I strongly recommend going through it.
It&amp;#8217;s well documented, and pretty much the de facto standard for any complex
free and open source project that has achieved escape velocity from a
centralised figure in charge of the whole decision making process. The real
achievement of the Python community is that it adopted this policy long
before their centralised figure called it quits. The interesting thing of
the &lt;span class="caps"&gt;PEP&lt;/span&gt; process is that it is used to codify the governance of the project
itself; the &lt;span class="caps"&gt;PEP&lt;/span&gt; template is a &lt;span class="caps"&gt;PEP&lt;/span&gt;; teams are defined through PEPs; target
platforms are defined through PEPs; deprecations are defined through PEPs;
all project-wide processes are defined through&amp;nbsp;PEPs.&lt;/p&gt;
&lt;h3&gt;Rust&lt;/h3&gt;
&lt;p&gt;Rust has a similar process for language, tooling, and standard library
changes, called &lt;a href="https://github.com/rust-lang/rfcs"&gt;&amp;#8220;&lt;span class="caps"&gt;RFC&lt;/span&gt;&amp;#8221;&lt;/a&gt;. The &lt;span class="caps"&gt;RFC&lt;/span&gt; process
is more lightweight on the formalities than Python&amp;#8217;s PEPs, but it&amp;#8217;s still
very well defined. Rust, being a project that came into existence in a
Post-&lt;span class="caps"&gt;PEP&lt;/span&gt; world, adopted the same type of process, and used it to codify
teams, governance, and any and all project-wide&amp;nbsp;processes.&lt;/p&gt;
&lt;h3&gt;Fedora&lt;/h3&gt;
&lt;p&gt;Fedora change proposals exist to discuss and document both self-contained
changes (usually fairly uncontroversial, given that they are proposed by the
same owners of module being changed) and system-wide changes. The main
difference between them is that most of the elements of a system-wide change
proposal are required, wheres for self-contained proposals they can be
optional; for instance, a system-wide change must have a contingency plan, a
way to test it, and the impact on documentation and release notes, whereas
as self-contained change does&amp;nbsp;not.&lt;/p&gt;
&lt;h3&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;Turns out that we once did have &lt;a href="https://gitlab.gnome.org/Archive/gep"&gt;&amp;#8220;&lt;span class="caps"&gt;GNOME&lt;/span&gt; Enhancement
Proposals&amp;#8221;&lt;/a&gt; (&lt;span class="caps"&gt;GEP&lt;/span&gt;), mainly modelled on
Python&amp;#8217;s &lt;span class="caps"&gt;PEP&lt;/span&gt; from 2002. If this comes as a surprise, that&amp;#8217;s because they
lasted for about a year, mainly because it was a reactionary process to try
and funnel some of the large controversies of the 2.0 development cycle into
a productive outlet that didn&amp;#8217;t involve flames and people dramatically
quitting the project. GEPs failed once the community fractured, and people
started working in silos, either under their own direction or, more likely,
under their management&amp;#8217;s direction. What&amp;#8217;s the point of discussing a
project-wide change, when that change was going to be implemented by people
already working&amp;nbsp;together?&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;GEP&lt;/span&gt; process mutated into the lightweight &amp;#8220;module proposal&amp;#8221; process,
where people discussed adding and removing dependencies on the desktop
development mailing list—something we also lost over the 2.x cycle, mainly
because the amount of discussions over time tended towards zero. The people
involved with the change knew what those modules brought to the release, and
people unfamiliar with them were either giving out unsolicited advice, or
were simply not reached by the desktop development mailing list. The
discussions turned into external dependencies notifications, which also died
up because apparently asking to compose an email to notify the release team
that a new dependency was needed to build a core module was far too much of
a bother for project&amp;nbsp;maintainers.&lt;/p&gt;
&lt;p&gt;The creation and failure of &lt;span class="caps"&gt;GEP&lt;/span&gt; and module proposals is both an indication
of the need for structure inside &lt;span class="caps"&gt;GNOME&lt;/span&gt;, and how this need collides with the
expectation that project maintainers have not just complete control over
every aspect of their domain, but that they can also drag out the process
until all the energy behind it has dissipated. Being in charge for the long
run allows people to just run out the clock on everybody&amp;nbsp;else.&lt;/p&gt;
&lt;h2&gt;Goals&lt;/h2&gt;
&lt;p&gt;So, what should be the goal of a proper technical governance model for the
&lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;project?&lt;/p&gt;
&lt;h3&gt;Diffusing&amp;nbsp;responsibilities&lt;/h3&gt;
&lt;p&gt;This should be goal zero of any attempt at structuring the technical
governance of &lt;span class="caps"&gt;GNOME&lt;/span&gt;. We have too few people in too many critical positions.
We can call it &amp;#8220;efficiency&amp;#8221;, we can call it &amp;#8220;bus factor&amp;#8221;, we can call it
&amp;#8220;bottleneck&amp;#8221;, but the result is the same: the responsibility for anything is
too concentrated. This is how you get conflict. This is how you get burnout.
This is how you paralise a whole project. By having too few people in
positions of responsibility, we don&amp;#8217;t have enough slack in the governance
model; it&amp;#8217;s an illusion of&amp;nbsp;efficiency.&lt;/p&gt;
&lt;p&gt;Responsibility is not something to hoard: it&amp;#8217;s something to&amp;nbsp;distribute.&lt;/p&gt;
&lt;h3&gt;Empowering the&amp;nbsp;community&lt;/h3&gt;
&lt;p&gt;The community of contributors should be able to know when and how a decision
is made; it should be able to know what to do once a decision is made. Right
now, the process is opaque because it&amp;#8217;s done inside a million different
rooms, and, more importantly, it is not recorded for posterity. Random
GitLab issues should not be the only place where people can be informed that
some decision was&amp;nbsp;taken.&lt;/p&gt;
&lt;h3&gt;Empowering&amp;nbsp;individuals&lt;/h3&gt;
&lt;p&gt;Individuals should be able to contribute to a decision without necessarily
becoming responsible for a whole project. It&amp;#8217;s daunting, and requires a
measure of &lt;em&gt;hubris&lt;/em&gt; that cannot be allowed to exist in a shared space. In a
similar fashion, we should empower people that want to contribute to the
project by reducing the amount of fluff coming from people with zero stakes
in it, and are interested only in giving out an opinion on their perfectly
spherical, frictionless desktop&amp;nbsp;environment.&lt;/p&gt;
&lt;p&gt;It is &lt;em&gt;free and open source software&lt;/em&gt;, not &lt;em&gt;free and open mic night down at
the pub&lt;/em&gt;.&lt;/p&gt;
&lt;h3&gt;Actual decision making&amp;nbsp;process&lt;/h3&gt;
&lt;p&gt;We say we work by rough consensus, but if a single person is responsible for
multiple modules inside the project, we&amp;#8217;re just deceiving ourselves. I
should not be able to design something on my own, commit it to all projects
I maintain, and then go home, regardless of whether what I designed is good
or&amp;nbsp;necessary.&lt;/p&gt;
&lt;h2&gt;Proposed &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;Changes✝&lt;/h2&gt;
&lt;p&gt;✝ Name subject to&amp;nbsp;change&lt;/p&gt;
&lt;h3&gt;PGCs&lt;/h3&gt;
&lt;p&gt;We have better tools than what the &lt;span class="caps"&gt;GEP&lt;/span&gt; used to use and be. We have better
communication venues in 2025; we have better validation; we have better
publishing&amp;nbsp;mechanisms.&lt;/p&gt;
&lt;p&gt;We can take a lightweight approach, with a well-defined process, and use it
not for actual design or decision-making, but for discussion and
documentation. If you are trying to design something and you use this
process, you are by definition Doing It Wrong™. You should have a design
ready, and series of steps to achieve it, as part of a proposal. You should
already know the projects involved, and already have an idea of the effort
needed to make something&amp;nbsp;happen.&lt;/p&gt;
&lt;p&gt;Once you have a formal proposal, you present it to the various stakeholders,
and iterate over it to improve it, clarify it, and amend it, until you have
something that has a rough consensus among all the parties involved. Once
that&amp;#8217;s done, the proposal is now in effect, and people can refer to it
during the implementation, and in the future. This way, we don&amp;#8217;t have to ask
people to remember a decision made six months, two years, ten years ago:
it&amp;#8217;s already&amp;nbsp;available.&lt;/p&gt;
&lt;h3&gt;Editorial&amp;nbsp;team&lt;/h3&gt;
&lt;p&gt;Proposals need to be valid, in order to be presented to the community at
large; that validation comes from an editorial team. The editors of the
proposals are not there to evaluate its contents: they are there to ensure
that the proposal is going through the expected steps, and that discussions
related to it remain relevant and constrained within the accepted period and
scope. They are there to steer the discussion, and avoid architecture
astronauts parachuting into the issue tracker or Discourse to give their
unwarranted&amp;nbsp;opinion.&lt;/p&gt;
&lt;p&gt;Once the proposal is open, the editorial team is responsible for its
inclusion in the public website, and for keeping track of its&amp;nbsp;state.&lt;/p&gt;
&lt;h3&gt;Steering&amp;nbsp;group&lt;/h3&gt;
&lt;p&gt;The steering group is the final arbiter of a proposal. They are responsible
for accepting it, or rejecting it, depending on the feedback from the
various stakeholders. The steering group does not design or direct &lt;span class="caps"&gt;GNOME&lt;/span&gt; as
a whole: they are the ones that ensure that communication between the parts
happens in a meaningful manner, and that rough consensus is&amp;nbsp;achieved.&lt;/p&gt;
&lt;p&gt;The steering group is also, by design, not the release team: it is made of
representatives from all the teams related to technical&amp;nbsp;matters.&lt;/p&gt;
&lt;h2&gt;Is this&amp;nbsp;enough?&lt;/h2&gt;
&lt;p&gt;Sadly,&amp;nbsp;no.&lt;/p&gt;
&lt;p&gt;Reviving a process for proposing changes in &lt;span class="caps"&gt;GNOME&lt;/span&gt; without addressing the
shortcomings of its first iteration would inevitably lead to a repeat of its&amp;nbsp;results.&lt;/p&gt;
&lt;p&gt;We have better tooling, but the problem is still that we&amp;#8217;re demanding that
each project maintainer gets on board with a process that has no mechanism
to enforce&amp;nbsp;compliance.&lt;/p&gt;
&lt;p&gt;Once again, the problem is that we have a bunch of fiefdoms that need to be
opened up to ensure that more people can work on&amp;nbsp;them.&lt;/p&gt;
&lt;h2&gt;Whither&amp;nbsp;maintainers&lt;/h2&gt;
&lt;p&gt;In what was, in retrospect, possibly one of my least gracious and yet most
prophetic moments on the desktop development mailing list, I once said that,
if it were possible, I would have already replaced all &lt;span class="caps"&gt;GNOME&lt;/span&gt; maintainers
with a shell script. Turns out that we did replace a lot of what maintainers
used to do, and we used &lt;a href="https://gitlab.gnome.org/Infrastructure/openshift-images/gnome-release-service"&gt;a large Python
service&lt;/a&gt;
to do&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;Individual maintainers should not exist in a complex project—for both the
project&amp;#8217;s and the contributors&amp;#8217; sake. They are inefficiency made manifest, a
bottleneck, a point of contention in a distributed environment like &lt;span class="caps"&gt;GNOME&lt;/span&gt;.
Luckily for us, we almost made them entirely redundant already! Thanks to
the release service and &lt;span class="caps"&gt;CI&lt;/span&gt; pipelines, we don&amp;#8217;t need a person spinning up a
release archive and uploading it into a file server. We just need somebody
to tag the source code repository, and anybody with the right permissions
could do&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;We need people to review contributions; we need people to write release
notes; we need people to triage the issue tracker; we need people to
contribute features and bug fixes. None of those tasks require the
&amp;#8220;maintainer&amp;#8221;&amp;nbsp;role.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s get rid of maintainers once and for all. We can delegate the
actual release tagging of core projects and applications to the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
release team; they are already releasing &lt;span class="caps"&gt;GNOME&lt;/span&gt; anyway, so what&amp;#8217;s the point
in having them wait every time for somebody else to do individual releases?
All people need to do is to write down what changed in a release, and that
should be part of a change itself; we have centralised release notes, and we
can easily extract the list of bug fixes from the commit log. If you can
ensure that a commit message is correct, you can also get in the habit of
updating the &lt;code&gt;NEWS&lt;/code&gt; file as part of a merge&amp;nbsp;request.&lt;/p&gt;
&lt;p&gt;Additional benefits of having all core releases done by a central authority
are that we get people to update the release notes every time something
changes; and that we can sign all releases with a &lt;span class="caps"&gt;GNOME&lt;/span&gt; key that downstreams
can rely&amp;nbsp;on.&lt;/p&gt;
&lt;h2&gt;Embracing special interest&amp;nbsp;groups&lt;/h2&gt;
&lt;p&gt;But it&amp;#8217;s still not&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;Especially when it comes to the application development platform, we have
already a bunch of components with an informal scheme of shared
responsibility. Why not make that scheme&amp;nbsp;official?&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s create the &lt;span class="caps"&gt;SDK&lt;/span&gt; special interest group; take all the developers for
the base libraries that are part of &lt;span class="caps"&gt;GNOME&lt;/span&gt;—GLib, Pango, &lt;span class="caps"&gt;GTK&lt;/span&gt;, libadwaita—and
formalise the group of people that currently does things like development,
review, bug fixing, and documentation writing. Everyone in the group should
feel empowered to work on all the projects that belong to that group. We
already are, except we end up deferring to somebody that is usually too busy
to cover every single&amp;nbsp;module.&lt;/p&gt;
&lt;p&gt;Other special interest groups should be formed around the desktop, the core
applications, the development tools, the &lt;span class="caps"&gt;OS&lt;/span&gt; integration, the accessibility
stack, the local search engine, the system&amp;nbsp;settings.&lt;/p&gt;
&lt;p&gt;Adding more people to these groups is not going to be complicated, or
introduce instability, because the responsibility is now shared; we would
not be taking somebody that is already overworked, or even potentially new
to the community, and plopping them into the hot seat, ready for a&amp;nbsp;burnout.&lt;/p&gt;
&lt;p&gt;Each special interest group would have a representative in the steering
group, alongside teams like documentation, design, and localisation, thus
ensuring that each aspect of the project technical direction is included in
any discussion. Each special interest group could also have additional
sub-groups, like a web services group in the system settings group; or a
networking group in the &lt;span class="caps"&gt;OS&lt;/span&gt; integration&amp;nbsp;group.&lt;/p&gt;
&lt;h2&gt;What happens if I say&amp;nbsp;no?&lt;/h2&gt;
&lt;p&gt;I get it. You like being in charge. You want to be the one calling the
shots. You feel responsible for your project, and you don&amp;#8217;t want other
people to tell you what to&amp;nbsp;do.&lt;/p&gt;
&lt;p&gt;If this is how you feel, then there&amp;#8217;s nothing wrong with parting ways with
the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; depends on a ton of projects hosted outside &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8217;s own
infrastructure, and we communicate with people maintaining those projects
every day. It&amp;#8217;s 2025, not 1997: there&amp;#8217;s no shortage of code hosting services
in the world, we don&amp;#8217;t need to have them all on &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;infrastructure.&lt;/p&gt;
&lt;p&gt;If you want to play with the other children, if you want to be part of
&lt;span class="caps"&gt;GNOME&lt;/span&gt;, you get to play with a shared set of rules; and that means sharing
all the toys, and not hoarding them for&amp;nbsp;yourself.&lt;/p&gt;
&lt;h2&gt;Civil&amp;nbsp;service&lt;/h2&gt;
&lt;p&gt;What we really want &lt;span class="caps"&gt;GNOME&lt;/span&gt; to be is a group of people working together. We
already are, somewhat, but we can be better at it. We don&amp;#8217;t want rule and
design by committee, but we do need structure, and we need that structure to
be based on expertise; to have distinct sphere of competence; to have
continuity across time; and to be based on rules. We need something
flexible, to take into account the needs of &lt;span class="caps"&gt;GNOME&lt;/span&gt; as a project, and be
capable of growing in complexity so that nobody can be singled out, brigaded
on, or burnt to a cinder on the sacrificial&amp;nbsp;altar.&lt;/p&gt;
&lt;p&gt;Our days of passing out in the middle of the dance floor are long gone. We
might not all be old—actually, I&amp;#8217;m fairly sure we aren&amp;#8217;t—but &lt;span class="caps"&gt;GNOME&lt;/span&gt; has long
ceased to be something we can throw together at the last minute just because
somebody assumed the mantle of a protean ruler, and managed to involve
themselves with every single project until they are the literal embodiement
of an autocratic force capable of dragging everybody else towards a goal,
until the burn out and have to leave for their own&amp;nbsp;sake.&lt;/p&gt;
&lt;p&gt;We &lt;strong&gt;can&lt;/strong&gt; do better than this. We &lt;strong&gt;must&lt;/strong&gt; do&amp;nbsp;better.&lt;/p&gt;
&lt;h2&gt;To sum&amp;nbsp;up&lt;/h2&gt;
&lt;p&gt;Stop releasing individual projects, and let the release team do it when&amp;nbsp;needed.&lt;/p&gt;
&lt;p&gt;Create teams to manage areas of interest, instead of single&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;Create a steering group from representatives of those&amp;nbsp;teams.&lt;/p&gt;
&lt;p&gt;Every change that affects one or more teams has to be discussed and
documented in a public setting among contributors, and then published for
future&amp;nbsp;reference.&lt;/p&gt;
&lt;p&gt;None of this should be controversial because, outside of the publishing bit,
it&amp;#8217;s how we are already doing things. This proposal aims at making it
official so that people can actually rely on it, instead of having to divine
the process out of thin&amp;nbsp;air.&lt;/p&gt;
&lt;hr&gt;
&lt;h2&gt;The next&amp;nbsp;steps&lt;/h2&gt;
&lt;p&gt;We&amp;#8217;re close to the &lt;span class="caps"&gt;GNOME&lt;/span&gt; 49 release, now that &lt;span class="caps"&gt;GUADEC&lt;/span&gt; 2025 has ended, so
people are busy working on tagging releases, fixing bugs, and the work on
the release notes has started. Nevertheless, we can already start planning
for an implementation of a new governance model for &lt;span class="caps"&gt;GNOME&lt;/span&gt; for the next&amp;nbsp;cycle.&lt;/p&gt;
&lt;p&gt;First of all, we need to create teams and special interest groups. We don&amp;#8217;t
have a formal process for that, so this is also a great chance at
introducing the change proposal process as a mechanism for structuring the
community, just like the Python and Rust communities do. Teams will need
their own space for discussing issues, and share the load. The first team
I&amp;#8217;d like to start is an &amp;#8220;introspection and language bindings&amp;#8221; group, for all
bindings hosted on &lt;span class="caps"&gt;GNOME&lt;/span&gt; infrastructure; it would act as a point of
reference for all decisions involving projects that consume the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
software development platform through its machine-readable &lt;span class="caps"&gt;ABI&lt;/span&gt; description.
Another group I&amp;#8217;d like to create is an editorial group for the developer and
user documentation; documentation benefits from a consistent editorial
voice, while the process of writing documentation should be open to
everybody in the&amp;nbsp;community.&lt;/p&gt;
&lt;p&gt;A very real issue that was raised during &lt;span class="caps"&gt;GUADEC&lt;/span&gt; is bootstrapping the
steering committee; who gets to be on it, what is the committee&amp;#8217;s remit, how
it works. There are options, but if we want the steering committee to be a
representation of the technical expertise of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; community, it also
has to be established by the very same community; in this sense, the board
of directors, as representatives of the community, could work on
defining the powers and compositions of this&amp;nbsp;committee.&lt;/p&gt;
&lt;p&gt;There are many more issues we are going to face, but I think we can start
from these and evaluate our own version of a technical governance model that
works for &lt;span class="caps"&gt;GNOME&lt;/span&gt;, and that can grow with the project. In the next couple of
weeks I&amp;#8217;ll start publishing drafts for team governance and the
power/composition/procedure of the steering committee, mainly for iteration
and&amp;nbsp;comments.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="governance"></category><category term="community"></category><category term="politics"></category></entry><entry><title>Introspection’s edge</title><link href="https://www.bassi.io/articles/2023/10/25/introspections-edge/" rel="alternate"></link><published>2023-10-25T09:31:00+01:00</published><updated>2023-10-25T09:43:52+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2023-10-25:/articles/2023/10/25/introspections-edge/</id><summary type="html">&lt;p&gt;In which I go over the plans for&amp;nbsp;gobject-introspection&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; The introspection data for GLib (and its sub-libraries) is now
generated by GLib itself instead of gobject-introspection; and in the near
future, libgirepository is going to be part of GLib as well. Yes, there&amp;#8217;s a
circular dependency, but there are plans for dealing with that. Developers
of language bindings should reach out to the GLib maintainers for future&amp;nbsp;planning.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;GLib-the-project is made of the following&amp;nbsp;components:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;glib, the base data types and C portability&amp;nbsp;library&lt;/li&gt;
&lt;li&gt;gmodule, a portable loadable module &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;gobject, the object oriented run time type&amp;nbsp;system&lt;/li&gt;
&lt;li&gt;gio, a grab bag of I/O, &lt;span class="caps"&gt;IPC&lt;/span&gt;, file, network, settings,&amp;nbsp;etc&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;&lt;p&gt;There are, of course, additional bits inside gobject-introspection,
like the regression and marshalling test suites, as well as the documentation
generators that very few people&amp;nbsp;use.&lt;/p&gt;&lt;/aside&gt;

&lt;p&gt;Just like GLib, the gobject-introspection project is actually three
components in a trench&amp;nbsp;coat:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;g-ir-scanner&lt;/code&gt;, the Python and flex based parser that generates the &lt;span class="caps"&gt;XML&lt;/span&gt;
  description of a GObject-based &lt;span class="caps"&gt;ABI&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;g-ir-compiler&lt;/code&gt;, the &amp;#8220;compiler&amp;#8221; that turns &lt;span class="caps"&gt;XML&lt;/span&gt; into an &lt;code&gt;mmap()&lt;/code&gt;-able binary&amp;nbsp;format&lt;/li&gt;
&lt;li&gt;libgirepository, the C &lt;span class="caps"&gt;API&lt;/span&gt; for loading the binary format, resolving
  types and symbols, and calling into the underlying C&amp;nbsp;library&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Since gobject-introspection depends on GLib for its implementation, the
introspection data for GLib has been, until now, generated during the
gobject-introspection build. This has proven to be extremely&amp;nbsp;messy:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;as the introspection data is generated from the source code,
  gobject-introspection needs to have access to the GLib headers and source&amp;nbsp;files&lt;/li&gt;
&lt;li&gt;this means building against an installed copy of GLib for the
  declarations, and the GLib sources for the&amp;nbsp;docblocks&lt;/li&gt;
&lt;li&gt;to avoid having access to the sources at all times, there is a small
  script that extracts all the docblocks from a GLib checkout; this script
  has to be run manually, and its results committed to the
  gobject-introspection&amp;nbsp;repository&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This means that the gobject-introspection maintainers have to manually keep
the GLib data in sync; that any change done to GLib&amp;#8217;s annotations and
documentation are updated typically at the end of the development cycle,
which also means that any issue with the annotations is discovered almost
always too late; and that any and all updates to the GLib introspection data
require a gobject-introspection release to end up inside downstream&amp;nbsp;distributions.&lt;/p&gt;
&lt;p&gt;The gobject-introspection build &lt;em&gt;can&lt;/em&gt; use GLib as a subproject, at the cost
of some awful, &lt;em&gt;awful&lt;/em&gt; build system messiness, but that does not help
anybody working on GLib; and, of course, since gobject-introspection depends
on GLib, we cannot build the former as a subproject of the&amp;nbsp;latter.&lt;/p&gt;
&lt;p&gt;As part of the push towards moving GLib&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; references towards the use of
&lt;a href="https://gitlab.gnome.org/GNOME/gi-docgen"&gt;gi-docgen&lt;/a&gt;, GLib now checks for
the availability of &lt;code&gt;g-ir-scanner&lt;/code&gt; and &lt;code&gt;g-ir-compiler&lt;/code&gt; on the installed system,
and if they are present, they are used to generate the GLib, GObject,
GModule, and &lt;span class="caps"&gt;GIO&lt;/span&gt; introspection&amp;nbsp;data.&lt;/p&gt;
&lt;p&gt;A good side benefit of having the actual project providing the &lt;span class="caps"&gt;ABI&lt;/span&gt; be in
charge of generating its machine-readable description is that we can now
decouple the release cycles of GLib and gobject-introspection; updates to
the introspection data of GLib will be released alongside GLib, while the
version of gobject-introspection can be updated whenever there&amp;#8217;s new &lt;span class="caps"&gt;API&lt;/span&gt;
inside libgirepository, instead of requiring a bump at every cycle to match&amp;nbsp;GLib.&lt;/p&gt;
&lt;p&gt;On the other hand, though, this change introduces a circular dependency
between GLib and gobject-introspection; this is less than ideal, and though
circular dependencies are a fact of life for whoever builds and packages
complex software, it&amp;#8217;d be better to avoid them; this means two&amp;nbsp;options:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;merging gobject-introspection into&amp;nbsp;GLib&lt;/li&gt;
&lt;li&gt;making gobject-introspection not depend on&amp;nbsp;GLib&lt;/li&gt;
&lt;/ul&gt;
&lt;aside&gt;
&lt;p&gt;This was the original plan for gobject-introspection, back in 2007-2009;
after iterating over a few cycles on the features required by language bindings,
the introspection format and &lt;span class="caps"&gt;API&lt;/span&gt; would be part of GLib, alongside the rest
of the type system. Best laid plans, and all&amp;nbsp;that…&lt;/p&gt;
&lt;/aside&gt;

&lt;p&gt;Sadly, the &lt;a href="https://gitlab.gnome.org/GNOME/glib/-/issues/2616"&gt;first option isn&amp;#8217;t really
workable&lt;/a&gt;, as it would
mean making GLib depend on flex, bison, and CPython in order to build
&lt;code&gt;g-ir-scanner&lt;/code&gt;, or (worse) rewriting &lt;code&gt;g-ir-scanner&lt;/code&gt; in C. There&amp;#8217;s also the
option of rewriting the C parser in pure Python, but that, too, isn&amp;#8217;t
exactly
&lt;a href="https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/231"&gt;strife-free&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The second option is more convoluted, but it has the advantage of being
realistically&amp;nbsp;implemented:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/glib/-/merge_requests/3642"&gt;move libgirepository into GLib as a new&amp;nbsp;sub-library&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;move &lt;code&gt;g-ir-compiler&lt;/code&gt; into GLib&amp;#8217;s&amp;nbsp;tools&lt;/li&gt;
&lt;li&gt;copy-paste the basic GLib data types used by the introspection scanner
   into&amp;nbsp;gobject-introspection&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Aside from breaking the circular dependency, this allows language bindings
that depend on libgirepository&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; (Python, JavaScript, Perl, etc) to
limit their dependency to GLib, since they don&amp;#8217;t need to deal with the
introspection parser bits; it also affords us the ability to clean up the
libgirepository &lt;span class="caps"&gt;API&lt;/span&gt;, provide better documentation, and formalise the file&amp;nbsp;formats.&lt;/p&gt;
&lt;p&gt;Speaking of file formats, and to manage expectations: I don&amp;#8217;t plan to change
the binary data layout; yes, we&amp;#8217;re close to saturation when it comes to
padding bits and fields, but there hasn&amp;#8217;t been a real case in which this has
been problematic. The &lt;span class="caps"&gt;API&lt;/span&gt;, on the other hand, really needs to be cleaned up,
because it got badly namespaced when we originally thought it could be moved
into GLib and then the effort was abandoned. This means that libgirepository
will be bumped to 2.0 (matching the rest of GLib&amp;#8217;s sub-libraries), and will
require some work in the language bindings that consume it. For that,
bindings developers should get in touch with GLib maintainers, so we can
plan the migration&amp;nbsp;appropriately.&lt;/p&gt;</content><category term="gnome"></category><category term="gobject"></category><category term="glib"></category><category term="introspection"></category><category term="bindings"></category><category term="development"></category></entry><entry><title>The Mirror</title><link href="https://www.bassi.io/articles/2023/08/23/the-mirror/" rel="alternate"></link><published>2023-08-23T21:23:00+01:00</published><updated>2023-08-23T21:23:57+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2023-08-23:/articles/2023/08/23/the-mirror/</id><summary type="html">&lt;p&gt;In which I go down the rabbit hole of the GObject type system design and a possible&amp;nbsp;future&lt;/p&gt;</summary><content type="html">&lt;p&gt;The GObject type system has been serving the &lt;span class="caps"&gt;GNOME&lt;/span&gt; community for more than 20 years. We have based an entire application development platform on top of the features it provides, and the rules that it enforces; we have integrated multiple programming languages on top of that, and in doing so, we expanded the scope of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; platform in a myriad of directions. Unlike &lt;span class="caps"&gt;GTK&lt;/span&gt;, the GObject &lt;span class="caps"&gt;API&lt;/span&gt; hasn&amp;#8217;t seen any major change since its introduction: aside from deprecations and little new functionality, the &lt;span class="caps"&gt;API&lt;/span&gt; is exactly the same today as it was when GLib 2.0 was released in March 2002. If you transported a &lt;span class="caps"&gt;GNOME&lt;/span&gt; developer from 2003 to 2023, they would have no problem understanding a newly written GObject class; though, they would likely appreciate the levels of boilerplate reduction, and the performance improvements that have been introduced over the&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;While having a stable &lt;span class="caps"&gt;API&lt;/span&gt; last this long is definitely a positive, it also imposes a burden on maintainers and users, because any change has to be weighted against the possibility of introducing unintended regressions in code that uses undefined, or undocumented, behaviour. There&amp;#8217;s a lot of leeway when it comes to playing games with C, and GObject has dark corners&amp;nbsp;everywhere.&lt;/p&gt;
&lt;p&gt;The other burden is that any major change to a foundational library like GObject cascades across the entire platform. Releasing GLib 3.0 today would necessitate breaking &lt;span class="caps"&gt;API&lt;/span&gt; in the entirety of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; stack and further beyond; it would require either a hard to execute &lt;a href="https://en.wikipedia.org/wiki/Flag_day_(computing)"&gt;&amp;#8220;flag day&amp;#8221;&lt;/a&gt;, or an impossibly long transition, reverberating across downstreams for years to come. Both solutions imply amounts of work that are simply not compatible with a volunteer-based project and ecosystem, especially the current one where volunteers of core components are now stretched thin across too many&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;And yet, we are now at a cross-roads: our foundational code base has reached the point where recruiting new resources capable of affecting change on the project has become increasingly difficult; where any attempt at performance improvement is heavily counterbalanced by the high possibility of introducing world-breaking regressions; and where fixing the safety and ergonomics of idiomatic code requires unspooling twenty years of limitations inherent to the current&amp;nbsp;design.&lt;/p&gt;
&lt;p&gt;Something must be done if we want to improve the coding practices, the performance, and the safety of the platform without a complete&amp;nbsp;rewrite.&lt;/p&gt;
&lt;h1&gt;The&amp;nbsp;Mirror&lt;/h1&gt;
&lt;blockquote&gt;
&lt;p&gt;‘Many things I can command the Mirror to reveal,’ she answered, ‘and to some I can show what they desire to see. But the Mirror also show things unbidden, and those are often stranger and more profitable than things we wish to behold. What you will see, if you leave the Mirror free to work, I cannot tell. For it shows things that were, and things that are, and things that yet may be. But which it is that he sees, even the wisest cannot always tell. Do you wish to look?’
&amp;#8212; Lady Galadriel, “The Lords of the Rings”, Volume 1: The Fellowship of the Ring, Book 2: The Ring Goes&amp;nbsp;South&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;In order to properly understand what we want to achieve, we need to understand the problem space that the type system is meant to solve, and the constraints upon which the type system was implemented. We do that by holding GObject up to Galadriel&amp;#8217;s Mirror, and gazing into its&amp;nbsp;surface.&lt;/p&gt;
&lt;h2&gt;Things that&amp;nbsp;were&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;History became legend. Legend became myth.
&amp;#8212; Lady Galadriel, “The Lord of the Rings: The Fellowship of the&amp;nbsp;Ring”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Before &lt;code&gt;GObject&lt;/code&gt; there was &lt;code&gt;GtkObject&lt;/code&gt;. It was a simpler time, it was a simpler stack. You added types only for the widgets and objects that related to the &lt;span class="caps"&gt;UI&lt;/span&gt; toolkit, and everything else was C89, with a touch of undefined behaviour, like calling function pointers with any number of arguments. Properties were &amp;#8220;arguments&amp;#8221;, likes were florps, and the timeline went&amp;nbsp;sideways.&lt;/p&gt;
&lt;p&gt;We had a class initialisation and an instance initialisation functions; properties were stored in a global hash table, but the property multiplexer pair of functions was stored on the type data instead of using the class structure. Types did not have private data: you only had keyed fields. No interfaces, only single inheritance. &lt;code&gt;GtkObject&lt;/code&gt; was reference counted, and had an initially &amp;#8220;floating&amp;#8221; reference, to allow transparent ownership transfer from child to parent container when writing C code, and make the life of every language binding maintainer miserable in the process. There were weak references attached to an instance that worked by invoking a callback when the instance&amp;#8217;s reference count reached zero. Signals operated exactly as they do today: large hash table of signal information, indexed by an&amp;nbsp;integer.&lt;/p&gt;
&lt;p&gt;None of this was thread safe. After all, &lt;span class="caps"&gt;GTK&lt;/span&gt; was not thread safe either, because X11 was not thread safe; and we&amp;#8217;re talking about 1997: who even had hardware capable of multi-threading at the time? &lt;a href="https://en.wikipedia.org/wiki/Native_POSIX_Thread_Library"&gt;&lt;span class="caps"&gt;NPTL&lt;/span&gt;&lt;/a&gt; wasn&amp;#8217;t even a thing,&amp;nbsp;yet.&lt;/p&gt;
&lt;p&gt;The introduction of &lt;code&gt;GObject&lt;/code&gt; in 2001 changed &lt;em&gt;some&lt;/em&gt; of the rules—mainly, around the idea of having dynamic types that could be loaded and unloaded in order to implement plugins. The basic design of the type system, after all, came from &lt;a href="https://github.com/tim-janik/beast/"&gt;Beast&lt;/a&gt;, a plugin-heavy audio application, and it was extended to subsume the (mostly) static use cases of &lt;span class="caps"&gt;GTK&lt;/span&gt;. In order to support unloading, the class aspect of the type system was allowed to be cleaned up, but the type data had to be registered and never unloaded; in other words, once a type was registered, it was there&amp;nbsp;forever.&lt;/p&gt;
&lt;p&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;Arguments&amp;#8221; were renamed to properties, and were extended to include more than basic types, provide validations, and notify of changes; the overall design was still using a global hash table to store all the properties across all types. Properties were tied to the &lt;code&gt;GObject&lt;/code&gt; type, but the property definition existed as a separate type hierarchy that was designed to validate values, but not manage fields inside a class. Signals were ported wholesale, with minimal changes mainly around the marshalling of values and abstracting&amp;nbsp;closures.&lt;/p&gt;
&lt;p&gt;The entire plan was to have &lt;code&gt;GObject&lt;/code&gt; as &lt;strong&gt;one&lt;/strong&gt; of the base classes at the root of a specific hierarchy, with all the required functionality for &lt;span class="caps"&gt;GTK&lt;/span&gt; to inherit from for its own &lt;code&gt;GtkObject&lt;/code&gt;, while leaving open the possibility of creating other hierarchies, or even other roots with different functionality, for more lightweight&amp;nbsp;objects.&lt;/p&gt;
&lt;p&gt;These constraints were entirely intentional; the idea was to be able to port &lt;span class="caps"&gt;GTK&lt;/span&gt; to the new type system, and to an out of tree GLib, during the 1.3 development phase, and minimise the amount of changes necessary to make the transition work not just inside &lt;span class="caps"&gt;GTK&lt;/span&gt;, but inside of &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;too.&lt;/p&gt;
&lt;p&gt;Little by little, the entire &lt;code&gt;GObject&lt;/code&gt; layer was ported towards thread safety in the only way that worked without breaking the type system: add global locks around everything; use read-write locks for the type data; lock the access and traversal of the property hash table and of the signals table. The only real world code bases that actively exercised multi-threading support were GStreamer and the &lt;span class="caps"&gt;GNOME&lt;/span&gt; &lt;span class="caps"&gt;VFS&lt;/span&gt; &lt;span class="caps"&gt;API&lt;/span&gt; that was mainly used by&amp;nbsp;Nautilus.&lt;/p&gt;
&lt;p&gt;With the 3.0 &lt;span class="caps"&gt;API&lt;/span&gt;, &lt;span class="caps"&gt;GTK&lt;/span&gt; dropped the &lt;code&gt;GtkObject&lt;/code&gt; base type: the whole floating reference mechanism was moved to &lt;code&gt;GObject&lt;/code&gt;, and a new type was introduced to provide the &amp;#8220;initial&amp;#8221; floating reference to derived types. Around the same time, a thread-safe version of weak references for &lt;code&gt;GObject&lt;/code&gt; appeared as a separate &lt;span class="caps"&gt;API&lt;/span&gt;, which confused the matter even&amp;nbsp;more.&lt;/p&gt;
&lt;h2&gt;Things that&amp;nbsp;are&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;Darkness crept back into the forests of the world. Rumour grew of a Shadow in the East, whispers of a Nameless Fear.
&amp;#8212; Lady Galadriel, “The Lord of the Rings: The Fellowship of the&amp;nbsp;Ring”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Let&amp;#8217;s address the elephant in the room: it&amp;#8217;s completely immaterial how many lines of code you have to deal with when creating a new type. It&amp;#8217;s a one-off cost, and for most cases, it&amp;#8217;s a matter of using the existing macros. The declaration and definition macros have the advantages of enforcing a series of best practices, and keep the code consistent across multiple projects. If you don&amp;#8217;t want to deal with boilerplate when using C, you chose the wrong language to begin with. The existence of excessive &lt;span class="caps"&gt;API&lt;/span&gt; is mainly a requirement to allow other languages to integrate their type system with GObject&amp;#8217;s&amp;nbsp;own.&lt;/p&gt;
&lt;p&gt;The dynamic part of the type system has gotten progressively less relevant. Yes: you can still create plugins, and those can register types; but classes are never unloaded, just like their type data. There is some attempt at enforcing an order of operations: you cannot just add an interface after a type has been instantiated any more; and while you can add properties and signals after class initialisation, it&amp;#8217;s mainly a functionality reserved for specific language bindings to maintain backward&amp;nbsp;compatibility.&lt;/p&gt;
&lt;p&gt;Yes, defining properties is boring, and could probably be simplified, but the real cost is not in defining and installing a &lt;code&gt;GParamSpec&lt;/code&gt;: it&amp;#8217;s in writing the set and get property multiplexers, validating the values, boxing and unboxing the data, and dealing with the different property flags; none of those things can be wrapped in some fancy C preprocessor macros—unless you go into the weeds with &lt;a href="https://en.wikipedia.org/wiki/X_macro"&gt;X macros&lt;/a&gt;. The other, big cost of properties is their storage inside a separate, global, lock-happy hash table. The main use case of this functionality—adding entirely separate classes of properties with the same semantics as &lt;code&gt;GObject&lt;/code&gt; properties, like style properties and child properties in &lt;span class="caps"&gt;GTK&lt;/span&gt;—has completely fallen out of favour, and for good reasons: it cannot be managed by generic code; it cannot be handled by documentation generators without prior knowledge; and, for the same reason, it cannot be introspected. Even calling these &amp;#8220;properties&amp;#8221; is kind of a misnomer: they are value validation objects that operate only when using the generic (and less performant) &lt;code&gt;GObject&lt;/code&gt; accessor &lt;span class="caps"&gt;API&lt;/span&gt;, something that is constrained to things like &lt;span class="caps"&gt;UI&lt;/span&gt; definition files in &lt;span class="caps"&gt;GTK&lt;/span&gt;, or language bindings. If you use the C accessors for your own &lt;code&gt;GObject&lt;/code&gt; type, you&amp;#8217;ll have to implement validation yourself; and since idiomatic code will have the generic &lt;code&gt;GObject&lt;/code&gt; accessors call the public C &lt;span class="caps"&gt;API&lt;/span&gt; of your type, you get twice the amount of validation for no reason&amp;nbsp;whatsoever.&lt;/p&gt;
&lt;p&gt;Signals have mostly been left alone, outside of performance improvements that were hard to achieve within the constraints of the existing implementation; the generic &lt;span class="caps"&gt;FFI&lt;/span&gt;-based closure turned out to be a net performance loss, and we&amp;#8217;re trying to walk it back even for D-Bus, which was the main driver for it to land in the first place. Marshallers are now generated with a variadic arguments variant, to reduce the amount of boxing and unboxing of &lt;code&gt;GValue&lt;/code&gt; containers. Still, there&amp;#8217;s not much left to squeeze out of the old GSignal &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The atomic nature of the reference counting can be a costly feature, especially for code bases that are by necessity single-threaded; the fact that the reference count field is part of the (somewhat) public &lt;span class="caps"&gt;API&lt;/span&gt; prevents fundamental refactorings, like switching to biased reference counting for faster operations on the same thread that created an instance. The lack of room on &lt;code&gt;GObject&lt;/code&gt; also prevents storing the thread &lt;span class="caps"&gt;ID&lt;/span&gt; that owns the instance, which in turn prevents calling the &lt;code&gt;GObjectClass.dispose()&lt;/code&gt; and &lt;code&gt;GObjectClass.finalize()&lt;/code&gt; virtual functions on the right thread, and requires scheduling the destruction of an object on a separate main context, or locking the contents of an object at a further&amp;nbsp;cost.&lt;/p&gt;
&lt;h2&gt;Things that yet may&amp;nbsp;be&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;The quest stands upon the edge of a knife: stray but a little, and it will fail to the ruin of all. Yet hope remains, while the company is true.
&amp;#8212; Lady Galadriel, “The Lord of the Rings: The Fellowship of the&amp;nbsp;Ring”&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Over the years, we have been strictly focusing on &lt;code&gt;GObject&lt;/code&gt;: speeding up its internals, figuring out ways to improve property registration and performance, adding new &lt;span class="caps"&gt;API&lt;/span&gt; and features to ensure it behaved more reliably. The type system has also been improved, mainly to streamline its use in idiomatic GObject code bases. Not everything worked: &lt;a href="https://gitlab.gnome.org/GNOME/glib/-/issues/1437"&gt;properties are still a problem&lt;/a&gt;; weak references and pointers are a mess, with two different &lt;span class="caps"&gt;API&lt;/span&gt; that interact badly with &lt;code&gt;GObject&lt;/code&gt;; signals still exists on a completely separate plane; &lt;code&gt;GObject&lt;/code&gt; is still wildly inefficient when it comes to&amp;nbsp;locking.&lt;/p&gt;
&lt;p&gt;The thesis of this strawman is that we reached the limits of backwards compatibility of &lt;code&gt;GObject&lt;/code&gt;, and any attempt at improving it will inevitably lead to a more brittle code, rife with potential regressions. The typical answer, in this case, would be to bump the &lt;span class="caps"&gt;API&lt;/span&gt;/&lt;span class="caps"&gt;ABI&lt;/span&gt; of GObject, remove the mistakes of the past, and provide a new idiomatic approach. Sadly, doing so not only would require a level of resources we, as the GLib project stewards, cannot provide, but it would also completely break the entire ecosystem in a way that is not recoverable. Either nobody would port to the new GObject-3.0 &lt;span class="caps"&gt;API&lt;/span&gt;; or the various projects that depend on GObject would inevitably fracture, following whichever &lt;span class="caps"&gt;API&lt;/span&gt; version they can commit to; in the meantime, downstream distributors would suffer the worst effects of the shared platform we call&amp;nbsp;&amp;#8220;Linux&amp;#8221;.&lt;/p&gt;
&lt;p&gt;Between inaction and slow death, and action with catastrophic consequences, there&amp;#8217;s the possibility of a third option: what if we stopped trying to emulate Java, and have a single &lt;a href="https://en.wikipedia.org/wiki/God_object"&gt;&amp;#8220;god&amp;#8221; type&lt;/a&gt;?&lt;/p&gt;
&lt;p&gt;Our type system is flexible enough to support partitioning various responsibilities, and we can defer complexity where it belongs: into faster moving dependencies, that have the benefit of being able to iterate and change at a much higher rate than the foundational library of the platform. What&amp;#8217;s the point of shoving every possible feature into the base class, in order to cover ever increasingly complex use cases across multiple languages, when we can let consumers decide to opt into their own well-defined behaviours? What GObject ought to provide is a set of reliable types that can be combined in expressive ways, and that can be inspected by generic &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;A new, old base&amp;nbsp;type&lt;/h3&gt;
&lt;p&gt;We already have a derivable type, called &lt;code&gt;GTypeInstance&lt;/code&gt;. Typed instances don&amp;#8217;t have any memory management: once instantiated, they can only be moved, or freed. All our objects already are typed instances, since &lt;code&gt;GObject&lt;/code&gt; inherits from it. Contrary to &lt;a href="https://www.bassi.io/articles/2020/06/02/type-instances/"&gt;the current common practices&lt;/a&gt; we should move towards using &lt;code&gt;GTypeInstance&lt;/code&gt; for our&amp;nbsp;types.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a distinct lack of convenience &lt;span class="caps"&gt;API&lt;/span&gt; for defining typed instances, mostly derived from the fact that &lt;code&gt;GTypeInstance&lt;/code&gt; is seen as a form of &amp;#8220;escape hatch&amp;#8221; for projects to use in order to avoid &lt;code&gt;GObject&lt;/code&gt;. In practice, there&amp;#8217;s nothing that prevents us from improving the convenience of creating new instantiatable/derivable types, especially if we start using them more often. The verbose &lt;span class="caps"&gt;API&lt;/span&gt; must still exist, to allow language bindings and introspection to handle this kind of types, but just like we made convenience macros for declaring and defining &lt;code&gt;GObject&lt;/code&gt; types, we can provide macros for new typed instances, and for setting up a &lt;code&gt;GValue&lt;/code&gt; table.&lt;/p&gt;
&lt;h3&gt;Optional&amp;nbsp;functionality&lt;/h3&gt;
&lt;p&gt;Typed instances require a wrapper &lt;span class="caps"&gt;API&lt;/span&gt; to free their contents before calling &lt;code&gt;g_type_free_instance()&lt;/code&gt;. Nothing prevents us from adding a &lt;code&gt;GFinalizable&lt;/code&gt; interface that can be implemented by a &lt;code&gt;GTypeInstance&lt;/code&gt;, though: interfaces exist at the type system level, and do not require &lt;code&gt;GObject&lt;/code&gt; to&amp;nbsp;work.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GFinalizable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GFinalizableInterface&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If a typed instance provides an implementation of &lt;code&gt;GFinalizable&lt;/code&gt;, then &lt;code&gt;g_type_free_instance()&lt;/code&gt; can free the contents of the instance by calling &lt;code&gt;g_finalizable_finalize()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;This interface is optional, in case your typed instance just contains simple values,&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;is_valid&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;x2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;y2&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Box&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and does not require deallocations outside of the instance&amp;nbsp;block.&lt;/p&gt;
&lt;p&gt;A similar interface can be introduced for cloning instances, allowing a copy operation alongside a&amp;nbsp;move:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GClonable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;clone&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GClonable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GClonable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We could then introduce &lt;code&gt;g_type_instance_clone()&lt;/code&gt; as a generic entry point that either used &lt;code&gt;GClonable&lt;/code&gt;, or simply allocated a new instance and called &lt;code&gt;memcpy()&lt;/code&gt; on it, using the size of the instance (and eventual private data) known to the type&amp;nbsp;system.&lt;/p&gt;
&lt;p&gt;The prior art for this kind of functionality exists in &lt;span class="caps"&gt;GIO&lt;/span&gt;, in the form of the &lt;code&gt;GInitable&lt;/code&gt; and &lt;code&gt;GAsyncInitable&lt;/code&gt; interfaces; unfortunately, those interfaces require &lt;code&gt;GObject&lt;/code&gt;, and they depend on &lt;code&gt;GCancellable&lt;/code&gt; and &lt;code&gt;GAsyncResult&lt;/code&gt; objects, which prevent us from moving them into the lower level &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Typed containers and life time&amp;nbsp;management&lt;/h3&gt;
&lt;p&gt;The main functionality provided by &lt;code&gt;GObject&lt;/code&gt; is garbage collection through reference counting: you acquire a (strong) reference when you need to access an instance, and release it when you don&amp;#8217;t need the instance any more. If the reference you released was the last one, the instance gets&amp;nbsp;finalized.&lt;/p&gt;
&lt;p&gt;Of course, once you introduce strong references you open the door to a veritable bestiary of other type of&amp;nbsp;references:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;weak references&lt;/em&gt;, used to keep a &amp;#8220;pointer&amp;#8221; to the instance, and get a notification when the last reference&amp;nbsp;drops&lt;/li&gt;
&lt;li&gt;&lt;em&gt;floating references&lt;/em&gt;, used as a C convenience to allow ownership transfer of newly constructed &amp;#8220;child&amp;#8221; objects to their&amp;nbsp;&amp;#8220;parent&amp;#8221;&lt;/li&gt;
&lt;li&gt;&lt;em&gt;toggle references&lt;/em&gt;, used by language bindings that acquire a strong reference on an instance they wrap with a native object; when the toggle reference gets triggered it means that the last reference being held is the one on the native wrapper, and the wrapper can be dropped causing the instance to be&amp;nbsp;finalized&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;All of these types of reference exist inside &lt;code&gt;GObject&lt;/code&gt;, but since they were introduced over the years, they are bolted on top of the base class using the keyed data storage, which comes with its own costly locking and ordering; they are also managed through the finalisation code, which means there are re-entrancy issues or undefined ordering behaviours that routinely crop up over the years, especially when trying to optimise construction and destruction&amp;nbsp;phases.&lt;/p&gt;
&lt;p&gt;None of this complexity is, strictly speaking, necessary; we don&amp;#8217;t care about an instance being reference counted: a &amp;#8220;parent&amp;#8221; object can move the memory of a &amp;#8220;child&amp;#8221; typed instance directly into its own code. What we care about is that, whenever other code interacts with ours, we can hand out a reference to that memory, so that ownership is&amp;nbsp;maintained.&lt;/p&gt;
&lt;p&gt;Other languages and standard libraries have the same&amp;nbsp;concept:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;C++&amp;#8217;s &lt;a href="https://en.cppreference.com/w/cpp/memory/shared_ptr"&gt;&lt;code&gt;shared_ptr&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;Rust&amp;#8217;s &lt;a href="https://doc.rust-lang.org/std/rc/index.html"&gt;&lt;code&gt;std::rc::Rc&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;These constructs are not part of a base class: they are wrappers around instances. This means you&amp;#8217;re not handing out a reference to an instance: you are handing out a reference to a container, which holds the instance for you. The behaviour of the value is made explicit by the type system, not implicit to the&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;A simple implementation of a typed &amp;#8220;reference counted&amp;#8221; container would provide us with both strong and weak&amp;nbsp;references:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_GWeak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GWeak&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;g_rc_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;g_rc_acquire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g_rc_release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g_rc_get_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;GWeak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;g_rc_downgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="nf"&gt;g_weak_upgrade&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GWeak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;bool&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g_weak_is_empty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GWeak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nf"&gt;g_weak_get_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GWeak&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;weak&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Alongside this type of containers, we could also have a specialisation for atomic reference counted containers; or pinned containers, which guarantee that an object is kept in the same memory location; or re-implement referenced containers inside each language binding, to ensure that the behaviour is tailored to the memory management of those&amp;nbsp;languages.&lt;/p&gt;
&lt;h3&gt;Specialised&amp;nbsp;types&lt;/h3&gt;
&lt;p&gt;Container types introduce the requirement of having the type system understand that an object can be the product of two types: the type of the container, and the type of the data. In order to allow properties, signals, and values to effectively provide introspection of this kind of container types we are going to need to introduce &amp;#8220;specialised&amp;#8221;&amp;nbsp;types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GRc&lt;/code&gt; exists as a &amp;#8220;generic&amp;#8221;, abstract type in the type&amp;nbsp;system&lt;/li&gt;
&lt;li&gt;any instance of &lt;code&gt;GRc&lt;/code&gt; that contains a instance of type &lt;code&gt;A&lt;/code&gt; gets a new type in the type&amp;nbsp;system&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;A basic implementation would look&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;g_rc_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Returns an existing GType if something else already&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// has registered the same GRc&amp;lt;T&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rc_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_generic_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_TYPE_RC&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Instantiates GRc, but gives it the type of&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// GRc&amp;lt;T&amp;gt;; there is only the base GRc class&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// and instance initialization functions, as&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// GRc&amp;lt;T&amp;gt; is not a pure derived type&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_type_create_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any instance of type &lt;code&gt;GRc&amp;lt;A&amp;gt;&lt;/code&gt; satisfies the &amp;#8220;is-a&amp;#8221; relationship with &lt;code&gt;GRc&lt;/code&gt;, but it is not a purely derived&amp;nbsp;type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rc_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;g_class&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g_type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="n"&gt;g_assert_true&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_type_is_a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;rc_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_RC&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;GRc&amp;lt;A&amp;gt;&lt;/code&gt; type does not have a different instance or class size, or its own class and instance initialisation functions; it&amp;#8217;s still an instance of the &lt;code&gt;GRc&lt;/code&gt; type, with a different &lt;code&gt;GType&lt;/code&gt;. The &lt;code&gt;GRc&amp;lt;A&amp;gt;&lt;/code&gt; type only exists at run time, as it is the result of the type instantiation; you &lt;strong&gt;cannot&lt;/strong&gt; instantiate a plain &lt;code&gt;GRc&lt;/code&gt;, or derive your type from &lt;code&gt;GRc&lt;/code&gt; in order to create your own reference counted type,&amp;nbsp;either:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// WRONG&lt;/span&gt;
&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;rc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_type_create_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_TYPE_RC&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// WRONG&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GtkWidget&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You can only use a &lt;code&gt;GRc&lt;/code&gt; inside your own&amp;nbsp;instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// GRc&amp;lt;GtkWidget&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// GRc&amp;lt;GtkWidget&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;first_child&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// GRc&amp;lt;GtkWidget&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GRc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;next_sibling&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GtkWidgetPrivate&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Tuple&amp;nbsp;types&lt;/h3&gt;
&lt;p&gt;Tuples are generic containers of N values, but right now we don&amp;#8217;t have any way of formally declaring them into the type system. A hack is to use arrays of similarly typed values, but with the deprecation of &lt;code&gt;GValueArray&lt;/code&gt;—which is a bad type that does not allow reference counting, and does not give you guarantees anyway—we only have C arrays and pointer&amp;nbsp;types.&lt;/p&gt;
&lt;p&gt;Registering a new tuple type would work like a generic type: a base &lt;code&gt;GTuple&lt;/code&gt; abstract type as the &amp;#8220;parent&amp;#8221;, and a number of&amp;nbsp;types:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_GTuple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GTuple&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;GTuple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;g_tuple_new_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tuple_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_tuple_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_TYPE_TUPLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n_elements&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_INT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTuple&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_type_create_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;tuple_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;for&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;lt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;n_elements&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_tuple_add&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;elements&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;i&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can also create specialised tuple types, like&amp;nbsp;pairs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_GPair&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GPair&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;GPair&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;g_pair_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;this_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;that_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="p"&gt;...);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This would give use the ability to standardise our &lt;span class="caps"&gt;API&lt;/span&gt; around fundamental types, and reduce the amount of &lt;em&gt;ad hoc&lt;/em&gt; container types that libraries have to define and bindings have to wrap with native&amp;nbsp;constructs.&lt;/p&gt;
&lt;h3&gt;Sum&amp;nbsp;types&lt;/h3&gt;
&lt;p&gt;Of course, once we start with specialised types, we end up with sum&amp;nbsp;types:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;SQUARE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;RECT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;CIRCLE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ShapeKind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;ShapeKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;kind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;side&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;origin&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Point&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;center&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;float&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;radius&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;shape&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Shape&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As of right now, discriminated unions don&amp;#8217;t have any special handling in the type system: they are generally boxed types, or typed instances, but they require type-specific &lt;span class="caps"&gt;API&lt;/span&gt; to deal with the discriminator field and type. Since we have types for enumerations and instances, we can register them at the same time, and provide offsets for direct&amp;nbsp;access:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GType&lt;/span&gt;
&lt;span class="nf"&gt;g_sum_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tag_enum_type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="n"&gt;offset_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;tag_field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This way it&amp;#8217;s possible to ask the type system&amp;nbsp;for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the offset of the tag in an instance, for direct&amp;nbsp;access&lt;/li&gt;
&lt;li&gt;all the possible values of the tag, by inspecting its &lt;code&gt;GEnum&lt;/code&gt; type&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From then on, we can easily build types like &lt;code&gt;Option&lt;/code&gt; and &lt;code&gt;Result&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;G_RESULT_OK&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;G_RESULT_ERR&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GResultKind&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GResultKind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;GError&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;error&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;g_sum_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;GResult&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GResultClass&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_RESULT_KIND&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                            &lt;/span&gt;&lt;span class="n"&gt;offsetof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;g_result_new_boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gboolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_generic_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_TYPE_RESULT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                    &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_BOOLEAN&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_type_create_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;res_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_value_set_boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;g_autoptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;obj_finish&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;task&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;switch&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_result_get_kind&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;G_RESULT_OK&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Result: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;g_result_get_boolean&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;?&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;true&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;false&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;case&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="no"&gt;G_RESULT_ERROR&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_printerr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Error: %s&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;g_result_get_error_message&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;break&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="n"&gt;g_autoptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GResult&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_input_stream_read_bytes&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;stream&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_result_is_error&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_autoptr&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GBytes&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_result_get_boxed&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;result&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Consolidating GLib and&amp;nbsp;GType&lt;/h3&gt;
&lt;p&gt;Having the type system in a separate shared library did make sense back when GLib was spun off from &lt;span class="caps"&gt;GTK&lt;/span&gt;; after all, GLib was mainly a set of convenient data types for a language that lacked a decent standard library. Additionally, not many C projects were interested in the type system, as it was perceived as a big chunk of functionality in an era where space was at a premium. These days, the smallest environment capable of running GLib code is plenty capable of running the GObject type system as well. The separation between GLib data types and the GObject type system has created data types that are not type safe, and work by copying data, by having run time defined destructor functions, or by storing pointers and assuming everything will be fine. This leads to code duplication between shared libraries, and prevents the use of GLib data types in the public &lt;span class="caps"&gt;API&lt;/span&gt;, lest the introspection information gets&amp;nbsp;lost.&lt;/p&gt;
&lt;p&gt;Moving the type system inside GLib would allow us to have properly typed generic container types, like a &lt;code&gt;GVector&lt;/code&gt; replacing &lt;code&gt;GArray&lt;/code&gt;, &lt;code&gt;GPtrArray&lt;/code&gt;, &lt;code&gt;GByteArray&lt;/code&gt;, as well as the deprecated &lt;code&gt;GValueArray&lt;/code&gt;; or a &lt;code&gt;GMap&lt;/code&gt; and a &lt;code&gt;GSet&lt;/code&gt;, replacing &lt;code&gt;GHashTable&lt;/code&gt;, &lt;code&gt;GSequence&lt;/code&gt;, and &lt;code&gt;GtkRBTree&lt;/code&gt;. Even the various list models could be assembled on top of these new types, and moved out of &lt;span class="caps"&gt;GTK&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Current consumers of GLib-only &lt;span class="caps"&gt;API&lt;/span&gt; would still have their basic C types, but if they don&amp;#8217;t want to link against a slightly bigger shared library that includes &lt;code&gt;GTypeInstance&lt;/code&gt;, &lt;code&gt;GTypeInterface&lt;/code&gt;, and the newly added generic, tuple, and sum types, then they would probably be better served by projects like &lt;a href="https://github.com/c-util"&gt;c-util&lt;/a&gt;&amp;nbsp;instead.&lt;/p&gt;
&lt;h3&gt;Properties&lt;/h3&gt;
&lt;p&gt;Instead of bolting properties on top of &lt;code&gt;GParamSpec&lt;/code&gt;, we can move their definition into the type system; after all, properties are a fundamental part of a type, so it does not make sense to bind them to the class instantiation. This would also remove the long-standing issue of properties being available for registration long after a class has been initialised; it would give us the chance to ship a utility for inspecting the type system to get all the meta-information on the hierarchy and generating introspection &lt;span class="caps"&gt;XML&lt;/span&gt; without having to compile a small&amp;nbsp;binary.&lt;/p&gt;
&lt;p&gt;If we move property registration to the type registration we can also finally move away from multiplexed accessors, and use direct instance field access where&amp;nbsp;applicable:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GPropertyBuilder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;g_property_builder_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_STRING&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;name&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// Stop using flags, and use proper setters; since&lt;/span&gt;
&lt;span class="c1"&gt;// there&amp;#39;s no use case for unsetting the readability&lt;/span&gt;
&lt;span class="c1"&gt;// flag, we don&amp;#39;t even need a boolean argument&lt;/span&gt;
&lt;span class="n"&gt;g_property_builder_set_readwrite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="c1"&gt;// The offset is used for read and write access...&lt;/span&gt;
&lt;span class="n"&gt;g_property_builder_set_private_offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;offsetof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GtkWidgetPrivate&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;span class="c1"&gt;// ... unless an accessor function is provided; in&lt;/span&gt;
&lt;span class="c1"&gt;// this case we want setting a property to go through&lt;/span&gt;
&lt;span class="c1"&gt;// a function&lt;/span&gt;
&lt;span class="n"&gt;g_property_builder_set_setter_func&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;gtk_widget_set_name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// Register the property into the type; we return the&lt;/span&gt;
&lt;span class="c1"&gt;// offset of the property into the type node, so we can&lt;/span&gt;
&lt;span class="c1"&gt;// access the property definition with a fast look up&lt;/span&gt;
&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_type_add_instance_property&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_property_builder_end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Accessing the property information would then be a case of looking into the type system under a single reader lock, instead of traversing all properties in a glorified globally locked hash&amp;nbsp;table.&lt;/p&gt;
&lt;p&gt;Once we have a property registered in the type system, accessing it is a matter of calling &lt;span class="caps"&gt;API&lt;/span&gt; on the &lt;code&gt;GProperty&lt;/code&gt; object:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;gtk_widget_set_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GtkWidget&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;widget&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                     &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GProperty&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_type_get_instance_property&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GTK_TYPE_WIDGET&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="n"&gt;properties&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;NAME&lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_property_set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;prop&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Signals&lt;/h3&gt;
&lt;p&gt;Moving signal registration into the type system would allow us to subsume the global locking into the type locks; it would also give us the chance to simplify some of the complexity for re-emission and&amp;nbsp;hooks:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GSignalBuilder&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;g_signal_builder_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;insert-text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g_signal_builder_set_args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GSignalArg&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;text&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gtype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_STRING&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;length&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gtype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_SIZE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;position&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;gtype&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_OFFSET&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="n"&gt;g_signal_builder_set_retval&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_OFFSET&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="n"&gt;g_signal_builder_set_class_offset&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;offsetof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;EditableClass&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;insert_text&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;signals&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="n"&gt;INSERT_TEXT&lt;/span&gt;&lt;span class="p"&gt;]&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_type_add_class_signal&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;g_signal_builder_end&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;builder&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;By taking the chance of moving signals out of the their own namespace we can also move to a model where each class is responsible for providing the &lt;span class="caps"&gt;API&lt;/span&gt; necessary to connect and emit signals, as well as providing callback types for each signal. This would allow us to increase type safety, and reduce the reliance on generic &lt;span class="caps"&gt;API&lt;/span&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;offset_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;EditableInsertText&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Editable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                         &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                         &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                         &lt;/span&gt;&lt;span class="n"&gt;offset_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;long&lt;/span&gt;
&lt;span class="nf"&gt;editable_connect_insert_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Editable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="n"&gt;EditableInsertText&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;user_data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                              &lt;/span&gt;&lt;span class="n"&gt;GSignalFlags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;flags&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="n"&gt;offset_t&lt;/span&gt;
&lt;span class="nf"&gt;editable_emit_insert_text&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Editable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;text&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;length&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="n"&gt;offset_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;position&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Extending the type&amp;nbsp;system&lt;/h3&gt;
&lt;p&gt;Some of the metadata necessary to provide properly typed properties and signals is missing from the type system. For instance, by design, there is no type representing a &lt;code&gt;uint16_t&lt;/code&gt;; we are supposed to create a &lt;code&gt;GParamSpec&lt;/code&gt; to validate the value of a &lt;code&gt;G_TYPE_INT&lt;/code&gt; in order to fit in the 16bit range. Of course, this leads to excessive run time validation, and relies on C&amp;#8217;s own promotion rules for variadic arguments; it also does not work for signals, as those do not use &lt;code&gt;GParamSpec&lt;/code&gt;. More importantly, though, the missing connection between C types and GTypes prevents gathering proper introspection information for properties and signal arguments: if we only have the GType we cannot generate the full metadata that can be used by documentation and language bindings, unless we&amp;#8217;re willing to lose&amp;nbsp;specificity.&lt;/p&gt;
&lt;p&gt;Not only the type system should be sufficient to contain all the standard C types that are now available, we also need the type system to provide us with enough information to be able to serialise those types into the introspection data, if we want to be able to generate code like signal &lt;span class="caps"&gt;API&lt;/span&gt;, type safe bindings, or accurate documentation for properties and signal&amp;nbsp;handlers.&lt;/p&gt;
&lt;h3&gt;Introspection&lt;/h3&gt;
&lt;p&gt;Introspection exists outside of GObject mainly because of dependencies; the parser, abstract syntax tree, and transformers are written in Python and interface with a low level C tokeniser. Adding a CPython dependency to GObject is too much of a stretch, especially when it comes to bootstrapping a system. While we could keep the dependency optional, and allow building GObject without support for introspection, keeping the code separate is a simpler&amp;nbsp;solution.&lt;/p&gt;
&lt;p&gt;Nevertheless, GObject should not ignore introspection. The current reflection &lt;span class="caps"&gt;API&lt;/span&gt; inside GObject should generate data that is compatible with the libgirepository &lt;span class="caps"&gt;API&lt;/span&gt; and with its &lt;span class="caps"&gt;GIR&lt;/span&gt; parser. Currently, gobject-introspection is tasked with generating a small C executable, compiling it, running it to extract metadata from the type system, as well as the properties and signals of a &lt;code&gt;GObject&lt;/code&gt; type, and generate &lt;span class="caps"&gt;XML&lt;/span&gt; that can be parsed and included into the larger &lt;span class="caps"&gt;GIR&lt;/span&gt; metadata for the rest of the &lt;span class="caps"&gt;ABI&lt;/span&gt; being introspected. GObject should ship a pre-built binary, instead; it should &lt;code&gt;dlopen&lt;/code&gt; the given library or executable, extract all the type information, and emit the introspection data. This would not make gobject-introspection more cross-compilable, but it would simplify its internals and its distributability. We would not need to know how to compile and run C code from a Python script, for one; a simple executable wrapper around a native copy of the GObject-provided binary would be&amp;nbsp;enough.&lt;/p&gt;
&lt;p&gt;Ideally, we could move the girepository &lt;span class="caps"&gt;API&lt;/span&gt; into GObject itself, and allow it to load the binary data compiled out of the &lt;span class="caps"&gt;XML&lt;/span&gt;; language bindings loading the data at run time would then need to depend on GObject instead of an additional library, and we could ship the &lt;span class="caps"&gt;GIR&lt;/span&gt; → typelib compiler directly with GLib, leaving gobject-introspection to deal only with the parsing of C headers, docblocks, and annotations, to generate the &lt;span class="caps"&gt;XML&lt;/span&gt; representation of the C/GObject &lt;span class="caps"&gt;ABI&lt;/span&gt;.&lt;/p&gt;
&lt;h2&gt;There and back&amp;nbsp;again&lt;/h2&gt;
&lt;blockquote&gt;
&lt;p&gt;And the ship went out into the High Sea and passed on into the West, until at last on a night of rain Frodo smelled a sweet fragrance on the air and heard the sound of singing that came over the water. And then it seemed to him that as in his dream in the house of Bombadil, the grey rain-curtain turned all to silver glass and was rolled back, and he beheld white shores and beyond them a far green country under a swift sunrise.
&amp;#8212; “The Lord of the Rings”, Volume 3: The Return of the King, Book 6: The End of the Third&amp;nbsp;Age&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The hard part of changing a project in a backward compatible way is resisting the temptation of fixing the existing design. Some times it&amp;#8217;s necessary to backtrack the chain of decisions, and consider the extant code base a dead branch; not because the code is wrong, or bug free, but because any attempt at doubling down on the same design will inevitably lead to breakage. In this sense, it&amp;#8217;s easy to just declare &amp;#8220;maintenance bankruptcy&amp;#8221;, and start from a new major &lt;span class="caps"&gt;API&lt;/span&gt; version: breaks allow us to fix the implementation, at the cost of adapting to new &lt;span class="caps"&gt;API&lt;/span&gt;. For instance, widgets are still the core of &lt;span class="caps"&gt;GTK&lt;/span&gt;, even after 4 major revisions; we did not rename them to &amp;#8220;elements&amp;#8221; or &amp;#8220;actors&amp;#8221;, and we did not change how the windows are structured. You are still supposed to build a tree of widgets, connect callbacks to signals, and let the main event loop run. Porting has been painful because of underlying changes in the graphics stack, or because of portability concerns, but even with the direction change of favouring composition over inheritance, the knowledge on how to use &lt;span class="caps"&gt;GTK&lt;/span&gt; has been transferred from &lt;span class="caps"&gt;GTK&lt;/span&gt; 1 to&amp;nbsp;4.&lt;/p&gt;
&lt;p&gt;We cannot do the same for &lt;code&gt;GObject&lt;/code&gt;. Changing how it is implemented implies changing everything that depends on it; it means introducing behavioural changes in subtle, and hard to predict ways. Luckily for us, the underlying type system is still flexible and nimble enough that it can give us the ability to change direction, and implement an entirely different approach to object orientation—one that is more in line with languages like modern C++ and Rust. By following new approaches we can slowly migrate our platform to other languages over time, with a smaller impedance mismatch caused by the current design of our object model. Additionally, by keeping the root of the type system, we maintain the ability to provide a stable C &lt;span class="caps"&gt;ABI&lt;/span&gt; that can be consumed by multiple languages, which is the strong selling point of the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;ecosystem.&lt;/p&gt;
&lt;p&gt;Why do all of this work, though? Compared to a full &lt;span class="caps"&gt;API&lt;/span&gt; break, this proposal has the advantage of being tractable and realistic; I cannot overemphasise enough how little appetite there is for a &amp;#8220;GObject 3.0&amp;#8221; in the ecosystem. The recent &lt;span class="caps"&gt;API&lt;/span&gt; bump from libsoup2 to libsoup3 has clearly identified that changes deep into the stack end up being too costly an effort: some projects have found it easier to switch to another &lt;span class="caps"&gt;HTTP&lt;/span&gt; library altogether, rather than support two versions of libsoup for a while; other projects have decided to drop compatibility with libsoup2, forcing the hand of every reverse dependency both upstream and downstream. Breaking GObject would end up breaking the ecosystem, with the hope of a &amp;#8220;perfect&amp;#8221; implementation way down the line and with very few users on one side, and a dead branch used by everybody else on the&amp;nbsp;other.&lt;/p&gt;
&lt;p&gt;Of course, the complexity of the change is not going to be trivial, and it will impact things like the introspection metadata and the various language bindings that exist today; some bindings may even require a complete redesign. Nevertheless, by implementing this new object model and leaving &lt;code&gt;GObject&lt;/code&gt; alone, we buy ourselves enough time and space to port our software development platform towards a different&amp;nbsp;future.&lt;/p&gt;
&lt;p&gt;Maybe this way we will get to save the Shire; and even if we give up some things, or even lose them, we still get to keep what&amp;nbsp;matters.&lt;/p&gt;</content><category term="gnome"></category><category term="gobject"></category><category term="gnome"></category><category term="development"></category><category term="bindings"></category></entry><entry><title>Configuring portals</title><link href="https://www.bassi.io/articles/2023/05/29/configuring-portals/" rel="alternate"></link><published>2023-05-29T18:31:00+01:00</published><updated>2023-05-30T14:59:41+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2023-05-29:/articles/2023/05/29/configuring-portals/</id><summary type="html">&lt;p&gt;In which I explain what desktop developers, distributions, and users can do to configure sandbox&amp;nbsp;portals&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the things I&amp;#8217;ve been recently working on at &lt;a href="https://igalia.com"&gt;Igalia&lt;/a&gt; is the
desktop portals implementation, the middleware layer of &lt;span class="caps"&gt;API&lt;/span&gt; for application
and toolkit developers that allows sandboxed applications to interact with
the host system. Sandboxing technologies like &lt;a href="https://docs.flatpak.org/en/latest/desktop-integration.html#portals"&gt;Flatpak&lt;/a&gt; and
&lt;a href="https://snapcraft.io/docs/xdg-desktop-portals"&gt;Snap&lt;/a&gt; expose the portal D-Bus interfaces inside the sandbox
they manage, to handle user-mediated interactions like opening a file that
exists outside of the locations available to the sandboxed process, or
talking to privileged components like the compositor to obtain a&amp;nbsp;screenshot.&lt;/p&gt;
&lt;p&gt;Outside of allowing dynamic permissions for sandboxed applications, portals
act as a vendor-neutral &lt;span class="caps"&gt;API&lt;/span&gt; for applications to target when dealing with
Linux as an &lt;span class="caps"&gt;OS&lt;/span&gt;; this is mostly helpful for commercial applications that are
not tied to a specific desktop environment, but don&amp;#8217;t want to re-implement
the layer of system integration from the first principles of &lt;span class="caps"&gt;POSIX&lt;/span&gt;&amp;nbsp;primitives.&lt;/p&gt;
&lt;p&gt;The architecture of desktop portals has been described pretty well in &lt;a href="http://who-t.blogspot.com/2021/08/flatpak-portals-how-do-they-work.html"&gt;a
blog post by Peter Hutterer&lt;/a&gt;, but to&amp;nbsp;recap:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;desktop portals are &lt;a href="https://flatpak.github.io/xdg-desktop-portal/"&gt;a series of D-Bus&amp;nbsp;interfaces&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;toolkits and applications call methods on those D-Bus&amp;nbsp;interfaces&lt;/li&gt;
&lt;li&gt;there is a user session daemon called
  &lt;a href="https://github.com/flatpak/xdg-desktop-portal"&gt;xdg-desktop-portal&lt;/a&gt; that provides a
  service for the D-Bus&amp;nbsp;interfaces&lt;/li&gt;
&lt;li&gt;xdg-desktop-portal implements some of those interface&amp;nbsp;directly&lt;/li&gt;
&lt;li&gt;for the interfaces that involve user interaction, or interaction with
  desktop-specific services, we have separate services that are proxied
  by xdg-desktop-portal; &lt;span class="caps"&gt;GNOME&lt;/span&gt; has &lt;a href="https://gitlab.gnome.org/GNOME/xdg-desktop-portal-gnome"&gt;xdg-desktop-portal-gnome&lt;/a&gt;,
  &lt;span class="caps"&gt;KDE&lt;/span&gt; has &lt;a href="https://invent.kde.org/plasma/xdg-desktop-portal-kde"&gt;xdg-desktop-portal-kde&lt;/a&gt;; Sway and wlroot-based
  compositors have &lt;a href="https://github.com/emersion/xdg-desktop-portal-wlr"&gt;xdg-desktop-portal-wlr&lt;/a&gt;; and so on, and so&amp;nbsp;forth&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;#8217;s also &lt;a href="https://github.com/flatpak/xdg-desktop-portal-gtk"&gt;xdg-desktop-portal-gtk&lt;/a&gt;, which acts a bit as a
reference portal implementation, and a shared desktop portal implementation
for a lot of &lt;span class="caps"&gt;GTK&lt;/span&gt;-based environments. Ideally, every desktop environment
should have their own desktop portal implementation, so that applications
using the portal &lt;span class="caps"&gt;API&lt;/span&gt; can be fully integrated with each desktop&amp;#8217;s interface
guidelines and specialised&amp;nbsp;services.&lt;/p&gt;
&lt;p&gt;One thing that is currently messy is the mechanism by which
xdg-desktop-portal finds the portal implementations available on the system,
and decides which implementation should be used for a specific&amp;nbsp;interface.&lt;/p&gt;
&lt;p&gt;Up until the current stable version of xdg-desktop-portal, the configuration
worked this&amp;nbsp;way:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;each portal implementation (xdg-desktop-portal-gtk, -gnome, -kde, …)
   ships a &lt;code&gt;${NAME}.portal&lt;/code&gt; file; the file is a simple &lt;span class="caps"&gt;INI&lt;/span&gt;-like desktop
   entry file with the following keys:&lt;ul&gt;
&lt;li&gt;&lt;code&gt;DBusName&lt;/code&gt;, which contains the service name of the portal, for
  instance, &lt;code&gt;org.freedesktop.impl.portal.desktop.gnome&lt;/code&gt; for the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
  portals; this name is used by xdg-desktop-portal to launch the portal&amp;nbsp;implementation&lt;/li&gt;
&lt;li&gt;&lt;code&gt;Interfaces&lt;/code&gt;, which contains a list of D-Bus interfaces under the
  &lt;code&gt;org.freedesktop.impl.portal.*&lt;/code&gt; namespace that are implemented by the
  desktop-specific portal; xdg-desktop-portal will match the portal
  implementation with the public facing D-Bus interface&amp;nbsp;internally&lt;/li&gt;
&lt;li&gt;&lt;code&gt;UseIn&lt;/code&gt;, which contains the name of the desktop to be matched with the
  contents of the &lt;code&gt;$XDG_CURRENT_DESKTOP&lt;/code&gt; environment&amp;nbsp;variable&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;li&gt;once xdg-desktop-portal starts, it finds all the &lt;code&gt;.portal&lt;/code&gt; files in a
   well-known location and builds a list of portal implementations currently
   installed in the system, containing all the interfaces they implement as
   well as their preferred desktop&amp;nbsp;environment&lt;/li&gt;
&lt;li&gt;whenever something calls a method on an interface in the
   &lt;code&gt;org.freedesktop.portal.*&lt;/code&gt; namespace, xdg-desktop-portal will check the
   current desktop using the &lt;code&gt;XDG_CURRENT_DESKTOP&lt;/code&gt; environment variable, and
   check if the portal that has a &lt;code&gt;UseIn&lt;/code&gt; key that matches the current&amp;nbsp;desktop&lt;/li&gt;
&lt;li&gt;once there&amp;#8217;s a match, xdg-desktop-portal will activate the portal
   implementation and proxy the calls made on the &lt;code&gt;org.freedesktop.portal&lt;/code&gt;
   interfaces over to the &lt;code&gt;org.freedesktop.impl.portal&lt;/code&gt; ones&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;This works perfectly fine for the average case of a Linux installation with
a single session, using a single desktop environment, and a single desktop
portal. Where things get messy is the case where you have multiple sessions
on the same system, each with its own desktop and portals, or even no
portals whatsoever. In a bad scenario, you may get the wrong desktop portal
just because the name sorts before the one you&amp;#8217;re interested in, so you get
the &lt;span class="caps"&gt;GTK&lt;/span&gt; &amp;#8220;reference&amp;#8221; portals instead of the &lt;span class="caps"&gt;KDE&lt;/span&gt;-specific ones; in the
worst case scenario, you may get a stall when launching an application just
because the wrong desktop portal is trying to contact a session service that
simply does not exist, and you have to wait 30 seconds for a D-Bus&amp;nbsp;timeout.&lt;/p&gt;
&lt;p&gt;The problem is that some desktop portal implementations are shared across
desktops, or cover only a limited amount of interfaces; a mandatory list of
desktop environments is far too coarse a tool to deal with this.
Additionally, xdg-desktop-portal has to have enough fallbacks to ensure
that, if it cannot find any implementation for the current desktop, it will
proxy to the first implementation it can find in order to give a meaningful
answer. Finally, since the supported desktops are shipped by the portal
themselves, there&amp;#8217;s no way to override this information by packagers,
admins, or&amp;nbsp;users.&lt;/p&gt;
&lt;p&gt;After &lt;a href="https://github.com/flatpak/xdg-desktop-portal/issues/906"&gt;iterating over the issue&lt;/a&gt;, I ended up writing the
support for a new configuration file. Instead of having portals say what
kind of desktop environment they require, we have desktop environments
saying which portal implementations they prefer. Now, each desktop should
ship a &lt;code&gt;${NAME}-portals.conf&lt;/code&gt; &lt;span class="caps"&gt;INI&lt;/span&gt;-like desktop entry file listing each
interface, and what kind of desktop portal should be used for it; for
instance, the &lt;span class="caps"&gt;GNOME&lt;/span&gt; desktop should ship a &lt;code&gt;gnome-portals.conf&lt;/code&gt; configuration
file that specifies a default for every&amp;nbsp;interface:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[preferred]&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gnome&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;On the other hand, you could have a &lt;em&gt;Foo&lt;/em&gt; desktop that relies on the &lt;span class="caps"&gt;GTK&lt;/span&gt;
portal for everything, except for specific interfaces that are implemented
by the &amp;#8220;foo&amp;#8221;&amp;nbsp;portal:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[preferred]&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gtk&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.Screenshot&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.Screencast&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;foo&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You could also disable all portals except for a specific interface (and its&amp;nbsp;dependencies):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[preferred]&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.Account&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gtk&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.FileChooser&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gtk&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.Lockdown&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gtk&lt;/span&gt;
&lt;span class="na"&gt;org.freedesktop.impl.portal.Settings&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;gtk&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or, finally, you could disable all portal&amp;nbsp;implementations:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[preferred]&lt;/span&gt;
&lt;span class="na"&gt;default&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s"&gt;none&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;A nice side effect of this work is that you can configure your own system,
by dropping a &lt;code&gt;portals.conf&lt;/code&gt; configuration file inside the
&lt;code&gt;XDG_CONFIG_HOME/xdg-desktop-portal&lt;/code&gt; directory; this should cover all the
cases in which people assemble their desktop out of disparate&amp;nbsp;components.&lt;/p&gt;
&lt;p&gt;By having desktop environments (or, in a pinch, the user themselves) owning
the kind of portals they require, we can avoid messy configurations in the
portal implementations, and clarify the intended behaviour to downstream
packagers; at the same time, generic portal implementations can be adopted
by multiple environments without necessarily having to know which ones&amp;nbsp;upfront.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;In a way, the desktop portals project is trying to fulfill the original
mission of freedesktop.org&amp;#8217;s Cross-desktop Group: a set of &lt;span class="caps"&gt;API&lt;/span&gt; that are not
bound to a single environment, and can be used to define &amp;#8220;the Linux desktop&amp;#8221;
as a&amp;nbsp;platform.&lt;/p&gt;
&lt;p&gt;Of course, there&amp;#8217;s a lot of work involved in creating a vendor-neutral
platform &lt;span class="caps"&gt;API&lt;/span&gt;, especially when it comes to designing both the user and the
developer experiences; ideally, more people should be involved in this
effort, so if you want to contribute to the Linux ecosystem, this is an area
where you can make the&amp;nbsp;difference.&lt;/p&gt;</content><category term="gnome"></category><category term="flatpak"></category><category term="portals"></category><category term="sandboxing"></category></entry><entry><title>Writing Bindable API, 2023 Edition</title><link href="https://www.bassi.io/articles/2023/02/20/bindable-api-2023/" rel="alternate"></link><published>2023-02-20T00:35:00+00:00</published><updated>2023-02-22T13:09:08+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2023-02-20:/articles/2023/02/20/bindable-api-2023/</id><summary type="html">&lt;p&gt;In which I make an attempt at encoding best introspection practices for &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;writers&lt;/p&gt;</summary><content type="html">&lt;p&gt;First of all, you should go on the &lt;a href="https://gi.readthedocs.io/en/latest/"&gt;gobject-introspection website&lt;/a&gt;
and read the page on &lt;a href="https://gi.readthedocs.io/en/latest/writingbindableapis.html"&gt;how to write bindable &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;. What
I&amp;#8217;m going to write here is going to build upon what&amp;#8217;s already documented, or
will update the best practices, so if you maintain a GObject/C library, or
you&amp;#8217;re writing one, you &lt;strong&gt;must&lt;/strong&gt; be familiar with the basics of
gobject-introspection. It&amp;#8217;s 2023: it&amp;#8217;s already too bad we&amp;#8217;re still writing C
libraries, we should &lt;em&gt;at the very least&lt;/em&gt; be responsible about&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;A specific note for people maintaining an existing GObject/C library with an
&lt;span class="caps"&gt;API&lt;/span&gt; designed &lt;em&gt;before&lt;/em&gt; the mainstream establishment of gobject-introspection
(basically, anything written prior to 2011): you should &lt;strong&gt;really&lt;/strong&gt; consider
writing all new types and entry points with gobject-introspection in mind,
and you should also consider phasing out older &lt;span class="caps"&gt;API&lt;/span&gt; and replacing it
piecemeal with a bindable one. You should have done this 10 years ago, and I
can already hear the objections, but: &lt;em&gt;too bad&lt;/em&gt;. Just because you made an
effort 10 years ago it doesn&amp;#8217;t mean things are frozen in time, and you don&amp;#8217;t
get to fix things. Maintenance means constantly tending to your code, and
that doubly applies if you&amp;#8217;re exposing an &lt;span class="caps"&gt;API&lt;/span&gt; to other&amp;nbsp;people.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Let&amp;#8217;s take the &amp;#8220;how to write bindable &lt;span class="caps"&gt;API&lt;/span&gt;&amp;#8221; recommendations, and elaborate
them a&amp;nbsp;bit.&lt;/p&gt;
&lt;h3&gt;Structures with custom memory&amp;nbsp;management&lt;/h3&gt;
&lt;p&gt;The recommendation is to use &lt;code&gt;GBoxed&lt;/code&gt; as a way to specify a copy and a free
function, in order to clearly define the memory management semantics of a&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;The important &lt;em&gt;caveat&lt;/em&gt; is that boxed types are necessary&amp;nbsp;for:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;opaque types that can only be heap&amp;nbsp;allocated&lt;/li&gt;
&lt;li&gt;using a type as a GObject&amp;nbsp;property&lt;/li&gt;
&lt;li&gt;using a type as an argument or return value for a GObject&amp;nbsp;signal&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;You don&amp;#8217;t &lt;strong&gt;need&lt;/strong&gt; a boxed type for the following&amp;nbsp;cases:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;your type is an argument or return value for a method, function, or
  virtual&amp;nbsp;function&lt;/li&gt;
&lt;li&gt;your type can be placed on the stack, or can be allocated with
  &lt;code&gt;malloc()&lt;/code&gt;/&lt;code&gt;free()&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, starting with gobject-introspection 1.76, you can specify the
copy and free function of a type &lt;em&gt;without&lt;/em&gt; necessarily registering a boxed
type, which leaves boxed types for the thing they were created: signals and&amp;nbsp;properties.&lt;/p&gt;
&lt;h4&gt;Addendum: object&amp;nbsp;types&lt;/h4&gt;
&lt;p&gt;Boxed types should only ever be used for plain old data types; if you need
inheritance, then the strong recommendation is to use &lt;code&gt;GObject&lt;/code&gt;. You can use
&lt;code&gt;GTypeInstance&lt;/code&gt;, but &lt;strong&gt;only if you know what you&amp;#8217;re doing&lt;/strong&gt;; for more
information on that, see &lt;a href="https://www.bassi.io/articles/2020/06/02/type-instances/"&gt;my old blog post about typed instances&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;Functionality only accessible through a C&amp;nbsp;macro&lt;/h3&gt;
&lt;p&gt;This ought to be fairly uncontroversial. C pre-processor symbols don&amp;#8217;t exist
at the &lt;span class="caps"&gt;ABI&lt;/span&gt; level, and gobject-introspection is a mechanism to describe a C
&lt;span class="caps"&gt;ABI&lt;/span&gt;. Never, &lt;strong&gt;ever&lt;/strong&gt; expose &lt;span class="caps"&gt;API&lt;/span&gt; only through C macros; those are for C
developers. C macros can be used to create convenience wrappers, but
remember that anything they call must be public &lt;span class="caps"&gt;API&lt;/span&gt;, and that other people
will need to re-implement the convenience wrappers themselves, so don&amp;#8217;t
overdo it. C developers deserve some convenience, but not at the expense of
everyone&amp;nbsp;else.&lt;/p&gt;
&lt;h4&gt;Addendum: inline&amp;nbsp;functions&lt;/h4&gt;
&lt;p&gt;Static inline functions are also not part of the introspectable &lt;span class="caps"&gt;ABI&lt;/span&gt; of a
library, because they cannot be used with &lt;code&gt;dlsym()&lt;/code&gt;; you can provide inlined
functions for performance reasons, but remember to always provide their
non-inlined&amp;nbsp;equivalent.&lt;/p&gt;
&lt;h3&gt;Direct C structure access for&amp;nbsp;objects&lt;/h3&gt;
&lt;p&gt;Again, another fairly uncontroversial rule. You shouldn&amp;#8217;t be putting
anything into an instance structure, as it makes your &lt;span class="caps"&gt;API&lt;/span&gt; harder to
future-proof, and direct access cannot do things like change notification,
or &lt;a href="https://en.wikipedia.org/wiki/Memoization"&gt;memoization&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Always provide accessor&amp;nbsp;functions.&lt;/p&gt;
&lt;h3&gt;&lt;code&gt;va_list&lt;/code&gt;&lt;/h3&gt;
&lt;p&gt;Variadic argument functions are mainly C convenience. Yes, some languages
can support them, but it&amp;#8217;s a bad idea to have this kind of &lt;span class="caps"&gt;API&lt;/span&gt; exposed as
the only way to do&amp;nbsp;things.&lt;/p&gt;
&lt;p&gt;Any variadic argument function should have two additional&amp;nbsp;variants:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a vector based version, using C arrays (zero terminated, or with an
  explicit&amp;nbsp;length)&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;va_list&lt;/code&gt; version, to be used when creating wrappers with variadic
  arguments&amp;nbsp;themselves&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;code&gt;va_list&lt;/code&gt; variant is kind of optional, since not many people go around
writing variadic argument C wrappers, these days, but at the end of the day
you might be going to write an internal function that takes a &lt;code&gt;va_list&lt;/code&gt;
anyway, so it&amp;#8217;s not particularly strange to expose it as part of your public
&lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The vector-based variant, on the other hand, is&amp;nbsp;fundamental.&lt;/p&gt;
&lt;p&gt;Incidentally, if you&amp;#8217;re using variadic arguments as a way to collect
similarly typed values,&amp;nbsp;e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// void&lt;/span&gt;
&lt;span class="c1"&gt;// some_object_method (SomeObject *self,&lt;/span&gt;
&lt;span class="c1"&gt;//                     ...) G_GNUC_NULL_TERMINATED&lt;/span&gt;

&lt;span class="n"&gt;some_object_method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;there&amp;#8217;s very little difference to using a vector and C99&amp;#8217;s compound&amp;nbsp;literals:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// void&lt;/span&gt;
&lt;span class="c1"&gt;// some_object_method (SomeObject *self,&lt;/span&gt;
&lt;span class="c1"&gt;//                     const char *args[])&lt;/span&gt;

&lt;span class="n"&gt;some_object_method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;foo&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;bar&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;baz&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                      &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Except that now the compiler will be able to do some basic type check and
scream at you if you&amp;#8217;re doing something egregiously&amp;nbsp;bad.&lt;/p&gt;
&lt;p&gt;Compound literals and designated initialisers also help when dealing with
key/value&amp;nbsp;pairs:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;union&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;v_str&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;v_int&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;enum&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;COLUMN_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;COLUMN_AGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;N_COLUMNS&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// void&lt;/span&gt;
&lt;span class="c1"&gt;// some_object_method (SomeObject *self,&lt;/span&gt;
&lt;span class="c1"&gt;//                     size_t n_columns,&lt;/span&gt;
&lt;span class="c1"&gt;//                     const ColumnValue values[])&lt;/span&gt;

&lt;span class="n"&gt;some_object_method&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;ColumnValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[])&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMN_NAME&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v_str&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Emmanuele&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;column&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;COLUMN_AGE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;v_int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;},&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;So you should seriously reconsider the amount of variadic arguments
convenience functions you&amp;nbsp;expose.&lt;/p&gt;
&lt;h3&gt;Multiple out&amp;nbsp;parameters&lt;/h3&gt;
&lt;p&gt;Using a structured type with a &lt;code&gt;out&lt;/code&gt; direction is a good recommendation as a
way to both limit the amount of &lt;code&gt;out&lt;/code&gt; arguments &lt;em&gt;and&lt;/em&gt; provide some
future-proofing for your &lt;span class="caps"&gt;API&lt;/span&gt;. It&amp;#8217;s easy to expand an opaque pointer type
with accessors, whereas adding more &lt;code&gt;out&lt;/code&gt; arguments requires an &lt;span class="caps"&gt;ABI&lt;/span&gt;&amp;nbsp;break.&lt;/p&gt;
&lt;h4&gt;Addendum: &lt;code&gt;inout&lt;/code&gt; arguments&lt;/h4&gt;
&lt;p&gt;Don&amp;#8217;t use in-out arguments. Just&amp;nbsp;don&amp;#8217;t.&lt;/p&gt;
&lt;p&gt;Pass an &lt;code&gt;in&lt;/code&gt; argument to the callable for its input, and take an &lt;code&gt;out&lt;/code&gt;
argument or a return value for the&amp;nbsp;output.&lt;/p&gt;
&lt;p&gt;Memory management and ownership of &lt;code&gt;inout&lt;/code&gt; arguments is &lt;em&gt;incredibly&lt;/em&gt; hard to
capture with static annotations; it mainly works for scalar values,&amp;nbsp;so:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="n"&gt;some_object_update_matrix&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;xx&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;yy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;xy&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="kt"&gt;double&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;yx&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;can work with &lt;code&gt;xx&lt;/code&gt;, &lt;code&gt;yy&lt;/code&gt;, &lt;code&gt;xy&lt;/code&gt;, &lt;code&gt;yx&lt;/code&gt; as &lt;code&gt;inout&lt;/code&gt; arguments, because there&amp;#8217;s
no ownership transfer; but as soon as you start throwing things in like
pointers to structures, or vectors of string, you open yourself to questions&amp;nbsp;like:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;who allocates the argument when it goes&amp;nbsp;in?&lt;/li&gt;
&lt;li&gt;who is responsible for freeing the argument when it comes&amp;nbsp;out?&lt;/li&gt;
&lt;li&gt;what happens if the function frees the argument in the &lt;code&gt;in&lt;/code&gt; direction and
  then re-allocates the &lt;code&gt;out&lt;/code&gt;?&lt;/li&gt;
&lt;li&gt;what happens if the function uses a different allocator than the one used
  by the&amp;nbsp;caller?&lt;/li&gt;
&lt;li&gt;what happens if the function has to allocate more&amp;nbsp;memory?&lt;/li&gt;
&lt;li&gt;what happens if the function modifies the argument and frees&amp;nbsp;memory?&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Even if gobject-introspection nailed down the rules, they could not be
enforced, or validated, and could lead to leaks or, worse,&amp;nbsp;crashes.&lt;/p&gt;
&lt;p&gt;So, once again: don&amp;#8217;t use &lt;code&gt;inout&lt;/code&gt; arguments. If your &lt;span class="caps"&gt;API&lt;/span&gt; already exposes
&lt;code&gt;inout&lt;/code&gt; arguments, especially for non-scalar types, consider deprecations
and adding new entry&amp;nbsp;points.&lt;/p&gt;
&lt;h4&gt;Addendum: &lt;code&gt;GValue&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Sadly, &lt;code&gt;GValue&lt;/code&gt; is one of the most notable cases of &lt;code&gt;inout&lt;/code&gt; abuse. The
oldest parts of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; stack use &lt;code&gt;GValue&lt;/code&gt; in a way that requires &lt;code&gt;inout&lt;/code&gt;
annotations because they expect the caller&amp;nbsp;to:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;initialise a &lt;code&gt;GValue&lt;/code&gt; with the desired&amp;nbsp;type&lt;/li&gt;
&lt;li&gt;pass the address of the&amp;nbsp;value&lt;/li&gt;
&lt;li&gt;let the function fill the&amp;nbsp;value&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The caller is then left with calling &lt;code&gt;g_value_unset()&lt;/code&gt; in order to free the
resources associated with a &lt;code&gt;GValue&lt;/code&gt;. This means that you&amp;#8217;re passing an
initialised value to a callable, the callable will do something to it (which
may or may not even entail re-allocating the value) and then you&amp;#8217;re going to
get it back at the same&amp;nbsp;address.&lt;/p&gt;
&lt;p&gt;It would be a lot easier if the &lt;span class="caps"&gt;API&lt;/span&gt; left the job of initialising the
&lt;code&gt;GValue&lt;/code&gt; to the callee; then functions could annotate the &lt;code&gt;GValue&lt;/code&gt; argument
with &lt;code&gt;out&lt;/code&gt; and &lt;code&gt;caller-allocates=1&lt;/code&gt;. This would leave the ownership to the
caller, and remove a whole lot of&amp;nbsp;uncertainty.&lt;/p&gt;
&lt;p&gt;Various new (comparatively speaking) &lt;span class="caps"&gt;API&lt;/span&gt; allow the caller to pass an
unitialised &lt;code&gt;GValue&lt;/code&gt;, and will leave initialisation to the callee, which is
how it should be, but this kind of change isn&amp;#8217;t always possible in a
backward compatible&amp;nbsp;way.&lt;/p&gt;
&lt;h3&gt;Arrays&lt;/h3&gt;
&lt;p&gt;You can use three types of C arrays in your &lt;span class="caps"&gt;API&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;zero-terminated arrays, which are the easiest to use, especially for
  pointers and&amp;nbsp;strings&lt;/li&gt;
&lt;li&gt;fixed-size&amp;nbsp;arrays&lt;/li&gt;
&lt;li&gt;arrays with length&amp;nbsp;arguments&lt;/li&gt;
&lt;/ul&gt;
&lt;h4&gt;Addendum: strings and byte&amp;nbsp;arrays&lt;/h4&gt;
&lt;p&gt;A &lt;code&gt;const char*&lt;/code&gt; argument for C strings with a length argument is &lt;strong&gt;not&lt;/strong&gt; an&amp;nbsp;array:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * some_object_load_data:&lt;/span&gt;
&lt;span class="cm"&gt; * @self: ...&lt;/span&gt;
&lt;span class="cm"&gt; * @str: the data to load&lt;/span&gt;
&lt;span class="cm"&gt; * @len: length of @str in bytes, or -1&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * ...&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="n"&gt;some_object_load_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;str&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="kt"&gt;ssize_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;strong&gt;Never&lt;/strong&gt; annotate the &lt;code&gt;str&lt;/code&gt; argument with &lt;code&gt;array length=len&lt;/code&gt;. Ideally, this
kind of function &lt;em&gt;should not exist in the first place&lt;/em&gt;. You should always
use &lt;code&gt;const char*&lt;/code&gt; for &lt;code&gt;NUL&lt;/code&gt;-terminated strings, possibly &lt;span class="caps"&gt;UTF&lt;/span&gt;-8 encoded; if
you allow embedded &lt;code&gt;NUL&lt;/code&gt; characters then use a bytes&amp;nbsp;array:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * some_object_load_data:&lt;/span&gt;
&lt;span class="cm"&gt; * @self: ...&lt;/span&gt;
&lt;span class="cm"&gt; * @data: (array length=len) (element-type uint8): the data to load&lt;/span&gt;
&lt;span class="cm"&gt; * @len: the length of the data in bytes&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * ...&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="n"&gt;some_object_load_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;unsigned&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="kt"&gt;size_t&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;len&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Instead of &lt;code&gt;unsigned char&lt;/code&gt; you can also use &lt;code&gt;uint8_t&lt;/code&gt;, just to drive the
point&amp;nbsp;home.&lt;/p&gt;
&lt;p&gt;Yes, it&amp;#8217;s slightly nicer to have a single entry point for strings and byte
arrays, but that&amp;#8217;s just a C convenience: decent languages will have a proper
string type, which always comes with a length; and string types are not
binary&amp;nbsp;data.&lt;/p&gt;
&lt;h4&gt;Addendum: &lt;code&gt;GArray&lt;/code&gt;, &lt;code&gt;GPtrArray&lt;/code&gt;, &lt;code&gt;GByteArray&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;Whatever you do, however low you feel on the day, whatever particular
tragedy befell your family at some point, please: &lt;strong&gt;never&lt;/strong&gt; use GLib array
types in your &lt;span class="caps"&gt;API&lt;/span&gt;. Nothing good will ever come of it, and you&amp;#8217;ll just spend
your days regretting this&amp;nbsp;choice.&lt;/p&gt;
&lt;p&gt;Yes: gobject-introspection transparently converts between GLib array types
and C types, to the point of allowing you to annotate the contents of the
array. The problem is that that information is static, and only exists at
the introspection level. There&amp;#8217;s nothing that prevents you from putting
other random data into a &lt;code&gt;GPtrArray&lt;/code&gt;, as long as it&amp;#8217;s pointer-sized.
There&amp;#8217;s nothing that prevents a version of a library from saying that you
own the data inside a &lt;code&gt;GArray&lt;/code&gt;, and have the next version assign a clear
function to the array to avoid leaking it all over the place on error
conditions, or when using &lt;code&gt;g_autoptr&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Adding support for GLib array types in the introspection was a
well-intentioned mistake that worked in very specific cases—for instance, in
a library that is private to an application. Any well-behaved, well-designed
general purpose library should not expose this kind of &lt;span class="caps"&gt;API&lt;/span&gt; to its&amp;nbsp;consumers.&lt;/p&gt;
&lt;p&gt;You should use &lt;code&gt;GArray&lt;/code&gt;, &lt;code&gt;GPtrArray&lt;/code&gt;, and &lt;code&gt;GByteArray&lt;/code&gt; internally; they are
good types, and remove a lot of the pain of dealing with C arrays. Those
types should never be exposed at the &lt;span class="caps"&gt;API&lt;/span&gt; boundary: always convert them to C
arrays, or wrap them into your own data types, with proper argument
validation and ownership&amp;nbsp;rules.&lt;/p&gt;
&lt;h4&gt;Addendum: &lt;code&gt;GHashTable&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;What&amp;#8217;s worse than a type that contains data with unclear ownership rules
decided at run time? A type that contains twice the amount of data with
unclear ownership rules decided at run&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;Just like the GLib array types, hash tables should be used but never
directly exposed to consumers of an &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h4&gt;Addendum: &lt;code&gt;GList&lt;/code&gt;, &lt;code&gt;GSList&lt;/code&gt;, &lt;code&gt;GQueue&lt;/code&gt;&lt;/h4&gt;
&lt;p&gt;See above, re: pain and misery. On top of that, linked lists are a
&lt;strong&gt;terrible&lt;/strong&gt; data type that people should rarely, if ever, use in the first&amp;nbsp;place.&lt;/p&gt;
&lt;h3&gt;Callbacks&lt;/h3&gt;
&lt;p&gt;Your callbacks should always be in the form of a simple callable with a
data&amp;nbsp;argument:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Any function that takes a callback should also take a &amp;#8220;user data&amp;#8221; argument
that will be passed &lt;em&gt;as is&lt;/em&gt; to the&amp;nbsp;callback:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;// scope: call; the callback data is valid until the&lt;/span&gt;
&lt;span class="c1"&gt;// function returns&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;some_object_do_stuff_immediately&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="n"&gt;SomeCallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                  &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// scope: notify; the callback data is valid until the&lt;/span&gt;
&lt;span class="c1"&gt;// notify function gets called&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;some_object_do_stuff_with_a_delay&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="n"&gt;SomeCallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="n"&gt;GDestroyNotify&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;notify&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// scope: async; the callback data is valid until the async&lt;/span&gt;
&lt;span class="c1"&gt;// callback is called&lt;/span&gt;
&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;some_object_do_stuff_but_async&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="n"&gt;GCancellable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;cancellable&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="n"&gt;GAsyncReadyCallback&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;callback&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// not pictured here: scope forever; the data is valid fori&lt;/span&gt;
&lt;span class="c1"&gt;// the entirety of the process lifetime&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If your function takes more than one callback argument, you should make sure
that it also takes a different user data for each callback, and that the
lifetime of the callbacks are well defined. The alternative is to use
&lt;code&gt;GClosure&lt;/code&gt; instead of a simple C function pointer—but that comes at a cost
of &lt;code&gt;GValue&lt;/code&gt; marshalling, so the recommendation is to stick with one callback
per&amp;nbsp;function.&lt;/p&gt;
&lt;h4&gt;Addendum: the &lt;code&gt;closure&lt;/code&gt; annotation&lt;/h4&gt;
&lt;p&gt;It seems that many people are unclear about the &lt;code&gt;closure&lt;/code&gt; annotation.&lt;/p&gt;
&lt;p&gt;Whenever you&amp;#8217;re describing a function that takes a callback, you should
&lt;strong&gt;always&lt;/strong&gt; annotate the &lt;em&gt;callback&lt;/em&gt; argument with the argument that contains
the &lt;em&gt;user data&lt;/em&gt; using the &lt;code&gt;(closure argument)&lt;/code&gt; annotation,&amp;nbsp;e.g.&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * some_object_do_stuff_immediately:&lt;/span&gt;
&lt;span class="cm"&gt; * @self: ...&lt;/span&gt;
&lt;span class="cm"&gt; * @callback: (scope call) (closure data): the callback&lt;/span&gt;
&lt;span class="cm"&gt; * @data: the data to be passed to the @callback&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * ...&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You should &lt;strong&gt;not&lt;/strong&gt; annotate the &lt;code&gt;data&lt;/code&gt; argument with a unary &lt;code&gt;(closure)&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;The unary &lt;code&gt;(closure)&lt;/code&gt; is meant to be used when annotating the &lt;strong&gt;callback
type&lt;/strong&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * SomeCallback:&lt;/span&gt;
&lt;span class="cm"&gt; * @self: ...&lt;/span&gt;
&lt;span class="cm"&gt; * @data: (closure): ...&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * ...&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;SomeCallback&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;SomeObject&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                               &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Yes, it&amp;#8217;s confusing, I&amp;nbsp;know.&lt;/p&gt;
&lt;p&gt;Sadly, the introspection parser isn&amp;#8217;t very clear about this, but in the
future it will emit a warning if it finds a unary &lt;code&gt;closure&lt;/code&gt; on anything that
isn&amp;#8217;t a callback&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;Ideally, you don&amp;#8217;t really need to annotate anything when you call your
argument &lt;code&gt;user_data&lt;/code&gt;, but it does not hurt to be&amp;nbsp;explicit.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;A cleaned up version of this blog post will go up on the
gobject-introspection website, and we should really have a proper set of
best &lt;span class="caps"&gt;API&lt;/span&gt; design practices on the Developer Documentation website by now;
nevertheless, I do hope people will actually follow these recommendations at
some point, and that they will be prepared for new recommendations in the
future. Only dead and unmaintained projects don&amp;#8217;t change, after all, and I
expect the &lt;span class="caps"&gt;GNOME&lt;/span&gt; stack to last a bit longer than the 25 years it already
spans&amp;nbsp;today.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="bindings"></category><category term="api"></category><category term="design"></category></entry><entry><title>On PyGObject</title><link href="https://www.bassi.io/articles/2022/12/02/on-pygobject/" rel="alternate"></link><published>2022-12-02T18:03:00+00:00</published><updated>2022-12-02T18:56:00+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2022-12-02:/articles/2022/12/02/on-pygobject/</id><summary type="html">&lt;p&gt;In which I look at the state of the Python bindings for the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;platform&lt;/p&gt;</summary><content type="html">&lt;p&gt;Okay, I can&amp;#8217;t believe I have to do this &lt;a href="https://www.bassi.io/articles/2017/02/13/on-vala/"&gt;&lt;strong&gt;again&lt;/strong&gt;&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;This time, let&amp;#8217;s leave &lt;a href="https://twitter.com"&gt;the Hellsite&lt;/a&gt; out of it, and
let&amp;#8217;s try to be nuanced from the start. I&amp;#8217;d like to avoid getting grief&amp;nbsp;online.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;The current state of the Python bindings for GObject-based libraries is
making it really hard to recommend using Python as a language for
developing &lt;span class="caps"&gt;GTK&lt;/span&gt; and &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;applications.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;PyGObject is currently &lt;em&gt;under&lt;/em&gt;maintained, even after the heroic efforts of
Christoph Reiter to keep the fires burning through the long night. The
Python community needs more people to work on the bindings, if we want
Python to be a first class citizen of the&amp;nbsp;ecosystem.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s a lot to do, and not nearly enough people left to do&amp;nbsp;it.&lt;/p&gt;
&lt;h3&gt;Case study: typed&amp;nbsp;instances&lt;/h3&gt;
&lt;p&gt;Yes, &lt;a href="https://www.bassi.io/articles/2020/06/02/type-instances/"&gt;&lt;em&gt;thou shall use GObject&lt;/em&gt;&lt;/a&gt; should be the
law of the land; &lt;strong&gt;but&lt;/strong&gt; there are legitimate reasons to use typed
instances, and &lt;span class="caps"&gt;GTK&lt;/span&gt; 4 has a few of&amp;nbsp;them:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://docs.gtk.org/gtk4/class.Expression.html"&gt;&lt;code&gt;GtkExpression&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gtk.org/gsk4/class.RenderNode.html"&gt;&lt;code&gt;GskRenderNode&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://docs.gtk.org/gdk4/class.Event.html"&gt;&lt;code&gt;GdkEvent&lt;/code&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;At this very moment, it is impossible to use the types above from Python.
PyGObject will literally error out if you try to do so. There are technical
reasons why that was a reasonable choice 15+ years ago, but most language
bindings written since then can handle typed instances just fine. In fact,
PyGObject &lt;em&gt;does&lt;/em&gt; handle them, since
&lt;a href="https://docs.gtk.org/gobject/class.ParamSpec.html"&gt;&lt;code&gt;GParamSpec&lt;/code&gt;&lt;/a&gt; is a
&lt;code&gt;GTypeInstance&lt;/code&gt;; of course, that&amp;#8217;s because PyGObject has some &lt;em&gt;ad hoc&lt;/em&gt; code
for&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Dealing with events and render nodes is not so important in &lt;span class="caps"&gt;GTK4&lt;/span&gt;; but not
having access to the expressions &lt;span class="caps"&gt;API&lt;/span&gt; makes writing list widgets incredibly
more complicated, requiring to set up everything through &lt;span class="caps"&gt;UI&lt;/span&gt; definition files
and never modifying the objects&amp;nbsp;programmatically.&lt;/p&gt;
&lt;h3&gt;Case study: constructing and&amp;nbsp;disposing&lt;/h3&gt;
&lt;p&gt;While most of the &lt;span class="caps"&gt;API&lt;/span&gt; in PyGObject is built through introspection, the base
wrapper for the GObject class is still very much written in CPython. This
requires, among other things, wiring the class&amp;#8217;s virtual functions manually,
and figuring out the interactions between Python, GObject, and the type
system wrappers. This means Python types that inherit from GObject don&amp;#8217;t
have automatic access to the &lt;code&gt;GObjectClass.constructed&lt;/code&gt; and
&lt;code&gt;GObjectClass.dispose&lt;/code&gt; virtual functions. Normally, this would not be an
issue, but modern GObject-based libraries have started to depend on being
able to control construction and destruction&amp;nbsp;sequences.&lt;/p&gt;
&lt;p&gt;For instance, it is necessary for any type that inherits from &lt;code&gt;GtkWidget&lt;/code&gt; to
ensure that all its child widgets are disposed manually. While that was
possible through the &amp;#8220;destroy&amp;#8221; signal in &lt;span class="caps"&gt;GTK3&lt;/span&gt;, in &lt;span class="caps"&gt;GTK4&lt;/span&gt; the signal was
removed and everything should go through the &lt;code&gt;GObjectClass.dispose&lt;/code&gt; virtual
function. Since PyGObject does not allow overriding or implementing that
virtual function, your Python class cannot inherit from &lt;code&gt;GtkWidget&lt;/code&gt;, but
must inherit from ancillary classes like &lt;code&gt;GtkBox&lt;/code&gt; or &lt;code&gt;AdwBin&lt;/code&gt;. That&amp;#8217;s even
more relevant for the disposal of resources created through the &lt;a href="https://pygobject.readthedocs.io/en/latest/guide/gtk_template.html"&gt;composite
template &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;.
Theoretically, using &lt;code&gt;Gtk.Template&lt;/code&gt; would take care of this, but since we
cannot plug the Python code into the underlying CPython, we&amp;#8217;re&amp;nbsp;stuck.&lt;/p&gt;
&lt;h3&gt;Case study: documentation, examples, and&amp;nbsp;tutorials&lt;/h3&gt;
&lt;p&gt;While I have been trying to write Python examples for the &lt;a href="https://developer.gnome.org/documentation"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; developers
documentation&lt;/a&gt;, I cannot write
&lt;em&gt;everything&lt;/em&gt; by myself. Plus, I can&amp;#8217;t convince Google to only link to what I
write. The result is that searching for &amp;#8220;Python&amp;#8221; and &amp;#8220;&lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8221; or &amp;#8220;&lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;#8221; will
inevitably lead people to the &lt;span class="caps"&gt;GTK3&lt;/span&gt; tutorials and&amp;nbsp;references.&lt;/p&gt;
&lt;p&gt;The fragmentation of the documentation is also an issue. The &lt;a href="https://pygobject.readthedocs.io"&gt;PyGObject
website&lt;/a&gt; is off to readthedocs.org, which
is understandable for a Python projects; then we have the &lt;a href="https://python-gtk-3-tutorial.readthedocs.io/en/latest/"&gt;&lt;span class="caps"&gt;GTK3&lt;/span&gt;
tutorial&lt;/a&gt;, which
hasn&amp;#8217;t been updated in a while, and for which &lt;a href="https://github.com/sebp/PyGObject-Tutorial/issues/191"&gt;there are no plans to have a
&lt;span class="caps"&gt;GTK&lt;/span&gt; 4 version&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, the &lt;a href="http://lazka.github.io/pgi-docs/"&gt;Python &lt;span class="caps"&gt;API&lt;/span&gt; reference&lt;/a&gt;
is currently stuck on &lt;span class="caps"&gt;GTK3&lt;/span&gt;, with &lt;a href="https://amolenaar.github.io/pgi-docgen/"&gt;Python references for &lt;span class="caps"&gt;GTK4&lt;/span&gt; and
friends&lt;/a&gt; off on the&amp;nbsp;side.&lt;/p&gt;
&lt;p&gt;It would be great to unify the reference sites, and possibly have them under
the &lt;span class="caps"&gt;GNOME&lt;/span&gt; infrastructure; but at this point, I&amp;#8217;d settle for having a single
place to find everything, like &lt;a href="https://gjs.guide"&gt;&lt;span class="caps"&gt;GJS&lt;/span&gt; did&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What can &lt;strong&gt;you&lt;/strong&gt;&amp;nbsp;do?&lt;/h2&gt;
&lt;p&gt;Pick up &lt;a href="https://gitlab.gnome.org/GNOME/pygobject"&gt;PyGObject&lt;/a&gt;. Learn how it
works, and how the GObject and CPython &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;interact.&lt;/p&gt;
&lt;p&gt;Write Python overrides to ensure that &lt;span class="caps"&gt;API&lt;/span&gt; like &lt;span class="caps"&gt;GTK&lt;/span&gt; and &lt;span class="caps"&gt;GIO&lt;/span&gt; are nice to use
with idiomatic&amp;nbsp;Python.&lt;/p&gt;
&lt;p&gt;Write tests for&amp;nbsp;PyGObject.&lt;/p&gt;
&lt;p&gt;Write&amp;nbsp;documentation.&lt;/p&gt;
&lt;p&gt;Port existing tutorials, examples, and demos to &lt;span class="caps"&gt;GTK4&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Help Christoph out when it comes to triaging issues, and reviewing merge&amp;nbsp;requests.&lt;/p&gt;
&lt;p&gt;Join &lt;a href="https://matrix.to/#/#python:gnome.org"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; Python on Matrix&lt;/a&gt;, or the
&lt;code&gt;#gnome-python&lt;/code&gt; channel on &lt;a href="https://libera.chat"&gt;Libera&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Ask questions and provide answers on
&lt;a href="https://discourse.gnome.org/tag/python"&gt;Discourse&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What happens if nobody does&amp;nbsp;anything?&lt;/h2&gt;
&lt;p&gt;Right now, we&amp;#8217;re in maintenance mode. Things work because of inertia, and
because nobody is &lt;em&gt;really&lt;/em&gt; pushing the bindings outside of their existing&amp;nbsp;functionality.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s be positive, for a change, and assume that people &lt;em&gt;will&lt;/em&gt; show up. They
did for Vala when I ranted about it five years ago after a particularly
frustrating week dealing with constant build failures in &lt;span class="caps"&gt;GNOME&lt;/span&gt;, so maybe the
magic will happen&amp;nbsp;again.&lt;/p&gt;
&lt;p&gt;If people do &lt;em&gt;not&lt;/em&gt; show up, though, what will likely happen is that Python
will just fall on the wayside inside &lt;span class="caps"&gt;GNOME&lt;/span&gt;. Python developers won&amp;#8217;t use &lt;span class="caps"&gt;GTK&lt;/span&gt;
to write &lt;span class="caps"&gt;GUI&lt;/span&gt; applications; existing Python applications targeting &lt;span class="caps"&gt;GNOME&lt;/span&gt; will
either wither and die, or get ported to other languages. The Python bindings
themselves may stop working with newer versions of Python, which will
inevitably lead downstream distributors to jettison the bindings&amp;nbsp;themselves.&lt;/p&gt;
&lt;p&gt;We have been through this dance with the C# bindings and Mono, and the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
and Mono communities are all the poorer for it, so I&amp;#8217;d like to avoid losing
&lt;em&gt;another&lt;/em&gt; community of talented developers. History does not need to repeat&amp;nbsp;itself.&lt;/p&gt;</content><category term="gnome"></category><category term="python"></category><category term="development"></category><category term="languages"></category><category term="gnome"></category></entry><entry><title>Amberol</title><link href="https://www.bassi.io/articles/2022/05/25/amberol/" rel="alternate"></link><published>2022-05-25T01:30:00+01:00</published><updated>2022-06-16T13:46:57+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2022-05-25:/articles/2022/05/25/amberol/</id><summary type="html">&lt;p&gt;In which I write a music player mostly for&amp;nbsp;me&lt;/p&gt;</summary><content type="html">&lt;h4&gt;In the&amp;nbsp;beginning…&lt;/h4&gt;
&lt;p&gt;In 1997, I downloaded my first &lt;span class="caps"&gt;MP3&lt;/span&gt; file. It was linked on a website, and all
I had was a 56k modem, so it took me ages to download the nearly 4 megabytes
of 128 kbit/s &lt;a href="https://www.youtube.com/watch?v=bPdisSAev0A"&gt;music goodness&lt;/a&gt;.
Before that file magically appeared on my hard drive, if we exclude a brief
dalliance with &lt;span class="caps"&gt;MOD&lt;/span&gt; files, the only music I had on my computer came either in
&lt;span class="caps"&gt;MIDI&lt;/span&gt; or in &lt;span class="caps"&gt;WAV&lt;/span&gt;&amp;nbsp;format.&lt;/p&gt;
&lt;p&gt;In the nearly 25 years passed since that seminal moment, my music collection
has steadily increased in size — to the point that I cannot comfortably keep
it in my laptop&amp;#8217;s internal storage without cutting into the available space
for other stuff and without taking ages when copying it to new machines; and
if I had to upload it to a cloud service, I&amp;#8217;d end up paying monthly storage
fees that would definitely not make me happy. Plus, I like being able to
listen to my music without having a network connection — say, when I&amp;#8217;m
travelling. For these reasons, I have my music collection on a dedicated
&lt;span class="caps"&gt;USB3&lt;/span&gt; drive and on various 128 &lt;span class="caps"&gt;GB&lt;/span&gt; &lt;span class="caps"&gt;SD&lt;/span&gt; cards that I use when travelling, to
avoid bumping around a spinning rust&amp;nbsp;drive.&lt;/p&gt;
&lt;p&gt;In order to listen to that first &lt;span class="caps"&gt;MP3&lt;/span&gt; file, I also had to download a music
player, and back in 1997 there was this little software called
&lt;a href="https://en.wikipedia.org/wiki/Winamp"&gt;Winamp&lt;/a&gt;, which apparently &lt;em&gt;really whipped the llama&amp;#8217;s ass&lt;/em&gt;.
Around that same time I was also dual-booting between Windows and Linux,
and, obviously, Linux had its own Winamp clone called &lt;a href="https://en.wikipedia.org/wiki/XMMS"&gt;x11amp&lt;/a&gt;.
This means that, since late 1997, I&amp;#8217;ve also tested more or less all
mainstream, &lt;span class="caps"&gt;GTK&lt;/span&gt;-based Linux music players—xmms, beep, xmms2, Rhythmbox,
Muine, Banshee, Lollypop, &lt;span class="caps"&gt;GNOME&lt;/span&gt; Music—and various less mainstream/non-&lt;span class="caps"&gt;GTK&lt;/span&gt;
ones—shout out to &lt;em&gt;ma boi&lt;/em&gt; mpg123. I also used iTunes on macOS and Windows,
but I don&amp;#8217;t speak of&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;Turns out that, with the very special exception of Muine, I can&amp;#8217;t stand any
of them. They are all fairly inefficient when it comes to managing my music
collection; or they are barely maintained; or (but, most often, and) they
are just iTunes clones—as if cloning iTunes was a worthy goal for anything
remotely connected to music, computing, or even human progress in&amp;nbsp;general.&lt;/p&gt;
&lt;p&gt;I did enjoy using Banshee, up to a point; it wasn&amp;#8217;t overly offensive to my
eyes and pointing devices, and had the advantage of being able to minimise
its &lt;span class="caps"&gt;UI&lt;/span&gt; without getting in the way. It just bitrotted with the rest of the
&lt;span class="caps"&gt;GNOME&lt;/span&gt; 2 platform even before &lt;span class="caps"&gt;GNOME&lt;/span&gt; bumped major version, and it still wasn&amp;#8217;t
as good as&amp;nbsp;Muine.&lt;/p&gt;
&lt;h4&gt;A detour: managing a music&amp;nbsp;collection&lt;/h4&gt;
&lt;p&gt;&lt;em&gt;I&amp;#8217;d like to preface this detour with a disclaimer: I am not talking about
specific applications; specific technologies/libraries; or specific
platforms. Any resemblance to real projects, existing or abandoned, is
purely coincidental.&amp;nbsp;Seriously.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Most music management software is, I feel, predicated on the fallacy that
the majority of people don&amp;#8217;t bother organising their files, and are thus
willing to accept a flat storage with complex views built at run time on top
of that; while simultaneously being willing to spend a disproportionate
amount of time classifying those files—without, of course, using a
hierarchical structure. This is a fundamental misunderstanding of human&amp;nbsp;nature.&lt;/p&gt;
&lt;p&gt;By way of an example: if we perceive the Universe in a techno-mazdeist
struggle between a πνεῦμα which creates fool-proof tools for users; and a
φύσις, which creates more and more adept fools; then we can easily see that,
for the entirety of history until now, the &lt;em&gt;pneuma&lt;/em&gt; has been kicked squarely
in the nuts by the &lt;em&gt;physis&lt;/em&gt;. In other words: any design or implementation
that does not take into account human nature in that particular problem
space is bound to&amp;nbsp;fail.&lt;/p&gt;
&lt;p&gt;While documents &lt;em&gt;might&lt;/em&gt; benefit from additional relations that are not
simply inferred by their type or location on the file system, media files do
not really have the same constraints. &lt;em&gt;Especially&lt;/em&gt; stuff like music or
videos. All the tracks of an album are in the same place not because I
decided that, but because the artist or the music producers willed it that
way; all the episodes of a series are in the same place because of course
they are, and they are divided by season because that&amp;#8217;s how &lt;span class="caps"&gt;TV&lt;/span&gt; series work;
all the episodes of a podcast are in the same place for the same reason,
maybe divided by year, or by season. If that structure already exists, then
what&amp;#8217;s the point of flattening it and then trying to recreate it every time
out of thin air with a database&amp;nbsp;query?&lt;/p&gt;
&lt;p&gt;The end result of constructing a &lt;span class="caps"&gt;UI&lt;/span&gt; that is just a view on top of a database
is that your &lt;span class="caps"&gt;UI&lt;/span&gt; will be indistiguishable from a database design and
management tool; which is why all music management software looks very much
like Microsoft Access from circa 1997 onwards. Of course you can dress it up
however you like, by adding fancy views of album covers, but at the end of
the day it&amp;#8217;s just an Excel spread sheet that &lt;em&gt;occasionally&lt;/em&gt; plays&amp;nbsp;music.&lt;/p&gt;
&lt;p&gt;Another side effect of writing a database that contains the metadata of a
bunch of files is that you&amp;#8217;ll end up changing the database instead of
changing the files; you could write the changes to the files, but
reconciling the files with the database is a hard problem, and it also
assumes you have read-write access to those files. Now that you have locked
your users into your own database, switching to a new application becomes
harder, unless your users enjoy figuring out what they changed over&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;A few years ago, before backing up everything in three separate storages,
I had a catastrophic failure on my primary music hard drive; after
recovering most of my data, I realised that &lt;em&gt;a lot&lt;/em&gt; of the changes I made in
the early years weren&amp;#8217;t written out to music files, but were stored in some
random SQLite database somewhere. I am still recovering from that particular&amp;nbsp;disaster.&lt;/p&gt;
&lt;p&gt;I want my music player to have read-only access to my music. I don&amp;#8217;t want
anything that isn&amp;#8217;t me writing to it. I also don&amp;#8217;t want to re-index my whole
music collection just because I fixed the metadata of one album, and I don&amp;#8217;t
want to lose all my changes when I find a better music&amp;nbsp;player.&lt;/p&gt;
&lt;h4&gt;Another detour: non-local&amp;nbsp;media&lt;/h4&gt;
&lt;p&gt;Yes, yes: everyone listens to streamed media these days, because media (and
software) companies are speed-running Adam Smith&amp;#8217;s &lt;em&gt;The Wealth of Nations&lt;/em&gt;
and have just arrived at the bit about rentier economy. After all, why
should they want to get paid once for something, when media conglomerates
can &amp;#8220;reap where they never sowed, and demand a rent even for its natural&amp;nbsp;produce&amp;#8221;.&lt;/p&gt;
&lt;p&gt;You know what streaming services don&amp;#8217;t like? Custom, third party clients
that they can&amp;#8217;t control, can&amp;#8217;t use for metrics, and can&amp;#8217;t use to serve
people&amp;nbsp;ads.&lt;/p&gt;
&lt;p&gt;You know what cloud services that offer to host music don&amp;#8217;t like? Duplicate
storage, and service files that may potentially infringe the &lt;span class="caps"&gt;IP&lt;/span&gt; of a very
litigious industry. Plus, of course, third party clients that they can&amp;#8217;t use
to serve you ads, as that&amp;#8217;s how they can operate at all, because this is the
Darkest Timeline, and adtech is the modern Moloch to which we must sacrifice
as many lives as we&amp;nbsp;can.&lt;/p&gt;
&lt;p&gt;You may have a music player that streams somebody&amp;#8217;s music collection, or
even yours if you can accept the remote service making a mess of it, but
you&amp;#8217;re always a bad &lt;span class="caps"&gt;IPO&lt;/span&gt; or a bad quarterly revenue report away from losing
access to&amp;nbsp;everything.&lt;/p&gt;
&lt;h4&gt;Writing a music player for fun and no&amp;nbsp;profit&lt;/h4&gt;
&lt;p&gt;For the past few years I&amp;#8217;ve been meaning to put some time into writing a
music player, mostly for my own amusement; I also had the idea of using this
project to learn the &lt;a href="https://www.rust-lang.org"&gt;Rust programming language&lt;/a&gt;.
In 2015 I was looking for a way to read the metadata of music files with
Rust, but since I couldn&amp;#8217;t find anything decent, I ended up writing the Rust
&lt;a href="https://github.com/ebassi/taglib-rust"&gt;bindings for taglib&lt;/a&gt;. I kept
noodling at this side project for the following years, but I was mostly
hitting the limits of &lt;span class="caps"&gt;GTK3&lt;/span&gt; when it came to dealing with my music collection;
every single iteration of the user interface ended up with a GtkTreeView and
a replica of iTunes&amp;nbsp;1.0.&lt;/p&gt;
&lt;p&gt;In the meantime, though, the Rust ecosystem got exponentially better, with
lots of crates dedicated to parsing music file metadata; &lt;span class="caps"&gt;GTK4&lt;/span&gt; got released
with &lt;a href="https://docs.gtk.org/gtk4/section-list-widget.html"&gt;new list widgets&lt;/a&gt;;
libadwaita is available to take care of nice &lt;span class="caps"&gt;UI&lt;/span&gt; layouts; and the Rust
bindings for &lt;span class="caps"&gt;GTK&lt;/span&gt; have become one of the most well curated and maintained
projects in the language bindings&amp;nbsp;ecosystem.&lt;/p&gt;
&lt;p&gt;Another few things that happened in the meantime: a pandemic, a year of
unemployment, and zero conferences, all of which pushed me to streaming my
free and open source software contributions on
&lt;a href="https://twitch.tv/ebassi"&gt;Twitch&lt;/a&gt;, as a way to break the&amp;nbsp;isolation.&lt;/p&gt;
&lt;p&gt;So, after spending the first couple of months of 2022 on writing the
beginners tutorial for the &lt;span class="caps"&gt;GNOME&lt;/span&gt; developer documentation website, in March
I began writing &lt;a href="https://gitlab.gnome.org/World/amberol"&gt;Amberol&lt;/a&gt;, a
local-only music player that has no plans of becoming more than&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Desktop&amp;nbsp;mode&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/amberol-1.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Amberol&amp;#8217;s scope sits in the same grand tradition of Winamp, and while its
&lt;span class="caps"&gt;UI&lt;/span&gt; started off as a Muine rip off—down to the same key shortcuts—it has
evolved into something that more closely resembles the music player I have
on my&amp;nbsp;phone.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Mobile&amp;nbsp;mode&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/amberol-2.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Amberol&amp;#8217;s explicit goal is to let me play music on my desktop the same way I
typically do when I am using my phone, which is: shuffling all the songs in
my music collection; or, alternatively, listening to all the songs in an
album or from an artist from start to&amp;nbsp;finish.&lt;/p&gt;
&lt;p&gt;Amberol&amp;#8217;s explicit &lt;em&gt;non goals&lt;/em&gt;&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;managing your music&amp;nbsp;collection&lt;/li&gt;
&lt;li&gt;figuring out your music&amp;nbsp;metadata&lt;/li&gt;
&lt;li&gt;building&amp;nbsp;playlists&lt;/li&gt;
&lt;li&gt;accessing external services for stuff like cover art, song lyrics, or the
  artist&amp;#8217;s Wikipedia&amp;nbsp;page&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The &lt;em&gt;actual&lt;/em&gt; main feature of this application is that it has forced me to
figure out how to deal with GStreamer after 15&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;I did try to write this application in a way that reflects the latest best
practices of &lt;span class="caps"&gt;GTK4&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;model&amp;nbsp;objects&lt;/li&gt;
&lt;li&gt;custom view&amp;nbsp;widgets&lt;/li&gt;
&lt;li&gt;composite widgets using&amp;nbsp;templates&lt;/li&gt;
&lt;li&gt;property bindings/expressions to couple model/state to its&amp;nbsp;view/representation&lt;/li&gt;
&lt;li&gt;actions and actionable&amp;nbsp;widgets&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The ability to rely on libadwaita has allowed me to implement the recoloring
of the main window without having to deal with breakage coming from rando
style&amp;nbsp;sheets:&lt;/p&gt;
&lt;p&gt;&lt;span class="videobox"&gt;
            &lt;video width="100%" height="480" preload="none" controls poster="None"&gt;&lt;source src='https://www.bassi.io/images/amberol-recolor-1.mp4' type='video/mp4; codecs="avc1.42E01E, mp4a.40.2"'&gt;&lt;/video&gt;&lt;/span&gt;&lt;/p&gt;
&lt;p&gt;The main thing I did not expect was how much of a good fit was Rust in all
of this. The &lt;a href="https://gtk-rs.org"&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt; bindings&lt;/a&gt; are top notch, and
constantly improving; the type system has helped me much more than hindering
me, a poor programmer whose mind has been twisted by nearly two decades of
C. Good idiomatic practices for &lt;span class="caps"&gt;GTK&lt;/span&gt; are entirely within the same ballpark of
idiomatic practices for Rust, especially for application&amp;nbsp;development.&lt;/p&gt;
&lt;p&gt;On the tooling side, Builder has been incredibly helpful in letting me
concentrate on the project—starting from the basic template for a &lt;span class="caps"&gt;GNOME&lt;/span&gt;
application in Rust, to dealing with the build system; from the Flatpak
manifest, to running the application under a debugger. My work was basically
ready to be submitted to
&lt;a href="https://flathub.org/apps/details/io.bassi.Amberol"&gt;Flathub&lt;/a&gt; from day one. I
did have some challenge with the AppData validation, mostly caused by
appstream-utils undocumented validation rules, but luckily it&amp;#8217;s entirely
possible to remove the validation after you deal with the basic&amp;nbsp;manifest.&lt;/p&gt;
&lt;p&gt;All in all, I am definitely happy with the results of basically two months
of hacking and refactoring, mostly off an on (and with two weeks of &lt;span class="caps"&gt;COVID&lt;/span&gt; in
the&amp;nbsp;middle).&lt;/p&gt;
&lt;div style="text-align:center"&gt;
&lt;a style="text-decoration:none" href="https://flathub.org/apps/details/io.bassi.Amberol"&gt;&lt;img src="https://flathub.org/assets/badges/flathub-badge-en.png" style="width:200px" width="200"/&gt;&lt;/a&gt;
&lt;/div&gt;</content><category term="gnome"></category><category term="amberol"></category><category term="muine"></category><category term="music"></category><category term="projects"></category><category term="development"></category><category term="rust"></category><category term="gtk"></category></entry><entry><title>Fair Weather Friends</title><link href="https://www.bassi.io/articles/2021/11/19/fair-weather-friends/" rel="alternate"></link><published>2021-11-19T20:48:00+01:00</published><updated>2023-02-20T00:31:37+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-11-19:/articles/2021/11/19/fair-weather-friends/</id><summary type="html">&lt;p&gt;In which I announce the release of the first GWeather-4 developers&amp;nbsp;snapshot&lt;/p&gt;</summary><content type="html">&lt;p&gt;Today I released
&lt;a href="https://gitlab.gnome.org/GNOME/libgweather/-/releases/3.90.0"&gt;libgweather-3.90.0&lt;/a&gt;,
the first developers snapshot of GWeather&amp;nbsp;4:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Behold! A project&amp;nbsp;logo&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gweather-docs.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This release is mostly meant to be used as a target for porting existing
code to the new &lt;span class="caps"&gt;API&lt;/span&gt;, and verifying that everything works as it&amp;nbsp;should.&lt;/p&gt;
&lt;p&gt;The major changes from GWeather-3.0&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the &lt;span class="caps"&gt;GTK3&lt;/span&gt; widgets have gone to a farm up state, so you&amp;#8217;ll have to write
  your own &lt;span class="caps"&gt;UI&lt;/span&gt; for searching&amp;nbsp;locations&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GWeatherLocation&lt;/code&gt; is a &lt;code&gt;GObject&lt;/code&gt; type, so you can use it with
  &lt;code&gt;GListModel&lt;/code&gt; and friends, which should help with the point&amp;nbsp;above&lt;/li&gt;
&lt;li&gt;the deprecated &lt;span class="caps"&gt;API&lt;/span&gt; has been&amp;nbsp;removed&lt;/li&gt;
&lt;li&gt;the &lt;span class="caps"&gt;API&lt;/span&gt; that will be part of GWeather 4.0 will be stable, and regular
  &lt;span class="caps"&gt;API&lt;/span&gt;/&lt;span class="caps"&gt;ABI&lt;/span&gt; stability guarantees will&amp;nbsp;apply&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you are using libgweather in your application, you should head over to
the &lt;a href="https://gnome.pages.gitlab.gnome.org/libgweather/migrating-3to4.html"&gt;migration guide&lt;/a&gt;
and check out what&amp;nbsp;changed.&lt;/p&gt;
&lt;p&gt;Ideally, there are still things that need to be cleaned up in the GWeather
&lt;span class="caps"&gt;API&lt;/span&gt;, for&amp;nbsp;instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GWeatherTimezone&lt;/code&gt; parses the &lt;code&gt;tzdata&lt;/code&gt; file directly, which comes with its
  own set of issues, like having to track whether the time zone database has
  changed or not; we should use
  &lt;a href="https://docs.gtk.org/glib/struct.TimeZone.html"&gt;&lt;code&gt;GTimeZone&lt;/code&gt;&lt;/a&gt; instead, but
  the &lt;span class="caps"&gt;API&lt;/span&gt; provided by the two types do not match entirely. I need to check
  the current users of that &lt;span class="caps"&gt;API&lt;/span&gt;, and if possible, just drop the whole&amp;nbsp;type.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GWeatherInfo&lt;/code&gt; has a bunch of getter functions that return the bare values
  and that can fail, and additional getter functions that always return a
  formatted string, and cannot fail; it&amp;#8217;s not a great &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GWeatherLocation&lt;/code&gt; returns the localised names by default, and has
  additional getters for the &amp;#8220;English&amp;#8221; (really: &lt;span class="caps"&gt;POSIX&lt;/span&gt; C locale)&amp;nbsp;names.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you encounter issues when porting, please: &lt;a href="https://gitlab.gnome.org/GNOME/libgweather/issues/new"&gt;file an issue on
GitLab&lt;/a&gt;.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="development"></category><category term="gweather"></category></entry><entry><title>GWeather next</title><link href="https://www.bassi.io/articles/2021/10/15/gweather-next/" rel="alternate"></link><published>2021-10-15T10:52:00+01:00</published><updated>2021-10-15T10:54:38+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-10-15:/articles/2021/10/15/gweather-next/</id><summary type="html">&lt;p&gt;In which I explain what is happening in the libgweather&amp;nbsp;repository&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;strong&gt;tl;dr&lt;/strong&gt; Libgweather, the small &lt;span class="caps"&gt;GNOME&lt;/span&gt; library that queries weather
services, is getting a major version bump to allow applications using it to
be ported to &lt;span class="caps"&gt;GTK4&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gnome-applets/-/commit/8e29cc8ad6a0213100249be1b4a8643bd7ec1c1f"&gt;In the beginning&lt;/a&gt;, there was a weather applet in the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
panel. It had a bunch of code that poked at a couple of websites to get the
&lt;a href="https://en.wikipedia.org/wiki/METAR"&gt;weather information&lt;/a&gt; for a given airport or weather observation
stations, and shipped with a list of locations and their nearest &lt;span class="caps"&gt;METAR&lt;/span&gt;&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;In 2007, the relevant code was moved to &lt;a href="https://gitlab.gnome.org/GNOME/libgweather/-/commit/32e0353d86ffc2df26b19608a680b19cfa3cc04f"&gt;its own separate
repository&lt;/a&gt;, so that other applications and system
settings could reuse the same code as the panel applet: the libgweather
library was born. Aside from the basic weather information and location
objects, libgweather also had a couple of widgets: one for selecting a
location (with autocompletion), and one for selecting a timezone using a&amp;nbsp;location.&lt;/p&gt;
&lt;p&gt;Since libgweather was still very much an &lt;em&gt;ad hoc&lt;/em&gt; library for a handful of
applications, there was no explicit &lt;span class="caps"&gt;API&lt;/span&gt; and &lt;span class="caps"&gt;ABI&lt;/span&gt; stability guarantee made by
its maintainers; in fact, in order to use it, you had to &amp;#8220;opt in&amp;#8221; with a
specific &lt;a href="https://gitlab.gnome.org/GNOME/libgweather/-/commit/3ee7dec78f43735f9942b874b8bf707022c6a58d"&gt;C pre-processor symbol&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Time passed, and a few more applications appeared during the initial &lt;span class="caps"&gt;GNOME&lt;/span&gt; 3
cycles—like &lt;a href="https://gitlab.gnome.org/GNOME/gnome-weather"&gt;Weather&lt;/a&gt;, followed by &lt;a href="https://gitlab.gnome.org/GNOME/gnome-clocks"&gt;Clocks&lt;/a&gt; a
month later. Most of the consumers of libgweather were actually going
through a language binding, which meant they were not really &amp;#8220;opting into&amp;#8221;
the &lt;span class="caps"&gt;API&lt;/span&gt; through the explicit pre-processor symbol; it also meant that
changes in the &lt;span class="caps"&gt;API&lt;/span&gt; and &lt;span class="caps"&gt;ABI&lt;/span&gt; could end up being found only &lt;em&gt;after&lt;/em&gt; a
libgweather release, instead of during a development cycle. Of course, back
then, we only had a single &lt;span class="caps"&gt;CI&lt;/span&gt;/&lt;span class="caps"&gt;CD&lt;/span&gt; pipeline for the whole project, with far
too little granularity and far too wide scope. Still, the GWeather consumers
were few and far between, and the &lt;span class="caps"&gt;API&lt;/span&gt; was not&amp;nbsp;stabilised.&lt;/p&gt;
&lt;p&gt;Fast forward to&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;The core &lt;span class="caps"&gt;GNOME&lt;/span&gt; applications using GWeather are in the process of being
&lt;a href="https://gitlab.gnome.org/GNOME/Initiatives/-/issues/26"&gt;ported to &lt;span class="caps"&gt;GTK4&lt;/span&gt;&lt;/a&gt;, but GWeather still ships with two &lt;span class="caps"&gt;GTK3&lt;/span&gt; widgets.
Since you cannot have &lt;span class="caps"&gt;GTK3&lt;/span&gt; and &lt;span class="caps"&gt;GTK4&lt;/span&gt; types in the same process, this requires
either porting GWeather to &lt;span class="caps"&gt;GTK4&lt;/span&gt; &lt;em&gt;or&lt;/em&gt; dropping the widgets. As it turns out,
the widgets are not really shared across applications using libgweather, and
all of them have also been redesigned or are using the libadwaita/&lt;span class="caps"&gt;GTK4&lt;/span&gt; port
as a chance to refresh their overall appearences. This makes our life a
little bit easier, as we can drop the widgets without really losing any
actual functionality that people do care&amp;nbsp;about.&lt;/p&gt;
&lt;p&gt;For &lt;span class="caps"&gt;GNOME&lt;/span&gt; 42, the plan for libgweather&amp;nbsp;is:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;bump up the &lt;span class="caps"&gt;API&lt;/span&gt; version to 4.0, and ensure parallel installability with
  the older libgweather-3; this requires renaming things like the pkg-config
  file and the settings schema, alongside the shared&amp;nbsp;library&lt;/li&gt;
&lt;li&gt;drop the &lt;span class="caps"&gt;GTK&lt;/span&gt; widgets, and some old &lt;span class="caps"&gt;API&lt;/span&gt; that hasn&amp;#8217;t been working in years,
  like getting the radar image&amp;nbsp;animation&lt;/li&gt;
&lt;li&gt;stabilise the &lt;span class="caps"&gt;API&lt;/span&gt;, and turn libgweather into a proper library, with the
  usual &lt;span class="caps"&gt;API&lt;/span&gt; and &lt;span class="caps"&gt;ABI&lt;/span&gt; stability guarantees (deprecations and new symbols added
  only during development cycles, no changes/removals until the following
  major &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;bump)&lt;/li&gt;
&lt;li&gt;make it easier to use libgweather objects with
  &lt;a href="https://docs.gtk.org/gio/iface.ListModel.html"&gt;&lt;code&gt;GListModel&lt;/code&gt;&lt;/a&gt;-based &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;document the &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;properly&lt;/li&gt;
&lt;li&gt;clean up the internals from various years of inconsistent coding style and&amp;nbsp;practices&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;I&amp;#8217;m also going through the issues imported from Bugzilla and closing the
ones that have long since been&amp;nbsp;fixed.&lt;/p&gt;
&lt;p&gt;In the meantime, the old libgweather-3 &lt;span class="caps"&gt;API&lt;/span&gt; is going to be frozen, for the
tools that still use it and won&amp;#8217;t be ported to &lt;span class="caps"&gt;GTK4&lt;/span&gt; any time&amp;nbsp;soon.&lt;/p&gt;
&lt;p&gt;For more information, you can&amp;nbsp;read:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://discourse.gnome.org/t/changes-in-libgweather-for-gnome-42/7770"&gt;the announcement topic on&amp;nbsp;Discourse&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/libgweather/-/issues/151"&gt;issue #151 on&amp;nbsp;GitLab&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you&amp;#8217;re using libgweather, I strongly recommend you to use the 40.0
release or build from the &lt;a href="https://gitlab.gnome.org/GNOME/libgweather/-/tree/libgweather-3"&gt;libgweather-3 branch&lt;/a&gt; until you
are planning to port to &lt;span class="caps"&gt;GTK4&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re distributing libgweather, I recommend you package the new
libgweather under a new name, given that it&amp;#8217;s parallel installable with the
old one; my recommendation is to use &lt;code&gt;libgweather4&lt;/code&gt; or &lt;code&gt;libgweather-4&lt;/code&gt; as
the name of the&amp;nbsp;package.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="development"></category><category term="gweather"></category></entry><entry><title>Properties, introspection, and you</title><link href="https://www.bassi.io/articles/2021/09/21/properties-introspection-and-you/" rel="alternate"></link><published>2021-09-21T21:22:00+01:00</published><updated>2021-09-21T21:23:18+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-09-21:/articles/2021/09/21/properties-introspection-and-you/</id><summary type="html">&lt;p&gt;In which I explain some changes in the GObject introspection format that landed in &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;41&lt;/p&gt;</summary><content type="html">&lt;p&gt;It is a truth universally acknowledged, that a GObject class in possession of a property, must be in want of an accessor&amp;nbsp;function.&lt;/p&gt;
&lt;p&gt;The main issue with that statement is that it&amp;#8217;s really hard to pair the GObject property with the accessor functions that set the property&amp;#8217;s value, and retrieve&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;From a documentation perspective, tools might not establish any relation (gtk-doc), or they might require some additional annotation to do so (gi-docgen); but at the introspection level there&amp;#8217;s nothing in the &lt;span class="caps"&gt;XML&lt;/span&gt; or the binary data that lets you go from a property name to a setter, or a getter, function. At least, until&amp;nbsp;now.&lt;/p&gt;
&lt;p&gt;GObject-introspection 1.70, released alongside GLib 2.70 and &lt;span class="caps"&gt;GNOME&lt;/span&gt; 41, introduced various annotations for both properties and methods that let you go from one to the other; additionally, new &lt;span class="caps"&gt;API&lt;/span&gt; was added to libgirepository to allow bindings to dynamic languages to establish that relation at run&amp;nbsp;time.&lt;/p&gt;
&lt;h3&gt;Annotations&lt;/h3&gt;
&lt;p&gt;If you have a property, and you document it as you should, you&amp;#8217;ll have something like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * YourWidget:your-property&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * A property that does something amazing.&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If you want to associate the setter and getter functions to this property, all you need to do is add the following identifier annotations to&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * YourWidget:your-property: (setter set_your_property) (getter get_your_property)&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * A property that does something amazing.&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;(setter)&lt;/code&gt; and &lt;code&gt;(getter)&lt;/code&gt; annotations take the name of the &lt;strong&gt;method&lt;/strong&gt; that is used to set, and get, the property, respectively. The method name is relative to the type, so you should not pass the C&amp;nbsp;symbol.&lt;/p&gt;
&lt;p&gt;On the accessor methods side, you have two additional&amp;nbsp;annotations:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * your_widget_set_your_property: (set-property your-property)&lt;/span&gt;
&lt;span class="cm"&gt; * @self: your widget&lt;/span&gt;
&lt;span class="cm"&gt; * @value: the value to set&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * Sets the given value for your property.&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * your_widget_get_your_property: (get-property your-property)&lt;/span&gt;
&lt;span class="cm"&gt; * @self: your widget&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * Retrieves the value of your property.&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * Returns: the value of the property&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;h3&gt;Heuristics&lt;/h3&gt;
&lt;p&gt;Of course, you&amp;#8217;re now tempted to go and add those annotations to all your properties and related accessors. Before you do that, though, you should know that the introspection scanner will try and match properties and accessors by itself, using appropriate&amp;nbsp;heuristics:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;if your object type has a writable, non-construct-only property, and a method that is called &lt;code&gt;set_&amp;lt;property&amp;gt;&lt;/code&gt;, then the property will have a setter and the method will be matched to the&amp;nbsp;property&lt;/li&gt;
&lt;li&gt;if your object type has a readable property, and a method that is called &lt;code&gt;get_&amp;lt;property&amp;gt;&lt;/code&gt;, then the property will have a getter and the method will be matched to the&amp;nbsp;property&lt;/li&gt;
&lt;li&gt;additionally, if the property is read-only and the property type is boolean, the scanner will look at a method that has the same name as the property as well; this is meant to catch getters like &lt;code&gt;gtk_widget_has_focus()&lt;/code&gt;, which accesses the read-only property &lt;code&gt;has-focus&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;&lt;span class="caps"&gt;API&lt;/span&gt;&lt;/h3&gt;
&lt;p&gt;All of the above ends up in the introspection &lt;span class="caps"&gt;XML&lt;/span&gt;, which is used by documentation tools and code generators. Bindings for dynamic languages using &lt;a href="https://gnome.pages.gitlab.gnome.org/gobject-introspection/girepository/"&gt;libgirepository&lt;/a&gt; can also access this information at run time, by using the &lt;span class="caps"&gt;API&lt;/span&gt; in &lt;a href="https://gnome.pages.gitlab.gnome.org/gobject-introspection/girepository/gi-GIPropertyInfo.html"&gt;&lt;code&gt;GIPropertyInfo&lt;/code&gt;&lt;/a&gt; to retrieve the setter and getter function information for a property; and the &lt;span class="caps"&gt;API&lt;/span&gt; in &lt;a href="https://gnome.pages.gitlab.gnome.org/gobject-introspection/girepository/gi-GIFunctionInfo.html#g-function-info-get-property"&gt;&lt;code&gt;GIFunctionInfo&lt;/code&gt;&lt;/a&gt; to retrieve the property being&amp;nbsp;set.&lt;/p&gt;
&lt;h3&gt;Future&lt;/h3&gt;
&lt;p&gt;Ideally, with this information, language bindings should be able to call the accessor functions instead of going through the generic &lt;code&gt;g_object_set_property()&lt;/code&gt; and &lt;code&gt;g_object_get_property()&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt;, except as a fallback. This should speed up the property access in various cases. Additionally, bindings could decide to stop exposing C accessors, and only expose the property, in order to make the &lt;span class="caps"&gt;API&lt;/span&gt; more&amp;nbsp;idiomatic.&lt;/p&gt;
&lt;p&gt;On the documentation side, this will ensure that tools like gi-docgen will be able to bind the properties and their accessors more reliably, without requiring &lt;a href="https://gnome.pages.gitlab.gnome.org/gi-docgen/attributes.html"&gt;extra attributes&lt;/a&gt;.&lt;/p&gt;
&lt;h3&gt;And one more&amp;nbsp;thing&lt;/h3&gt;
&lt;p&gt;One thing that did not make it in time for the 1.70 release, but will land early in the next development cycle for gobject-introspection, is the validation for properties. Language bindings don&amp;#8217;t really like it when the C &lt;span class="caps"&gt;API&lt;/span&gt; exposes properties that have the same name of methods and virtual functions; we &lt;a href="https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/277"&gt;already have a validation pass ready to land&lt;/a&gt;, so expect warnings in the near&amp;nbsp;future.&lt;/p&gt;
&lt;p&gt;Another feature that will land early in the cycle is the &lt;code&gt;(emitter)&lt;/code&gt; annotation, which will bind a method emitting a signal with the signal name. This is a feature taken from Vala&amp;#8217;s metadata, and should improve the quality of life of people using introspection data with Vala, as well as removing the need for another attribute in&amp;nbsp;gi-docgen.&lt;/p&gt;
&lt;p&gt;Finally, if you maintain a language binding: &lt;strong&gt;please&lt;/strong&gt; look at &lt;a href="https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/204"&gt;!204&lt;/a&gt;, and make sure you&amp;#8217;re not calling &lt;code&gt;g_assert_not_reached()&lt;/code&gt; or &lt;code&gt;g_error()&lt;/code&gt; when encountering a new scope type. The &lt;code&gt;forever&lt;/code&gt; scope cannot land if it breaks every single binding in&amp;nbsp;existence.&lt;/p&gt;</content><category term="gnome"></category><category term="introspection"></category><category term="gobject"></category><category term="development"></category></entry><entry><title>Publishing your documentation</title><link href="https://www.bassi.io/articles/2021/08/26/publishing-your-documentation/" rel="alternate"></link><published>2021-08-26T00:51:00+01:00</published><updated>2021-08-26T01:01:43+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-08-26:/articles/2021/08/26/publishing-your-documentation/</id><summary type="html">&lt;p&gt;In which I explain how to build and publish your library&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; reference on&amp;nbsp;GitLab&lt;/p&gt;</summary><content type="html">&lt;p&gt;The main function of &lt;a href="https://gitlab.gnome.org/Infrastructure/library-web"&gt;library-web&lt;/a&gt;, the tool that published the
&lt;span class="caps"&gt;API&lt;/span&gt; reference of the various &lt;span class="caps"&gt;GNOME&lt;/span&gt; libraries, was to take release archives
and put their contents in a location that would be visible to a web server.
In 2006, this was the apex of automation, of course. These days? Not so&amp;nbsp;much.&lt;/p&gt;
&lt;p&gt;Since library-web is going the way of the Dodo, and we &lt;em&gt;do&lt;/em&gt; have better ways
to automate the build and publishing of files with GitLab, how do we replace
library-web in 2021? The answer is, unsurprisingly: &lt;a href="https://docs.gitlab.com/ee/ci/pipelines/"&gt;continuous integration
pipelines&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I will assume that you&amp;#8217;re already building—and testing—your library using
GitLab&amp;#8217;s &lt;span class="caps"&gt;CI&lt;/span&gt;; if you aren&amp;#8217;t, then you have bigger problems than just
publishing your &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s start with these&amp;nbsp;preconditions:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;your project is hosted on &lt;a href="https://gitlab.gnome.org"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8217;s GitLab&amp;nbsp;instance&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;your project is using &lt;a href="https://mesonbuild.com"&gt;Meson&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;your project is using &lt;a href="https://gitlab.gnome.org/GNOME/gtk-doc/"&gt;gtk-doc&lt;/a&gt; or &lt;a href="https://gitlab.gnome.org/GNOME/gi-docgen/"&gt;gi-docgen&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If your project doesn&amp;#8217;t satisfy these preconditions you might want to work
on doing so; alternatively, you can implement your own &lt;span class="caps"&gt;CI&lt;/span&gt;&amp;nbsp;pipeline.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s start with a simple job&amp;nbsp;template:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Expected variables:&lt;/span&gt;
&lt;span class="c1"&gt;# PROJECT_DEPS: the dependencies for your own project&lt;/span&gt;
&lt;span class="c1"&gt;# MESON_VERSION: the version of Meson you depend on&lt;/span&gt;
&lt;span class="c1"&gt;# MESON_EXTRA_FLAGS: additional Meson setup options&lt;/span&gt;
&lt;span class="c1"&gt;#   you wish to pass to the configuration phase&lt;/span&gt;
&lt;span class="c1"&gt;# DOCS_FLAGS: the Meson setup option for enabling the&lt;/span&gt;
&lt;span class="c1"&gt;#   documentation, if any&lt;/span&gt;
&lt;span class="c1"&gt;# DOCS_PATH: the path of the generated reference,&lt;/span&gt;
&lt;span class="c1"&gt;#   relative to the build root&lt;/span&gt;
&lt;span class="nt"&gt;.gidocgen-build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fedora:latest&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;before_script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;dnf install -y&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3-pip&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3-wheel&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;gobject-introspection-devel&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;graphviz&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;ninja-build&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;redhat-rpm-config&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;dnf install -y ${PROJECT_DEPS}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;pip3 install&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;meson==${MESON_VERSION}&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;gi-docgen&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;jinja2&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;Markdown&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;markupsafe&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;pygments&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;toml&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;typogrify&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;meson setup ${MESON_EXTRA_FLAGS} ${DOCS_FLAGS} _docs .&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;meson compile -C _docs&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;pushd &amp;quot;_docs/${DOCS_PATH}&amp;quot; &amp;gt; /dev/null &lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;tar cfJ ${CI_PROJECT_NAME}-docs.tar.xz .&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;popd &amp;gt; /dev/null&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;mv _docs/${DOCS_PATH}/${CI_PROJECT_NAME}-docs.tar .&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;when&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;always&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Documentation&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;expose_as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Download&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reference&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${CI_PROJECT_NAME}-docs.tar.xz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This &lt;span class="caps"&gt;CI&lt;/span&gt; template&amp;nbsp;will:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;download all the required dependencies for building the &lt;span class="caps"&gt;API&lt;/span&gt; reference
  using&amp;nbsp;gi-docgen&lt;/li&gt;
&lt;li&gt;build your project, including the &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;reference&lt;/li&gt;
&lt;li&gt;create an archive with the &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;reference&lt;/li&gt;
&lt;li&gt;store the archive as a &lt;span class="caps"&gt;CI&lt;/span&gt; artefact that you can easily&amp;nbsp;download&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Incidentally, by adding a &lt;code&gt;meson test -C _build&lt;/code&gt; to the &lt;code&gt;script&lt;/code&gt; section,
you can easily test your build as well; and if you have a &lt;code&gt;test()&lt;/code&gt; target in
your build that runs &lt;a href="https://gnome.pages.gitlab.gnome.org/gi-docgen/tools/check.html"&gt;&lt;code&gt;gi-docgen check&lt;/code&gt;&lt;/a&gt;, then you can
verify that your documentation is always&amp;nbsp;complete.&lt;/p&gt;
&lt;p&gt;Now, all you have to do is create your own &lt;span class="caps"&gt;CI&lt;/span&gt; job that inherits from the
template inside its own stage. I will use &lt;span class="caps"&gt;JSON&lt;/span&gt;-GLib as a&amp;nbsp;reference:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;stages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docs&lt;/span&gt;

&lt;span class="nt"&gt;api-reference&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docs&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;extends&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;.gidocgen-build&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;[]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;variables&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;MESON_VERSION&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;0.55.3&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;DOCS_FLAGS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;-Dgtk_doc=true&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;PROJECT_DEPS&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;gcc&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;git&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;gettext&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;glib2-devel&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;DOCS_PATH&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docs/json-glib-1.0&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;span class="dquo"&gt;&amp;#8220;&lt;/span&gt;What about gtk-doc!&amp;#8221;, I hear from the back of the room. Well, fear not,
because there&amp;#8217;s a similar template you can use if you&amp;#8217;re still using gtk-doc
in your&amp;nbsp;project:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Expected variables:&lt;/span&gt;
&lt;span class="c1"&gt;# PROJECT_DEPS: the dependencies for your own project&lt;/span&gt;
&lt;span class="c1"&gt;# MESON_VERSION: the version of Meson you depend on&lt;/span&gt;
&lt;span class="c1"&gt;# MESON_EXTRA_FLAGS: additional Meson setup options you&lt;/span&gt;
&lt;span class="c1"&gt;#   wish to pass to the configuration phase&lt;/span&gt;
&lt;span class="c1"&gt;# DOCS_FLAGS: the Meson setup option for enabling the&lt;/span&gt;
&lt;span class="c1"&gt;#   documentation, if any&lt;/span&gt;
&lt;span class="c1"&gt;# DOCS_TARGET: the Meson target for building the&lt;/span&gt;
&lt;span class="c1"&gt;#   documentation, if any&lt;/span&gt;
&lt;span class="c1"&gt;# DOCS_PATH: the path of the generated reference,&lt;/span&gt;
&lt;span class="c1"&gt;#   relative to the build root&lt;/span&gt;
&lt;span class="nt"&gt;.gtkdoc-build&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;image&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;fedora:latest&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;before_script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;export PATH=&amp;quot;$HOME/.local/bin:$PATH&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;dnf install -y&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3-pip&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;python3-wheel&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;gtk-doc&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;ninja-build&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;redhat-rpm-config&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;dnf install -y ${PROJECT_DEPS}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;pip3 install  meson==${MESON_VERSION}&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;meson setup ${MESON_EXTRA_FLAGS} ${DOCS_FLAGS} _docs .&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# This is exceedingly annoying, but sadly its how&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="c1"&gt;# gtk-doc works in Meson&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;ninja -C _docs ${DOCS_TARGET}&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;pushd &amp;quot;_docs/${DOCS_PATH}&amp;quot; &amp;gt; /dev/null &lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;tar cfJ ${CI_PROJECT_NAME}-docs.tar.xz .&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="no"&gt;popd &amp;gt; /dev/null&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;mv _docs/${DOCS_PATH}/${CI_PROJECT_NAME}-docs.tar .&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;when&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;always&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;name&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Documentation&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;expose_as&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;Download&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;the&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;API&lt;/span&gt;&lt;span class="nv"&gt; &lt;/span&gt;&lt;span class="s"&gt;reference&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;${CI_PROJECT_NAME}-docs.tar.xz&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And now you can use &lt;code&gt;extends: .gtkdoc-build&lt;/code&gt; in your &lt;code&gt;api-reference&lt;/code&gt; job.&lt;/p&gt;
&lt;p&gt;Of course, this is just half of the job: the actual goal is to publish the
documentation using &lt;a href="https://docs.gitlab.com/ee/user/project/pages/"&gt;GitLab&amp;#8217;s Pages&lt;/a&gt;. For that, you will need
another &lt;span class="caps"&gt;CI&lt;/span&gt; job in your pipeline, this time using the &lt;code&gt;deploy&lt;/code&gt; stage:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;stages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;docs&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy&lt;/span&gt;

&lt;span class="c1"&gt;# ... the api-reference job goes here...&lt;/span&gt;

&lt;span class="nt"&gt;pages&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;stage&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;deploy&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;needs&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p p-Indicator"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;api-reference&amp;#39;&lt;/span&gt;&lt;span class="p p-Indicator"&gt;]&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;script&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;mkdir public &amp;amp;&amp;amp; cd public&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;tar xfJ ../${CI_PROJECT_NAME}-docs.tar.xz&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;public&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;only&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;master&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;main&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Now, once you push to your main development branch, your &lt;span class="caps"&gt;API&lt;/span&gt; reference will
be built by your &lt;span class="caps"&gt;CI&lt;/span&gt; pipeline, and the results published in your project&amp;#8217;s
Pages space—&lt;a href="https://gnome.pages.gitlab.gnome.org/json-glib/"&gt;like &lt;span class="caps"&gt;JSON&lt;/span&gt;-GLib&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;CI&lt;/span&gt; pipeline and GitLab Pages are also useful for building complex,
static websites presenting multiple versions of the documentation; or
presenting multiple libraries. An example of the former is
&lt;a href="https://gnome.pages.gitlab.gnome.org/libadwaita/"&gt;libadwaita&amp;#8217;s website&lt;/a&gt;, while an example of the latter is &lt;a href="https://docs.gtk.org"&gt;the &lt;span class="caps"&gt;GTK&lt;/span&gt;
documentation website&lt;/a&gt;. I&amp;#8217;ll write a blog post about them another&amp;nbsp;time.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Given that the &lt;span class="caps"&gt;CI&lt;/span&gt; templates are pretty generic, I&amp;#8217;m working on adding them
into the &lt;a href="https://gitlab.gnome.org/GNOME/citemplates/-/merge_requests/29"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; ci-templates&lt;/a&gt; repository, so you will be
able to use something&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;https://gitlab.gnome.org/GNOME/citemplates/raw/HEAD/docs/gidocgen.yml&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;or:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nt"&gt;include&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;https://gitlab.gnome.org/GNOME/citemplates/raw/HEAD/docs/gtkdoc.yml&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;without having to copy-paste the template in your own &lt;code&gt;.gitlab-ci.yml&lt;/code&gt; file.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The obvious limitation of this approach is that you will need to depend on
the latest version of Fedora to build your project. Sadly, we cannot use
Flatpak and the &lt;span class="caps"&gt;GNOME&lt;/span&gt; run time images for this, mainly because we are
building libraries, not applications; and because extracting files out of a
Flatpak build after it has completed isn&amp;#8217;t entirely trivial. Another side
effect is that if you bump up the dependencies of your project to something
on the bleeding edge and currently not packaged on the latest stable Fedora,
you will need to have it included as a Meson sub-project. Of course, you
should already be doing that, so it&amp;#8217;s a minor&amp;nbsp;downside.&lt;/p&gt;
&lt;p&gt;Ideally, if &lt;span class="caps"&gt;GNOME&lt;/span&gt; built &lt;a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/issues/350"&gt;actual run time images for the &lt;span class="caps"&gt;SDK&lt;/span&gt;&lt;/a&gt;, we
could install gtk-doc, gi-docgen, and all their dependencies into the &lt;span class="caps"&gt;SDK&lt;/span&gt;
itself, and avoid depending on a real Linux distribution for the libraries
in our&amp;nbsp;platform.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="development"></category><category term="documentation"></category><category term="automation"></category><category term="gitlab"></category><category term="ci"></category></entry><entry><title>Documenting GNOME for developers</title><link href="https://www.bassi.io/articles/2021/08/01/documenting-gnome-for-developers/" rel="alternate"></link><published>2021-08-01T19:31:00+01:00</published><updated>2021-08-02T10:32:04+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-08-01:/articles/2021/08/01/documenting-gnome-for-developers/</id><summary type="html">&lt;p&gt;In which I outline what comes next in the developers documentation of the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;platform&lt;/p&gt;</summary><content type="html">&lt;p&gt;You may have just now
&lt;a href="https://discourse.gnome.org/t/new-gnome-developer-documentation-website/7134/1"&gt;noticed&lt;/a&gt;
that the &lt;a href="https://developer.gnome.org"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; developers documentation website has changed after 15
years&lt;/a&gt;. You may also have noticed that it
contains drastically &lt;em&gt;less&lt;/em&gt; content than it used to.  Before you pick up
torches and pitchforks, let me give you a short &lt;strong&gt;tl;dr&lt;/strong&gt; of the&amp;nbsp;changes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Yes, this is entirely&amp;nbsp;intentional&lt;/li&gt;
&lt;li&gt;Yes, I know that stuff has been&amp;nbsp;moved&lt;/li&gt;
&lt;li&gt;Yes, I know that old URLs don&amp;#8217;t&amp;nbsp;work&lt;/li&gt;
&lt;li&gt;Yes, some redirections will be put in&amp;nbsp;place&lt;/li&gt;
&lt;li&gt;No, we can&amp;#8217;t go&amp;nbsp;back&lt;/li&gt;
&lt;/ul&gt;
&lt;hr&gt;
&lt;p&gt;So let&amp;#8217;s recap a bit the state of the developers documentation website in
2021, for those who weren&amp;#8217;t in attendance at my &lt;a href="https://gitlab.gnome.org/ebassi/guadec-2021/"&gt;&lt;span class="caps"&gt;GUADEC&lt;/span&gt; 2021
presentation&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web"&gt;library-web&lt;/a&gt; is a
   Python application, which started as a Summer of Code project in 2006,
   whose job was to take Autotools release tarballs, explode them, fiddle
   with their contents, and then publish files on the gnome.org&amp;nbsp;infrastructure.&lt;/li&gt;
&lt;li&gt;library-web relies heavily on Autotools and&amp;nbsp;gtk-doc.&lt;/li&gt;
&lt;li&gt;library-web does a lot of pre-processing of the documentation to rewrite
   links and &lt;span class="caps"&gt;CSS&lt;/span&gt; from the &lt;span class="caps"&gt;HTML&lt;/span&gt; files it&amp;nbsp;receives.&lt;/li&gt;
&lt;li&gt;library-web is very much a locally sourced, organic, artisanal pile of
   hacks that revolve very much around the &lt;span class="caps"&gt;GNOME&lt;/span&gt; infrastructure from around&amp;nbsp;2007-2009.&lt;/li&gt;
&lt;li&gt;library-web is incredibly hard to test locally, even when running inside
   a container, and the logging is virtually&amp;nbsp;non-existent.&lt;/li&gt;
&lt;li&gt;library-web is still running on Python&amp;nbsp;2.&lt;/li&gt;
&lt;li&gt;library-web is entirely&amp;nbsp;unmaintained.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;That should cover the infrastructure side of things. Now let&amp;#8217;s look at the&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;The developers documentation is divided in four&amp;nbsp;sections:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a platform&amp;nbsp;overview&lt;/li&gt;
&lt;li&gt;the Human Interface&amp;nbsp;guidelines&lt;/li&gt;
&lt;li&gt;guides and&amp;nbsp;tutorials&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;references&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The platform overview is slightly out of date; the design team has been
reviewing the &lt;span class="caps"&gt;HIG&lt;/span&gt; and using &lt;a href="https://gitlab.gnome.org/Teams/Design/hig-www"&gt;a new documentation
format&lt;/a&gt;; the guides and
tutorials still like &lt;span class="caps"&gt;GTK1&lt;/span&gt; and &lt;span class="caps"&gt;GTK2&lt;/span&gt; content; or how to port &lt;span class="caps"&gt;GNOME&lt;/span&gt; 2
applications to &lt;span class="caps"&gt;GNOME&lt;/span&gt; 3; or how to write a Metacity&amp;nbsp;theme.&lt;/p&gt;
&lt;p&gt;This leaves us with the &lt;span class="caps"&gt;API&lt;/span&gt; references, which are a grab bag of
miscellaneous things, listed by version numbers. Outside of the C &lt;span class="caps"&gt;API&lt;/span&gt;
documentation, the only other references hosted on developer.gnome.org are
the C++ bindings—which, incidentally, use Doxygen and when they aren&amp;#8217;t
broken by library-web messing about with the &lt;span class="caps"&gt;HTML&lt;/span&gt;, they have their own
franken-style mash up of gtkmm.org &lt;em&gt;and&lt;/em&gt;&amp;nbsp;developer.gnome.org.&lt;/p&gt;
&lt;h2&gt;Why didn&amp;#8217;t I know about&amp;nbsp;this?&lt;/h2&gt;
&lt;p&gt;If you&amp;#8217;re asking this question, allow me to be blunt for a second: the
reason you never noticed that the developers documentation website was
broken is that you never actually experienced it for its intended use case.
Most likely, you either just looked in a couple of well known places and
never ventured outside of those; and/or you are a maintainer, and you never
literally cared how things worked (or didn&amp;#8217;t work) after you uploaded a
release tarball somewhere. Like all infrastructure, it was somebody else&amp;#8217;s&amp;nbsp;problem.&lt;/p&gt;
&lt;p&gt;I completely understand that we&amp;#8217;re all volunteers, and that things that work
can be ignored because everyone has more important things to think&amp;nbsp;about.&lt;/p&gt;
&lt;p&gt;Sadly, things change: we don&amp;#8217;t use Autotools (that much), which means
release archives do not contain the generated documentation any more; this
means library-web cannot be updated, unless somebody modifies the
configuration to look for a separate documentation tarball that the
maintainer has to generate manually &lt;em&gt;and&lt;/em&gt; upload in a magic location on the
gnome.org file server—this has happened for &lt;span class="caps"&gt;GTK4&lt;/span&gt; and GLib for the past two&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;Projects change the way they lay out the documentation, or gtk-doc changes
something, and that causes library-web to stop extracting the right files;
you can look at &lt;a href="https://developer-old.gnome.org/atk/2.30/"&gt;the &lt;span class="caps"&gt;ATK&lt;/span&gt;
reference&lt;/a&gt; for the past year and
a half for an&amp;nbsp;example.&lt;/p&gt;
&lt;p&gt;Projects bump up their &lt;span class="caps"&gt;API&lt;/span&gt;, and now the cross-referencing gets broken, like
the &lt;span class="caps"&gt;GTK3&lt;/span&gt; pages linking &lt;span class="caps"&gt;GDK2&lt;/span&gt;&amp;nbsp;types.&lt;/p&gt;
&lt;p&gt;Finally, projects decide to change how their documentation is generated,
which means that library-web has no idea how to extract the &lt;span class="caps"&gt;HTML&lt;/span&gt; files, or
how to fiddle with&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re still using Autotools and gtk-doc, and haven&amp;#8217;t done an &lt;span class="caps"&gt;API&lt;/span&gt; bump in
15 years, and all you care about is copying a release archive to the
gnome.org infrastructure I&amp;#8217;m sure all of this will come as a surprise, and
I&amp;#8217;m sorry you&amp;#8217;re just now being confronted with a completely broken
infrastructure. Sadly, the infrastructure was broken for everybody else long
before this&amp;nbsp;point.&lt;/p&gt;
&lt;h2&gt;What did you&amp;nbsp;do?&lt;/h2&gt;
&lt;p&gt;I tried to make library-web deal with the changes in our infrastructure. I
personally built and uploaded multiple versions of the documentation for
GLib (three different archives for each release) for a year and a half; I
configured library-web to add more &amp;#8220;extra tarball&amp;#8221; locations for various
projects; I tried making library-web understand the new layout of various
projects; I even tried making library-web publish the gi-docgen references
used by &lt;span class="caps"&gt;GTK&lt;/span&gt;, Pango, and other&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;Sadly, every change broke something else—and I&amp;#8217;m not just talking about the
horrors of the code base. As library-web is responsible for determining the
structure of the documentation, any change to how the documentation is
handled leads to broken URLs, broken links, or broken&amp;nbsp;redirections.&lt;/p&gt;
&lt;p&gt;The entire castle of cards &lt;em&gt;needed to go&lt;/em&gt;.&lt;/p&gt;
&lt;p&gt;Which brings us to &lt;a href="https://mail.gnome.org/archives/gnome-doc-list/2021-May/msg00000.html"&gt;the
plan&lt;/a&gt;.&lt;/p&gt;
&lt;h2&gt;What are you going to&amp;nbsp;do?&lt;/h2&gt;
&lt;p&gt;Well, the first step has been made: the new developer.gnome.org website does
not use library-web. The content has been refreshed, and more content is on
the&amp;nbsp;way.&lt;/p&gt;
&lt;p&gt;Again, this leaves the &lt;span class="caps"&gt;API&lt;/span&gt; references. For those, there are two things that
need to happen—and are planned for &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;41:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;all the libraries that are part of the &lt;span class="caps"&gt;GNOME&lt;/span&gt; &lt;span class="caps"&gt;SDK&lt;/span&gt; run time, built by
    &lt;a href="https://gitlab.gnome.org/GNOME/gnome-build-meta"&gt;gnome-build-meta&lt;/a&gt; must
    also build their documentation, which will be published as part of the
    &lt;code&gt;org.gnome.Sdk.Docs&lt;/code&gt; extension; the contents of the extension will also
    be published&amp;nbsp;online.&lt;/li&gt;
&lt;li&gt;every library that is hosted on gnome.org infrastructure should publish
    their documentation through their &lt;span class="caps"&gt;CI&lt;/span&gt; pipeline; for that, I&amp;#8217;m working on
    a &lt;span class="caps"&gt;CI&lt;/span&gt; template file and image that should take care of the easy projects,
    and will act as model for projects that are more&amp;nbsp;complicated.&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;I&amp;#8217;m happy to guide maintainers to deal with that, and I&amp;#8217;m also happy to open
merge requests on various&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;In the meantime, the old documentation is &lt;a href="https://developer-old.gnome.org"&gt;still
available&lt;/a&gt; as a static snapshot, and the
sysadmins are going to set up some redirections to bridge us from the old
platform to the new—and hopefully we&amp;#8217;ll soon be able to redirect to each
project&amp;#8217;s GitLab&amp;nbsp;pages.&lt;/p&gt;
&lt;h2&gt;Can we go back,&amp;nbsp;please?&lt;/h2&gt;
&lt;p&gt;Sadly, since nobody has ever bothered picking up the developers
documentation when it was still possible to incrementally fix it, going back
to a broken infrastructure isn&amp;#8217;t going to help&amp;nbsp;anybody.&lt;/p&gt;
&lt;p&gt;We also cannot keep the old developer.gnome.org and add a new one, of
course; now we&amp;#8217;d have two websites, one of which broken and unmaintained and
&lt;em&gt;linked all over the place&lt;/em&gt;, and a new one that nobody knows&amp;nbsp;exists.&lt;/p&gt;
&lt;p&gt;The only way is forward, for better or&amp;nbsp;worse.&lt;/p&gt;
&lt;h2&gt;What about&amp;nbsp;Devhelp&lt;/h2&gt;
&lt;p&gt;Some of you may have noticed that I picked up the maintenance of
&lt;a href="https://gitlab.gnome.org/GNOME/devhelp"&gt;Devhelp&lt;/a&gt;, and landed a few fixes to
ensure that it can read the &lt;span class="caps"&gt;GTK4&lt;/span&gt; documentation. Outside of some visual
refresh for the &lt;span class="caps"&gt;UI&lt;/span&gt;, I also am working on making it load the contents of the
&lt;code&gt;org.gnome.Sdk.Docs&lt;/code&gt; run time extension, which means it&amp;#8217;ll be able to load
all the core &lt;span class="caps"&gt;API&lt;/span&gt; references. Ideally, we&amp;#8217;re also going to see a port to &lt;span class="caps"&gt;GTK4&lt;/span&gt;
and libadwaita, as soon as WebKitGTK for &lt;span class="caps"&gt;GTK4&lt;/span&gt; is more wideley&amp;nbsp;available.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="documentation"></category><category term="development"></category></entry><entry><title>Final Types</title><link href="https://www.bassi.io/articles/2021/07/27/final-types/" rel="alternate"></link><published>2021-07-27T17:30:00+01:00</published><updated>2021-07-28T11:02:30+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-07-27:/articles/2021/07/27/final-types/</id><summary type="html">&lt;p&gt;In which I introduce a new GObject&amp;nbsp;feature&lt;/p&gt;</summary><content type="html">&lt;p&gt;The type system at the base of our platform, GType, has various kinds of&amp;nbsp;derivability:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;simple derivability, where you&amp;#8217;re allowed to create your derived version of an existing type, but you cannot derive your type any&amp;nbsp;further;&lt;/li&gt;
&lt;li&gt;deep derivability, where you&amp;#8217;re allowed to derive types from other&amp;nbsp;types;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;An example of the first kind is any type inheriting from &lt;code&gt;GBoxed&lt;/code&gt;, whereas an example of the second kind is anything that inherits from &lt;code&gt;GTypeInstance&lt;/code&gt;, like &lt;code&gt;GObject&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;Additionally, any derivable type can be marked as &lt;em&gt;abstract&lt;/em&gt;; an abstract type cannot be instantiated, but you can create your own derived type which may or may not be &amp;#8220;concrete&amp;#8221;. Looking at the GType reference documentation, you&amp;#8217;ll notice various macros and flags that exist to implement this functionality—including macros that were introduced to cut down the boilerplate necessary to declare and define new&amp;nbsp;types.&lt;/p&gt;
&lt;p&gt;The &lt;code&gt;G_DECLARE_*&lt;/code&gt; family of macros, though, introduced a new concept in the type system: a &amp;#8220;final&amp;#8221; type. Final types are leaf nodes in the type hierarchy: they can be instantiated, but they cannot be derived any further. &lt;span class="caps"&gt;GTK&lt;/span&gt; 4 makes use of this kind of types to nudge developers towards composition, instead of inheritance. The main problem is that the concept of a &amp;#8220;final&amp;#8221; type is entirely orthogonal to the type system; there&amp;#8217;s no way to programmatically know that a type is &amp;#8220;final&amp;#8221;—unless you have access to the introspection data and start playing with heuristics about symbol visibility. This means that language bindings are unable to know without human intervention if a type can actually be inherited from or&amp;nbsp;not.&lt;/p&gt;
&lt;p&gt;In GLib 2.70 we finally &lt;a href="https://gitlab.gnome.org/GNOME/glib/-/issues/2321"&gt;plugged the hole in the type system&lt;/a&gt;, and we introduced the &lt;code&gt;G_TYPE_FLAG_FINAL&lt;/code&gt; flag. Types defined as &amp;#8220;final&amp;#8221; cannot be derived any further: as soon as you attempt to register your new type that inherits from a &amp;#8220;final&amp;#8221; type, you&amp;#8217;ll get a warning at run time. There are macros available that will let you define final types, as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;Thanks to the &amp;#8220;final&amp;#8221; flag, we can also include this information into &lt;a href="https://gitlab.gnome.org/GNOME/gobject-introspection/-/merge_requests/257"&gt;the introspection data&lt;/a&gt;; this will allow language bindings to warn you if you attempt at inheriting from a &amp;#8220;final&amp;#8221; type, likely using language-native tools, instead of getting a run time&amp;nbsp;warning.&lt;/p&gt;
&lt;p&gt;If you are using &lt;code&gt;G_DECLARE_FINAL_TYPE&lt;/code&gt; in your code you should bump up your GObject dependency to 2.70, and switch your implementation from &lt;code&gt;G_DEFINE_TYPE&lt;/code&gt; and friends to &lt;code&gt;G_DEFINE_FINAL_TYPE&lt;/code&gt;.&lt;/p&gt;</content><category term="gnome"></category><category term="gobject"></category><category term="introspection"></category></entry><entry><title>More documentation changes</title><link href="https://www.bassi.io/articles/2021/03/17/more-documentation-changes/" rel="alternate"></link><published>2021-03-17T22:29:00+00:00</published><updated>2021-10-07T00:54:06+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-03-17:/articles/2021/03/17/more-documentation-changes/</id><summary type="html">&lt;p&gt;In which I report about the status of&amp;nbsp;gi-docgen&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;#8217;s been nearly a month since I&amp;#8217;ve talked about
&lt;a href="https://gnome.pages.gitlab.gnome.org/gi-docgen/"&gt;gi-docgen&lt;/a&gt;, my little tool to
generate &lt;span class="caps"&gt;API&lt;/span&gt; references from introspection data. In between &lt;a href="https://www.bassi.io/articles/2021/02/19/documentation-changes/"&gt;my blog
post&lt;/a&gt; and now, a few things have&amp;nbsp;changed:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the generated &lt;span class="caps"&gt;API&lt;/span&gt; reference has had a few improvements, most notably the
   use of summaries in all index&amp;nbsp;pages&lt;/li&gt;
&lt;li&gt;all inheritable types now show the properties, signals, and methods
   inherited from their ancestors and from the implemented interfaces; this
   should hopefully make the reference much more useful for newcomers to
   &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;we allow cross-linking between dependent namespaces; this is done using an
   optional &lt;span class="caps"&gt;URL&lt;/span&gt; map, with links re-written on page load. Websites hosting
   the &lt;span class="caps"&gt;API&lt;/span&gt; reference would need only to provide an &lt;code&gt;urlmap.js&lt;/code&gt; file to
   rewrite those links, instead of doing things like parsing the &lt;span class="caps"&gt;HTML&lt;/span&gt; and
   changing the &lt;code&gt;href&lt;/code&gt; attribute of every link &lt;em&gt;cough&lt;/em&gt; library-web &lt;em&gt;cough&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;we parse &lt;a href="https://gnome.pages.gitlab.gnome.org/gi-docgen/attributes.html"&gt;custom &lt;span class="caps"&gt;GIR&lt;/span&gt; attributes&lt;/a&gt;
   to provide better cross-linking between methods, properties, and&amp;nbsp;signals.&lt;/li&gt;
&lt;li&gt;we generate an index file with all the possible end-points, and a
   dictionary of terms that can be used for searching; the terms are
   stemmed using the &lt;a href="https://en.wikipedia.org/wiki/Stemming"&gt;Porter stemming&amp;nbsp;algorithm&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;the default template will let you search using the generated index; the
   search supports scoping, so using &lt;code&gt;method:show widget&lt;/code&gt; will look for all
   the symbols in which the term &lt;code&gt;show&lt;/code&gt; appears in method descriptions,
   alongside the &lt;code&gt;widget&lt;/code&gt; term&lt;/li&gt;
&lt;li&gt;we also generate a DevHelp file, so theoretically DevHelp can load up the
   &lt;span class="caps"&gt;API&lt;/span&gt; references built by gi-docgen; there is still &lt;a href="https://gitlab.gnome.org/GNOME/devhelp/-/issues/28"&gt;work to be done&lt;/a&gt;,
   there, but thanks to the help of Jan Tojnar, it&amp;#8217;s not entirely&amp;nbsp;hopeless&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to all these changes, both Pango and &lt;span class="caps"&gt;GTK&lt;/span&gt; have switched from gtk-doc
to gi-docgen for their &lt;span class="caps"&gt;API&lt;/span&gt; references in their respective main development&amp;nbsp;branches.&lt;/p&gt;
&lt;p&gt;Now, here&amp;#8217;s the part where it gets&amp;nbsp;complicated.&lt;/p&gt;
&lt;h3&gt;Using&amp;nbsp;gi-docgen&lt;/h3&gt;
&lt;p&gt;Quick reminder: the first and foremost use case for gi-docgen is &lt;span class="caps"&gt;GTK&lt;/span&gt; (and
&lt;em&gt;some&lt;/em&gt; of its dependencies). If it works for you, I&amp;#8217;m happy, but I will
&lt;strong&gt;not&lt;/strong&gt; go out of my way to make your use case work—especially if it comes
at the expense of Job #1, i.e. generating the &lt;span class="caps"&gt;API&lt;/span&gt; reference for &lt;span class="caps"&gt;GTK&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Since gi-docgen is currently a slightly moving target, I &lt;strong&gt;strongly&lt;/strong&gt;
recommend using it as a Meson subproject. I also &lt;strong&gt;strongly&lt;/strong&gt; recommend
vendoring it inside your release tarballs,&amp;nbsp;using:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;meson&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;dist&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="k"&gt;include&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="nv"&gt;subprojects&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;when generating the distribution archive. Do &lt;strong&gt;not&lt;/strong&gt; try and depend on an
installed copy of&amp;nbsp;gi-docgen.&lt;/p&gt;
&lt;p&gt;Additionally, it&amp;#8217;s possible to include the gi-docgen &lt;span class="caps"&gt;API&lt;/span&gt;
reference into the Meson tarball by using &lt;a href="https://gitlab.gnome.org/GNOME/pango/-/blob/master/build-aux/meson/dist-docs.py"&gt;a dist script&lt;/a&gt;.
The &lt;span class="caps"&gt;API&lt;/span&gt; reference will be re-generated when building, but it can be
extracted from the tarball, like in the good old gtk-doc-on-Autotools&amp;nbsp;days.&lt;/p&gt;
&lt;h3&gt;Publishing your &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;reference&lt;/h3&gt;
&lt;p&gt;The tool we use to generate developer.gnome.org,
&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web"&gt;library-web&lt;/a&gt;, is
unmaintained and, quite frankly, fairly broken. It is a Python2 script that
got increasingly more complicated without actually getting more reliable; it
got progressively more broken once we started having more than two &lt;span class="caps"&gt;GTK&lt;/span&gt;
modules, and then it got severely broken once we started using Meson and
CMake, instead of Autotools. These days, you&amp;#8217;ll be lucky to get your &lt;span class="caps"&gt;API&lt;/span&gt;
reference uploaded to developer.gnome.org (as a separate archive), and you
can definitely forget about cross-linking, because the tool will most likely
get things wrong in its quest to restyle any &lt;span class="caps"&gt;HTML&lt;/span&gt; it finds, and then fix the
references to what &lt;em&gt;it thinks&lt;/em&gt; is the correct&amp;nbsp;place:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web/-/issues/71"&gt;issue&amp;nbsp;71&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web/-/issues/95"&gt;issue&amp;nbsp;95&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web/-/issues/93"&gt;issue&amp;nbsp;93&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web/-/issues/92"&gt;issue&amp;nbsp;92&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/Infrastructure/library-web/-/issues/84"&gt;issue&amp;nbsp;84&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;and the list goes on and&amp;nbsp;on…&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The support for Doxygen (which is used by the C++ bindings) is minimal, and
it ended up breaking a few times. Switching away from gtk-doc to gi-docgen
is basically the death knell for the whole&amp;nbsp;thing:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;first of all, it cannot match the documentation module with the
   configuration for it, because git-docgen does not have the concept of a
   &amp;#8220;documentation module&amp;#8221;; at most, it has a project configuration&amp;nbsp;file.&lt;/li&gt;
&lt;li&gt;additionally, we &lt;strong&gt;really&lt;/strong&gt; don&amp;#8217;t want library-web messing about with the
   generated &lt;span class="caps"&gt;HTML&lt;/span&gt;, especially if the end result breaks&amp;nbsp;stuff.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;So, the current solution is to try and make library-web detect if we&amp;#8217;re
using gi-docgen, by looking for &lt;code&gt;toml&lt;/code&gt; and &lt;code&gt;toml.in&lt;/code&gt; files in the release
archive, and then upload various files as they are. It&amp;#8217;s a bad and fragile
stop gap solution, but it&amp;#8217;s the best we can do without breaking everything
in even more terrible&amp;nbsp;ways.&lt;/p&gt;
&lt;p&gt;For &lt;span class="caps"&gt;GNOME&lt;/span&gt; 41 my plan is to sidestep the whole thing, and send library-web
to a farm upstate. We&amp;#8217;re going to use gnome-build-meta to build the &lt;span class="caps"&gt;API&lt;/span&gt;
references of the projects we have in our &lt;span class="caps"&gt;SDK&lt;/span&gt;, and then publish them
according to the &lt;span class="caps"&gt;SDK&lt;/span&gt;&amp;nbsp;version.&lt;/p&gt;
&lt;p&gt;My recommendation for library authors, in any case, is to build the &lt;span class="caps"&gt;API&lt;/span&gt;
reference for the development branch of their project as part of their &lt;span class="caps"&gt;CI&lt;/span&gt;,
and then publish it to the GitLab pages space. For&amp;nbsp;instance:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gnome.pages.gitlab.gnome.org/gtk/gtk4/"&gt;&lt;span class="caps"&gt;GTK4&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gnome.pages.gitlab.gnome.org/pango/Pango/"&gt;Pango&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This way, you&amp;#8217;ll always have access to the latest&amp;nbsp;documentation.&lt;/p&gt;
&lt;p&gt;Sadly, we can&amp;#8217;t have per-branch references, because GitLab pages are nuked
every time a branch gets built; for that, we&amp;#8217;d have to upload the artifacts
somewhere else, like an S3&amp;nbsp;bucket.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Things are going to get better in the near future, after 10 years of
stagnation; sadly, this means we&amp;#8217;re living in Interesting Times, so I ask of
you to please be patient while we transition towards a new and improved way
to document our&amp;nbsp;platform.&lt;/p&gt;</content><category term="gnome"></category><category term="documentation"></category><category term="introspection"></category><category term="gtk"></category><category term="development"></category></entry><entry><title>Documentation changes</title><link href="https://www.bassi.io/articles/2021/02/19/documentation-changes/" rel="alternate"></link><published>2021-02-19T21:16:00+00:00</published><updated>2021-02-21T01:34:59+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2021-02-19:/articles/2021/02/19/documentation-changes/</id><summary type="html">&lt;p&gt;In which I talk about a new tool to generate the &lt;span class="caps"&gt;API&lt;/span&gt; reference for &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Back in the late &amp;#8216;90s, people working on &lt;span class="caps"&gt;GTK&lt;/span&gt; had the exact same problem we have
today: how do we document the collection of functions, types, macros, and
assorted symbols that we call &amp;#8220;an &lt;span class="caps"&gt;API&lt;/span&gt;&amp;#8221;. It&amp;#8217;s all well and good to strive for
an &lt;span class="caps"&gt;API&lt;/span&gt; that can be immediately grasped by adhering to a set of well defined
conventions and naming; but nothing is, or really can be, &amp;#8220;self&amp;nbsp;documenting&amp;#8221;.&lt;/p&gt;
&lt;p&gt;When &lt;span class="caps"&gt;GTK&lt;/span&gt; 1.0 was released, the documentation was literally stored in
handwritten &lt;a href="https://www.gnu.org/software/texinfo/"&gt;Texinfo files&lt;/a&gt;; the &lt;span class="caps"&gt;API&lt;/span&gt;
footprint of &lt;span class="caps"&gt;GTK&lt;/span&gt; was small enough to still make it possible, but not really
maintainable in the longer term. In 1998, a new system was devised for
documenting &lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;nbsp;1.2:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a script, to parse the source files for the various declarations
   and dump them into machine parseable &amp;#8220;templates&amp;#8221;, that would then
   be modified to include the actual documentation, and committed to
   the source&amp;nbsp;repository&lt;/li&gt;
&lt;li&gt;a small tool that would generate, compile, and run a small tool
   to introspect the type system for things like hierarchy and&amp;nbsp;signals&lt;/li&gt;
&lt;li&gt;a script to take the templates, the list of symbols divided into
   logical &amp;#8220;sections&amp;#8221;, an index file, and generate a bunch of DocBook
   &lt;span class="caps"&gt;XML&lt;/span&gt;&amp;nbsp;files&lt;/li&gt;
&lt;li&gt;finally, a script to convert DocBook to &lt;span class="caps"&gt;HTML&lt;/span&gt; or man pages, via
   &lt;code&gt;xsltproc&lt;/code&gt; and an &lt;span class="caps"&gt;XML&lt;/span&gt;&amp;nbsp;stylesheet&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Whenever somebody added a new symbol to &lt;span class="caps"&gt;GTK&lt;/span&gt;, they would need to run the
script, find the symbol in the template files, write the documentation using
DocBook tags if necessary, and then commit the changes alongside the rest of
the&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;Since this was 1998, and the scripts had to parse a bunch of text files
using regular expressions, they were written in Perl and strung together
with a bunch of Makefile&amp;nbsp;rules.&lt;/p&gt;
&lt;p&gt;Thus, &lt;a href="https://gitlab.gnome.org/GNOME/gtk-doc"&gt;gtk-doc&lt;/a&gt; was&amp;nbsp;born.&lt;/p&gt;
&lt;p&gt;Of course, since other libraries needed to provide an &lt;span class="caps"&gt;API&lt;/span&gt; reference to those
poor souls using them, gtk-doc ended up being shared across the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
platform. We even built part of our website and release infrastructure
around&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;At some point between 1998 and 2009, gtk-doc gained the ability to generate
those template files incrementally, straight from the C sources; this
allowed moving the preambles of each section into the corresponding source
file, thus removing the templates from the repository, and keeping the
documentation close to the code it references, in the hope it would lead to
fewer instances of docs&amp;nbsp;drift.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Between 2009 and 2021, a few things&amp;nbsp;happened:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;&lt;a href="https://gi.readthedocs.io/en/latest/"&gt;gobject-introspection&lt;/a&gt; has become
   &amp;#8220;a thing&amp;#8221;; g-i also parses the C code, and does it slightly more thoroughly
   than gtk-doc, to gather the same information: declarations, hierarchy,
   interfaces, properties, and signals, and even documentation, which is all
   shoved into a well-defined &lt;span class="caps"&gt;XML&lt;/span&gt; file; on top of that, g-i needs annotations
   in the source to produce a machine-readable description of the C &lt;span class="caps"&gt;ABI&lt;/span&gt; of a
   library, which can then be used to generate language&amp;nbsp;bindings&lt;/li&gt;
&lt;li&gt;turns out that DocBook is pretty terrible, and running &lt;code&gt;xsltproc&lt;/code&gt; on large,
   complex DocBook files is &lt;em&gt;really&amp;nbsp;slow&lt;/em&gt;&lt;/li&gt;
&lt;li&gt;Perl isn&amp;#8217;t really a Hot Language™ like it was in the late &amp;#8216;90s; many
   Linux distributions dropped it from the core installation, and not many
   people speak it that fluently, which means not many people will want to
   help with a large Perl&amp;nbsp;application&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;To cope with issue (1), gtk-doc had to learn to parse introspection&amp;nbsp;annotations.&lt;/p&gt;
&lt;p&gt;Issue (2) led to replacing DocBook tags inside the inline documentation with
subset of &lt;a href="https://daringfireball.net/projects/markdown/"&gt;Markdown&lt;/a&gt;,
augmented with custom code blocks and intra-document anchors for specific&amp;nbsp;sections.&lt;/p&gt;
&lt;p&gt;Issue (3) led to a wholesale rewrite in Python, in the hope that more people
would contribute to the maintenance of&amp;nbsp;gtk-doc.&lt;/p&gt;
&lt;p&gt;Sadly, all three solutions ended up breaking things in different&amp;nbsp;ways:&lt;/p&gt;
&lt;ol&gt;
&lt;li&gt;gtk-doc never really managed to express the introspection information in
    the generated documentation, outside of references to an ancillary
    appendix. If an annotation says &amp;#8220;this argument can be &lt;span class="caps"&gt;NULL&lt;/span&gt;&amp;#8221;, for
    instance, there&amp;#8217;s no need to write &amp;#8220;or &lt;span class="caps"&gt;NULL&lt;/span&gt;&amp;#8221; in the documentation
    itself: the documentation tool can write it out for&amp;nbsp;you.&lt;/li&gt;
&lt;li&gt;the move to Markdown means that existing DocBook tags in the
    documentation are now ignored or, worse, misinterpreted for &lt;span class="caps"&gt;HTML&lt;/span&gt; and
    not rendered; this requires porting all the documentation in every
    library, in a giant flag day, to avoid broken docs; on top of that,
    DocBook&amp;#8217;s style sheet to generate &lt;span class="caps"&gt;HTML&lt;/span&gt; started exhibiting regressions
    after a build system change, which led, among other things, to the
    disappearance of per-version symbols&amp;nbsp;indices&lt;/li&gt;
&lt;li&gt;the port to Python probably came too late, and ended up having many,
    many regressions; gtk-doc is still a pretty complex tool, and it still
    caters to many different use cases, spanning two decades; as much as its
    use is documented and tested, its internals are really not, meaning that
    it&amp;#8217;s not an easy project to pick&amp;nbsp;up&lt;/li&gt;
&lt;/ol&gt;
&lt;p&gt;Over the past 10 years various projects started migrating away from gtk-doc;
gobject-introspection itself shipped a documentation tool capable of
generating &lt;span class="caps"&gt;API&lt;/span&gt; references, though it mostly is a demonstrator of potential
capabilities more than an actual tool. Language bindings, on the other hand,
adopted the introspection data as the source for their documentation, and
you can see it in &lt;a href="http://lazka.github.io/pgi-docs/"&gt;Python&lt;/a&gt;,
&lt;a href="https://gjs-docs.gnome.org/"&gt;JavaScript&lt;/a&gt;, and
&lt;a href="https://gtk-rs.org/docs/gtk/"&gt;Rust&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As much as I&amp;#8217;d like to contribute to gtk-doc, I&amp;#8217;m afraid we reached the
point where we might want to experiment with something more radical,
instead of patching something up, and end up breaking what&amp;#8217;s&amp;nbsp;left.&lt;/p&gt;
&lt;p&gt;So, since we&amp;#8217;re starting from the bottom up, let&amp;#8217;s figure out what are the
requirements for a tool to generate the documentation for &lt;span class="caps"&gt;GTK&lt;/span&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;em&gt;be fast&lt;/em&gt;. Building &lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;#8217;s &lt;span class="caps"&gt;API&lt;/span&gt; reference takes a long time. The &lt;span class="caps"&gt;API&lt;/span&gt;
   footprint of &lt;span class="caps"&gt;GDK&lt;/span&gt;, &lt;span class="caps"&gt;GSK&lt;/span&gt;, and &lt;span class="caps"&gt;GTK&lt;/span&gt; is not small, but there&amp;#8217;s no reason why
   building the documentation should take a comparable amount of time
   as building the library. We moved to Meson because it has improved the
   build times of &lt;span class="caps"&gt;GTK&lt;/span&gt;, we don&amp;#8217;t want to get into a bottleneck&amp;nbsp;now.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;no additional source parsing&lt;/em&gt;. We already parse the C sources in order
   to generate the introspection data, we don&amp;#8217;t need another pass at&amp;nbsp;that.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;tailored for &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/em&gt;. Whenever &lt;span class="caps"&gt;GTK&lt;/span&gt; changes, the tool must change with &lt;span class="caps"&gt;GTK&lt;/span&gt;;
   the output must adapt to the style of documentation &lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;nbsp;uses.&lt;/li&gt;
&lt;li&gt;&lt;em&gt;integrated with &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/em&gt;. We don&amp;#8217;t want an external dependency that makes it
   harder to deploy the &lt;span class="caps"&gt;GTK&lt;/span&gt; documentation on non-Linux platforms. Using it
   as a sub-project would be the best option, followed by being able to
   install it everywhere without additional, Linux-only&amp;nbsp;dependencies.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The explicit non-goal is to create a general purpose documentation tool. We
don&amp;#8217;t need that; in fact: we&amp;#8217;re actively avoiding it. Regardless of what
you&amp;#8217;ve been taught at university, or your geeky instincts tell you, &lt;em&gt;not
every problem requires a generic solution&lt;/em&gt;. The whole reason why we are in
this mess is that we took a tool for generating the &lt;span class="caps"&gt;GTK&lt;/span&gt; documentation and
then generalised the approach until it fell apart under its own&amp;nbsp;weight.&lt;/p&gt;
&lt;p&gt;If you want a general purpose documentation tool for C and C++ libraries,
there are many to choose&amp;nbsp;from:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://www.doxygen.nl/index.html"&gt;Doxygen&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://hotdoc.github.io/"&gt;HotDoc&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://casual-effects.com/markdeep/"&gt;MarkDeep&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;There&amp;#8217;s also gtk-doc: if you&amp;#8217;re using it already, I strongly recommend
helping out with its&amp;nbsp;maintenance.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Back in November 2020, as a side project while we were closing in to the &lt;span class="caps"&gt;GTK&lt;/span&gt;
4.0 release date, &lt;a href="https://gitlab.gnome.org/ebassi/gi-docgen"&gt;I started exploring the
idea&lt;/a&gt; of parsing the
introspection data to generate the C &lt;span class="caps"&gt;API&lt;/span&gt; reference for &lt;span class="caps"&gt;GTK&lt;/span&gt;. I wanted to
start from scratch, and see how far I could go, so I deliberately avoided
taking the &lt;span class="caps"&gt;GIR&lt;/span&gt; parser from gobject-introspection; armed only with the &lt;a href="https://gitlab.gnome.org/GNOME/gobject-introspection/-/blob/master/docs/gir-1.2.rnc"&gt;&lt;span class="caps"&gt;GIR&lt;/span&gt;
schema&lt;/a&gt;
and a bunch of Python, I ended up writing a decent parser that would be able
to load the &lt;span class="caps"&gt;GTK&lt;/span&gt; introspection &lt;span class="caps"&gt;XML&lt;/span&gt; data, including its dependencies, and dump
the whole tree of C identifiers and symbols. After a break, at the end of
January 2021, I decided to take a page out the static website generator rule
book, and plugged the &lt;a href="https://jinja.palletsprojects.com/en/2.11.x/"&gt;Jinja&lt;/a&gt;
templates into the introspection data. The whole thing took about a couple
of weeks to go from&amp;nbsp;this:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Everybody loves a tree-like output on the command&amp;nbsp;line&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gi-docgen-cli.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;to&amp;nbsp;this:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Behold! My&amp;nbsp;stuff!&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gi-docgen-web-old.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;My evil plan of generating something decent enough to be usable and then
showing it to people with actual taste and web development skills paid off,
because I got a whole merge request from Martin Zilz to create a beautiful
theme, with support for responsive layout and even for a dark&amp;nbsp;variant:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Amazing what actual taste and skill can&amp;nbsp;accomplish&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gi-docgen-web-new.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Like night and&amp;nbsp;day&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gi-docgen-web-light-dark.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Turns out that when you stop parsing C files and building small binaries to
introspect the type system, and remove DocBook and &lt;code&gt;xsltproc&lt;/code&gt; from the
pipeline, things get fast. Who&amp;nbsp;knew…&lt;/p&gt;
&lt;p&gt;Additionally, once you move the template and the styling outside of the
generator, and you can create more complex documentation hierarchies, while
retaining the ability for people that are not programmers to change the
resulting &lt;span class="caps"&gt;HTML&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The interesting side effect of using introspection data is that our &lt;span class="caps"&gt;API&lt;/span&gt;
reference is now matching what language bindings are able to see and
consume—and oh boy, do &lt;em&gt;we&lt;/em&gt; suck at that. Part of the fault lies in the
introspection parser not being able to cover some of the nastiest parts of
C, like macros—though, hopefully, that will improve in the near future; but
a lot of issues come from our own &lt;span class="caps"&gt;API&lt;/span&gt; design. Even after 10 years since the
introduction of introspection, we&amp;#8217;re still doing some very dumb things when
it comes to C &lt;span class="caps"&gt;API&lt;/span&gt;—ad let&amp;#8217;s ignore stuff that happened 20 years ago and that
we haven&amp;#8217;t been able to fix yet. Hopefully, the documentation slapping us in
the face is going to help us figuring things out &lt;em&gt;before&lt;/em&gt; they hit stable&amp;nbsp;releases.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;What&amp;#8217;s missing from gi-docgen? Well, you can look at the &lt;a href="https://gitlab.gnome.org/ebassi/gi-docgen/-/milestones/1"&gt;2021.1 milestone
on GitLab&lt;/a&gt;:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;more documentation on the ancillary files used for project and template
   configuration; stabilising the key/value pairs would also be part of the
   documentation&amp;nbsp;effort&lt;/li&gt;
&lt;li&gt;client-side search, with symbols exposed to tools like &lt;span class="caps"&gt;GNOME&lt;/span&gt; Builder
   through something that isn&amp;#8217;t quite as tragic as DevHelp&amp;nbsp;files&lt;/li&gt;
&lt;li&gt;automatic cross-linking with dependencies documented by gi-docgen,
   especially for libraries with multiple namespaces, like &lt;span class="caps"&gt;GTK&lt;/span&gt; and&amp;nbsp;Pango&lt;/li&gt;
&lt;li&gt;generating proper dependency files, for the consumption of build
   tools like&amp;nbsp;Meson&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;In the meantime, what&amp;#8217;s missing for &lt;span class="caps"&gt;GTK&lt;/span&gt; to use this? Mainly, porting the
documentation away from the various gtk-doc-isms, like marking symbols with
sigils, or using &lt;code&gt;|[ ... ]|&lt;/code&gt; to define code blocks. Additionally, since the
introspection scanner only attaches &lt;code&gt;SECTION&lt;/code&gt; blocks to the documentation
element of a class, all the sections that operate as &amp;#8220;grab bag of related
symbols&amp;#8221; need to be moved to a separate Markdown&amp;nbsp;file.&lt;/p&gt;
&lt;p&gt;&lt;strong&gt;It must needs be remarked&lt;/strong&gt;: gi-docgen is &lt;strong&gt;not&lt;/strong&gt; a generic solution for
documenting C libraries. If your library does not have introspection,
doesn&amp;#8217;t use type classes, or has a very different &lt;span class="caps"&gt;ABI&lt;/span&gt; exposed through
introspection than the actual C &lt;span class="caps"&gt;API&lt;/span&gt;, then you&amp;#8217;re not going to find it
useful—and I don&amp;#8217;t have any plans to cater to your use cases either. You
should keep using gtk-doc if it still works for you; or you may want to
consider other documentation&amp;nbsp;tools.&lt;/p&gt;
&lt;p&gt;Anything that complicates the goal of this tool—generating the &lt;span class="caps"&gt;API&lt;/span&gt; reference
for &lt;span class="caps"&gt;GTK&lt;/span&gt; and ancillary libraries—is completely out of&amp;nbsp;scope.&lt;/p&gt;
&lt;hr&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/ebassi/gi-docgen"&gt;The &lt;code&gt;gi-docgen&lt;/code&gt; repository&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://people.gnome.org/~ebassi/docs/_build/Gtk/4.0/"&gt;A demo render of the &lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;nbsp;reference&lt;/a&gt;&lt;/li&gt;
&lt;li&gt;&lt;a href="https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/3222"&gt;The &lt;span class="caps"&gt;MR&lt;/span&gt; for &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="gnome"></category><category term="documentation"></category><category term="introspection"></category><category term="gtk"></category><category term="development"></category></entry><entry><title>Type instances</title><link href="https://www.bassi.io/articles/2020/06/02/type-instances/" rel="alternate"></link><published>2020-06-02T16:06:00+01:00</published><updated>2020-06-02T16:06:27+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2020-06-02:/articles/2020/06/02/type-instances/</id><summary type="html">&lt;p&gt;In which we talk about derivable types that are not&amp;nbsp;GObject&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.amazon.co.uk/Neoreaction-Basilisk-Essays-Around-Alt-Right-ebook/dp/B0782JDGVQ/"&gt;Let us assume we are writing a library&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;The particular nature of our work is up for any amount of debate, but the
basic fact of it comes with a few requirements, and they are by and large
inevitable if you wish to be a well-behaved, well-integrated member of the
&lt;span class="caps"&gt;GNOME&lt;/span&gt; community. One of which is: &amp;#8220;please, think of the language bindings&amp;#8221;.
These days, luckily for all of us, this means writing introspectable
interfaces that adhere to fairly sensible best practices and&amp;nbsp;conventions.&lt;/p&gt;
&lt;p&gt;One of the basic conventions has to do with types. By and large, types
exposed by libraries fall into these two&amp;nbsp;categories:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;plain old data structures, which are represented by what&amp;#8217;s called a
   &amp;#8220;boxed&amp;#8221; type; these are simple types with a copy and a free function,
   mostly meant for marshalling things around so that language bindings can
   implement properties, signal handlers, and abide to ownership transfer
   rules. &lt;em&gt;Boxed types cannot have sub-types&lt;/em&gt;.&lt;/li&gt;
&lt;li&gt;object types, used for everything else: properties, emitting signals,
   inheritance, interface implementation, the whole&amp;nbsp;shebang.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Boxed and object types cover most of the functionality in a modern,
GObject-based &lt;span class="caps"&gt;API&lt;/span&gt;, and people can consume the very same &lt;span class="caps"&gt;API&lt;/span&gt; from languages
that are not&amp;nbsp;C.&lt;/p&gt;
&lt;p&gt;Except that there&amp;#8217;s a third, kind of niche data&amp;nbsp;type:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;fully opaque, with instance fields only known within the scope of the
   project&amp;nbsp;itself&lt;/li&gt;
&lt;li&gt;immutable, or at least with low-mutability, after&amp;nbsp;construction&lt;/li&gt;
&lt;li&gt;reference counted, with optional cloning and&amp;nbsp;serialization&lt;/li&gt;
&lt;li&gt;derivable within the scope of the project, typically with a base
   abstract&amp;nbsp;class&lt;/li&gt;
&lt;li&gt;without signals or&amp;nbsp;properties&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;Boxing&lt;/h3&gt;
&lt;p&gt;One strategy used to implement this niche type has been to use a boxed type,
and then invent some private, ad hoc derivation technique, with some
structure containing function pointers used as a vtable, for&amp;nbsp;instance:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;boxed-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 3-79]&lt;/span&gt;&lt;a href='/code/types/boxed-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/* {{{ Base */&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Base&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseClass&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseClass&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;type_name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;gsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Base&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base_class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Shared field&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// Allocate the instance described in the vtable&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;base_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Simple check to ensure that the derived instance includes the&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// parent base type&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Use the atomic refcounted boxing to allocated the requested&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// instance size&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_atomic_rc_box_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Store the vtable&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;base_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;vtable&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Initialize the base instance fields&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Allow derived types to clear up their own instance data&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;base_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;base_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_atomic_rc_box_acquire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_atomic_rc_box_release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_finalize&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;base_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;base_class&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Add a GType for the base type&lt;/span&gt;
&lt;span class="n"&gt;G_DEFINE_BOXED_TYPE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_ref&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_unref&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="cm"&gt;/* }}} */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;The code above lets us create derived types that conform to the base type
&lt;span class="caps"&gt;API&lt;/span&gt; contract, while providing additional functionality; for&amp;nbsp;instance:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;boxed-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 81-123]&lt;/span&gt;&lt;a href='/code/types/boxed-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/* {{{ DerivedA */&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;type_name&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DerivedA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_finalize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// defined elsewhere&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// defined elsewhere&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;derived_a_class&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_strdup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_get_some_other_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="cm"&gt;/* }}} */&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;Since the &lt;code&gt;Base&lt;/code&gt; type is also a boxed type, it can be used for signal
marshallers and GObject properties at zero&amp;nbsp;cost.&lt;/p&gt;
&lt;p&gt;This whole thing seems pretty efficient, and fairly simple to wrap your head
around, but things fall apart pretty quickly as soon as you make this &lt;span class="caps"&gt;API&lt;/span&gt;
public and tell people to use it from languages that are not&amp;nbsp;C.&lt;/p&gt;
&lt;p&gt;As I said above, &lt;em&gt;boxed types cannot have sub-types&lt;/em&gt;; the type system has no
idea that &lt;code&gt;DerivedA&lt;/code&gt; implements the &lt;code&gt;Base&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt; contract. Additionally, since
the whole introspection system is based on conventions applied on top of
some C &lt;span class="caps"&gt;API&lt;/span&gt;, there is no way for language bindings to know that the
&lt;code&gt;derived_a_get_some_other_field()&lt;/code&gt; function is really a &lt;code&gt;DerivedA&lt;/code&gt; method,
meant to operate on &lt;code&gt;DerivedA&lt;/code&gt; instances. Instead, you&amp;#8217;ll only be able to
access the method as a static function,&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;obj&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;Namespace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;derived_a_new&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="n"&gt;Namespace&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;derived_a_get_some_other_field&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;obj&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;instead of the idiomatic, and&amp;nbsp;natural:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;obj = Namespace.DerivedA.new()
obj.get_some_other_field()
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In short: please, don&amp;#8217;t use boxed types for this, unless you&amp;#8217;re planning to
hide this functionality from the public &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Typed&amp;nbsp;instances&lt;/h3&gt;
&lt;p&gt;At this point the recommendation would be to switch to GObject for your
type; make the type derivable in your project&amp;#8217;s scope, avoid properties and
signals, and you get fairly idiomatic code, and a bunch of other features,
like weak references, toggle references, and keyed instance data. You can
use your types for properties and signals, and you&amp;#8217;re pretty much&amp;nbsp;done.&lt;/p&gt;
&lt;p&gt;But &lt;em&gt;what if you don&amp;#8217;t want to use&amp;nbsp;GObject…&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Well, in that case GLib lets you create your own type hierarchy, with its
own rules, by using &lt;a href="https://developer.gnome.org/gobject/stable/gobject-Type-Information.html#GTypeInstance"&gt;&lt;code&gt;GTypeInstance&lt;/code&gt;&lt;/a&gt; as the base&amp;nbsp;type.&lt;/p&gt;
&lt;p&gt;&lt;code&gt;GTypeInstance&lt;/code&gt; is the common ancestor for everything that is meant to be
derivable; it&amp;#8217;s the base type for &lt;code&gt;GObject&lt;/code&gt; as well. Implementing a
&lt;code&gt;GTypeInstance&lt;/code&gt;-derived hierarchy doesn&amp;#8217;t take much effort: it&amp;#8217;s mostly low
level glue&amp;nbsp;code:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;instance-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 4-189]&lt;/span&gt;&lt;a href='/code/types/instance-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Base&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseClass&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseTypeInfo&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;BaseTypeInfo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="cp"&gt;#define BASE_TYPE               (base_get_type())&lt;/span&gt;
&lt;span class="cp"&gt;#define BASE_GET_CLASS(obj)     (G_TYPE_INSTANCE_GET_CLASS ((obj), BASE_TYPE, &lt;/span&gt;

&lt;span class="c1"&gt;// Simple macro that lets you chain up to the parent type&amp;#39;s implementation&lt;/span&gt;
&lt;span class="c1"&gt;// of a virtual function, e.g.:&lt;/span&gt;
&lt;span class="c1"&gt;//&lt;/span&gt;
&lt;span class="c1"&gt;//   BASE_SUPER (self)-&amp;gt;finalize (obj);&lt;/span&gt;
&lt;span class="cp"&gt;#define BASE_SUPER(obj)         ((BaseClass *) g_type_class_peek (g_type_parent (G_TYPE_FROM_INSTANCE (obj))))&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseClass&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_Base&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent_instance&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;gatomicrefcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Shared field&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;some_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// A structure to be filled out by derived types when registering&lt;/span&gt;
&lt;span class="c1"&gt;// themselves into the type system; it copies the vtable into the&lt;/span&gt;
&lt;span class="c1"&gt;// class structure, and defines the size of the instance&lt;/span&gt;
&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nc"&gt;_BaseTypeInfo&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;gsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="c1"&gt;// GValue table, so that you can initialize, compare, and clear&lt;/span&gt;
&lt;span class="c1"&gt;// your type inside a GValue, as well as collect/copy it when&lt;/span&gt;
&lt;span class="c1"&gt;// dealing with variadic arguments&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;value_base_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;value_base_free_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;base_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;value_base_copy_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                       &lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt;       &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;!=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;dst&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;
&lt;span class="nf"&gt;value_expression_peek_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;value_base_collect_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="n"&gt;guint&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;n_collect_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="n"&gt;GTypeCValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;collect_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="n"&gt;guint&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;collect_flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;parent_instance&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;g_class&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_strconcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;invalid unclassed Base pointer for &amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;value type &amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;G_VALUE_TYPE_NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gchar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;value_base_lcopy_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GValue&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;guint&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;n_collect_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;GTypeCValue&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;collect_values&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;guint&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;collect_flags&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;**&lt;/span&gt;&lt;span class="n"&gt;base_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;collect_values&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_strconcat&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;value location for &amp;#39;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="n"&gt;G_VALUE_TYPE_NAME&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&amp;#39; passed as NULL&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                        &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;collect_flags&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;G_VALUE_NOCOPY_CONTENTS&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base_p&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;value&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;data&lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;].&lt;/span&gt;&lt;span class="n"&gt;v_pointer&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register the Base type&lt;/span&gt;
&lt;span class="n"&gt;GType&lt;/span&gt;
&lt;span class="nf"&gt;base_get_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_type__volatile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_once_init_enter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;base_type__volatile&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// This is a derivable type; we also want to allow&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// its derived types to be derivable&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GTypeFundamentalInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;finfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;G_TYPE_FLAG_CLASSED&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_FLAG_INSTANTIATABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_FLAG_DERIVABLE&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;|&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_FLAG_DEEP_DERIVABLE&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// The gunk for dealing with GValue&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GTypeValueTable&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;value_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_free_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_copy_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_peek_pointer&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_collect_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;p&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;value_base_lcopy_value&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// Base type information&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GTypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Class&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GtkExpressionClass&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GBaseInitFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GBaseFinalizeFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GClassInitFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_class_init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GClassFinalizeFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// Instance&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GtkExpression&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GInstanceInitFunc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_init&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="c1"&gt;// GValue&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;value_table&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// Register the Base type as a new, abstract fundamental type&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;g_type_register_fundamental&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_type_fundamental_next&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(),&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="n"&gt;g_intern_static_string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Base&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;event_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;finfo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                     &lt;/span&gt;&lt;span class="n"&gt;G_TYPE_FLAG_ABSTRACT&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;g_once_init_leave&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;base_type__volatile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;expression_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_type__volatile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;Yes, this is &lt;strong&gt;a lot&lt;/strong&gt; of&amp;nbsp;code.&lt;/p&gt;
&lt;p&gt;The base code stays pretty much the&amp;nbsp;same:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;instance-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 191-243]&lt;/span&gt;&lt;a href='/code/types/instance-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_real_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_type_free_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="n"&gt;GTypeInstance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_class_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_real_finalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Initialize the base instance fields&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_atomic_ref_count_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;42&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;base_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_type_is_a&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_get_type&lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Instantiate a new type derived by Base&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_type_create_instance&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;base_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_atomic_ref_count_inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_atomic_ref_count_dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;BASE_GET_CLASS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;BASE_GET_CLASS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;BASE_GET_CLASS&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;except:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the reference counting is explicit, as we must use
   &lt;code&gt;g_type_create_instance()&lt;/code&gt; and &lt;code&gt;g_type_free_instance()&lt;/code&gt; to allocate and
   free the memory associated to the&amp;nbsp;instance&lt;/li&gt;
&lt;li&gt;you need to get the class structure from the instance using the GType
   macros instead of direct pointer&amp;nbsp;access&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Finally, you will need to add code to let you register derived types; since
we want to tightly control the derivation, we use an &lt;em&gt;ad hoc&lt;/em&gt; structure for
the virtual functions, and we use a generic class initialization&amp;nbsp;function:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;instance-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 245-290]&lt;/span&gt;&lt;a href='/code/types/instance-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;base_generic_class_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_class&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="n"&gt;gpointer&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class_data&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;BaseTypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;class_data&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_class&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;klass&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;info&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// The info structure was copied, so we now need&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// to release the resources associated with it&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;class_data&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="c1"&gt;// Register a derived typed of Base&lt;/span&gt;
&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;
&lt;span class="nf"&gt;base_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;type_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseTypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Simple check to ensure that the derived instance includes the&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// parent base type&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_assert&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;GTypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// All derived types have the same class and cannot add new virtual&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// functions&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseClass&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;base_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Fill out the class vtable from the BaseTypeInfo structure&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_generic_class_init&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;class_data&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_memdup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BaseTypeInfo&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Instance information&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;n_preallocs&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;value_table&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;BASE_TYPE&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type_name&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;type_info&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;Otherwise, you could re-use the &lt;code&gt;G_DEFINE_TYPE&lt;/code&gt; macro—yes, it does not
require GObject—but then you&amp;#8217;d have to implement your own class
initialization and instance initialization&amp;nbsp;functions.&lt;/p&gt;
&lt;p&gt;After you defined the base type, you can structure your types in the same
way as the boxed type&amp;nbsp;code:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;instance-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 294-347]&lt;/span&gt;&lt;a href='/code/types/instance-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;parent&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// We need to chain up to the parent&amp;#39;s finalize() or we&amp;#39;re&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// going to leak the instance&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;BASE_SUPER&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;BaseTypeInfo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_info&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;instance_size&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;sizeof&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;finalize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_finalize&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;foo&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_foo&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// defined elsewhere&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;bar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_a_bar&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;// defined elsewhere&lt;/span&gt;
&lt;span class="p"&gt;};&lt;/span&gt;

&lt;span class="n"&gt;GType&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_get_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;volatile&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gsize&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_type__volatile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_once_init_enter&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;derived_type__volatile&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="c1"&gt;// Register the type&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;GType&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="n"&gt;base_type_register_static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_intern_static_string&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;DerivedA&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;derived_a_info&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;g_once_init_leave&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;derived_type__volatile&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_type&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;derived_type__volatile&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base_alloc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;derived_a_get_type&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;());&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_strdup&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;The nice bit is that you can tell the introspection scanner how to deal with
each derived type through annotations, and keep the &lt;span class="caps"&gt;API&lt;/span&gt; simple to use in C
while idiomatic to use in other&amp;nbsp;languages:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;instance-type.c&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 349-363]&lt;/span&gt;&lt;a href='/code/types/instance-type.c'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="cm"&gt;/**&lt;/span&gt;
&lt;span class="cm"&gt; * derived_a_get_some_other_field:&lt;/span&gt;
&lt;span class="cm"&gt; * @base: (type DerivedA): a derived #Base instance&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * Retrieves the `some_other_field` of a derived #Base instance.&lt;/span&gt;
&lt;span class="cm"&gt; *&lt;/span&gt;
&lt;span class="cm"&gt; * Returns: (transfer none): the contents of the field&lt;/span&gt;
&lt;span class="cm"&gt; */&lt;/span&gt;
&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;derived_a_get_some_other_field&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Base&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;DerivedA&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;base&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;self&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;some_other_field&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;h3&gt;Cost-benefit&lt;/h3&gt;
&lt;p&gt;Of course, there are costs to this approach. In no particular&amp;nbsp;order:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;
&lt;p&gt;The type system boilerplate is &lt;em&gt;a lot&lt;/em&gt;; the code size more than doubled
   from the boxed type approach. This is quite annoying, but at least it is
   a one-off cost, and you won&amp;#8217;t likely ever need to change it. It would be
   nice to have it hidden by some magic macro incantation, but it&amp;#8217;s
   understandably hard to do so without imposing restrictions on the kind of
   types you can create; since you&amp;#8217;re trying to escape the restrictions of
   GObject, it would not make sense to impose a different set of&amp;nbsp;restrictions.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;If you want to be able to use this new type with properties and you
   cannot use &lt;code&gt;G_TYPE_POINTER&lt;/code&gt; as a generic, hands-off container, you
   &lt;strong&gt;will&lt;/strong&gt; need to derive &lt;code&gt;GParamSpec&lt;/code&gt;, and add &lt;em&gt;ad hoc&lt;/em&gt; &lt;span class="caps"&gt;API&lt;/span&gt; for &lt;code&gt;GValue&lt;/code&gt;,
   which is even more annoying boilerplate. I&amp;#8217;ve skipped it in the example,
   because that would add about 100 more lines of&amp;nbsp;code.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Generated signal marshallers, and the generic one using libffi, do not
   know how to marshal typed instances; you will need custom written
   marshallers, or you&amp;#8217;re going to use &lt;code&gt;G_TYPE_POINTER&lt;/code&gt; everywhere and
   assume the risk of untyped boxing. The same applies to anything that uses
   the type system to perform things like serialization and deserialization,
   or &lt;code&gt;GValue&lt;/code&gt; boxing and unboxing. You decided to build your own theme park
   on the Moon, and the type system has no idea how to represent it, or
   access its&amp;nbsp;functionality.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;
&lt;p&gt;Language bindings need to be able to deal with &lt;code&gt;GTypeInstance&lt;/code&gt; and
   fundamental types; this is not always immediately necessary, so some
   maintainers do not add the code to handle this aspect of the type&amp;nbsp;system.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The benefit is, of course, the fact that you are using a separate type
hierarchy, and you get to make your own rules on things like memory
management, lifetimes, and ownership. You can control the inheritance chain,
and the rules on the overridable virtual functions. Since you control the
whole type, you can add things like serialization and deserialization, or
instance cloning, right at the top of the hierarchy. You could even
implement properties without using &lt;code&gt;GParamSpec&lt;/code&gt;.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Please, please use GObject. Writing type system code is already boring and
error prone, which is why we added a ton of macros to avoid people shooting
themselves in both their feet, and we hammered away all the special
snowflake &lt;span class="caps"&gt;API&lt;/span&gt; flourishes that made parsing C &lt;span class="caps"&gt;API&lt;/span&gt; to generate introspection
data&amp;nbsp;impossible.&lt;/p&gt;
&lt;p&gt;I can only recommend you go down the &lt;code&gt;GTypeInstance&lt;/code&gt; route if you&amp;#8217;ve done
your due diligence on what that entails, and are aware that it is a last
resort if GObject simply does not work within your project&amp;#8217;s&amp;nbsp;constraints.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="glib"></category><category term="gobject"></category></entry><entry><title>Another layer</title><link href="https://www.bassi.io/articles/2019/08/15/another-layer/" rel="alternate"></link><published>2019-08-15T10:16:00+01:00</published><updated>2019-08-15T10:38:29+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2019-08-15:/articles/2019/08/15/another-layer/</id><summary type="html">&lt;p&gt;In which I announce a new release of&amp;nbsp;Graphene&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.bassi.io/articles/2014/05/03/graphene/"&gt;Five years (and change) ago&lt;/a&gt; I was looking
at the data types and &lt;span class="caps"&gt;API&lt;/span&gt; that were needed to write a 3D-capable scene graph
&lt;span class="caps"&gt;API&lt;/span&gt;; I was also learning about &lt;span class="caps"&gt;SIMD&lt;/span&gt; instructions and compiler builtins on &lt;span class="caps"&gt;IA&lt;/span&gt;
and &lt;span class="caps"&gt;ARM&lt;/span&gt;, as well as a bunch of math I didn&amp;#8217;t really study in my brush offs
with formal higher education. The result was a small library called
&lt;a href="https://ebassi.github.io/graphene"&gt;Graphene&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Over the years I &lt;a href="https://www.bassi.io/articles/2014/12/06/layer-by-layer/"&gt;added more &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/a&gt;, &lt;a href="https://www.bassi.io/articles/2016/06/09/experiments-in-meson/"&gt;moved the
build system from Autotools over to Meson&lt;/a&gt;,
and &lt;a href="https://www.bassi.io/articles/2019/03/14/a-little-testing/"&gt;wrote a whole separate library for its test suite&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;In the meantime, GStreamer started using Graphene in its &lt;span class="caps"&gt;GL&lt;/span&gt; element; &lt;span class="caps"&gt;GTK&lt;/span&gt;
3.9x is very much using Graphene internally and exposing it as public &lt;span class="caps"&gt;API&lt;/span&gt;;
Mutter developers are working on reimplementing the various math types in
their copies of Cogl and Clutter using Graphene; and
&lt;a href="https://blogs.gnome.org/alexl"&gt;Alex&lt;/a&gt; wrote &lt;a href="https://github.com/alexlarsson/gthree"&gt;an entire 3D
engine&lt;/a&gt; using&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Not bad for a side&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;Of course, now I&amp;#8217;ll have to start maintaining Graphene like a proper
grownup, which also means reporting its changes, bug fixes, and features
when I&amp;#8217;m at the end of a development&amp;nbsp;cycle.&lt;/p&gt;
&lt;p&gt;While the 1.8 development cycle consisted mostly of bug fixes with no new
&lt;span class="caps"&gt;API&lt;/span&gt;, there have been a few major internal changes during the development
cycle towards&amp;nbsp;1.10:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I rewrote the Euler angles conversion to and from quaternions and
    matrices; the original implementation I cribbed from here and there was
    not really adequate, and broke pretty horribly when you tried to
    roundtrip from Euler angles to a transformation matrix and back. This
    also affected the conversion between Euler angles and quaternions. The
    new implementation is more correct, and as a side effect it now includes
    not just the Tait–Bryan angles, but also the classic Euler angles. All
    possible orders are available in both the intrinsic and extrinsic axes&amp;nbsp;variants.&lt;/li&gt;
&lt;li&gt;We&amp;#8217;re dealing with floating point comparison and with infinities a bit
    better, now; this is usually necessary because the various vector
    implementations may have different behaviour, depending on the toolchain
    in use. A shout out goes to Intel, who bothered to add an instruction to
    check for infinities only in &lt;span class="caps"&gt;AVX&lt;/span&gt; 512, making it pointless for me, and
    causing a lot more grief than&amp;nbsp;necessary.&lt;/li&gt;
&lt;li&gt;The &lt;span class="caps"&gt;ARM&lt;/span&gt; &lt;span class="caps"&gt;NEON&lt;/span&gt; implementation of &lt;code&gt;graphene_simd4f_t&lt;/code&gt; has been fixed and
    tested on actual &lt;span class="caps"&gt;ARM&lt;/span&gt; devices (an old Odroid I had lying around for ARMv7
    and a Raspberry Pi3 for Aarch64); this means that the &amp;#8220;this is experimental&amp;#8221;
    compiler warning has been removed. I still need to run the &lt;span class="caps"&gt;CI&lt;/span&gt; on an &lt;span class="caps"&gt;ARM&lt;/span&gt;
    builder, but at least I can check if I&amp;#8217;m doing something dumb,&amp;nbsp;now.&lt;/li&gt;
&lt;li&gt;As mentioned in the blog posts above, the whole test suite has been
    rewritten using µTest, which dropped a dependency on GLib; you still need
    GLib to get the integration with GObject, but if you&amp;#8217;re not using that,
    Graphene should now be easier to build and&amp;nbsp;test.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;there are a bunch of new functions for &lt;code&gt;graphene_rect_t&lt;/code&gt;, courtesy of
    Georges Basile Stavracas Neto and Marco&amp;nbsp;Trevisan&lt;/li&gt;
&lt;li&gt;thanks to Marco, the &lt;code&gt;graphene_rect_round()&lt;/code&gt; function has been deprecated
    in favour of the more reliable &lt;code&gt;graphene_rect_round_extents()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;graphene_quaternion_t&lt;/code&gt; gained new operators, like &lt;code&gt;add()&lt;/code&gt;, &lt;code&gt;multiply()&lt;/code&gt;
    and &lt;code&gt;scale()&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;thanks to Alex Larsson, &lt;code&gt;graphene_plane_t&lt;/code&gt; can now be transformed using
    a&amp;nbsp;matrix&lt;/li&gt;
&lt;li&gt;I added equality and near-equality operators for &lt;code&gt;graphene_matrix_t&lt;/code&gt;,
    and a getter function to retrieve the translation components of a
    transformation&amp;nbsp;matrix&lt;/li&gt;
&lt;li&gt;I added interpolation functions for the 2, 3, and 4-sized&amp;nbsp;vectors&lt;/li&gt;
&lt;li&gt;I&amp;#8217;m working on exposing the matrix decomposition code for Gthree, but
    that requires some untangling of messy code so I&amp;#8217;ll be in the next
    development&amp;nbsp;snapshot.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On the documentation&amp;nbsp;side:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;I&amp;#8217;ve reworked the contribution guide, and added a code of conduct to the
    project; doesn&amp;#8217;t matter how many times you say &amp;#8220;patches welcome&amp;#8221; if you
    also aren&amp;#8217;t clear on how those patches should be written, submitted,
    and reviewed, and if you aren&amp;#8217;t clear on what constitutes acceptable
    behaviour when it comes to interactions between contributors and the&amp;nbsp;maintainer&lt;/li&gt;
&lt;li&gt;this landed at the tail end of 1.8, but I&amp;#8217;ve hopefully clearly
    documented the conventions of the matrix/matrix and matrix/vector
    operations, to the point that people can use the Graphene &lt;span class="caps"&gt;API&lt;/span&gt; without
    necessarily having to read the code to understand how to use&amp;nbsp;it&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This concludes the changes that will appear with the next 1.10 stable
release, which will be available by the time &lt;span class="caps"&gt;GNOME&lt;/span&gt; 3.34 is out. For the
time being, you can check out &lt;a href="https://github.com/ebassi/graphene/releases/tag/1.9.6"&gt;the latest development
snapshot&lt;/a&gt; available
on&amp;nbsp;Github.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t have many plans for the future, to be quite honest; I&amp;#8217;ll keep an
eye out for what &lt;span class="caps"&gt;GTK&lt;/span&gt; and Gthree need, and I expect that once Mutter starts
using Graphene I&amp;#8217;ll start receiving bug&amp;nbsp;reports.&lt;/p&gt;
&lt;p&gt;One thing I did try was moving to a &amp;#8220;static&amp;#8221; &lt;span class="caps"&gt;API&lt;/span&gt; reference using
&lt;a href="http://casual-effects.com/markdeep"&gt;Markdeep&lt;/a&gt;, just like I did for µTest,
and drop yet another dependency; sadly, since we need to use gtk-doc
annotations for the GObject introspection data generation, we&amp;#8217;re going to
depend on gtk-doc for a little while&amp;nbsp;longer.&lt;/p&gt;
&lt;p&gt;Of course, if you are using Graphene and you find some missing
functionality, feel free to &lt;a href="https://github.com/ebassi/graphene/issues/new"&gt;open an issue&lt;/a&gt;,
or a merge&amp;nbsp;request.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="graphene"></category></entry><entry><title>More little testing</title><link href="https://www.bassi.io/articles/2019/06/01/more-little-testing/" rel="alternate"></link><published>2019-06-01T12:15:00+01:00</published><updated>2023-02-20T00:32:07+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2019-06-01:/articles/2019/06/01/more-little-testing/</id><summary type="html">&lt;p&gt;In which I announce that Graphene moved to a new testing &lt;span class="caps"&gt;API&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;Back in March, &lt;a href="https://www.bassi.io/articles/2019/03/14/a-little-testing/"&gt;I wrote about µTest&lt;/a&gt;, a
&lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development"&gt;Behavior-Driven Development&lt;/a&gt; testing &lt;span class="caps"&gt;API&lt;/span&gt; for C libraries,
and that I was planning to use it to replace the GLib testing &lt;span class="caps"&gt;API&lt;/span&gt; in
&lt;a href="https://ebassi.github.io/graphene/"&gt;Graphene&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As I was busy with other things in &lt;span class="caps"&gt;GTK&lt;/span&gt;, it took me a while to get back
to µTest—especially because I needed some time to set up a development
environment on Windows in order to port µTest there. I managed to find
some time over various weekends and evenings, and ended up fixing a couple
of small issues here and there, to the point that I could run µTest&amp;#8217;s own
test suite on my Windows 10 box, and then get the &lt;span class="caps"&gt;CI&lt;/span&gt; build job I have on
Appveyor to succeed as&amp;nbsp;well.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Setting up &lt;span class="caps"&gt;MSYS2&lt;/span&gt; was the most time consuming bit,&amp;nbsp;really&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/mutest-msys2.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;While at it, I also cleaned up the &lt;span class="caps"&gt;API&lt;/span&gt; and properly documented&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Since depending on gtk-doc would defeat the purpose, and since I honestly
dislike Doxygen, I was looking for a way to write the &lt;span class="caps"&gt;API&lt;/span&gt; reference and
publish it as &lt;span class="caps"&gt;HTML&lt;/span&gt;. As luck would have it, I remembered a mention on Twitter
about &lt;a href="http://casual-effects.com/markdeep/"&gt;Markdeep&lt;/a&gt;, a self-contained bit of JavaScript capable of
turning a Markdown document into a half decent &lt;span class="caps"&gt;HTML&lt;/span&gt; page client side.
Coupled with GitHub pages, I ended up with a fairly decent &lt;a href="https://ebassi.github.io/mutest/mutest.md.html"&gt;online &lt;span class="caps"&gt;API&lt;/span&gt;
reference&lt;/a&gt; that also works offline, falls back to a Markdown
document when not running through JavaScript, and can get fixed via pull&amp;nbsp;requests.&lt;/p&gt;
&lt;p&gt;Now that µTest is in a decent state, I ported the Graphene test suite over
to it and, now I can run it on Windows using &lt;span class="caps"&gt;MSVC&lt;/span&gt;—and &lt;span class="caps"&gt;MSYS2&lt;/span&gt;, as soon as the
issue with &lt;span class="caps"&gt;GCC&lt;/span&gt; gets fixed upstream. This means that, hopefully, we won&amp;#8217;t
have regressions on Windows in the&amp;nbsp;future.&lt;/p&gt;
&lt;p&gt;The µTest &lt;span class="caps"&gt;API&lt;/span&gt; is small enough, now, that I don&amp;#8217;t plan major changes; I don&amp;#8217;t
want to commit to full &lt;span class="caps"&gt;API&lt;/span&gt; stability &lt;strong&gt;just yet&lt;/strong&gt;, but I think we&amp;#8217;re getting
close to a first stable release soon; definitely before Graphene 1.10 gets&amp;nbsp;released.&lt;/p&gt;
&lt;p&gt;In case you think this could be useful for you: feedback, in the form of
&lt;a href="https://github.com/ebassi/mutest/issues"&gt;issues&lt;/a&gt; and &lt;a href="https://github.com/ebassi/mutest/pulls"&gt;pull requests&lt;/a&gt;, is&amp;nbsp;welcome.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="bdd"></category><category term="testing"></category></entry><entry><title>(New) Adventures in CI</title><link href="https://www.bassi.io/articles/2019/04/13/adventures-in-ci/" rel="alternate"></link><published>2019-04-13T17:33:00+01:00</published><updated>2019-04-14T17:02:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2019-04-13:/articles/2019/04/13/adventures-in-ci/</id><summary type="html">&lt;p&gt;In which I talk about test reports with GitLab &lt;span class="caps"&gt;CI&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;One of the great advantages of moving the code hosting in &lt;a href="https://gitlab.gnome.org"&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt;&lt;/a&gt;
to &lt;a href="https://gitlab.com"&gt;GitLab&lt;/a&gt; is the ability to run per-project, per-branch, and
per-merge request continuous integration pipelines. While we&amp;#8217;ve had a &lt;span class="caps"&gt;CI&lt;/span&gt;
pipeline for &lt;a href="https://build.gnome.org"&gt;the whole of &lt;span class="caps"&gt;GNOME&lt;/span&gt;&lt;/a&gt; since 2012, it is limited to
the &lt;code&gt;master&lt;/code&gt; branch of everything, so it only helps catching build issues
post-merge. Additionally, we haven&amp;#8217;t been able to run test suites on
Continuous since early&amp;nbsp;2016.&lt;/p&gt;
&lt;p&gt;Being able to run your test suite is, of course, great—assuming you do have
a test suite, and you&amp;#8217;re good at keeping it working; gating all merge
requests on whether your &lt;span class="caps"&gt;CI&lt;/span&gt; pipeline passes or fails is incredibly powerful,
as it not only keeps your from unknowingly merging broken code, but it also
nudges you in the direction of never pushing commits to the &lt;code&gt;master&lt;/code&gt; branch.
The downside is that it lacks nuance; if your test suite is composed of
hundreds of tests you need a way to know at a glance which ones failed.
Going through the job log is kind of crude, and it&amp;#8217;s easy to miss&amp;nbsp;things.&lt;/p&gt;
&lt;p&gt;Luckily for us, GitLab has &lt;a href="https://docs.gitlab.com/ee/ci/junit_test_reports.html"&gt;the ability to create a cover
report&lt;/a&gt; for your test suite results, and present it on the
merge request summary, if you generate an &lt;span class="caps"&gt;XML&lt;/span&gt; report and tell the &lt;span class="caps"&gt;CI&lt;/span&gt;
machinery where you put&amp;nbsp;it:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;reports&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nt"&gt;junit&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;${CI_PROJECT_DIR}/_build/report.xml&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Sadly, the &lt;span class="caps"&gt;XML&lt;/span&gt; format chosen by GitLab is the one generated by
&lt;a href="https://junit.org/junit5/"&gt;JUnit&lt;/a&gt;, and we aren&amp;#8217;t really writing Java classes. The JUnit &lt;span class="caps"&gt;XML&lt;/span&gt;
format is woefully underdocumented, with only &lt;a href="https://llg.cubic.org/docs/junit/"&gt;an unofficial
breakdown&lt;/a&gt; of the entities and structure available. On top of
that, since JUnit&amp;#8217;s &lt;span class="caps"&gt;XML&lt;/span&gt; format is undocumented, GitLab has its &lt;a href="https://gitlab.com/gitlab-org/gitlab-ce/issues/50964"&gt;own
quirks&lt;/a&gt; in how it parses&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Okay, assuming we have nailed down the output, how about the input? Since
we&amp;#8217;re using &lt;a href="http://mesonbuild.com/"&gt;Meson&lt;/a&gt; on various projects, we can rely on &lt;a href="http://mesonbuild.com/IDE-integration.html#tests"&gt;machine
parseable logs&lt;/a&gt; for the test suite log. Unfortunately, Meson
currently outputs something that is not really valid &lt;span class="caps"&gt;JSON&lt;/span&gt;—you have to break
the log into separate lines, and parse each line into a &lt;span class="caps"&gt;JSON&lt;/span&gt; object, which
is somewhat less than optimal. Hopefully future versions of Meson will
generate an actual &lt;span class="caps"&gt;JSON&lt;/span&gt; file, and reduce the overhead in the tooling
consuming Meson&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;Nevertheless, after an afternoon of figuring out Meson&amp;#8217;s output, and reverse
engineering the JUnit &lt;span class="caps"&gt;XML&lt;/span&gt; format and the GitLab JUnit parser, I managed to
write &lt;a href="https://gist.github.com/ebassi/e5296ec77ae9e0d3a33fd483b5613b09"&gt;a simple script&lt;/a&gt; that translates Meson&amp;#8217;s
&lt;code&gt;testlog.json&lt;/code&gt; file into a JUnit &lt;span class="caps"&gt;XML&lt;/span&gt; report that you can use with GitLab
after you ran the test suite in your &lt;span class="caps"&gt;CI&lt;/span&gt; pipeline. For instance, this is what
&lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;nbsp;does:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;set&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;+e

xvfb-run&lt;span class="w"&gt; &lt;/span&gt;-a&lt;span class="w"&gt; &lt;/span&gt;-s&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;-screen 0 1024x768x24&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;meson&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;-C&lt;span class="w"&gt; &lt;/span&gt;_build&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;         &lt;/span&gt;--timeout-multiplier&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;--print-errorlogs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;--suite&lt;span class="o"&gt;=&lt;/span&gt;gtk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;--no-suite&lt;span class="o"&gt;=&lt;/span&gt;gtk:gsk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;     &lt;/span&gt;--no-suite&lt;span class="o"&gt;=&lt;/span&gt;gtk:a11y

&lt;span class="c1"&gt;# Save the exit code, so we can reuse it&lt;/span&gt;
&lt;span class="c1"&gt;# later to pass/fail the job&lt;/span&gt;
&lt;span class="nv"&gt;exit_code&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;$?&lt;/span&gt;

&lt;span class="c1"&gt;# We always run the report generator, even&lt;/span&gt;
&lt;span class="c1"&gt;# if the tests failed&lt;/span&gt;
&lt;span class="nv"&gt;$srcdir&lt;/span&gt;/.gitlab-ci/meson-junit-report.py&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--project-name&lt;span class="o"&gt;=&lt;/span&gt;gtk&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--job-id&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CI_JOB_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--output&lt;span class="o"&gt;=&lt;/span&gt;_build/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CI_JOB_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;-report.xml&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;_build/meson-logs/testlog.json

&lt;span class="nb"&gt;exit&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;$exit_code&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which results in&amp;nbsp;this:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Some assembly required; those are &lt;span class="caps"&gt;XFAIL&lt;/span&gt; reftests, but JUnit doesn&amp;#8217;t understand the&amp;nbsp;concept&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gitlab-cover-report.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The JUnit cover report in GitLab is &lt;a href="https://gitlab.com/gitlab-org/gitlab-ce/issues/54067"&gt;only shown inside the merge request
summary&lt;/a&gt;, so it&amp;#8217;s not entirely useful if you&amp;#8217;re developing in a branch
without opening an &lt;span class="caps"&gt;MR&lt;/span&gt; immediately after you push to the repository. I prefer
working on feature branches and getting the &lt;span class="caps"&gt;CI&lt;/span&gt; to run on my changes without
necessarily having to care about opening the &lt;span class="caps"&gt;MR&lt;/span&gt; until my work is ready for
review—especially since GitLab is not a speed demon when it comes to MRs
with lots of rebases/fixup commits in them. Having a summary of the test
suite results in that case is still useful, so I wrote &lt;a href="https://gist.github.com/ebassi/0c6189bb9b414672ad36b9f984624843"&gt;a small conversion
script&lt;/a&gt; that takes the &lt;code&gt;testlog.json&lt;/code&gt; and turns it into
an &lt;span class="caps"&gt;HTML&lt;/span&gt; page, with a bit of &lt;a href="http://jinja.pocoo.org/"&gt;Jinja&lt;/a&gt; templating thrown into it to
avoid hardcoding the whole thing into string chunks. Like the JUnit
generator above, we can call the &lt;span class="caps"&gt;HTML&lt;/span&gt; generator right after running the test&amp;nbsp;suite:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nv"&gt;$srcdir&lt;/span&gt;/.gitlab-ci/meson-html-report.py&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--project-name&lt;span class="o"&gt;=&lt;/span&gt;GTK&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--job-id&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CI_JOB_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;--output&lt;span class="o"&gt;=&lt;/span&gt;_build/&lt;span class="si"&gt;${&lt;/span&gt;&lt;span class="nv"&gt;CI_JOB_NAME&lt;/span&gt;&lt;span class="si"&gt;}&lt;/span&gt;-report.html&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;_build/meson-logs/testlog.json
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then, we take the &lt;span class="caps"&gt;HTML&lt;/span&gt; file and store it as an&amp;nbsp;artifact:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nt"&gt;artifacts&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;when&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="l l-Scalar l-Scalar-Plain"&gt;always&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nt"&gt;paths&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="p p-Indicator"&gt;-&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;${CI_PROJECT_DIR}/_build/${CI_JOB_NAME}-report.html&amp;quot;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And GitLab will store it for us, so that we can download it or view it in
the web &lt;span class="caps"&gt;UI&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;There are additional improvements that can be made. For instance, the
reftests test suite in &lt;span class="caps"&gt;GTK&lt;/span&gt; generates images, and we&amp;#8217;re already uploading
them as artifacts; since the image names are stable and determined by the
test name, we can create a link to them in the &lt;span class="caps"&gt;HTML&lt;/span&gt; report itself, so we can
show the result of the failed tests. With some more fancy &lt;span class="caps"&gt;HTML&lt;/span&gt;, &lt;span class="caps"&gt;CSS&lt;/span&gt;, and
JavaScript, we could have a nicer output, with collapsible sections hiding
the full console log. If we had a place to upload test results from multiple
pipelines, we could even graph the trends in the test suite on a particular
branch, and track our&amp;nbsp;improvements.&lt;/p&gt;
&lt;p&gt;All of this is, of course, not incredibly novel; nevertheless, the network
effect of having a build system in Meson that lends itself to integration
with additional tooling, and a code hosting infrastructure with native &lt;span class="caps"&gt;CI&lt;/span&gt;
capabilities in GitLab, allows us to achieve really cool results with
minimal glue&amp;nbsp;code.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="ci"></category><category term="testing"></category></entry><entry><title>A little testing</title><link href="https://www.bassi.io/articles/2019/03/14/a-little-testing/" rel="alternate"></link><published>2019-03-14T15:01:00+00:00</published><updated>2023-02-20T00:32:32+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2019-03-14:/articles/2019/03/14/a-little-testing/</id><summary type="html">&lt;p&gt;In which I present a small testing framework for C&amp;nbsp;code&lt;/p&gt;</summary><content type="html">&lt;p&gt;Years ago I started writing &lt;a href="https://ebassi.github.io/graphene/"&gt;Graphene&lt;/a&gt; as a small library of 3D
transformation-related math types to be used by &lt;span class="caps"&gt;GTK&lt;/span&gt; (and possibly Clutter,
even if that didn&amp;#8217;t pan out until Georges &lt;a href="https://gitlab.gnome.org/GNOME/mutter/merge_requests/458"&gt;started working&lt;/a&gt;
on the Clutter fork inside&amp;nbsp;Mutter).&lt;/p&gt;
&lt;p&gt;Graphene&amp;#8217;s only requirement is a C99 compiler and a decent toolchain capable
of either taking &lt;span class="caps"&gt;SSE&lt;/span&gt; builtins or support vectorization on appropriately
aligned types. This means that, unless you decide to enable the GObject
types for each Graphene type, Graphene doesn&amp;#8217;t really need GLib types or
&lt;span class="caps"&gt;API&lt;/span&gt;—except that&amp;#8217;s a bit of a&amp;nbsp;lie.&lt;/p&gt;
&lt;p&gt;As I wanted to test what I was doing, Graphene has an optional build time
dependency on GLib for its test suite; the library itself may not use
anything from GLib, but if you want to build and run the test suite then you
need to have GLib&amp;nbsp;installed.&lt;/p&gt;
&lt;p&gt;This build time dependency makes testing Graphene on Windows a lot more
complicated than it ought to be. For instance, I need to install a ton of
packages when using the &lt;span class="caps"&gt;MSYS2&lt;/span&gt; toolchain on the &lt;span class="caps"&gt;CI&lt;/span&gt; instance on AppVeyor,
which takes roughly 6 minutes each for the 32bit and the 64bit builds; and I
can&amp;#8217;t build the test suite at all when using &lt;span class="caps"&gt;MSVC&lt;/span&gt;, because then I&amp;#8217;d have to
download and build GLib as well—and just to access the GTest &lt;span class="caps"&gt;API&lt;/span&gt;, &lt;em&gt;which I
don&amp;#8217;t even like&lt;/em&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;What&amp;#8217;s wrong with&amp;nbsp;GTest&lt;/h3&gt;
&lt;p&gt;&lt;a href="https://developer.gnome.org/glib/stable/glib-Testing.html"&gt;GTest&lt;/a&gt; is kind of problematic—outside of Google hijacking the
name of the &lt;span class="caps"&gt;API&lt;/span&gt; for their own testing framework, which makes looking for it
a pain. GTest is &lt;strong&gt;a lot&lt;/strong&gt; more complicated than a small unit testing &lt;span class="caps"&gt;API&lt;/span&gt;
needs to be, for starters; it was originally written to be used with a
specific harness, &lt;a href="https://developer.gnome.org/glib/stable/gtester.html"&gt;gtester&lt;/a&gt;, in order to generate a very brief
&lt;span class="caps"&gt;HTML&lt;/span&gt; report using &lt;a href="https://developer.gnome.org/glib/stable/gtester-report.html"&gt;gtester-report&lt;/a&gt;, including some
timing information on each unit—except that &lt;code&gt;gtester&lt;/code&gt; is now deprecated
because the build system gunk to make it work was terrible to deal with. So,
we pretty much told everyone to stop bothering, add a &lt;code&gt;--tap&lt;/code&gt; argument when
calling every test binary, and use the &lt;a href="https://testanything.org/"&gt;&lt;span class="caps"&gt;TAP&lt;/span&gt;&lt;/a&gt; harness in&amp;nbsp;Autotools.&lt;/p&gt;
&lt;p&gt;Of course, this means that the testing framework now has a completely
useless output format, and with it, a bunch of default behaviours driven by
said useless output format, and we&amp;#8217;re still deciding if we should break
backward compatibility to ensure that the supported output format has a sane
default&amp;nbsp;behaviour.&lt;/p&gt;
&lt;p&gt;On top of that, GTest piggybacks on GLib&amp;#8217;s own assertion mechanism, which
has two major&amp;nbsp;downsides:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;it can be disabled at compile time by defining &lt;code&gt;G_DISABLE_ASSERT&lt;/code&gt; before
   including &lt;code&gt;glib.h&lt;/code&gt;, which, surprise, people tend to use when releasing;
   thus, you can&amp;#8217;t run tests on builds that would most benefit from a test&amp;nbsp;suite&lt;/li&gt;
&lt;li&gt;it literally &lt;code&gt;abort()&lt;/code&gt;s the test unit, which breaks any test harness
   in existence that does not expect things to &lt;code&gt;SIGABRT&lt;/code&gt; midway through
   a test suite—which includes GLib&amp;#8217;s own deprecated &lt;code&gt;gtester&lt;/code&gt; harness&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;To solve the first problem we added a lot of wrappers around &lt;code&gt;g_assert()&lt;/code&gt;,
like &lt;code&gt;g_assert_true()&lt;/code&gt; and &lt;code&gt;g_assert_no_error()&lt;/code&gt;, that won&amp;#8217;t be disabled
depending on your build options and thus won&amp;#8217;t break your test suite—and if
your test suite is still using &lt;code&gt;g_assert()&lt;/code&gt;, you&amp;#8217;re strongly encouraged to
port to the newer &lt;span class="caps"&gt;API&lt;/span&gt;. The second issue is still standing, and makes running
GTest-based test suite under &lt;em&gt;any&lt;/em&gt; harness a pain, but especially under a
&lt;span class="caps"&gt;TAP&lt;/span&gt; harness, which requires listing the amount of tests you&amp;#8217;ve run, or that
you&amp;#8217;re planning to&amp;nbsp;run.&lt;/p&gt;
&lt;p&gt;The remaining issues of GTest are the convoluted way to add tests using a
unique path; the bizarre pattern matching &lt;span class="caps"&gt;API&lt;/span&gt; for warnings and errors; the
whole sub-process &lt;span class="caps"&gt;API&lt;/span&gt; that relaunches the test binary and calls a single
test unit in order to allow it to assert safely and capture its output. It&amp;#8217;s
very much &lt;strong&gt;the&lt;/strong&gt; GLib test suite, except when it tries to use non-GLib &lt;span class="caps"&gt;API&lt;/span&gt;
internally, like the command line option parser, or its own logging
primitives; it&amp;#8217;s also sorely lacking in the GObject/&lt;span class="caps"&gt;GIO&lt;/span&gt; side of things, so
you can&amp;#8217;t use standard &lt;span class="caps"&gt;API&lt;/span&gt; to create a mock GObject type, or a mock&amp;nbsp;GFile.&lt;/p&gt;
&lt;p&gt;If you want to contribute to GLib, then working on improving the GTest &lt;span class="caps"&gt;API&lt;/span&gt;
would be a good investment of your time; since my project does not depend on
GLib, though, I had the chance of starting with a clean&amp;nbsp;slate.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;A clean&amp;nbsp;slate&lt;/h3&gt;
&lt;p&gt;For the last couple of years I&amp;#8217;ve been playing off and on with a small test
framework &lt;span class="caps"&gt;API&lt;/span&gt;, mostly inspired by &lt;a href="https://en.wikipedia.org/wiki/Behavior-driven_development"&gt;&lt;span class="caps"&gt;BDD&lt;/span&gt;&lt;/a&gt; frameworks like
&lt;a href="https://mochajs.org/"&gt;Mocha&lt;/a&gt; and &lt;a href="https://jasmine.github.io/"&gt;Jasmine&lt;/a&gt;. &lt;em&gt;Behaviour Driven Development&lt;/em&gt; is
kind of a buzzword, like &lt;em&gt;test driven development&lt;/em&gt;, but I particularly like
the idea of describing a test suite in terms of &lt;em&gt;specifications&lt;/em&gt; and
&lt;em&gt;expectations&lt;/em&gt;: you specify what a piece of code does, and you match results
to your&amp;nbsp;expectations.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;API&lt;/span&gt; for describing the test suites is modelled on natural language
(assuming your language is English,&amp;nbsp;sadly):&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nx"&gt;describe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;your data type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kd"&gt;function&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;does something&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;doSomething&lt;/span&gt;&lt;span class="p"&gt;()).&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nx"&gt;it&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;can greet you&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;=&amp;gt;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;getHelloWorld&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="nx"&gt;expect&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;).&lt;/span&gt;&lt;span class="nx"&gt;not&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;toBe&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s2"&gt;&amp;quot;Goodbye World&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course, C is more verbose that JavaScript, but we can adopt a similar&amp;nbsp;mechanism:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;something&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;doSomething&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;bool_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;()),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;to_be&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;const&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_hello_world&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;expect&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;getHelloWorld&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;string_value&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;greeting&lt;/span&gt;&lt;span class="p"&gt;),&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="k"&gt;not&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;to_be&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;quot;Goodbye World&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="nb"&gt;NULL&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="n"&gt;type_suite&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;does something&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;do_something&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;it&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;can greet you&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;greet&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="err"&gt;…&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;describe&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;your data type&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;type_suite&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="err"&gt;…&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;If only C11 got blocks from Clang, this would look a lot less&amp;nbsp;clunkier.&lt;/p&gt;
&lt;p&gt;The value wrappers are also necessary, because C is only type safe as long
as every type you have is an&amp;nbsp;integer.&lt;/p&gt;
&lt;p&gt;Since we&amp;#8217;re good C citizens, we should namespace the &lt;span class="caps"&gt;API&lt;/span&gt;, which requires
naming this library—let&amp;#8217;s call it &lt;a href="https://github.com/ebassi/mutest"&gt;µTest&lt;/a&gt;, in a fit of&amp;nbsp;unoriginality.&lt;/p&gt;
&lt;p&gt;One of the nice bits of Mocha and Jasmine is the output of running a test&amp;nbsp;suite:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;./tests/general&lt;span class="w"&gt; &lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;General
&lt;span class="w"&gt;    &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;at&lt;span class="w"&gt; &lt;/span&gt;least&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;spec&lt;span class="w"&gt; &lt;/span&gt;with&lt;span class="w"&gt; &lt;/span&gt;an&lt;span class="w"&gt; &lt;/span&gt;expectation
&lt;span class="w"&gt;      &lt;/span&gt;✓&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;✓&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;219&lt;/span&gt;.00&lt;span class="w"&gt; &lt;/span&gt;µs&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;can&lt;span class="w"&gt; &lt;/span&gt;contain&lt;span class="w"&gt; &lt;/span&gt;multiple&lt;span class="w"&gt; &lt;/span&gt;specs
&lt;span class="w"&gt;      &lt;/span&gt;✓&lt;span class="w"&gt; &lt;/span&gt;str&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;✓&lt;span class="w"&gt; &lt;/span&gt;str&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;✓&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;fragments

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;145&lt;/span&gt;.00&lt;span class="w"&gt; &lt;/span&gt;µs&lt;span class="o"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;    &lt;/span&gt;should&lt;span class="w"&gt; &lt;/span&gt;be&lt;span class="w"&gt; &lt;/span&gt;skipped
&lt;span class="w"&gt;      &lt;/span&gt;-&lt;span class="w"&gt; &lt;/span&gt;skip&lt;span class="w"&gt; &lt;/span&gt;this&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;test&lt;/span&gt;

&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;31&lt;/span&gt;.00&lt;span class="w"&gt; &lt;/span&gt;µs&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;skipped


Total
&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;passing&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="m"&gt;810&lt;/span&gt;.00&lt;span class="w"&gt; &lt;/span&gt;µs&lt;span class="o"&gt;)&lt;/span&gt;
&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;skipped
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Or, with&amp;nbsp;colors:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Using colors means immediately taking this more&amp;nbsp;seriously&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/mutest-output-mocha.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The colours go automatically away if you redirect the output to something
that is not a &lt;span class="caps"&gt;TTY&lt;/span&gt;, so your logs won&amp;#8217;t be messed up by escape&amp;nbsp;sequences.&lt;/p&gt;
&lt;p&gt;If you have a test harness, then you can use the &lt;code&gt;MUTEST_OUTPUT&lt;/code&gt; environment
variable to control the output; for instance, if you&amp;#8217;re using &lt;span class="caps"&gt;TAP&lt;/span&gt; you&amp;#8217;ll&amp;nbsp;get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MUTEST_OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tap&lt;span class="w"&gt; &lt;/span&gt;./tests/general
&lt;span class="c1"&gt;# General&lt;/span&gt;
&lt;span class="c1"&gt;# contains at least a spec with an expectation&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;true&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;a&lt;span class="w"&gt; &lt;/span&gt;is&lt;span class="w"&gt; &lt;/span&gt;not&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;false&lt;/span&gt;
&lt;span class="c1"&gt;# can contain multiple specs&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;str&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;hello&amp;#39;&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;4&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;str&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;world&amp;#39;&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;5&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;contains&lt;span class="w"&gt; &lt;/span&gt;all&lt;span class="w"&gt; &lt;/span&gt;fragments
&lt;span class="c1"&gt;# should be skipped&lt;/span&gt;
ok&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="c1"&gt;# skip: skip this test&lt;/span&gt;
&lt;span class="m"&gt;1&lt;/span&gt;..6
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which can be passed through to &lt;code&gt;prove&lt;/code&gt; to&amp;nbsp;get:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;MUTEST_OUTPUT&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;tap&lt;span class="w"&gt; &lt;/span&gt;prove&lt;span class="w"&gt; &lt;/span&gt;./tests/general
./tests/general&lt;span class="w"&gt; &lt;/span&gt;..&lt;span class="w"&gt; &lt;/span&gt;ok
All&lt;span class="w"&gt; &lt;/span&gt;tests&lt;span class="w"&gt; &lt;/span&gt;successful.
&lt;span class="nv"&gt;Files&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;1&lt;/span&gt;,&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;Tests&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="m"&gt;6&lt;/span&gt;,&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;wallclock&lt;span class="w"&gt; &lt;/span&gt;secs&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;(&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;usr&lt;span class="w"&gt; &lt;/span&gt;+&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.00&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nv"&gt;sys&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="m"&gt;0&lt;/span&gt;.02&lt;span class="w"&gt; &lt;/span&gt;CPU&lt;span class="o"&gt;)&lt;/span&gt;
Result:&lt;span class="w"&gt; &lt;/span&gt;PASS
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;I&amp;#8217;m planning to add some additional output formatters, like &lt;span class="caps"&gt;JSON&lt;/span&gt; and &lt;span class="caps"&gt;XML&lt;/span&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Using&amp;nbsp;µTest&lt;/h3&gt;
&lt;p&gt;Ideally, µTest should be used as a sub-module or a Meson sub-project of your
own; if you&amp;#8217;re using it as a sub-project, you can tell Meson to build a
static library that won&amp;#8217;t get installed on your system,&amp;nbsp;e.g.:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;mutest_dep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;fallback&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest_dep&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;default_options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;static=true&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="nb"&gt;disabler&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;true&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="c"&gt;# Or, if you&amp;#39;re using Meson &amp;lt; 0.49.0&lt;/span&gt;
&lt;span class="n"&gt;mutest_dep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest-1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;not&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mutest_dep&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;mutest&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;subproject&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;default_options&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;static=true&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kc"&gt;false&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mutest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;found&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mutest_dep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;mutest&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;#39;mutest_dep&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;else&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="n"&gt;mutest_dep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nb"&gt;disabler&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;span class="k"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then you can make the tests conditional on &lt;code&gt;mutest_dep.found()&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;µTest is kind of experimental, and I&amp;#8217;m still breaking its &lt;span class="caps"&gt;API&lt;/span&gt; in places, as
a result of documenting it and trying it out, by &lt;a href="https://github.com/ebassi/graphene/tree/mutest"&gt;porting the Graphene test
suite to it&lt;/a&gt;. There&amp;#8217;s still
a bunch of &lt;span class="caps"&gt;API&lt;/span&gt; that I&amp;#8217;d like to land, like custom matchers/formatters for
complex data types, and a decent want to skip a specification or a whole
suite; plus, as I said above, some additional formatted&amp;nbsp;output.&lt;/p&gt;
&lt;p&gt;If you have feedback, feel free to open an issue—or a pull request &lt;em&gt;wink
wink nudge nudge&lt;/em&gt;.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="bdd"></category><category term="testing"></category></entry><entry><title>And I’m home</title><link href="https://www.bassi.io/articles/2018/12/14/and-im-home/" rel="alternate"></link><published>2018-12-14T19:00:00+00:00</published><updated>2018-12-14T19:26:22+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2018-12-14:/articles/2018/12/14/and-im-home/</id><summary type="html">&lt;p&gt;In which I talk about life this past year, and changing jobs from Endless to the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;Foundation&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;#8217;s almost the end of the year, so it&amp;#8217;s time for a recap of the previous
episodes, I&amp;nbsp;guess.&lt;/p&gt;
&lt;p&gt;The &lt;em&gt;tl;dr&lt;/em&gt; of 2018: started pretty much the same; massive dip in the
middle; and, finally, got better at the very&amp;nbsp;end.&lt;/p&gt;
&lt;p&gt;The first couple of months of the year were pretty good; had a good time at
the &lt;span class="caps"&gt;GTK&lt;/span&gt; hackfest and &lt;span class="caps"&gt;FOSDEM&lt;/span&gt;, and went to the Recipes hackfest in Yogyakarta
in&amp;nbsp;February.&lt;/p&gt;
&lt;p&gt;In March, my wife Marta was diagnosed with breast cancer; Marta already had
(different types of) cancer twice in her life, and had been in full
remission for a couple of years, which meant she was able to cope with the
mechanics of the process, but it was still a solid blow. Since she had
already gone through a round of radiotheraphy 20 years ago—which had likely
a hand in the cancer appearing now—her only option was surgery to remove the
whole breast tissue and the associated lymph nodes. Not fun, but surgery
went well, and she didn&amp;#8217;t even need chemotherapy, so all in all it could
have been way, way&amp;nbsp;worse.&lt;/p&gt;
&lt;p&gt;While Marta and I were dealing with that, I suddenly found myself out of a
job, after working five years at&amp;nbsp;Endless.&lt;/p&gt;
&lt;p&gt;To be fair, this left me with enough time to help out Marta while she was
recovering—which is why I didn&amp;#8217;t come to &lt;span class="caps"&gt;GUADEC&lt;/span&gt;. After Marta was back on her
feet, and was able to raise her right arm above her head, I took the first
vacation in, I think, about four years. I relaxed, read a bunch of books,
played some video games, built &lt;a href="https://www.instagram.com/p/Bq7R5HfhjR2/"&gt;many&lt;/a&gt;, &lt;a href="https://www.instagram.com/p/BppihJyBEMq/"&gt;many&lt;/a&gt;,
&lt;a href="https://www.instagram.com/p/Bm0hDJGD6Ki/"&gt;&lt;strong&gt;many&lt;/strong&gt;&lt;/a&gt; Gundam plastic models, recharged my batteries—and ended
up finally having time to spend on &lt;a href="https://www.bassi.io/articles/2018/10/25/history-of-gnome-episode-0/"&gt;a project that I had pushed back for a
while&lt;/a&gt;, because I really needed to add writing and producing 15 to 20
minutes of audio every week, after perusing thousands of email archives and
old web pages on the &lt;a href="http://web.archive.org/"&gt;Wayback Machine&lt;/a&gt;. Side note: donate to
the Wayback Machine, if you can. They provide a fundamental service for
everybody using the Web, and especially for people like me who want to trace
the history of things that happen on the&amp;nbsp;Web.&lt;/p&gt;
&lt;p&gt;Of course I couldn&amp;#8217;t stay home playing video games, recording podcasts, and
building gunplas forever, and so I had to figure out where to go to work
next, as I do enjoy being able to have a roof above my head, as well as
buying food and stuff. By a crazy random happenstance, the &lt;span class="caps"&gt;GNOME&lt;/span&gt; Foundation
announced that, thanks to a generous anonymous donation, it would start
hiring staff, and that one of the open positions was for a &lt;span class="caps"&gt;GTK&lt;/span&gt; developer. I
decided to apply, as, let&amp;#8217;s be honest, it&amp;#8217;s basically &lt;strong&gt;the&lt;/strong&gt; dream job for
me. I&amp;#8217;ve been contributing to &lt;span class="caps"&gt;GNOME&lt;/span&gt; components for about 15 years, and to
&lt;span class="caps"&gt;GTK&lt;/span&gt; for 12; and while I&amp;#8217;ve been paid to contribute to some &lt;span class="caps"&gt;GNOME&lt;/span&gt;-related
projects over the years, it was always as part of non-&lt;span class="caps"&gt;GNOME&lt;/span&gt; related&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;The hiring process was really thorough, but in the end I managed to land the
most amazing job I could possibly hope&amp;nbsp;for.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re wondering what I&amp;#8217;ll be working on, here&amp;#8217;s a rough&amp;nbsp;list:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;improving performance, especially on less powerful&amp;nbsp;devices&lt;/li&gt;
&lt;li&gt;identify and land new&amp;nbsp;features&lt;/li&gt;
&lt;li&gt;identify and fix pain points for current consumers of &lt;span class="caps"&gt;GTK&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;On top of that, I&amp;#8217;ll try to do my best to increase the awareness of the work
being done on both the &lt;span class="caps"&gt;GTK&lt;/span&gt; 3.x stable branch, and the 4.x development
branch, so expect more content appearing on the development&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;The overall idea is to ensure that &lt;span class="caps"&gt;GTK&lt;/span&gt; gets more exposure and mindshare in
the next 5 years as the main toolkit for Linux and Unix-like operating
systems, as well better functionality for application developers that want
to make sure their projects work on other&amp;nbsp;platforms.&lt;/p&gt;
&lt;p&gt;Finally, we want to make sure that more people feel confident enough to
contribute to the core application development platform; if you have your
pet feature or your pet bug inside &lt;span class="caps"&gt;GTK&lt;/span&gt;, and you want guidance, feel free
to reach out to&amp;nbsp;me.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hopefully, the next year will &lt;strong&gt;not&lt;/strong&gt; look like this one, and will be a
bit better. Of course, if we in the &lt;span class="caps"&gt;UK&lt;/span&gt; don&amp;#8217;t all die in the fiery chaos
that is the Brexit&amp;nbsp;circus…&lt;/p&gt;</content><category term="gnome"></category><category term="work"></category><category term="life"></category><category term="gnome"></category></entry><entry><title>The History of GNOME</title><link href="https://www.bassi.io/articles/2018/10/25/the-history-of-gnome/" rel="alternate"></link><published>2018-10-25T19:00:00+01:00</published><updated>2018-12-15T14:52:38+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2018-10-25:/articles/2018/10/25/the-history-of-gnome/</id><summary type="html">&lt;p&gt;In which I announce my podcast on the history of the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;project&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve done &lt;a href="https://www.bassi.io/category/history/podcast.xml"&gt;a thing&lt;/a&gt; which may be of interest if you&amp;#8217;re
following the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;community.&lt;/p&gt;
&lt;p&gt;As I said &lt;a href="https://twitter.com/ebassi/status/1055492942125821952"&gt;on Twitter&lt;/a&gt;, I have spare time, and I like boring
people to death by talking about things that matter to me a lot; one of the
things that matter to me is &lt;span class="caps"&gt;GNOME&lt;/span&gt; and its community—and especially its&amp;nbsp;history.&lt;/p&gt;
&lt;p&gt;Of course, I had to go and make it about &lt;em&gt;liminal spaces&lt;/em&gt; and &lt;em&gt;magic
rituals&lt;/em&gt;, because that&amp;#8217;s what makes it fun. This, though, &lt;strong&gt;is&lt;/strong&gt; a magic
ritual.  I&amp;#8217;m holding a &lt;em&gt;seance&lt;/em&gt;, and I&amp;#8217;m calling forth the past of the &lt;span class="caps"&gt;GNOME&lt;/span&gt;
project for the people that live down its&amp;nbsp;light-cone.&lt;/p&gt;
&lt;p&gt;&lt;span class="caps"&gt;GNOME&lt;/span&gt; has the luxury of having a lot of people that stuck around—some even
from the early days when there was no &lt;span class="caps"&gt;GNOME&lt;/span&gt;; there are also other people,
though, some of them born after Miguel&amp;#8217;s announcement, that are now starting
to contribute to &lt;span class="caps"&gt;GNOME&lt;/span&gt;. I guess that means that it&amp;#8217;s time to look back a
bit, and give some more context to the history of the&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;I hope I won&amp;#8217;t bore you that much with this; I hope that people will learn
something new, or re-discover something that was forgotten. In general, I do
hope people will have fun with&amp;nbsp;it.&lt;/p&gt;</content><category term="gnome"></category><category term="gnome"></category><category term="podcast"></category></entry><entry><title>Reference counting in modern GLib</title><link href="https://www.bassi.io/articles/2018/09/04/ref-counting/" rel="alternate"></link><published>2018-09-04T16:35:00+01:00</published><updated>2018-09-11T22:24:49+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2018-09-04:/articles/2018/09/04/ref-counting/</id><summary type="html">&lt;p&gt;In which I explain how to implement reference counting with new GLib ≥&amp;nbsp;2.58&lt;/p&gt;</summary><content type="html">&lt;p&gt;Reference counting is a fairly common garbage collection technique used in
many projects; the core &lt;span class="caps"&gt;GNOME&lt;/span&gt; platform uses pretty much all the time, from
container data types, to&amp;nbsp;GObject.&lt;/p&gt;
&lt;p&gt;Implementing reference counting in C is typically fairly easy. Add a field
to your data&amp;nbsp;type:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Then initialise it when creating a new&amp;nbsp;instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_new0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Instead of a &lt;code&gt;person_copy()&lt;/code&gt; and a &lt;code&gt;person_free()&lt;/code&gt; pair of functions, you
need to write a &lt;code&gt;person_ref()&lt;/code&gt; and a &lt;code&gt;person_unref()&lt;/code&gt; pair:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Acquire a reference&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="o"&gt;++&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="k"&gt;static&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;person_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Free the data&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Free the instance&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;person_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// Release a reference&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// If this was the last reference, free the data&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// associated to the instance and then the instance&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// itself&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;==&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;person_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Of course, &lt;em&gt;trivial&lt;/em&gt; doesn&amp;#8217;t mean &lt;em&gt;correct&lt;/em&gt;. For instance, the code above
assumes that all reference acquisition and release operations will happen
from the same thread; if that&amp;#8217;s not the case, you&amp;#8217;ll have to use atomic
integer operations to increase and decrease the reference count.
Additionally, the code above does not check for overflows in the reference
counting, which means that the value could saturate and lead to&amp;nbsp;leaks.&lt;/p&gt;
&lt;p&gt;Reimplementing all the checks and behaviours is not only boring, but it
inevitably leads to mistakes along the way. For this reason, GLib 2.58
introduced two new&amp;nbsp;types:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;grefcount&lt;/code&gt;, to implement simple reference&amp;nbsp;counting&lt;/li&gt;
&lt;li&gt;&lt;code&gt;gatomicrefcount&lt;/code&gt;, to implement atomic reference&amp;nbsp;counting&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Both come with their own &lt;span class="caps"&gt;API&lt;/span&gt;, which leads to this&amp;nbsp;code:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;grefcount&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// or: gatomicrefcount ref_count;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// same as above&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_new0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;1&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_ref_count_init&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// or: g_atomic_ref_count_init (&amp;amp;res-&amp;gt;ref_count);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;res&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_ref_count_inc&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// or: g_atomic_ref_count_inc (&amp;amp;p-&amp;gt;ref_count);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;person_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;if&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;g_ref_count_dec&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="o"&gt;&amp;amp;&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="o"&gt;-&amp;gt;&lt;/span&gt;&lt;span class="n"&gt;ref_count&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// or: if (g_atomic_ref_count_dec (&amp;amp;p-&amp;gt;ref_count))&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;      &lt;/span&gt;&lt;span class="n"&gt;person_free&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;    &lt;/span&gt;&lt;span class="p"&gt;}&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The &lt;code&gt;grefcount&lt;/code&gt; and &lt;code&gt;gatomicrefcount&lt;/code&gt; make it immediately obvious that the
field is used to implement reference counting semantics; the &lt;span class="caps"&gt;API&lt;/span&gt; checks for
saturation of the counters, and will emit a warning; the atomic operations
are verified. Additionally, the &lt;span class="caps"&gt;API&lt;/span&gt; checks if you&amp;#8217;re trying to pass an
atomic reference count to the &lt;code&gt;grefcount&lt;/code&gt; &lt;span class="caps"&gt;API&lt;/span&gt;, and vice versa, so you have a
layer of protection there during eventual refactoring, even if the types are
both integer&amp;nbsp;aliases.&lt;/p&gt;
&lt;p&gt;We did not stop there,&amp;nbsp;though.&lt;/p&gt;
&lt;p&gt;Adding a reference count field to a structure is not always possible; for
instance, if you have &lt;span class="caps"&gt;ABI&lt;/span&gt; compatibility restrictions, or if the type
defition is public, adding a field may just not be something you can do
within the same &lt;span class="caps"&gt;API&lt;/span&gt; version. By way of an example: you may have a type meant
to be typically placed on the stack, so it needs a public, complete
declaration, in order to have a well-defined size at compile time. You may
also want to pass around an instance of the type as the argument for a
GObject signal, or as a property — but it may be expensive to copy the data
around, so you really want to have an optional reference counting mechanism
that is invisible to the vast majority of the use&amp;nbsp;cases.&lt;/p&gt;
&lt;p&gt;This is why we also added an allocator function that adds reference
counting semantics to the memory areas it returns, called &lt;code&gt;GRcBox&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;typedef&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="k"&gt;struct&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;name&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;address&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;city&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="kt"&gt;int&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;age&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;;&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="kt"&gt;void&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_rc_box_new0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;
&lt;span class="nf"&gt;person_ref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="k"&gt;return&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_rc_box_acquire&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;

&lt;span class="kt"&gt;void&lt;/span&gt;
&lt;span class="nf"&gt;person_unref&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;Person&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// person_free() is copied from the code above; we use&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// g_rc_box_release_full() because we have data to free&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// as well, but there&amp;#39;s a variant for structures that&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// do not have internal allocations&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_rc_box_release_full&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;p&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;person_free&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, this cuts down the boilerplate and repetition&amp;nbsp;considerably.&lt;/p&gt;
&lt;p&gt;The data returned to you by &lt;code&gt;g_rc_box_new()&lt;/code&gt; and friends is exactly the same
as you&amp;#8217;d get from &lt;code&gt;g_new()&lt;/code&gt;, so you can pass it around to your &lt;span class="caps"&gt;API&lt;/span&gt; exactly
the same — but it is transparently augmented with reference counting
semantics. You acquire and release references without having an explicit
reference counter. The only restriction is that you cannot reallocate the
data, so calling &lt;code&gt;realloc()&lt;/code&gt; is not allowed; and, of course, you cannot free
the memory directly with &lt;code&gt;free()&lt;/code&gt; — you need to release the last&amp;nbsp;reference.&lt;/p&gt;
&lt;p&gt;Similar to &lt;code&gt;GRcBox&lt;/code&gt;, there&amp;#8217;s a &lt;code&gt;GAtomicRcBox&lt;/code&gt;, which provides atomic
reference counting semantics, with a similar &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Both &lt;code&gt;GRcBox&lt;/code&gt; and &lt;code&gt;GAtomicRcBox&lt;/code&gt; are Valgrind-safe, so you won&amp;#8217;t get false
positives or unreachable memory if run your code under&amp;nbsp;Valgrind.&lt;/p&gt;
&lt;p&gt;You don&amp;#8217;t even need to have a structure to allocate: you can use &lt;code&gt;GRcBox&lt;/code&gt; to
allocate any memory area with a non-zero size. Incidentally, this is how we
implemented a oft-requested feature: reference counted strings, which are
also available in GLib&amp;nbsp;2.58.&lt;/p&gt;
&lt;p&gt;Reference counted strings work exactly like any other C string, but instead
of copying them and freeing them, you acquire and release references to&amp;nbsp;them:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="kt"&gt;char&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_ref_string_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello, world!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// &amp;quot;s&amp;quot; is just like any other C string&lt;/span&gt;
&lt;span class="n"&gt;g_print&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;s[&amp;#39;%s&amp;#39;] length = %d&lt;/span&gt;&lt;span class="se"&gt;\n&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;strlen&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;));&lt;/span&gt;

&lt;span class="n"&gt;g_ref_string_release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Reference counted strings can also be interned, which means that calling
&lt;code&gt;g_ref_string_new_intern()&lt;/code&gt; with the same string twice will give you a new
reference the second time around, instead of allocating a new string; once
the last reference to the interned string is dropped, the string is
un-interned, and the resource allocated for it are&amp;nbsp;freed.&lt;/p&gt;
&lt;p&gt;Since you may be wary of passing around &lt;code&gt;char *&lt;/code&gt; for reference counted
strings, there&amp;#8217;s a handy &lt;code&gt;GRefString&lt;/code&gt; C type you can use to improve
readability, like we have &lt;code&gt;GStrv&lt;/code&gt; for &lt;code&gt;char **&lt;/code&gt;:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;GRefString&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_ref_string_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="c1"&gt;// ...&lt;/span&gt;

&lt;span class="n"&gt;g_ref_string_release&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;&lt;code&gt;GRefString&lt;/code&gt; also has an autocleanup function, so you can&amp;nbsp;do:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="p"&gt;{&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;g_autoptr&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;GRefString&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;g_ref_string_new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;hello!&amp;quot;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;

&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="c1"&gt;// ...&lt;/span&gt;
&lt;span class="p"&gt;}&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and the string will automatically be released once it goes out of&amp;nbsp;scope.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="glib"></category><category term="memory-management"></category></entry><entry><title>pkg-config and paths</title><link href="https://www.bassi.io/articles/2018/03/15/pkg-config-and-paths/" rel="alternate"></link><published>2018-03-15T16:45:00+00:00</published><updated>2018-03-15T17:00:50+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2018-03-15:/articles/2018/03/15/pkg-config-and-paths/</id><summary type="html">&lt;p&gt;In which I explain how to use paths and pkg-config&amp;nbsp;variables&lt;/p&gt;</summary><content type="html">&lt;p&gt;This is something of a frequently asked question, as it comes up every once
in a while. The &lt;a href="https://people.freedesktop.org/~dbn/pkg-config-guide.html"&gt;pkg-config&lt;/a&gt; documentation is fairly terse,
and even &lt;a href="http://pkgconf.org/"&gt;pkgconf&lt;/a&gt; hasn&amp;#8217;t improved on&amp;nbsp;that.&lt;/p&gt;
&lt;h3&gt;The&amp;nbsp;problem&lt;/h3&gt;
&lt;p&gt;Let&amp;#8217;s assume you maintain a project that has a dependency using&amp;nbsp;pkg-config.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s also assume that the project you are depending on loads some files
from a system path, and your project plans to install some files under that&amp;nbsp;path.&lt;/p&gt;
&lt;p&gt;The questions&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;how can the project you are depending on provide an appropriate way for
   you to discover where that path&amp;nbsp;is&lt;/li&gt;
&lt;li&gt;how can the project you maintain use that&amp;nbsp;information&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;The answer to both questions is: &lt;em&gt;by using variables in the pkg-config file&lt;/em&gt;.
Sadly, there&amp;#8217;s still some confusion as to how those variables work, so this
is my attempt at clarifying the&amp;nbsp;issue.&lt;/p&gt;
&lt;h3&gt;Defining variables in pkg-config&amp;nbsp;files&lt;/h3&gt;
&lt;p&gt;The typical preamble stanza of a pkg-config file is something like&amp;nbsp;this:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;prefix=/some/prefix
libdir=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/lib
datadir=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/share
includedir=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/include
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Each variable can reference other variables; for instance, in the example
above, all the other directories are relative to the &lt;code&gt;prefix&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Those variables that can be extracted via pkg-config&amp;nbsp;itself:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pkg-config&lt;span class="w"&gt; &lt;/span&gt;--variable&lt;span class="o"&gt;=&lt;/span&gt;includedir&lt;span class="w"&gt; &lt;/span&gt;project-a
/some/prefix/include
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;As you can see, the &lt;code&gt;--variable&lt;/code&gt; command line argument will automatically
expand the &lt;code&gt;${prefix}&lt;/code&gt; token with the content of the &lt;code&gt;prefix&lt;/code&gt; variable.&lt;/p&gt;
&lt;p&gt;Of course, you can define any and all variables inside your own pkg-config
file; for instance, this is the definition of the &lt;code&gt;giomoduledir&lt;/code&gt; variable
inside the &lt;code&gt;gio-2.0&lt;/code&gt; pkg-config&amp;nbsp;file:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;prefix=/usr
libdir=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;prefix&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/lib

…

giomoduledir=&lt;span class="cp"&gt;${&lt;/span&gt;&lt;span class="n"&gt;libdir&lt;/span&gt;&lt;span class="cp"&gt;}&lt;/span&gt;/gio/modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This way, the &lt;code&gt;giomoduledir&lt;/code&gt; variable will be expanded to
&lt;code&gt;/usr/lib/gio/modules&lt;/code&gt; when asking for&amp;nbsp;it.&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;If you are defining a path inside your project&amp;#8217;s pkg-config file,
&lt;strong&gt;always&lt;/strong&gt; make sure you&amp;#8217;re using a relative&amp;nbsp;path!&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;We&amp;#8217;re going to see why this is important in the next&amp;nbsp;section.&lt;/p&gt;
&lt;h3&gt;Using variables from pkg-config&amp;nbsp;files&lt;/h3&gt;
&lt;p&gt;Now, this is where things get&amp;nbsp;complicated.&lt;/p&gt;
&lt;p&gt;As I said above, pkg-config will expand the variables using the definitions
coming from the pkg-config file; so, in the example above, getting the
&lt;code&gt;giomoduledir&lt;/code&gt; will use the prefix provided by the &lt;code&gt;gio-2.0&lt;/code&gt; pkg-config
file, which is the prefix into which &lt;span class="caps"&gt;GIO&lt;/span&gt; was installed. This is all well and
good if you just want to know where &lt;span class="caps"&gt;GIO&lt;/span&gt; installed its own modules, in the
same way you want to know where its headers are installed, or where the
library is&amp;nbsp;located.&lt;/p&gt;
&lt;p&gt;What happens, though, if your own project needs to install &lt;span class="caps"&gt;GIO&lt;/span&gt; modules in a
shared location? More importantly, what happens if you&amp;#8217;re building your
project in a separate&amp;nbsp;prefix?&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re thinking: &amp;#8220;I should install it into the same location as specified
by the &lt;span class="caps"&gt;GIO&lt;/span&gt; pkg-config file&amp;#8221;, think again. What happens if you are building
against the system&amp;#8217;s &lt;span class="caps"&gt;GIO&lt;/span&gt; library? The prefix into which it has been
installed is only going to be accessible by the administrator user; or it
could be on a read-only volume, managed by libostree, so &lt;code&gt;sudo&lt;/code&gt; won&amp;#8217;t save&amp;nbsp;you.&lt;/p&gt;
&lt;p&gt;Since you&amp;#8217;re using a separate prefix, you really want to install the files
provided by your project under the prefix used to configure your project.
That does require knowing all the possible paths used by your dependencies,
hard coding them into your own project, and ensuring that they never&amp;nbsp;change.&lt;/p&gt;
&lt;p&gt;This is clearly not great, and it places additional burdens on your role as
a&amp;nbsp;maintainer.&lt;/p&gt;
&lt;p&gt;The correct solution is to tell pkg-config to expand variables using your
own&amp;nbsp;values:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;$&lt;span class="w"&gt; &lt;/span&gt;pkg-config&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;--define-variable&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="nv"&gt;prefix&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;/your/prefix&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="se"&gt;\&lt;/span&gt;
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;--variable&lt;span class="o"&gt;=&lt;/span&gt;giomoduledir
&amp;gt;&lt;span class="w"&gt; &lt;/span&gt;gio-2.0
/your/prefix/lib/gio/modules
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This lets you rely on the paths as defined by your dependencies, and does
not attempt to install files in locations you don&amp;#8217;t have access&amp;nbsp;to.&lt;/p&gt;
&lt;h3&gt;Build&amp;nbsp;systems&lt;/h3&gt;
&lt;p&gt;How does this work, in practice, when building your own&amp;nbsp;software?&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re using &lt;a href="http://mesonbuild.com"&gt;Meson&lt;/a&gt;, you can use the
&lt;code&gt;get_pkgconfig_variable()&lt;/code&gt; method of the &lt;code&gt;dependency&lt;/code&gt; object, making sure to
replace&amp;nbsp;variables:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;gio_dep&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gio-2.0&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;giomoduledir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gio_dep&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_pkgconfig_variable&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;giomoduledir&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;define_variable&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;[&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;libdir&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;get_option&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;libdir&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;],&lt;/span&gt;
&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This is the equivalent of the &lt;code&gt;--define-variable/--variable&lt;/code&gt; command line&amp;nbsp;arguments.&lt;/p&gt;
&lt;p&gt;If you are using Autotools, sadly, the &lt;code&gt;PKG_CHECK_VAR&lt;/code&gt; m4 macro won&amp;#8217;t be
able to help you, because it does not allow you to expand variables. This
means you&amp;#8217;ll have to deal with it in the old fashioned&amp;nbsp;way:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;giomoduledir&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;PKG_CONFIG&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;define&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;libdir&lt;/span&gt;&lt;span class="o"&gt;=$&lt;/span&gt;&lt;span class="n"&gt;libdir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;variable&lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="n"&gt;giomoduledir&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;gio&lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;2.0&lt;/span&gt;&lt;span class="err"&gt;`&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Which is annoying, and yet another reason why you should move off from
Autotools and to Meson.&amp;nbsp;😃&lt;/p&gt;
&lt;h3&gt;Caveats&lt;/h3&gt;
&lt;p&gt;All of this, of course, works &lt;strong&gt;only&lt;/strong&gt; if paths are expressed as locations
relative to other variables. If that does not happen, you&amp;#8217;re going to have a
bad time. You&amp;#8217;ll still get the variable as requested, but you won&amp;#8217;t be able
to make it relative to your&amp;nbsp;prefix.&lt;/p&gt;
&lt;p&gt;If you maintain a project with paths expressed as variables in your
pkg-config file, check them now, and make them relative to existing
variables, like &lt;code&gt;prefix&lt;/code&gt;, &lt;code&gt;libdir&lt;/code&gt;, or &lt;code&gt;datadir&lt;/code&gt;.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re using Meson to generate your pkg-config file, make sure that the
paths are relative to other variables, and file bugs if they&amp;nbsp;aren&amp;#8217;t.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category></entry><entry><title>Recipes hackfest</title><link href="https://www.bassi.io/articles/2018/03/02/recipes-hackfest-2018/" rel="alternate"></link><published>2018-03-02T01:50:00+01:00</published><updated>2023-02-20T00:36:55+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2018-03-02:/articles/2018/03/02/recipes-hackfest-2018/</id><summary type="html">&lt;p&gt;In which I recap the Recipes hackfest held in&amp;nbsp;Yogyakarta&lt;/p&gt;</summary><content type="html">&lt;p&gt;The Recipes application started as a celebration of &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;#8217;s community and
history, and it&amp;#8217;s grown to be a great showcase for what &lt;span class="caps"&gt;GNOME&lt;/span&gt; is&amp;nbsp;about:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;design guidelines and attention to&amp;nbsp;detail&lt;/li&gt;
&lt;li&gt;a software development platform for modern&amp;nbsp;applications&lt;/li&gt;
&lt;li&gt;new technologies, strongly integrated with the &lt;span class="caps"&gt;OS&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;people-centered&amp;nbsp;development&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, Recipes has become a place where to iterate design and
technology for the rest of the &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;applications.&lt;/p&gt;
&lt;p&gt;Nevertheless, while design patterns, toolkit features, Flatpak and portals,
are part of the development experience, without content provided by the
people using Recipes there would not be an application to begin&amp;nbsp;with.&lt;/p&gt;
&lt;p&gt;If we look at the work Endless has been doing on its own
&lt;a href="https://endlessm.github.io/eos-knowledge-lib"&gt;framework&lt;/a&gt; for content-driven applications, there&amp;#8217;s a
natural fit — which is why I was really happy to attend the &lt;a href="https://wiki.gnome.org/Hackfests/Recipes2018"&gt;Recipes
hackfest&lt;/a&gt; in Yogyakarta, this&amp;nbsp;week.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Fried Jawanese noodle make a healty&amp;nbsp;breakfast&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/fried-jawanese-noodles.jpg"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;In the Endless framework we take structured data — like a web page, or a &lt;span class="caps"&gt;PDF&lt;/span&gt;
document, or a mix of video and text — and we construct &amp;#8220;shards&amp;#8221;, which
embed both the content, its metadata, and a &lt;a href="http://xapian.org"&gt;Xapian&lt;/a&gt; database that
can be used for querying the data. We take the shards and distribute them
though &lt;a href="https://flatpak.org"&gt;Flatpak&lt;/a&gt; as a runtime extension for our applications, which
means we can take advantage of Flatpak for shipping updates&amp;nbsp;efficiently.&lt;/p&gt;
&lt;p&gt;During the hackfest we talked about how to take advantage of the data model
Endless applications use, as well as its distribution model; instead of
taking tarballs with the recipe text, the images, and the metadata attached
to each, we can create shards that can be mapped to a custom data model.
Additionally, we can generate those shards locally when exporting the
recipes created by new chefs, and easily re-integrate them with the shared
recipe shards — with the possibility, in the future, to have a whole web
application that lets you submit new recipes, and the maintainers review
them without necessarily going through Matthias&amp;#8217;s email.&amp;nbsp;😉&lt;/p&gt;
&lt;p&gt;The data model discussion segued into how to display that data. The Endless
framework has the concept of &lt;a href="https://vimeo.com/120858063"&gt;cards&lt;/a&gt;, which are context-aware
data views; depending on context, they can have more or less details exposed
to the user — and all those details are populated from the data model
itself. Recipes has custom widgets that do a very similar job, so we talked
about how to create a shared layer that can be reused both by Endless
applications and by &lt;span class="caps"&gt;GNOME&lt;/span&gt;&amp;nbsp;applications.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Sadly, I don&amp;#8217;t remember the name of this soup, only that it had chicken hearts in it, and that Cosimo loved&amp;nbsp;it&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/unnamed-soup.jpg"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;At the end of the hackfest we were able to have a proof of concept of
Recipes loading the data from a custom shard, and using the Endless
framework to display it; translating that into shareable code and libraries
that can be used by other projects is the next step of the&amp;nbsp;roadmap.&lt;/p&gt;
&lt;p&gt;All of this, of course, will benefit more than just the Recipes application.
For instance, we could have a Dictionary application that worked offline,
and used Wiktionary as a source, and allowed better queries than just
substring matching; we could have applications like Photos and Documents
reuse the same &lt;span class="caps"&gt;UI&lt;/span&gt; elements as Recipes for their collection views; Software
and Recipes already share a similar &amp;#8220;landing page&amp;#8221; design (and widgets),
which means that Software could also use the &amp;#8220;card&amp;#8221; &lt;span class="caps"&gt;UI&lt;/span&gt;&amp;nbsp;elements.&lt;/p&gt;
&lt;p&gt;There&amp;#8217;s lots for everyone to do, but exciting times are&amp;nbsp;ahead!&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;And after we&amp;#8217;re done we can relax by the&amp;nbsp;pool&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/poolside.jpg"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;I&amp;#8217;d be remiss if I didn&amp;#8217;t thank our hosts at the &lt;a href="http://www.amikom.ac.id"&gt;Amikom university&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Yogyakarta is a great city; I&amp;#8217;ve never been in Indonesia before, and I&amp;#8217;ve
greatly enjoyed my time here. There&amp;#8217;s lots to see, and I strongly recommend
visiting. I&amp;#8217;ve loved the food, and the people&amp;#8217;s&amp;nbsp;warmth.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d like to thank my employer, Endless, for letting me take some time to
attend the hackfest; and the &lt;span class="caps"&gt;GNOME&lt;/span&gt; Foundation, for sponsoring my&amp;nbsp;travel.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;The travelling&amp;nbsp;Wilber&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/wilber-in-motion.jpg"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;div style="text-align:center"&gt;
  &lt;img class="center" src="https://www.bassi.io/images/sponsored-badge-simple.png" alt="Sponsored by the GNOME Foundation"/&gt;
&lt;/div&gt;</content><category term="gnome"></category><category term="hackfest"></category><category term="recipes"></category><category term="gtk"></category><category term="design"></category></entry><entry><title>GLib tools rewrite</title><link href="https://www.bassi.io/articles/2017/10/13/glib-tools/" rel="alternate"></link><published>2017-10-13T12:39:00+01:00</published><updated>2017-10-13T16:21:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-10-13:/articles/2017/10/13/glib-tools/</id><summary type="html">&lt;p class="first last"&gt;In which I make a public service announcement about the small utilities provided by&amp;nbsp;GLib&lt;/p&gt;
</summary><content type="html">&lt;p&gt;You can safely skip this article if you&amp;#8217;re not building software using
enumeration types and signal handlers; or if you&amp;#8217;re already using &lt;a class="reference external" href="http://mesonbuild.com"&gt;Meson&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;For more that 15 years, GLib has been shipping with two small&amp;nbsp;utilities:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt;, which scans a list of header files and generates &lt;tt class="docutils literal"&gt;GEnum&lt;/tt&gt;
and &lt;tt class="docutils literal"&gt;GFlags&lt;/tt&gt; types out of them, for use in GObject properties and&amp;nbsp;signals&lt;/li&gt;
&lt;li&gt;&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt;, which reads a file containing a description of marshaller
functions, and generates C code for you to use when declaring&amp;nbsp;signals&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you update to GLib 2.54, released in September 2017, you may notice that the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt; tools have become sligly more verbose and
slightly more strict about their&amp;nbsp;input.&lt;/p&gt;
&lt;p&gt;During the 2.54 development cycle, both utilities have been rewritten in Python
from a fairly ancient Perl, in the case of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt;; and from C, in the
case of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt;. This port was done to address the proliferation of
build time dependencies on GLib; the cross-compilation hassle of having a small
C utility being built and used during the build; and the move to Meson as the
default (and hopefully only) build system for future versions of GLib. Plus, the
port introduced colorised output, and we all know everything looks better with&amp;nbsp;colors.&lt;/p&gt;
&lt;p&gt;Sadly, none of the behaviours and expected input or output of both tools have
ever been documented, specified, or tested in any way. Additionally, it turns
out that lots of people either figured out how to exploit undefined behaviour,
or simply cargo-culted the use of these tools into their own project. This is
entirely on us, and I&amp;#8217;m going to try and provide &lt;a class="reference external" href="https://bugzilla.gnome.org/show_bug.cgi?id=788948"&gt;better documentation&lt;/a&gt; to both
tools in the form of a decent man page, with examples of integration inside
Autotools-based&amp;nbsp;projects.&lt;/p&gt;
&lt;p&gt;In the interest of keeping old projects building, both utilities will try to
replicate the undefined behaviours as much as possible, but now you&amp;#8217;ll get a
warning instead of the silent treatment, and maybe you&amp;#8217;ll get a chance at
fixing your&amp;nbsp;build.&lt;/p&gt;
&lt;p&gt;If you are maintaining a project using those two utilities, these are the
things to watch out for, and ideally to fix by strictly depending on
GLib ≥&amp;nbsp;2.54.&lt;/p&gt;
&lt;div class="section" id="glib-genmarshal"&gt;
&lt;h2&gt;glib-genmarshal&lt;/h2&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;if you&amp;#8217;re using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt; &lt;span class="pre"&gt;--header&lt;/span&gt; &lt;span class="pre"&gt;--body&lt;/span&gt;&lt;/tt&gt; to avoid the &amp;#8220;missing
prototypes&amp;#8221; compiler warning when compiling the generated marshallers
source file, please switch to using &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--prototypes&lt;/span&gt; &lt;span class="pre"&gt;--body&lt;/span&gt;&lt;/tt&gt;. This will
ensure you&amp;#8217;ll get &lt;strong&gt;only&lt;/strong&gt; the prototypes in the source file, instead of
a whole copy of the&amp;nbsp;header.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;Similarly, if you&amp;#8217;re doing something like the stanza below in order to
include the header inside the&amp;nbsp;body:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
foo-marshal.h: foo-marshal.list Makefile
        $(AM_V_GEN) \
          $(GLIB_GENMARSHAL) --header foo-marshal.list \
        &amp;gt; foo-marshal.h
foo-marshal.c: foo-marshal.h
        $(AM_V_GEN) (
          echo '#include &amp;quot;foo-marshal.h&amp;quot;' ; \
          $(GLIB_GENMARSHAL) --body foo-marshal.list \
        ) &amp;gt; foo-marshal.c
&lt;/pre&gt;
&lt;p&gt;you can use the newly added &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--include-header&lt;/span&gt;&lt;/tt&gt; command line argument,&amp;nbsp;instead.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;The stanza above has also been used to inject &lt;tt class="docutils literal"&gt;#define&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;#undef&lt;/tt&gt;
pre-processor directives; these can be replaced with the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-D&lt;/span&gt;&lt;/tt&gt; and
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;-U&lt;/span&gt;&lt;/tt&gt; newly added command line arguments, which work just like the
&lt;span class="caps"&gt;GCC&lt;/span&gt;&amp;nbsp;ones.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;This is not something that came from the Python port, as it&amp;#8217;s been
true since the inclusion of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt; in GLib, &lt;strong&gt;17 years ago&lt;/strong&gt;:
the &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;NONE&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;BOOL&lt;/span&gt;&lt;/tt&gt; tokens are deprecated, and should &lt;em&gt;not&lt;/em&gt; be
used; use &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;VOID&lt;/span&gt;&lt;/tt&gt; and &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;BOOLEAN&lt;/span&gt;&lt;/tt&gt;, respectively. The new version of
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt; will now properly warn about this, instead of just
silently converting them, and never letting you know you should fix
your marshal.list&amp;nbsp;file.&lt;/p&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;If you want to silence all messages outside of errors, you can now use the
&lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--quiet&lt;/span&gt;&lt;/tt&gt; command line option; conversely, use &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;--verbose&lt;/span&gt;&lt;/tt&gt; if you want
to get more&amp;nbsp;messages.&lt;/p&gt;
&lt;/div&gt;
&lt;div class="section" id="glib-mkenums"&gt;
&lt;h2&gt;glib-mkenums&lt;/h2&gt;
&lt;p&gt;The &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt; port has been much more painful than the marshaller
generator one; mostly, because there are many, many more ways to screw up
code generation when you have command line options and file templates, and
mostly because the original code base relied heavily on Perl behaviour and
side effects. Cargo culting Autotools stanzas is also much more of a thing
when it comes to enumerations than marshallers, apparently. Imagine what
we could achieve if the tools that we use to build our code didn&amp;#8217;t actively
work against&amp;nbsp;us.&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;p class="first"&gt;First of all, try and avoid having mixed encoding inside source code
files that are getting parsed; mixing Unicode and &lt;span class="caps"&gt;ISO&lt;/span&gt;-8859 encoding is
not a great plan, and C does not have a way to specify the encoding
to begin with. Yes, you may be doing that inside comments, so who
cares? Well, &lt;em&gt;a tool that parses comments might&lt;/em&gt;.&lt;/p&gt;
&lt;/li&gt;
&lt;li&gt;&lt;p class="first"&gt;If you&amp;#8217;re mixing template files with command line arguments for some
poorly thought-out reason, like&amp;nbsp;this:&lt;/p&gt;
&lt;pre class="literal-block"&gt;
foo-enums.h: foo-enums.h.in Makefile
        $(AM_V_GEN) $(GLIB_MKENUMS) \
          --fhead '#ifdef FOO_ENUMS_H' \
          --fhead '#defineFOO_ENUMS_H' \
          --template foo-enums.h.in \
          --ftail '#endif /* FOO_ENUMS_H */' \
        &amp;gt; foo-enums.h
&lt;/pre&gt;
&lt;p&gt;the old version of &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt; would basically build templates
depending on the phase of the moon, as well as some internal detail
of how Perl works. The new tool has a specified&amp;nbsp;order:&lt;/p&gt;
&lt;ul class="simple"&gt;
&lt;li&gt;the &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;HEAD&lt;/span&gt;&lt;/tt&gt; stanzas specified on the command line are always prepended
to the template&amp;nbsp;file&lt;/li&gt;
&lt;li&gt;the &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;PROD&lt;/span&gt;&lt;/tt&gt; stanzas specified on the command line are always appended
to the template&amp;nbsp;file&lt;/li&gt;
&lt;li&gt;the &lt;tt class="docutils literal"&gt;&lt;span class="caps"&gt;TAIL&lt;/span&gt;&lt;/tt&gt; stanzas specified on the command line are always appended
to the template&amp;nbsp;file&lt;/li&gt;
&lt;/ul&gt;
&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Like with &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt;, the &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt; tool also tries to be
more verbose in what it&amp;nbsp;expects.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;Ideally, by this point, you should have switched to &lt;a class="reference external" href="http://mesonbuild.com"&gt;Meson&lt;/a&gt;, and you&amp;#8217;re now
using a sane build system that generates this stuff for&amp;nbsp;you.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re still stuck with Autotools, though, you may also want to consider
dropping &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-genmarshal&lt;/span&gt;&lt;/tt&gt;, and use the &lt;span class="caps"&gt;FFI&lt;/span&gt;-based generic marshaller in
your signal definitions — which comes at a small performance cost, but if
you&amp;#8217;re putting signal emission inside a performance-critical path you should
just be ashamed of&amp;nbsp;yourself.&lt;/p&gt;
&lt;p&gt;For enumerations, you could use something like &lt;a class="reference external" href="https://github.com/endlessm/xapian-glib/blob/master/xapian-glib/xapian-enums.cc#L22"&gt;this macro&lt;/a&gt;, which I tend
to employ in all my projects with just few, small enumeration types, and
where involving a whole separate pass at parsing C files is kind of overkill.
Ideally, GLib &lt;a class="reference external" href="https://bugzilla.gnome.org/show_bug.cgi?id=627241"&gt;would ship its own version&lt;/a&gt;, so maybe it&amp;#8217;ll be replaced
in a new&amp;nbsp;version.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;Many thanks to Jussi Pakkanen, Nirbheek Chauhan, Tim-Philipp Müller, and
Christoph Reiter for the work on porting &lt;tt class="docutils literal"&gt;&lt;span class="pre"&gt;glib-mkenums&lt;/span&gt;&lt;/tt&gt;, as well as
fixing my awful&amp;nbsp;Parseltongue.&lt;/p&gt;
&lt;/div&gt;
</content><category term="gnome"></category><category term="gnome"></category><category term="development"></category><category term="glib"></category><category term="autotools"></category></entry><entry><title>GUADEC 2017</title><link href="https://www.bassi.io/articles/2017/08/11/2017-guadec/" rel="alternate"></link><published>2017-08-11T13:45:00+01:00</published><updated>2017-08-11T14:33:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-08-11:/articles/2017/08/11/2017-guadec/</id><summary type="html">&lt;p class="first last"&gt;In which I report my activities at &lt;span class="caps"&gt;GUADEC&lt;/span&gt;&amp;nbsp;2017&lt;/p&gt;
</summary><content type="html">&lt;p&gt;Another year, another &lt;a class="reference external" href="https://2017.guadec.org"&gt;&lt;span class="caps"&gt;GUADEC&lt;/span&gt;&lt;/a&gt; — my 13th to date. Definitely not getting
younger, here.&amp;nbsp;😉&lt;/p&gt;
&lt;p&gt;As usual, it was great to see so many faces, old and new. Lots of faces,
as well; attendance has been really good, this&amp;nbsp;year.&lt;/p&gt;
&lt;p&gt;The 20th anniversary party was a blast; the venue was brilliant, and
watching people going around the tables in order to fill in slots for the
raffle tickets was hilarious. I loved every minute of it — even if the
&amp;#8216;90s music was an assault on my teenage years. See above, re: getting&amp;nbsp;older.&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;Waiting for the &lt;a href="https://twitter.com/hashtag/GnomeParty?src=hash"&gt;#GnomeParty&lt;/a&gt; raffle to begin &lt;a href="https://t.co/BdCQDgV6UZ"&gt;pic.twitter.com/BdCQDgV6UZ&lt;/a&gt;&lt;/p&gt;&amp;mdash; Emmanuele Bassi (@ebassi) &lt;a href="https://twitter.com/ebassi/status/891390130900140032"&gt;July 29, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;&lt;p&gt;The talks were, as usual, stellar. It&amp;#8217;s always so hard to chose from the
embarrassment of riches that is the submission pool, but every year I
think the quality of what ends up on the schedule is so high that I cannot
be&amp;nbsp;sad.&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;First &lt;a href="https://twitter.com/hashtag/guadec2017?src=hash"&gt;#guadec2017&lt;/a&gt; keynote by &lt;a href="https://twitter.com/o0karen0o"&gt;@o0karen0o&lt;/a&gt; - “The Battle over our technology” &lt;a href="https://t.co/P0WnlASxe1"&gt;pic.twitter.com/P0WnlASxe1&lt;/a&gt;&lt;/p&gt;&amp;mdash; Emmanuele Bassi (@ebassi) &lt;a href="https://twitter.com/ebassi/status/890921497937584128"&gt;July 28, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;Flatpaks for the Flatpak throne! &lt;a href="https://twitter.com/hashtag/guadec2017?src=hash"&gt;#guadec2017&lt;/a&gt; &lt;a href="https://t.co/RrfLRdlgGN"&gt;pic.twitter.com/RrfLRdlgGN&lt;/a&gt;&lt;/p&gt;&amp;mdash; Emmanuele Bassi (@ebassi) &lt;a href="https://twitter.com/ebassi/status/890882943270440960"&gt;July 28, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;&lt;p&gt;Lots and lots of people were happy to see the &lt;a class="reference external" href="https://endlessos.com/"&gt;Endless&lt;/a&gt; contingent at the
conference; the talks from my colleagues were really well received, and
I&amp;#8217;m sure we&amp;#8217;re going to see even more collaboration spring from the seeds
planted this&amp;nbsp;year.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;My &lt;a class="reference external" href="https://ebassi.github.io/2017-guadec"&gt;talk&lt;/a&gt; about continuous integration in &lt;span class="caps"&gt;GNOME&lt;/span&gt; was well-received, I think;
I had to speed up a bit at the end because I lost time while connecting to
the projector (not enough juice when on battery to power the &lt;span class="caps"&gt;HDMI&lt;/span&gt;-over-&lt;span class="caps"&gt;USB&lt;/span&gt;
C connector; lesson learned for the next talk). I would have liked to get
some more time to explain what I&amp;#8217;d like to achieve with &lt;a class="reference external" href="https://build.gnome.org"&gt;Continuous&lt;/a&gt;.&lt;/p&gt;
&lt;figure&gt;
   &lt;figcaption class="image-caption"&gt;
     &lt;p&gt;Do not disturb the build&amp;nbsp;sheriff&lt;/p&gt;
   &lt;/figcaption&gt;
   &lt;div&gt;&lt;img src="https://www.bassi.io/images/do-not-disturb.jpg"/&gt;&lt;/div&gt;
&lt;/figure&gt;&lt;p&gt;I ended up talking with many people at the unconference days, in any case.
If you&amp;#8217;re interested in helping out the automated build of &lt;span class="caps"&gt;GNOME&lt;/span&gt; components
and to improve the reliability of the project, feel free to drop by on
irc.gnome.org (or on Matrix!) in the &lt;tt class="docutils literal"&gt;#testable&lt;/tt&gt; channel.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;The &lt;a class="reference external" href="https://wiki.gnome.org/GUADEC/2017/Unconference/"&gt;unconference&lt;/a&gt; days were also very productive, for me. The &lt;span class="caps"&gt;GTK&lt;/span&gt;+ session
was, as usual, a great way to plan ahead for the future; last year we
defined the new &lt;a class="reference external" href="https://blog.gtk.org/2016/09/01/versioning-and-long-term-stability-promise-in-gtk/"&gt;release cycle&lt;/a&gt; for &lt;span class="caps"&gt;GTK&lt;/span&gt;+ and jump start the 4.0 development
cycle. This year we drafted a &lt;a class="reference external" href="https://wiki.gnome.org/Projects/GTK%2B/Roadmap/GTK4"&gt;roadmap&lt;/a&gt; with the remaining&amp;nbsp;tasks.&lt;/p&gt;
&lt;p&gt;I talked about Flatpak, FlatHub, Builder, performance in Mutter and &lt;span class="caps"&gt;GNOME&lt;/span&gt;
Shell; I wanted to attend the Rust and &lt;span class="caps"&gt;GJS&lt;/span&gt; sessions, but that would have
required the ability to clone myself, or be in more than one place at&amp;nbsp;once.&lt;/p&gt;
&lt;p&gt;During the unconference, I was also able to finally finish the &lt;span class="caps"&gt;GDK&lt;/span&gt;-Pixbuf
port of the build system to &lt;a class="reference external" href="http://mesonbuild.com"&gt;Meson&lt;/a&gt;. Testing is very much welcome, before
we bin the Autotools build and bring one of the oldest modules in &lt;span class="caps"&gt;GNOME&lt;/span&gt;
into the&amp;nbsp;future.&lt;/p&gt;
&lt;p&gt;Additionally, I was invited to the &lt;span class="caps"&gt;GNOME&lt;/span&gt; Release Team, mostly to deal with
the various continuous integration build issues. This, sadly, does not mean
that I&amp;#8217;m one step closer to my ascendance as the power mad dictator of all
of &lt;span class="caps"&gt;GNOME&lt;/span&gt;, but it means that if there are issues with your module, you have
a more-or-less official point of&amp;nbsp;contact.&lt;/p&gt;
&lt;hr class="docutils" /&gt;
&lt;p&gt;I can&amp;#8217;t wait for &lt;span class="caps"&gt;GUADEC&lt;/span&gt; 2018! See you all in&amp;nbsp;Almería!&lt;/p&gt;
</content><category term="gnome"></category><category term="guadec"></category><category term="gnome"></category><category term="conferences"></category><category term="activities"></category></entry><entry><title>Dev v Ops</title><link href="https://www.bassi.io/articles/2017/08/10/dev-v-ops/" rel="alternate"></link><published>2017-08-10T16:51:00+01:00</published><updated>2017-08-10T18:55:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-08-10:/articles/2017/08/10/dev-v-ops/</id><summary type="html">&lt;p&gt;In which application development and packaging are discussed, vis-a-vis old and new&amp;nbsp;practices&lt;/p&gt;</summary><content type="html">&lt;p&gt;In &lt;a href="https://2017.guadec.org/talks-and-events/#abstract-1-resurrecting_dinosaurs_what_can_possibly_go_wrong"&gt;his talk&lt;/a&gt; at the 2017 &lt;span class="caps"&gt;GUADEC&lt;/span&gt; in Manchester, Richard Brown
presented a set of objections to the current trend of new packaging systems
— mostly AppImage, Snap, and Flatpak — from the perspective of a Linux
distribution&amp;nbsp;integrator.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m not entirely sure he managed to convince everybody in the attendance,
but he definitely presented a well-reasoned argument, steeped in history. I
freely admit I went in not expecting to be convinced, but fully expecting to
be engaged and I can definitely say I left the room thoroughly satisfied,
and full of questions on how we can make the application development and
distribution story on Linux much better. Talking with other people involved
with &lt;a href="http://flatpak.org"&gt;Flatpak&lt;/a&gt; and &lt;a href="https://flathub.org"&gt;Flathub&lt;/a&gt; we already identified
various places where things need to be improved, and how to set up automated
tools to ensure we don&amp;#8217;t&amp;nbsp;regress.&lt;/p&gt;
&lt;p&gt;In the end, though, all I could think of in order to summarise it when
describing the presentation to people that did not attend it, was&amp;nbsp;this:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;Linux distribution developer tells application and system developers that
packaging is a solved problem, as long as everyone uses the same &lt;span class="caps"&gt;OS&lt;/span&gt;,
distribution, tools, and becomes a distro&amp;nbsp;packager.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;Which, I&amp;#8217;m the first to admit, seems to subject the presentation to
impressive levels of lossy compression. I want to reiterate that I think
Richard&amp;#8217;s argument was presented much better than this; even if the talk was
really doom and gloom predictions from a person who sees new technologies
encroaching in his domain, Richard had wholesome intentions, so I feel a bit
bad about condensing them into a&amp;nbsp;quip.&lt;/p&gt;
&lt;p&gt;Of course, this leaves me in quite a bind. It would be easy — &lt;em&gt;incredibly&lt;/em&gt;
easy — to dismiss a lot of the objections and points raised by Richard as a
case of the Italian idiom &amp;#8220;do not ask to the inn-keeper if the house wine is
good&amp;#8221;. Nevertheless, I want to understand why those objections where made in
the first place, because it&amp;#8217;s not going to be the last we are going to be
hearing&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve been turning an answer to that question in my head for a while, now,
and I think I finally came up with something that tries to rise to the level
of Richard&amp;#8217;s presentation, in the sense that I tried to capture the issue
behind it, instead of just reacting to&amp;nbsp;it.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Like many things in tech, it all comes down to developers and system&amp;nbsp;administators.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t think I&amp;#8217;m being controversial, or exposing some knowledge for
initiates, when I say that Linux distributions are not made by the people
that write the software they distribute. Of course, there are various
exceptions, with upstream developers being involved (by volunteer or more
likely paid work) with &lt;em&gt;a particular distribution&lt;/em&gt; of their software, but by
and large there has been a complete disconnect between who &lt;em&gt;writes&lt;/em&gt; the code
and who &lt;em&gt;packages&lt;/em&gt;&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Another, I hope, uncontroversial statement is that people on the Linux
distribution side of things are mostly interested in making sure that the
overall &lt;span class="caps"&gt;OS&lt;/span&gt; fits into a fairly specific view of how computer systems should
work: a central authority that oversees, via policies and validation tools
that implement those policies, how all the pieces fit together, up to a
certain point. There&amp;#8217;s a name for that kind of authority: system&amp;nbsp;administrators.&lt;/p&gt;
&lt;p&gt;Linux distributions are the continuation of system administration policies
via other means: all installed Linux machines are viewed as part of the same
shared domain, with clear lines of responsibility and ownership that trace
from a user installation to the packager, to the people that set up the
policies of integration, and which may or may not involve the people that
make the software in the first place — after all, that&amp;#8217;s what distro patches
are&amp;nbsp;for.&lt;/p&gt;
&lt;p&gt;You may have noticed that in the past 35 years the landscape of computing
has been changed by the introduction of the personal computer; that the
release of Windows 95 introduced the concept of a mass marketable operating
system; and that, by and large, there has been a complete disintermediation
between software vendors and users. A typical computer user won&amp;#8217;t have an
administrator giving them a machine with the &lt;span class="caps"&gt;OS&lt;/span&gt;, validating and managing all
the updates; instead of asking an admin to buy, test, and deploy an
application for them, users went to a shop and bought a box with floppies or
an optical storage — and now they just go to online version of that shop
(typically owned by the &lt;span class="caps"&gt;OS&lt;/span&gt; vendor) and download it. The online store may
just provide users with the guarantee that the app won&amp;#8217;t steal all their
money without asking in advance, but that&amp;#8217;s pretty much where the
responsibility of the owners of the store&amp;nbsp;ends.&lt;/p&gt;
&lt;p&gt;Linux does not have&amp;nbsp;stores.&lt;/p&gt;
&lt;p&gt;You&amp;#8217;re still supposed to go ask your sysadmin for an application to be
available, and you&amp;#8217;re still supposed to give your application to the
sysadmin so that they can deploy it — with or without&amp;nbsp;modifications.&lt;/p&gt;
&lt;p&gt;Yet, in the 25 years of their history, Linux distribution haven&amp;#8217;t managed to
convince the developers&amp;nbsp;of&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Perl&lt;/li&gt;
&lt;li&gt;Python&lt;/li&gt;
&lt;li&gt;Ruby&lt;/li&gt;
&lt;li&gt;JavaScript&lt;/li&gt;
&lt;li&gt;Rust&lt;/li&gt;
&lt;li&gt;Go&lt;/li&gt;
&lt;li&gt;&lt;span class="caps"&gt;PHP&lt;/span&gt;&lt;/li&gt;
&lt;li&gt;&lt;code&gt;insert_your_language_here&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;applications to defer all their dependency handling and integration to
distro&amp;nbsp;packagers.&lt;/p&gt;
&lt;p&gt;They have just about managed to convince C and C++ developers, because the
practices of those languages are so old and entrenched, the tools so poor,
and because they share part of the same heritage; and TeX writers, for some
weird reason, as you can witness by looking at how popular distribution
package all the &lt;code&gt;texlive&lt;/code&gt; modules.&lt;/p&gt;
&lt;p&gt;The crux is that nobody, on any existing major (≥ 5% of market penetration)
platform, develops applications like Linux distributors want them to. Nobody
&lt;strong&gt;wants to&lt;/strong&gt;. Not even the walled gardens you keep in your pocket and use to
browse the web, watch a video, play a game, and occasionally make a phone
call, work like that, and those are the closest thing to a heavily managed
system you can get outside of a data&amp;nbsp;center.&lt;/p&gt;
&lt;p&gt;The issue is not the &amp;#8220;managed by somebody&amp;#8221; part; the issue is the inevitable
intermediary between an application developer and an application&amp;nbsp;user.&lt;/p&gt;
&lt;p&gt;Application developers want to be able to test and have a reproducible
environment, because it makes it easier for them to find bugs and to ensure
that their project works as they intented; the easiest way to do that is to
have people literally use the developer&amp;#8217;s computer — this is why web
applications deployed on top of a web browser engine that consumes all your
&lt;span class="caps"&gt;CPU&lt;/span&gt; cores in a fiery pit are eating everybody&amp;#8217;s lunch; or because software
as a service even exists. The closest thing application developers have
found to ship their working laptop to the users of our applications without
physically shipping hardware, is to give them a read-only file system image
that we have built ourselves, or a list of dependencies hosted on a public
source code repository that the build system will automatically check out
prior to deploying the&amp;nbsp;application.&lt;/p&gt;
&lt;p&gt;The Linux distribution model is to have system administrators turned
packagers control all the dependencies and the way they interact on a
system; check all the licensing terms and security issues, when not
accidentally introducing them; and then fight among themselves on the
practicalities and ideologies of how that software should be distributed,
installed, and&amp;nbsp;managed.&lt;/p&gt;
&lt;p&gt;The more I think about it, the less I understand how that ever worked in the
first place. It is not a mystery, though, why it&amp;#8217;s a dying&amp;nbsp;model.&lt;/p&gt;
&lt;p&gt;When I say that &amp;#8220;nobody develops applications like the Linux distributions
encourages and prefers&amp;#8221; I&amp;#8217;m not kidding around: Windows, macOS, iOS,
Electron, and Android application developers are heavily based on the
concept of a core set of &lt;span class="caps"&gt;OS&lt;/span&gt; services; a parallel installable blocks of
system dependencies shipped and retired by the &lt;span class="caps"&gt;OS&lt;/span&gt; vendor; and a bundling
system that allows application developers to provide their own dependencies,
and control&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Sounds&amp;nbsp;familiar?&lt;/p&gt;
&lt;p&gt;If it does, it&amp;#8217;s becase, in the past 25 years, every other platform (and I
include programming languages with a fairly comprehensive standard library
in that definition, not just operating systems) has implemented something
like this — even in free and open source software, where this kind of
invention mostly exists both as a way to replicate Linux distributions on
Windows, and to route around Linux distributions on&amp;nbsp;Linux.&lt;/p&gt;
&lt;p&gt;It should not come as a surprise that there&amp;#8217;s going to be friction; while
for the past two decades architects of both operating systems and
programming languages have been trying to come up with a car, Linux
distributions have been investing immeasurable efforts in order to come up
with a jet fueled, &lt;span class="caps"&gt;SRB&lt;/span&gt;-augmented horse. Sure: it&amp;#8217;s so easy to run &lt;code&gt;apt
install foo&lt;/code&gt; and get &lt;code&gt;foo&lt;/code&gt; installed. How did &lt;code&gt;foo&lt;/code&gt; get into the repository?
How can you host a repository, if you can&amp;#8217;t, or don&amp;#8217;t want to host it on
somebody else&amp;#8217;s infrastructure? What happens when you have to deal with a
bajillion, slightly conflicting, ever changing policies? How do you keep
your work up to date for everyone, and every combination? What happens if
you cannot give out the keys to your application to everyone, even if the
application itself may be free&amp;nbsp;software?&lt;/p&gt;
&lt;p&gt;Scalability is the problem; too many intermediaries, too many gatekeepers.
Even if we had a single one, that&amp;#8217;s still one too many. People using
computers expect to access whatever application they need, at the touch of a
finger or at the click of a pointer; if they cannot get to something in time
for the task they have to complete, they will simply leave and never come
back. Sure, they can probably appreciate the ease of installing 30 different
console text editors, 25 &lt;span class="caps"&gt;IRC&lt;/span&gt; clients, and 12 email clients, all in various
state of disrepair and functionality; it won&amp;#8217;t really mean much, though,
because they will be using something else by that&amp;nbsp;time.&lt;/p&gt;
&lt;p&gt;Of course, now we in the Linux world are in the situation of reimplementing
the past 20 years of mistakes other platforms have made; of course, there
will be growing pains, and &lt;strong&gt;maybe&lt;/strong&gt;, if we&amp;#8217;re careful enough, we can
actually learn for somebody else&amp;#8217;s blunders, and avoid falling into common
traps. We&amp;#8217;re going to have new and exciting traps to fall&amp;nbsp;into!&lt;/p&gt;
&lt;p&gt;Does this mean it&amp;#8217;s futile, and that we should just give up on everything
and just go back to our comfort zone? If we did, it would not only be a
disservice to our existing users, but also to the users of every other
platform. Our — and I mean the larger free software ecosystem — proposition
is that we wish all users to have the tools to modify the software they are
using; to ensure that the software in question has not been modified against
their will or knowledge; and to access their own data, instead of merely
providing it to third parties and renting out services with it. We should
have fewer intermediaries, not more. We should push for adoption and access.
We should provide a credible alternative to other&amp;nbsp;platforms.&lt;/p&gt;
&lt;p&gt;This will not be&amp;nbsp;easy.&lt;/p&gt;
&lt;p&gt;We will need to grow up a lot, and in little time; adopt better standards
than just &amp;#8220;it builds on my laptop&amp;#8221; or &amp;#8220;it works if you have been in the
business for 15 years and know all the missing stairways, and by the way,
isn&amp;#8217;t that a massive bear trap covered with a tarpaulin on the way to the
goal&amp;#8221;. Complex upstream projects will have to start caring about things like
reproducibility; licensing; security updates; continuous integration; &lt;span class="caps"&gt;QA&lt;/span&gt; and
validation. We will need to care about stable system services, and backward
compatibility. We will not be shielded by a third party any&amp;nbsp;more.&lt;/p&gt;
&lt;p&gt;The good news is: we have a lot of people that know about this stuff, and we
can ask them how to make it work. We can take existing tools and make them
generic and part of our build pipeline, instead of having them inside silos.
We can adopt shared policies upstream instead of applying them downstream,
and twisting software to adapt to all of&amp;nbsp;them.&lt;/p&gt;
&lt;p&gt;Again, this won&amp;#8217;t be&amp;nbsp;easy.&lt;/p&gt;
&lt;p&gt;If we wanted easy, though, we would not be making free and open source
software for&amp;nbsp;everyone.&lt;/p&gt;</content><category term="gnome"></category><category term="design"></category><category term="free software"></category><category term="distribution"></category><category term="platform"></category><category term="security"></category></entry><entry><title>Further experiments in Meson</title><link href="https://www.bassi.io/articles/2017/05/19/further-experiments-in-meson/" rel="alternate"></link><published>2017-05-19T18:20:00+01:00</published><updated>2017-05-19T18:23:43+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-05-19:/articles/2017/05/19/further-experiments-in-meson/</id><summary type="html">&lt;p&gt;in which more components gets ported to&amp;nbsp;Meson&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="http://mesonbuild.com"&gt;Meson&lt;/a&gt; is definitely getting more traction in &lt;span class="caps"&gt;GNOME&lt;/span&gt; (and other
projects), with many components adding support for it in parallel to
autotools, or outright switching to it. There are still bugs, here and
there, and we definitely need to improve build environments — like
Continuous — to support Meson out of the box, but all in all I&amp;#8217;m really
happy about not having to deal with autotools any more, as well as being
able to build the G* stack much more quickly when doing continuous&amp;nbsp;integration.&lt;/p&gt;
&lt;p&gt;Now that &lt;span class="caps"&gt;GTK&lt;/span&gt;+ has added Meson support, though, it&amp;#8217;s time to go through the
dependency chain in order to clean up and speed up the build in the lower
bits of our stack. After an aborted attempt at porting GdkPixbuf, I decided
to &lt;a href="https://git.gnome.org/browse/pango/log/?h=wip/meson"&gt;port Pango&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;All in all, Pango proved to be an easy win; it took me about one day to port
from Autotools to Meson, and most of it was mechanical translation from
weird autoconf/automake incantations that should have been removed years
ago&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;. Most of the remaining bits&amp;nbsp;were:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;ensuring that both Autotools and Meson would build the same
   DSOs, with the same&amp;nbsp;symbols&lt;/li&gt;
&lt;li&gt;generating the same introspection data and&amp;nbsp;documentation&lt;/li&gt;
&lt;li&gt;installing tests and data in the appropriate&amp;nbsp;locations&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Thanks to the ever vigilant eye of &lt;a href="http://blog.nirbheek.in/"&gt;Nirbheek Chauhan&lt;/a&gt;, and
thanks to the new &lt;a href="http://mesonbuild.com/Reference-manual.html"&gt;Meson reference&lt;/a&gt;, I was also able to
make the Meson build slightly more idiomatic than a straight, 1:1 port would
have&amp;nbsp;done.&lt;/p&gt;
&lt;p&gt;The results are a full Meson build that takes about the same time as
&lt;code&gt;./autogen.sh&lt;/code&gt; to&amp;nbsp;run:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;autogen&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;sh&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="w"&gt;                         &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;meson&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m11&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;149&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;525&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;153&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;609&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;363&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;206&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;make&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;j&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;((&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;nproc&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="mi"&gt;2&lt;/span&gt;&lt;span class="p"&gt;))&lt;/span&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ninja&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m9&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;186&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m3&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;387&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m16&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;295&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m6&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;887&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;337&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                  &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;318&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;

&lt;span class="o"&gt;--------------------------------------------------------------&lt;/span&gt;

&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;autotools&lt;/span&gt;&lt;span class="w"&gt;                           &lt;/span&gt;&lt;span class="o"&gt;*&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;meson&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;ninja&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m27&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;669&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;real&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m5&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;772&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m45&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;622&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;user&lt;/span&gt;&lt;span class="w"&gt;          &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m8&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;465&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;span class="w"&gt;  &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;         &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m10&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;698&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;&lt;span class="w"&gt;                 &lt;/span&gt;&lt;span class="n"&gt;sys&lt;/span&gt;&lt;span class="w"&gt;           &lt;/span&gt;&lt;span class="mi"&gt;0&lt;/span&gt;&lt;span class="n"&gt;m2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="mi"&gt;357&lt;/span&gt;&lt;span class="n"&gt;s&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Not bad for a day&amp;#8217;s worth of&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;My plan would be to merge this in the &lt;code&gt;master&lt;/code&gt; branch pretty soon; I also
have a branch that &lt;a href="https://git.gnome.org/browse/pango/log/?h=wip/meson-only"&gt;drops Autotools entirely&lt;/a&gt;
but that can wait a cycle, as far as I&amp;#8217;m&amp;nbsp;concerned.&lt;/p&gt;
&lt;p&gt;Now comes the hard part: porting libraries like GdkPixbuf, &lt;span class="caps"&gt;ATK&lt;/span&gt;,
gobject-introspection, and GLib to Meson. There&amp;#8217;s already a GLib port,
courtesy of &lt;a href="http://www.centricular.com/"&gt;Centricular&lt;/a&gt;, but it needs further testing;
GdkPixbuf is pretty terrible, since it&amp;#8217;s a &lt;em&gt;really&lt;/em&gt; old library; I don&amp;#8217;t
expect &lt;span class="caps"&gt;ATK&lt;/span&gt; and GObject introspection to be complicated, but the latter has a
non-recursive Make layout that is full of&amp;nbsp;bees.&lt;/p&gt;
&lt;p&gt;It would be nice to get to &lt;a href="https://2017.guadec.org"&gt;&lt;span class="caps"&gt;GUADEC&lt;/span&gt;&lt;/a&gt; and have the
whole G* stack build with Meson and Ninja. If you want to help out, reach
out in &lt;code&gt;#gtk+&lt;/code&gt;, on &lt;span class="caps"&gt;IRC&lt;/span&gt; or on&amp;nbsp;Matrix.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;The Windows support still checks for &lt;span class="caps"&gt;GCC&lt;/span&gt; 2.x or 3.x flags, for
  instance.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="gnome"></category><category term="development"></category><category term="build systems"></category><category term="meson"></category><category term="pango"></category><category term="gnome"></category></entry><entry><title>On Vala</title><link href="https://www.bassi.io/articles/2017/02/13/on-vala/" rel="alternate"></link><published>2017-02-13T13:12:00+00:00</published><updated>2024-08-19T11:53:06+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-02-13:/articles/2017/02/13/on-vala/</id><summary type="html">&lt;p&gt;In which I look at the state of Vala and hope for some introspection to&amp;nbsp;happen&lt;/p&gt;</summary><content type="html">&lt;p&gt;It seems I raised a bit of a stink on Twitter last&amp;nbsp;week:&lt;/p&gt;
&lt;blockquote class="twitter-tweet" data-lang="en"&gt;&lt;p lang="en" dir="ltr"&gt;&lt;span class="caps"&gt;PSA&lt;/span&gt;: if you want to write a new &lt;a href="https://twitter.com/gnome"&gt;@gnome&lt;/a&gt; application, don&amp;#39;t use Vala; if you&amp;#39;re already using it, consider porting to a non-dead&amp;nbsp;language.&lt;/p&gt;&amp;mdash; Emmanuele Bassi (@ebassi) &lt;a href="https://twitter.com/ebassi/status/827482509982195712"&gt;February 3, 2017&lt;/a&gt;&lt;/blockquote&gt;
&lt;script async src="//platform.twitter.com/widgets.js" charset="utf-8"&gt;&lt;/script&gt;

&lt;p&gt;Of course, and with reason, I&amp;#8217;ve been called out on this by various people.
Luckily, it was on Twitter, so we haven&amp;#8217;t seen articles on Slashdot and
Phoronix and &lt;span class="caps"&gt;LWN&lt;/span&gt; with headlines like &amp;#8220;&lt;span class="caps"&gt;GNOME&lt;/span&gt; developer says Vala is dead and
will be removed from all servers for all eternity and you all suck&amp;#8221;. At
least, I&amp;#8217;ve only seen a bunch of comments on Reddit about this, but nobody
cares about that particular cesspool of&amp;nbsp;humanity.&lt;/p&gt;
&lt;p&gt;Sadly, 140 characters do not leave any room for nuance, so maybe I should
probably clarify what I wrote on a venue with no character&amp;nbsp;limit.&lt;/p&gt;
&lt;p&gt;First of all, I&amp;#8217;d like to apologise to people that felt I was attacking them
or their technical choices: it was not my intention, but see above, re:
character count. I may have only about 1000 followers on Twitter, but it
seems that the network effect is still a bit greater than that, so I should
be careful when wording opinions. I&amp;#8217;d like to point out that it&amp;#8217;s my private
Twitter account, and you can only get to what it says if you follow me, or
if you follow people who follow me and decide to retweet what I&amp;nbsp;write.&lt;/p&gt;
&lt;p&gt;My &lt;span class="caps"&gt;PSA&lt;/span&gt; was intended as a reflection on the state of Vala, and its impact on
the &lt;span class="caps"&gt;GNOME&lt;/span&gt; ecosystem in terms of newcomers, from the perspective of a person
that used Vala for his own personal projects; recommended Vala to newcomers;
and has to deal with the various build issues that arise in &lt;span class="caps"&gt;GNOME&lt;/span&gt; because
something broke in Vala or in projects using Vala. If you&amp;#8217;re using Vala
outside of &lt;span class="caps"&gt;GNOME&lt;/span&gt;, you have two options: either ignore all I&amp;#8217;m saying, as it
does not really apply to your case; or do a bit of soul searching, and see
if what I wrote &lt;strong&gt;does&lt;/strong&gt; indeed apply to&amp;nbsp;you.&lt;/p&gt;
&lt;p&gt;First of all, I&amp;#8217;d like to qualify my assertion that Vala is a &amp;#8220;dead
language&amp;#8221;. Of course people see activity in the &lt;a href="https://git.gnome.org/browse/vala"&gt;Git repository&lt;/a&gt;,
see the recent commits and think &amp;#8220;the project is still alive&amp;#8221;. Recent
commits do not tell a complete&amp;nbsp;story.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s look at the project history for the past 10 cycles (roughly 2.5
years). These are the commits for every cycle, broken up in two values: one
for the full repository, the other one for the whole repository &lt;em&gt;except&lt;/em&gt; the
&lt;code&gt;vapi&lt;/code&gt; directory, which contains the &lt;span class="caps"&gt;VAPI&lt;/span&gt; files for language&amp;nbsp;bindings:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Commits" src="https://www.bassi.io/images/vala-repo-commits.png"&gt;&lt;/p&gt;
&lt;p&gt;Aside from the latest cycle, Vala has seen very little activity; the project
itself, if we exclude binding updates, has seen less than 100 commits for
every cycle — some times even far less. The latest cycle is a bit of an
outlier, but we can notice a pattern of very little work for two/three
cycles, followed by a spike. If we look at the currently in progress cycle,
we can already see that the number of commits has decreased back to 55/42,
as of this&amp;nbsp;morning.&lt;/p&gt;
&lt;p&gt;&lt;img alt="Commits" src="https://www.bassi.io/images/vala-repo-commits-2.png"&gt;&lt;/p&gt;
&lt;p&gt;Number of commits is just a metric, though; more important is the number of
contributors. After all, small, incremental changes may be a good thing in a
language — though, spoiler alert: they are usually an indication of a series
of larger issues, and we&amp;#8217;ll come to that point&amp;nbsp;later.&lt;/p&gt;
&lt;p&gt;These are the number of developers over the same range of cycles, again
split between committers to the full repository and to the full repository
minus the &lt;code&gt;vapi&lt;/code&gt; directory:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Developers" src="https://www.bassi.io/images/vala-repo-developers.png"&gt;&lt;/p&gt;
&lt;p&gt;As you can see, the number of authors of changes is mostly stable, but still
low. If we have few people that actively commit to the repository it means
we have few people that can review a patch. It means patches linger longer
and longer, while reviewers go through their queues; it means that
contributors get discouraged; and, since nobody is paid to work full time on
Vala, it means that any interruption caused by paid jobs will be a
bottleneck on the project&amp;nbsp;itself.&lt;/p&gt;
&lt;p&gt;These concerns are not unique of a programming language: they exist for
every volunteer-driven free and open source project. Programming languages,
though, like core libraries, are problematic because any bottleneck causes
ripple effects. You can take any stalled project you depend on, and vendor
it into your own, but if that happens to the programming language you&amp;#8217;re
using, then you&amp;#8217;re pretty much&amp;nbsp;screwed.&lt;/p&gt;
&lt;p&gt;For these reasons, we should also look at how well-distributed is the
workload in Vala, i.e. which percentage of the work is done by the authors
of those commits; the results are &lt;strong&gt;not&lt;/strong&gt; encouraging. Over that range of
cycles, Only two developers routinely crossed the 5% of&amp;nbsp;commits:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Rico&amp;nbsp;Tzschichholz&lt;/li&gt;
&lt;li&gt;Jürg&amp;nbsp;Billeter&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;And Rico has been the only one to consistently author &amp;gt;50% of the commits.
This means there&amp;#8217;s only one person dealing with the project on a day to day&amp;nbsp;basis.&lt;/p&gt;
&lt;p&gt;As the maintainer of a project who basically had to do all the work, I
cannot even begin to tell you how soul-crushing that can become. You get
burned out, and you feel responsible for everyone using your code, and then
you get burned out some more. I honestly don&amp;#8217;t want Rico to burn out, and
you shouldn&amp;#8217;t,&amp;nbsp;either.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s go into unfair territory. These are the commits for
&lt;a href="https://www.rust-lang.org/"&gt;Rust&lt;/a&gt; — the compiler and standard&amp;nbsp;library:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Rust" src="https://www.bassi.io/images/rust-commits.png"&gt;&lt;/p&gt;
&lt;p&gt;These are the commits for &lt;a href="https://golang.org/"&gt;Go&lt;/a&gt; — the compiler and base&amp;nbsp;library:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Go" src="https://www.bassi.io/images/go-commits.png"&gt;&lt;/p&gt;
&lt;p&gt;These are the commits for Vala — both compiler and&amp;nbsp;bindings:&lt;/p&gt;
&lt;p&gt;&lt;img alt="Vala" src="https://www.bassi.io/images/vala-commits.png"&gt;&lt;/p&gt;
&lt;p&gt;These are the number of commits over the past &lt;strong&gt;year&lt;/strong&gt;. Both languages are
younger than Vala, have more tools than Vala, and are more used than Vala.
&lt;em&gt;Of course&lt;/em&gt;, it&amp;#8217;s completely unfair to compare them, but those numbers
should give you a sense of scale, of what is the current high bar for a
successful programming language these days. Vala is a niche language, after
all; it&amp;#8217;s heavily piggy-backing on the &lt;span class="caps"&gt;GNOME&lt;/span&gt; community because it transpiles
to C and needs a standard library and an ecosystem like the one &lt;span class="caps"&gt;GNOME&lt;/span&gt;
provides. I never expected Vala to rise to the level of mindshare that Go
and Rust currently&amp;nbsp;occupy.&lt;/p&gt;
&lt;p&gt;Nevertheless, we need to draw some conclusions about the current state of
Vala — starting from &lt;a href="https://mail.gnome.org/archives/vala-list/2016-September/msg00001.html"&gt;this thread&lt;/a&gt;, perhaps, as it best
encapsulates the issues the project is&amp;nbsp;facing.&lt;/p&gt;
&lt;p&gt;Vala, as a project, is limping along. There aren&amp;#8217;t enough developers to
actively effect change on the project; there aren&amp;#8217;t enough developers to
work on ancillary tooling — like build system integration, debugging and
profiling tools, documentation. Saying that &amp;#8220;Vala compiles to C so you can
use tools meant for C&amp;#8221; is comically missing the point, and it&amp;#8217;s effectively
like saying that &amp;#8220;C compiles to binary code, so you can disassemble a
program if you want to debug it&amp;#8221;. Being able to inspect the language using
tools native to the language is a powerful thing; if you have to do the name
mangling in your head in order to set a breakpoint in &lt;span class="caps"&gt;GDB&lt;/span&gt; you are elevating
the barrier of contributions way above the head of many&amp;nbsp;newcomers.&lt;/p&gt;
&lt;p&gt;Being able to effect change means also being able to introduce change
effectively and without fear. This means things like continuous integration
and a full test suite heavily geared towards regression testing. The test
suite in Vala is made of 210 units, for a total of 5000 lines of code; the
code base of Vala (vala &lt;span class="caps"&gt;AST&lt;/span&gt;, codegen, C code emitter, and the compiler) is
nearly 75 thousand lines of code. There is no continuous integration,
outside of the one that &lt;span class="caps"&gt;GNOME&lt;/span&gt; Continuous performs when building Vala, or the
one &lt;span class="caps"&gt;GNOME&lt;/span&gt; developers perform when using jhbuild. Regressions are found after
days or weeks, because developers of projects using Vala update their
compiler and suddenly their projects cease to&amp;nbsp;build.&lt;/p&gt;
&lt;p&gt;I don&amp;#8217;t want to minimise the enormous amount of work that every Vala
contributor brought to the project; they are heroes, all of them, and they
deserve as much credit and praise as we can give. The idea of a
project-oriented, community-oriented programming language has been
vindicated many times over, in the past 5&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;If I scared you, or incensed you, then you can still blame me, and my lack
of tact. You can still call me an asshole, and you can think that I&amp;#8217;m
completely uncool. What I do hope, though, is that this blog post pushes
you into action. Either to contribute to Vala, or to re-new your commitment
to it, so that we can look at my words in 5 years and say &amp;#8220;boy, was
Emmanuele wrong&amp;#8221;; or to look at alternatives, and explore new venues in
order to make &lt;span class="caps"&gt;GNOME&lt;/span&gt; (and the larger free software ecosystem)&amp;nbsp;better.&lt;/p&gt;</content><category term="gnome"></category><category term="vala"></category><category term="development"></category><category term="languages"></category><category term="gnome"></category></entry><entry><title>Epoxy</title><link href="https://www.bassi.io/articles/2017/02/11/epoxy/" rel="alternate"></link><published>2017-02-11T01:34:00+00:00</published><updated>2017-02-11T01:37:36+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-02-11:/articles/2017/02/11/epoxy/</id><summary type="html">&lt;p&gt;In which I recount the process of moving libepoxy to Meson and becoming its&amp;nbsp;maintainer&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://github.com/anholt/libepoxy"&gt;Epoxy&lt;/a&gt; is a small library that &lt;span class="caps"&gt;GTK&lt;/span&gt;+,
and other projects, use in order to access the OpenGL &lt;span class="caps"&gt;API&lt;/span&gt; in somewhat sane
fashion, hiding all the awful bits of craziness that actually need to happen
because apparently somebody dosed the water supply at &lt;span class="caps"&gt;SGI&lt;/span&gt; with large
quantities of &lt;span class="caps"&gt;LSD&lt;/span&gt; in the mid-&amp;#8216;90s, or&amp;nbsp;something.&lt;/p&gt;
&lt;p&gt;As an added advantage, Epoxy is also portable on different platforms, which
is a plus for &lt;span class="caps"&gt;GTK&lt;/span&gt;+.&lt;/p&gt;
&lt;p&gt;Since I&amp;#8217;ve started using &lt;a href="http://mesonbuild.com"&gt;Meson&lt;/a&gt; for my personal (and
some &lt;a href="https://github.com/ebassi/emeus"&gt;work-related&lt;/a&gt;) projects as well, I&amp;#8217;ve
been on the lookout for adding Meson build rules to other free and open
source software projects, in order to improve both their build time and
portability, and to improve Meson&amp;nbsp;itself.&lt;/p&gt;
&lt;p&gt;As a small, portable project, Epoxy sounded like a good candidate for the
port of its build system from autotools to &lt;a href="http://mesonbuild.com"&gt;Meson&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;To the Bat Build&amp;nbsp;Machine!&lt;/p&gt;
&lt;h3&gt;tl;dr&lt;/h3&gt;
&lt;p&gt;Since you may be interested just in &lt;a href="https://github.com/ebassi/libepoxy/wiki/Moving-Epoxy-to-Meson"&gt;the numbers&lt;/a&gt;,
building Epoxy with Meson on my Kaby Lake four Core i7 and NMVe &lt;span class="caps"&gt;SSD&lt;/span&gt; takes about
45% less time than building it with&amp;nbsp;autotools.&lt;/p&gt;
&lt;p&gt;A fairly good fraction of the autotools time is spent going through the
autogen and configure phases, because they both aren&amp;#8217;t parallelised, and
create a ton of shell&amp;nbsp;invocations.&lt;/p&gt;
&lt;p&gt;Conversely, Meson&amp;#8217;s configuration phase is incredibly fast; the &lt;strong&gt;whole&lt;/strong&gt;
Meson build of Epoxy fits in the same time the autogen.sh and configure
scripts complete their&amp;nbsp;run.&lt;/p&gt;
&lt;h3&gt;Administrivia&lt;/h3&gt;
&lt;p&gt;Epoxy is a simple library, which means it does not need a hugely complicated
build system set up; it does have some interesting deviations, though, which
made the porting an interesting&amp;nbsp;challenge.&lt;/p&gt;
&lt;p&gt;For instance, on Linux and similar operating systems Epoxy uses &lt;code&gt;pkg-config&lt;/code&gt;
to find things like the &lt;span class="caps"&gt;EGL&lt;/span&gt; availability and the X11 headers and libraries;
on Windows, though, it relies on finding the &lt;code&gt;opengl32&lt;/code&gt; shared or static
library object itself. This means that we get something straightforward in
the former case,&amp;nbsp;like:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Optional dependencies&lt;/span&gt;
&lt;span class="n"&gt;gl_dep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;egl_dep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;dependency&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;egl&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;false&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and something slightly less straightforward in the latter&amp;nbsp;case:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;host_system&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;windows&amp;#39;&lt;/span&gt;
  &lt;span class="c1"&gt;# Required dependencies on Windows&lt;/span&gt;
  &lt;span class="n"&gt;opengl32_dep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;opengl32&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
  &lt;span class="n"&gt;gdi32_dep&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;find_library&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;gdi32&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt; &lt;span class="n"&gt;required&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;true&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And, still, this is miles better than what you have to deal with when using&amp;nbsp;autotools.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s take a messy thing in autotools, like checking whether or not the
compiler supports a set of arguments; usually, this involves some m4 macro
that&amp;#8217;s either part of &lt;a href="https://www.gnu.org/software/autoconf-archive/"&gt;autoconf-archive&lt;/a&gt;
or some additional repository, like the &lt;a href="https://cgit.freedesktop.org/xorg/util/macros"&gt;xorg macros&lt;/a&gt;.
Meson handles this in a much better way, out of the&amp;nbsp;box:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="c1"&gt;# Use different flags depending on the compiler&lt;/span&gt;
&lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;msvc&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;test_cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;-W3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;elif&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;get_id&lt;/span&gt;&lt;span class="p"&gt;()&lt;/span&gt; &lt;span class="o"&gt;==&lt;/span&gt; &lt;span class="s1"&gt;&amp;#39;gcc&amp;#39;&lt;/span&gt;
  &lt;span class="n"&gt;test_cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt;
    &lt;span class="s1"&gt;&amp;#39;-Wpointer-arith&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
    &lt;span class="o"&gt;...&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
  &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="k"&gt;else&lt;/span&gt;
  &lt;span class="n"&gt;test_cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
&lt;span class="n"&gt;endif&lt;/span&gt;

&lt;span class="n"&gt;common_cflags&lt;/span&gt; &lt;span class="o"&gt;=&lt;/span&gt; &lt;span class="p"&gt;[]&lt;/span&gt;
&lt;span class="n"&gt;foreach&lt;/span&gt; &lt;span class="n"&gt;cflag&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt; &lt;span class="n"&gt;test_cflags&lt;/span&gt;
  &lt;span class="k"&gt;if&lt;/span&gt; &lt;span class="n"&gt;cc&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;has_argument&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;cflag&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;
    &lt;span class="n"&gt;common_cflags&lt;/span&gt; &lt;span class="o"&gt;+=&lt;/span&gt; &lt;span class="p"&gt;[&lt;/span&gt; &lt;span class="n"&gt;cflag&lt;/span&gt; &lt;span class="p"&gt;]&lt;/span&gt;
  &lt;span class="n"&gt;endif&lt;/span&gt;
&lt;span class="n"&gt;endforeach&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;In terms of speed, the configuration step could be made even faster by
parallelising the compiler argument checks; right now, Meson has to do them
all in a series, but nothing except some additional parsing effort would
prevent Meson from running the whole set of checks in parallel, and gather
the results at the&amp;nbsp;end.&lt;/p&gt;
&lt;h3&gt;Generating&amp;nbsp;code&lt;/h3&gt;
&lt;p&gt;In order to use the &lt;span class="caps"&gt;GL&lt;/span&gt; entry points without linking against &lt;code&gt;libGL&lt;/code&gt; or
&lt;code&gt;libGLES*&lt;/code&gt; Epoxy takes the &lt;span class="caps"&gt;XML&lt;/span&gt; description of the &lt;span class="caps"&gt;API&lt;/span&gt; from the Khronos
repository and generates the code that ends up being compiled by using a
Python script to parse the &lt;span class="caps"&gt;XML&lt;/span&gt; and generating header and source&amp;nbsp;files.&lt;/p&gt;
&lt;p&gt;Additionally, and unlike most libraries in the G* stack, Epoxy stores its
public headers inside a separate directory from its&amp;nbsp;sources:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;libepoxy&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;cross&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;doc&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;include&lt;/span&gt;
&lt;span class="err"&gt;│&lt;/span&gt;&lt;span class="w"&gt;   &lt;/span&gt;&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;epoxy&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;registry&lt;/span&gt;
&lt;span class="err"&gt;├──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;src&lt;/span&gt;
&lt;span class="err"&gt;└──&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;test&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;The autotools build has the &lt;code&gt;src/gen_dispatch.py&lt;/code&gt; script create both the
source and the header file for each &lt;span class="caps"&gt;XML&lt;/span&gt; at the same time using a rule
processed when recursing inside the &lt;code&gt;src&lt;/code&gt; directory, and proceeds to put the
generated header under &lt;code&gt;$(top_builddir)/include/epoxy&lt;/code&gt;, and the generated
source under &lt;code&gt;$(top_builddir)/src&lt;/code&gt;. Each code generation rule in the
&lt;code&gt;Makefile&lt;/code&gt; manually creates the &lt;code&gt;include/epoxy&lt;/code&gt; directory under the build
root to make up for parallel dispatch of each&amp;nbsp;rule.&lt;/p&gt;
&lt;p&gt;Meson makes is harder to do this kind of spooky-action-at-a-distance build,
so we need to generate the headers in one pass, and the source in another.
This is a bit of a let down, to be honest, and yet a build that invokes the
generator script twice for each &lt;span class="caps"&gt;API&lt;/span&gt; description file is still faster under
Ninja than a build with the single invocation under&amp;nbsp;Make.&lt;/p&gt;
&lt;p&gt;There are sill issues in this step that are being addressed by the Meson
developers; for instance, right now we have to use a custom target for each
generated header and source separately instead of declaring a generator and
calling it multiple times. Hopefully, this will be fixed fairly&amp;nbsp;soon.&lt;/p&gt;
&lt;h3&gt;Documentation&lt;/h3&gt;
&lt;p&gt;Epoxy has a &lt;strong&gt;very&lt;/strong&gt; small footprint, in terms of &lt;span class="caps"&gt;API&lt;/span&gt;, but it still benefits
from having some documentation on its use. I decided to generate the &lt;span class="caps"&gt;API&lt;/span&gt;
reference using &lt;a href="http://www.stack.nl/~dimitri/doxygen/"&gt;Doxygen&lt;/a&gt;, as it&amp;#8217;s
not a G* library and does not need the additional features of gtk-doc.
Sadly, Doxygen&amp;#8217;s default style is absolutely terrible; it would be great if
somebody could fix it to make it look half as good as the look gtk-doc gets
out of the&amp;nbsp;box.&lt;/p&gt;
&lt;h3&gt;Cross-compilation and native&amp;nbsp;builds&lt;/h3&gt;
&lt;p&gt;Now we get into &amp;#8220;interesting&amp;#8221;&amp;nbsp;territory.&lt;/p&gt;
&lt;p&gt;Epoxy is portable; it works on Linux and *&lt;span class="caps"&gt;BSD&lt;/span&gt; systems; on macOS; and on
Windows. Epoxy also works on both Intel Architecture and on &lt;span class="caps"&gt;ARM&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Making it run on Unix-like systems is not at all complicated. When it comes
to Windows, though, things get weird&amp;nbsp;fast.&lt;/p&gt;
&lt;p&gt;Meson uses &lt;a href="https://github.com/mesonbuild/meson/wiki/Cross%20compilation"&gt;cross files&lt;/a&gt;
to determine the environment and toolchain of the &lt;em&gt;host machine&lt;/em&gt;, i.e. the
machine where the result of the build will eventually run. These are simple
text files with key/value pairs that you can either keep in a separate
repository, in case you want to share among projects; or you can keep them
in your own project&amp;#8217;s repository, especially if you want to easily set up
continuous integration of cross-compilation&amp;nbsp;builds.&lt;/p&gt;
&lt;p&gt;Each toolchain has its own; for instance, this is the description of a cross
compilation done on Fedora with&amp;nbsp;MingW:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[binaries]&lt;/span&gt;
&lt;span class="na"&gt;c&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/x86_64-w64-mingw32-gcc&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;cpp&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/x86_64-w64-mingw32-cpp&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;ar&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/x86_64-w64-mingw32-ar&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;strip&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/x86_64-w64-mingw32-strip&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;pkgconfig&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/bin/x86_64-w64-mingw32-pkg-config&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;exe_wrapper&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;wine&amp;#39;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;This section tells Meson where the binaries of the MingW toolchain are; the
&lt;code&gt;exe_wrapper&lt;/code&gt; key is useful to run the tests under Wine, in this&amp;nbsp;case.&lt;/p&gt;
&lt;p&gt;The cross file also has an additional section for things like special
compiler and linker&amp;nbsp;flags:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="k"&gt;[properties]&lt;/span&gt;
&lt;span class="na"&gt;root&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;&amp;#39;/usr/x86_64-w64-mingw32/sys-root/mingw&amp;#39;&lt;/span&gt;
&lt;span class="na"&gt;c_args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[ &amp;#39;-pipe&amp;#39;, &amp;#39;-Wp,-D_FORTIFY_SOURCE=2&amp;#39;, &amp;#39;-fexceptions&amp;#39;, &amp;#39;--param=ssp-buffer-size=4&amp;#39;, &amp;#39;-I/usr/x86_64-w64-mingw32/sys-root/mingw/include&amp;#39; ]&lt;/span&gt;
&lt;span class="na"&gt;c_link_args&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s"&gt;[ &amp;#39;-L/usr/x86_64-w64-mingw32/sys-root/mingw/lib&amp;#39; ]&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;These values are taken from the equivalent bits that Fedora provides in
their MingW&amp;nbsp;RPMs.&lt;/p&gt;
&lt;p&gt;Luckily, the tool that generates the headers and source files is written in
Python, so we don&amp;#8217;t need an additional layer of complexity, with a tool
built and run on a different platform and architecture in order to generate
files to be built and run on a different&amp;nbsp;platform.&lt;/p&gt;
&lt;h3&gt;Continuous&amp;nbsp;Integration&lt;/h3&gt;
&lt;p&gt;Of course, any decent process of porting, these days, should deal with
continuous integration. &lt;span class="caps"&gt;CI&lt;/span&gt; gives us confidence as to whether or not any
change whatsoever we make actually works — and not just on our own computer,
and our own&amp;nbsp;environment.&lt;/p&gt;
&lt;p&gt;Since Epoxy is hosted on GitHub, the quickest way to deal with continuous
integration is to use &lt;a href="https://travis-ci.org"&gt;TravisCI&lt;/a&gt;, for Linux and
macOS; and &lt;a href="https://www.appveyor.com/"&gt;Appveyor&lt;/a&gt; for&amp;nbsp;Windows.&lt;/p&gt;
&lt;p&gt;The requirements for Meson are just Python3 and Ninja; Epoxy also requires
Python 2.7, for the dispatch generation script, and the shared libraries for
&lt;span class="caps"&gt;GL&lt;/span&gt; and the native &lt;span class="caps"&gt;API&lt;/span&gt; needed to create a &lt;span class="caps"&gt;GL&lt;/span&gt; context (&lt;span class="caps"&gt;GLX&lt;/span&gt;, &lt;span class="caps"&gt;EGL&lt;/span&gt;, or &lt;span class="caps"&gt;WGL&lt;/span&gt;); it
also optionally needs the X11 libraries and headers and Xvfb for running the
test&amp;nbsp;suite.&lt;/p&gt;
&lt;p&gt;Since Travis offers an older version of Ubuntu &lt;span class="caps"&gt;LTS&lt;/span&gt; as its base system, we
cannot build Epoxy with Meson; additionally, running the test suite is a
crapshoot because the Mesa version if hopelessly out of date and will either
cause most of the tests to be skipped or, worse, make them segfault. To
sidestep this particular issue, I&amp;#8217;ve prepared a &lt;a href="https://github.com/ebassi/epoxyci"&gt;Docker image&lt;/a&gt;
with its own harness, and I use it as the containerised environment for&amp;nbsp;Travis.&lt;/p&gt;
&lt;p&gt;On Appveyor, thanks to the contribution of &lt;a href="https://github.com/tmarrinan"&gt;Thomas Marrinan&lt;/a&gt;
we just need to download Python3, Python2, and Ninja, and build everything
inside its own root; as an added bonus, Appveyor allows us to take the build
artefacts when building from a tag, and shoving them into a zip file that
gets deployed to the release page on&amp;nbsp;GitHub.&lt;/p&gt;
&lt;h3&gt;Conclusion&lt;/h3&gt;
&lt;p&gt;Most of this work has been done off and on over a couple of months; the
rough Meson build conversion was done last December, with the
cross-compilation and native builds taking up the last bit of&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;Since &lt;a href="http://anholt.livejournal.com/"&gt;Eric&lt;/a&gt; does not have any more spare
time to devote to Epoxy, he was kind enough to give me access to the
original repository, and I&amp;#8217;ve tried to reduce the amount of open pull
requests and issues&amp;nbsp;there.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ve also &lt;a href="https://github.com/anholt/libepoxy/releases/tag/v1.4"&gt;released version 1.4.0&lt;/a&gt;
and I plan to do a 1.4.1 release soon-ish, now that I&amp;#8217;m positive Epoxy works
on&amp;nbsp;Windows.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;d like to&amp;nbsp;thank:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;Eric Anholt, for writing Epoxy and helping out when I needed a hand
   with&amp;nbsp;it&lt;/li&gt;
&lt;li&gt;&lt;a href="http://nibblestew.blogspot.co.uk/"&gt;Jussi Pakkanen&lt;/a&gt; and
   &lt;a href="http://blog.nirbheek.in/search/label/gnome"&gt;Nirbheek Chauhan&lt;/a&gt;, for writing
   Meson and for helping me out with my dumb questions on &lt;code&gt;#mesonbuild&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;Thomas Marrinan, for working on the Appveyor integration and testing
   Epoxy builds on&amp;nbsp;Windows&lt;/li&gt;
&lt;li&gt;Yaron Cohen-Tal, for maintaining Epoxy in the&amp;nbsp;interim&lt;/li&gt;
&lt;/ul&gt;</content><category term="gnome"></category><category term="build systems"></category><category term="meson"></category><category term="libepoxy"></category><category term="development"></category></entry><entry><title>Constraints editing</title><link href="https://www.bassi.io/articles/2017/01/11/constraints-editing/" rel="alternate"></link><published>2017-01-11T14:30:00+00:00</published><updated>2023-05-31T15:36:09+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2017-01-11:/articles/2017/01/11/constraints-editing/</id><summary type="html">&lt;p&gt;In which a wild editor of constraints appears inside&amp;nbsp;Emeus&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://www.bassi.io/articles/2016/11/01/constraints-reprise/"&gt;Last year&lt;/a&gt; I talked about the newly added support for Apple&amp;#8217;s
Visual Format Language in &lt;a href="https://ebassi.github.io/emeus/"&gt;Emeus&lt;/a&gt;, which allows to quickly
describe layouts using a cross between &lt;span class="caps"&gt;ASCII&lt;/span&gt; art and predicates. For
instance, I can&amp;nbsp;use:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-[&lt;/span&gt;&lt;span class="n"&gt;icon(==256)&lt;/span&gt;&lt;span class="o"&gt;]-[&lt;/span&gt;&lt;span class="n"&gt;name_label&lt;/span&gt;&lt;span class="o"&gt;]-|&lt;/span&gt;
&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;surname_label&lt;/span&gt;&lt;span class="o"&gt;]-|&lt;/span&gt;
&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;email_label&lt;/span&gt;&lt;span class="o"&gt;]-|&lt;/span&gt;
&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-[&lt;/span&gt;&lt;span class="n"&gt;button(&amp;lt;=icon)&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-[&lt;/span&gt;&lt;span class="n"&gt;icon(==256)&lt;/span&gt;&lt;span class="o"&gt;]&lt;/span&gt;
&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-[&lt;/span&gt;&lt;span class="n"&gt;name_label&lt;/span&gt;&lt;span class="o"&gt;]-[&lt;/span&gt;&lt;span class="n"&gt;surname_label&lt;/span&gt;&lt;span class="o"&gt;]-[&lt;/span&gt;&lt;span class="n"&gt;email_label&lt;/span&gt;&lt;span class="o"&gt;]-|&lt;/span&gt;
&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;[&lt;/span&gt;&lt;span class="n"&gt;button&lt;/span&gt;&lt;span class="o"&gt;]-|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;and obtain a layout like this&amp;nbsp;one:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;Boxes approximate&amp;nbsp;widgets&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/emeus-user-details.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Thanks to the contribution of my colleague Martin Abente Lahaye, now Emeus
supports extensions to the &lt;span class="caps"&gt;VFL&lt;/span&gt;,&amp;nbsp;namely:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;arithmetic operators for constant and multiplication factors inside
    predicates, like &lt;code&gt;[button1(button2 * 2 + 16)]&lt;/code&gt;&lt;/li&gt;
&lt;li&gt;explicit attribute references, like &lt;code&gt;[button1(button1.height / 2)]&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;This allows more expressive layout descriptions, like keeping aspect ratios
between &lt;span class="caps"&gt;UI&lt;/span&gt; elements, without requiring hitting the code&amp;nbsp;base.&lt;/p&gt;
&lt;p&gt;Of course, editing &lt;span class="caps"&gt;VFL&lt;/span&gt; descriptions blindly is not what I consider a fun
activity, so I took some time to write a simple, primitive editing tool that
lets you visualize a layout expressed through &lt;span class="caps"&gt;VFL&lt;/span&gt;&amp;nbsp;constraints:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;I warned you that it was primitive and&amp;nbsp;simple&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/emeus-edit-constraints.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Here&amp;#8217;s a couple of videos showing it in&amp;nbsp;action:&lt;/p&gt;
&lt;p&gt;&lt;span class="videobox"&gt;
                    &lt;iframe width="640" height="480"
                        src='https://www.youtube.com/embed/wroDZQi7HWA'
                        frameborder='0' webkitAllowFullScreen
                        mozallowfullscreen allowFullScreen&gt;
                    &lt;/iframe&gt;
                &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;&lt;span class="videobox"&gt;
                    &lt;iframe width="640" height="480"
                        src='https://www.youtube.com/embed/_nTvuEx1Wvs'
                        frameborder='0' webkitAllowFullScreen
                        mozallowfullscreen allowFullScreen&gt;
                    &lt;/iframe&gt;
                &lt;/span&gt;&lt;/p&gt;
&lt;p&gt;At some point, this could lead to a new &lt;span class="caps"&gt;UI&lt;/span&gt; tool to lay out widgets inside
&lt;a href="https://wiki.gnome.org/Apps/Builder"&gt;Builder&lt;/a&gt; and/or&amp;nbsp;Glade.&lt;/p&gt;
&lt;p&gt;As of now, I consider Emeus in a stable enough state for other people to
experiment with it — I&amp;#8217;ll probably make a release soon-ish. The Emeus
&lt;a href="https://ebassi.github.io/emeus/"&gt;website&lt;/a&gt; is up to date, as it is &lt;a href="https://ebassi.github.io/emeus/docs/"&gt;the &lt;span class="caps"&gt;API&lt;/span&gt; reference&lt;/a&gt;,
and I&amp;#8217;m happy to review pull requests and feature&amp;nbsp;requests.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="layout"></category><category term="gtk"></category><category term="constraints"></category><category term="editing"></category></entry><entry><title>Constraints (reprise)</title><link href="https://www.bassi.io/articles/2016/11/01/constraints-reprise/" rel="alternate"></link><published>2016-11-01T17:07:00+00:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-11-01:/articles/2016/11/01/constraints-reprise/</id><summary type="html">&lt;p&gt;Further experiments with constraint-based layout systems for &lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/p&gt;</summary><content type="html">&lt;p&gt;After the &lt;a href="https://www.bassi.io/articles/2016/10/17/constraints/"&gt;first article on Emeus&lt;/a&gt; various people expressed
interest in the internals of the library, so I decided to talk a bit about
what makes it&amp;nbsp;work.&lt;/p&gt;
&lt;p&gt;Generally, you can think about constraints as linear&amp;nbsp;equations:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;view1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;view2&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="err"&gt;×&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;multiplier&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;+&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;You take the the value of &lt;code&gt;attr2&lt;/code&gt; on the widget &lt;code&gt;view2&lt;/code&gt;, multiply it by a
&lt;code&gt;multiplier&lt;/code&gt;, add a &lt;code&gt;constant&lt;/code&gt;, and apply the value to the attribute &lt;code&gt;attr1&lt;/code&gt;
on the widget &lt;code&gt;view1&lt;/code&gt;. You don&amp;#8217;t need &lt;code&gt;view2.attr2&lt;/code&gt; either, for&amp;nbsp;instance:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;view1&lt;/span&gt;&lt;span class="o"&gt;.&lt;/span&gt;&lt;span class="n"&gt;attr1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="n"&gt;constant&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;is a perfectly valid&amp;nbsp;constraint.&lt;/p&gt;
&lt;p&gt;You also don&amp;#8217;t need to use an equality; these two&amp;nbsp;constraints:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;view1.width ≥ 180
view1.width ≤ 250
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;specify that the &lt;code&gt;width&lt;/code&gt; of &lt;code&gt;view1&lt;/code&gt; must be in the &lt;code&gt;[ 180, 250 ]&lt;/code&gt; range,
extremes&amp;nbsp;included.&lt;/p&gt;
&lt;h3&gt;Layout&lt;/h3&gt;
&lt;p&gt;A layout, then, is just a pile of linear equations that describe the
relations between each element. So, if we have a simple&amp;nbsp;grid:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nb"&gt;+--------------------------------------------+&lt;/span&gt;
&lt;span class="c"&gt;| super                                      |&lt;/span&gt;
&lt;span class="c"&gt;|  &lt;/span&gt;&lt;span class="nb"&gt;+----------------+&lt;/span&gt;&lt;span class="c"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;+-----------------+&lt;/span&gt;&lt;span class="c"&gt;  |&lt;/span&gt;
&lt;span class="c"&gt;|  |     child1     |   |     child2      |  |&lt;/span&gt;
&lt;span class="c"&gt;|  |                |   |                 |  |&lt;/span&gt;
&lt;span class="c"&gt;|  &lt;/span&gt;&lt;span class="nb"&gt;+----------------+&lt;/span&gt;&lt;span class="c"&gt;   &lt;/span&gt;&lt;span class="nb"&gt;+-----------------+&lt;/span&gt;&lt;span class="c"&gt;  |&lt;/span&gt;
&lt;span class="c"&gt;|                                            |&lt;/span&gt;
&lt;span class="c"&gt;|  &lt;/span&gt;&lt;span class="nb"&gt;+--------------------------------------+&lt;/span&gt;&lt;span class="c"&gt;  |&lt;/span&gt;
&lt;span class="c"&gt;|  |               child3                 |  |&lt;/span&gt;
&lt;span class="c"&gt;|  |                                      |  |&lt;/span&gt;
&lt;span class="c"&gt;|  &lt;/span&gt;&lt;span class="nb"&gt;+--------------------------------------+&lt;/span&gt;&lt;span class="c"&gt;  |&lt;/span&gt;
&lt;span class="c"&gt;|                                            |&lt;/span&gt;
&lt;span class="nb"&gt;+--------------------------------------------+&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;We can describe each edge&amp;#8217;s position and size using constraints. It&amp;#8217;s
important to note that there&amp;#8217;s an implicit &amp;#8220;reading&amp;#8221; order that makes it
easier to write constraints; in this case, we start from left to right, and
from top to bottom. Generally speaking, it&amp;#8217;s possible to describe
constraints in any order, but the &lt;a href="http://constraints.cs.washington.edu/cassowary/"&gt;Cassowary&lt;/a&gt; solving
algorithm is geared towards the &amp;#8220;reading&amp;#8221; order&amp;nbsp;above.&lt;/p&gt;
&lt;p&gt;Each layout has some implicit constraint already available. For instance,
the &amp;#8220;trailing&amp;#8221; edge is equal to the leading edge plus the width; the bottom
edge is equal to the top edge plus the height; the center point is equal to
the width or height, divided by two, plus the leading or bottom edges. These
constraints help solving the layout, as well as provide additional values to
other&amp;nbsp;constraints.&lt;/p&gt;
&lt;p&gt;So, let&amp;#8217;s&amp;nbsp;start.&lt;/p&gt;
&lt;p&gt;From the first&amp;nbsp;row:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the leading edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the leading
     edge of &lt;code&gt;child1&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the trailing edge of &lt;code&gt;child1&lt;/code&gt; is the same as the leading edge of
     &lt;code&gt;child2&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the trailing edge of &lt;code&gt;child2&lt;/code&gt; is the same as the trailing edge of
     the &lt;code&gt;super&lt;/code&gt; container, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the width of &lt;code&gt;child1&lt;/code&gt; is the same as the width of &lt;code&gt;child2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From the second&amp;nbsp;row:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the leading edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the leading
     edge of &lt;code&gt;child3&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the trailing edge of &lt;code&gt;child2&lt;/code&gt; is the same as the trailing edge of
     the &lt;code&gt;super&lt;/code&gt; container, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From the first&amp;nbsp;column:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the top edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the top edge
     of &lt;code&gt;child1&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the bottom edge of &lt;code&gt;child1&lt;/code&gt; is the same as the top edge of &lt;code&gt;child3&lt;/code&gt;,
     minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the bottom edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the bottom
     edge of &lt;code&gt;child3&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the height of &lt;code&gt;child3&lt;/code&gt; is the same as the height of &lt;code&gt;child1&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;From the second&amp;nbsp;column:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;the top edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the top edge
     of the &lt;code&gt;child2&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the bottom edge of &lt;code&gt;child1&lt;/code&gt; is the same as the top edge of &lt;code&gt;child3&lt;/code&gt;,
     minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the bottom edge of the &lt;code&gt;super&lt;/code&gt; container is the same as the bottom
     edge of &lt;code&gt;child3&lt;/code&gt;, minus a&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;the height of &lt;code&gt;child3&lt;/code&gt; is the same as the height of &lt;code&gt;child2&lt;/code&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;As you can see, there are some redundancies; these are necessary to ensure
that the layout is fully resolved, though obviously there are some
properties of the elements of the layout that implicitly eliminate some
results. For instance, if &lt;code&gt;child3&lt;/code&gt;&lt;span class="quo"&gt;&amp;#8216;&lt;/span&gt;s height is the same as &lt;code&gt;child1&lt;/code&gt;, and
&lt;code&gt;child1&lt;/code&gt; lies on the same row as &lt;code&gt;child2&lt;/code&gt; and it&amp;#8217;s an axis-aligned
rectangle, the it immediately follows that &lt;code&gt;child3&lt;/code&gt; must have the same
height of &lt;code&gt;child2&lt;/code&gt; as well. It&amp;#8217;s important to note that, from a solver
perspective, there only are values, not boxes, and you could use the solver
with any kind of geometric shape; only the constraints give us the
information on what those shapes should be. It&amp;#8217;s also easier to start from a
fully constrained layout and then remove constraints, than to start from a
loosely constrained layout and add constraints until it&amp;#8217;s&amp;nbsp;stable.&lt;/p&gt;
&lt;h3&gt;Representation&lt;/h3&gt;
&lt;p&gt;From the text description we can now get into a system of&amp;nbsp;equations:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;super.start = child1.start -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child1.end = child2.start -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;super.end = child2.end -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child1.width =&amp;nbsp;child2.width&lt;/li&gt;
&lt;li&gt;super.start = child3.start -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;super.end = child3.end -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;super.top = child1.top -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child1.bottom = child3.top -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;super.bottom = child3.bottom -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child3.height =&amp;nbsp;child1.height&lt;/li&gt;
&lt;li&gt;super.top = child2.top -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child2.bottom = child3.top -&amp;nbsp;padding&lt;/li&gt;
&lt;li&gt;child3.height =&amp;nbsp;child2.height&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Apple, in its &lt;a href="https://en.wikipedia.org/wiki/Apple_Newton"&gt;infinite wisdom and foresight&lt;/a&gt;, decided that
this form is still too verbose. After looking at the &lt;a href="http://perldoc.perl.org/perlform.html"&gt;Perl format&lt;/a&gt;
page for far too long, Apple engineers came up with the Visual Format
Language, or &lt;a href="https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/VisualFormatLanguage.html"&gt;&lt;span class="caps"&gt;VFL&lt;/span&gt;&lt;/a&gt; for&amp;nbsp;short.&lt;/p&gt;
&lt;p&gt;Using &lt;span class="caps"&gt;VFL&lt;/span&gt;, the constraints above&amp;nbsp;become:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child1(==child2)&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child2&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;span class="nl"&gt;H&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child3&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child1(==child3)&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child3&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child2(==child3)&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child3&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Emeus, incidentally, ships with a simple utility that can take a set of &lt;span class="caps"&gt;VFL&lt;/span&gt;
format strings and generate GtkBuilder descriptions that you can embed into
your&amp;nbsp;templates.&lt;/p&gt;
&lt;h3&gt;Change&lt;/h3&gt;
&lt;p&gt;We&amp;#8217;ve used a fair amount of constraints, or four lines of faily cryptic
&lt;span class="caps"&gt;ASCII&lt;/span&gt; art, to basically describe a non-generic &lt;code&gt;GtkGrid&lt;/code&gt; with two equally
sized horizontal cells on the first row, and a single cell with a column
span of two; compared to the common layout managers inside &lt;span class="caps"&gt;GTK&lt;/span&gt;+, this does
not seem like a great trade&amp;nbsp;off.&lt;/p&gt;
&lt;p&gt;Except that we can describe any other layout without necessarily having to
pack widgets inside boxes, with margins and spacing and alignment rules; we
also don&amp;#8217;t have to change the &lt;em&gt;hierarchy&lt;/em&gt; of the boxes if we want to change
the layout. For instance, let&amp;#8217;s say that we want &lt;code&gt;child3&lt;/code&gt; to have a
different horizontal padding, and a minimum and maximum width; we just need
to change the constraints involved in that&amp;nbsp;row:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;H:|-(hpadding)-[child3(&amp;gt;=250,&amp;lt;=500)]-(hpadding)-|
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;Additionally, we now want to decouple &lt;code&gt;child1&lt;/code&gt; and &lt;code&gt;child3&lt;/code&gt; heights, and
make &lt;code&gt;child1&lt;/code&gt; a fixed height&amp;nbsp;item:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child1(==250)&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child3&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;And make the height of &lt;code&gt;child3&lt;/code&gt; move within a range of&amp;nbsp;values:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="nl"&gt;V&lt;/span&gt;&lt;span class="p"&gt;:&lt;/span&gt;&lt;span class="o"&gt;|-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child2&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-[&lt;/span&gt;&lt;span class="n"&gt;child3(&amp;gt;=200,&amp;lt;=300)&lt;/span&gt;&lt;span class="o"&gt;]-&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="n"&gt;padding&lt;/span&gt;&lt;span class="p"&gt;)&lt;/span&gt;&lt;span class="o"&gt;-|&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For all these cases we&amp;#8217;d have to add intermediate boxes in between our
children and the parent container — with all the issues of theming and
updating things like GtkBuilder &lt;span class="caps"&gt;XML&lt;/span&gt; descriptions that come with&amp;nbsp;that.&lt;/p&gt;
&lt;h3&gt;Future&lt;/h3&gt;
&lt;p&gt;The truth is, though, that describing layouts in terms of constraints is
another case of software engineering your way out of talking with
designers; it&amp;#8217;s great to start talking about incremental simplex solvers,
and systems of linear equations, and &lt;span class="caps"&gt;ASCII&lt;/span&gt; art to describe your layouts, but
it doesn&amp;#8217;t make &lt;span class="caps"&gt;UI&lt;/span&gt; designers &lt;em&gt;really&lt;/em&gt; happy. They can deal with it, and
having a declarative language to describe constraints is more helpful than
parachuting them into an &lt;span class="caps"&gt;IDE&lt;/span&gt; with a Swiss army knife and a can of beans, but
I wouldn&amp;#8217;t recommend it as a solid approach to developer&amp;nbsp;experience.&lt;/p&gt;
&lt;p&gt;Havoc wrote &lt;a href="https://blog.ometer.com/2016/09/17/layout-apis-dont-have-to-be-terrible-lessons-from-bokeh/"&gt;a great article&lt;/a&gt; on how layout management
&lt;span class="caps"&gt;API&lt;/span&gt; doesn&amp;#8217;t necessarily have to&amp;nbsp;suck:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;we can come up with a better, descriptive &lt;span class="caps"&gt;API&lt;/span&gt; that does not make
    engineers and designers cringe in different&amp;nbsp;ways&lt;/li&gt;
&lt;li&gt;we should have support from our tools, in order to manipulate constraints
    and &lt;span class="caps"&gt;UI&lt;/span&gt;&amp;nbsp;elements&lt;/li&gt;
&lt;li&gt;we should be able to combine boxes (which are easy to style) and
    constraints (which are easy to lay out) together in a natural and
    flexible&amp;nbsp;way&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Improving layout management should be a goal in the development of &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 4.0,
so feel free to jump in and help&amp;nbsp;out.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="layout"></category><category term="gtk"></category><category term="constraints"></category><category term="solvers"></category></entry><entry><title>Constraints</title><link href="https://www.bassi.io/articles/2016/10/17/constraints/" rel="alternate"></link><published>2016-10-17T18:30:00+01:00</published><updated>2023-02-20T00:37:38+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-10-17:/articles/2016/10/17/constraints/</id><summary type="html">&lt;p&gt;Experiments with constraint-based layout systems for &lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;span class="caps"&gt;GUI&lt;/span&gt; toolkits have different ways to lay out the elements that compose an
application&amp;#8217;s &lt;span class="caps"&gt;UI&lt;/span&gt;. You can go from the fixed layout management — somewhat
best represented by the old &amp;#8216;90s Visual tools from Microsoft; to the
&amp;#8220;springs and struts&amp;#8221; model employed by the Apple toolkits until recently; to
the &amp;#8220;boxes inside boxes inside boxes&amp;#8221; model that &lt;span class="caps"&gt;GTK&lt;/span&gt;+ uses to this day. All
of these layout policies have their own distinct pros and cons, and it&amp;#8217;s not
unreasonable to find that many toolkits provide support for more than one
policy, in order to cater to more use&amp;nbsp;cases.&lt;/p&gt;
&lt;p&gt;For instance, while &lt;span class="caps"&gt;GTK&lt;/span&gt;+ user interfaces are mostly built using nested boxes
to control margins, spacing, and alignment of widgets, there&amp;#8217;s a sizeable
portion of &lt;span class="caps"&gt;GTK&lt;/span&gt;+ developers that end up using &lt;a href="https://developer.gnome.org/gtk3/stable/GtkFixed.html"&gt;GtkFixed&lt;/a&gt; or
&lt;a href="https://developer.gnome.org/gtk3/stable/GtkLayout.html"&gt;GtkLayout&lt;/a&gt; containers because they need fixed positioning
of children widget — until they regret it, because now they have to handle
things like reflowing, flipping contents in right-to-left locales, or font
size&amp;nbsp;changes.&lt;/p&gt;
&lt;p&gt;Additionally, most &lt;span class="caps"&gt;UI&lt;/span&gt; designers do not tend to &amp;#8220;think with boxes&amp;#8221;, unless
it&amp;#8217;s for Web pages, and even in that case &lt;span class="caps"&gt;CSS&lt;/span&gt; affords a certain freedom that
cannot be replicated in a &lt;span class="caps"&gt;GUI&lt;/span&gt; toolkit. This usually results in engineers
translating a &lt;span class="caps"&gt;UI&lt;/span&gt; specification made of ties and relations between &lt;span class="caps"&gt;UI&lt;/span&gt;
elements into something that can be expressed with a pile of grids, boxes,
bins, and stacks — with all the back and forth, validation, and resources
that the translation&amp;nbsp;entails.&lt;/p&gt;
&lt;p&gt;It would certainly be easier if we could express a &lt;span class="caps"&gt;GUI&lt;/span&gt; layout in the same
set of relationships that can be traced on a piece of paper, a &lt;span class="caps"&gt;UI&lt;/span&gt; design
tool, or a design&amp;nbsp;document:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;this label is at 8px from the leading edge of the&amp;nbsp;box&lt;/li&gt;
&lt;li&gt;this entry is on the same horizontal line as the label, its leading
    edge at 12px from the trailing edge of the&amp;nbsp;label&lt;/li&gt;
&lt;li&gt;the entry has a minimum size of 250px, but can grow to fill the
    available&amp;nbsp;space&lt;/li&gt;
&lt;li&gt;there&amp;#8217;s a 90px button that sits between the trailing edge of the
    entry and the trailing edge of the box, with 8px between either
    edges and&amp;nbsp;itself&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Sure, all of these constraints can be replaced by a couple of boxes; some
packing properties; margins; and minimum preferred sizes. If the design
changes, though, like it often does, reconstructing the &lt;span class="caps"&gt;UI&lt;/span&gt; can become
arbitrarily hard. This, in turn, leads to pushback to design changes from
engineers — and the cost of iterating over a &lt;span class="caps"&gt;GUI&lt;/span&gt; is compounded by technical&amp;nbsp;inertia.&lt;/p&gt;
&lt;p&gt;For my daily work at Endless I&amp;#8217;ve been interacting with our design team for
a while, and trying to get from design specs to applications more quickly,
and with less inertia. Having &lt;span class="caps"&gt;CSS&lt;/span&gt; available allowed designers to be more
involved in the iterative development process, but the &lt;span class="caps"&gt;CSS&lt;/span&gt; subset that &lt;span class="caps"&gt;GTK&lt;/span&gt;+
implements is not allowed — for eminently good reasons — to change the &lt;span class="caps"&gt;UI&lt;/span&gt;
layout. We could go &amp;#8220;full Web&amp;#8221;, but that comes with a very large set of
drawbacks — performance on low end desktop devices,  distribution,
interaction with system services being just the most glaring ones. A native
toolkit is still the preferred target for our platform, so I started looking
at ways to improve the lives of &lt;span class="caps"&gt;UI&lt;/span&gt; designers with the tools at our&amp;nbsp;disposal.&lt;/p&gt;
&lt;p&gt;Expressing layout through easier to understand relationships between its
parts is not a new problem, and as such it does not have new solutions;
other platforms, like the &lt;a href="https://developer.apple.com/library/content/documentation/UserExperience/Conceptual/AutolayoutPG/"&gt;Apple operating systems&lt;/a&gt;, or
Google&amp;#8217;s &lt;a href="https://developer.android.com/training/constraint-layout/index.html"&gt;Android&lt;/a&gt;, have started to provide this kind
of functionality — mostly available through their own &lt;span class="caps"&gt;IDE&lt;/span&gt; and &lt;span class="caps"&gt;UI&lt;/span&gt; building
tools, but also available programmatically. It&amp;#8217;s even available for
platforms like &lt;a href="http://ijzerenhein.github.io/autolayout.js/"&gt;the Web&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;What many of &lt;a href="http://overconstrained.io"&gt;these solutions&lt;/a&gt; seem to have in common
is using more or less the same solving algorithm — &lt;a href="http://constraints.cs.washington.edu/cassowary/"&gt;Cassowary&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Cassowary&amp;nbsp;is:&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;an incremental constraint solving toolkit that efficiently solves systems
of linear equalities and inequalities. Constraints may be either
requirements or preferences. Client code specifies the constraints to be
maintained, and the solver updates the constrained variables to have
values that satisfy the&amp;nbsp;constraints.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;This makes it particularly suited for user&amp;nbsp;interfaces.&lt;/p&gt;
&lt;p&gt;The original implementation of Cassowary was written in 1998, in Java, C++,
and Smalltalk; since then, various other re-implementations surfaced:
Python, JavaScript, Haskell, slightly-more-modern-C++,&amp;nbsp;etc.&lt;/p&gt;
&lt;aside&gt;To continue in the naming policy of Cassowary implementations, this
small library is named after yet another flightless bird&lt;/aside&gt;

&lt;p&gt;To that collection, I&amp;#8217;ve now added my own — written in C/GObject — called
&lt;a href="https://github.com/ebassi/emeus"&gt;Emeus&lt;/a&gt;, which provides a &lt;span class="caps"&gt;GTK&lt;/span&gt;+ container and layout manager that
uses the Cassowary constraint solving algorithm to compute the allocation
of each&amp;nbsp;child.&lt;/p&gt;
&lt;p&gt;In spirit, the implementation is pretty simple: you create a new
&lt;code&gt;EmeusConstraintLayout&lt;/code&gt; widget instance, add a bunch of widgets to it, and
then use &lt;code&gt;EmeusConstraint&lt;/code&gt; objects to determine the relations between
children of the&amp;nbsp;layout:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;simple-grid.js&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 89-170]&lt;/span&gt;&lt;a href='/code/emeus/simple-grid.js'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Child 1&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child1&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Child 2&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child2&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="kd"&gt;let&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;=&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Gtk&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Button&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;label&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;Child 3&amp;#39;&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;});&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;pack&lt;/span&gt;&lt;span class="p"&gt;(&lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="s1"&gt;&amp;#39;child3&amp;#39;&lt;/span&gt;&lt;span class="p"&gt;);&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;show&lt;/span&gt;&lt;span class="p"&gt;();&lt;/span&gt;

&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="k"&gt;this&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;_layout&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;add_constraints&lt;/span&gt;&lt;span class="p"&gt;([&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WIDTH&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;WIDTH&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;START&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;END&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;TOP&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;12.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button1&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HEIGHT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HEIGHT&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button2&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;HEIGHT&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="ow"&gt;new&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;Constraint&lt;/span&gt;&lt;span class="p"&gt;({&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;target_object&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;button3&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;target_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;relation&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintRelation&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;EQ&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;source_attribute&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="nx"&gt;Emeus&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;ConstraintAttribute&lt;/span&gt;&lt;span class="p"&gt;.&lt;/span&gt;&lt;span class="nx"&gt;BOTTOM&lt;/span&gt;&lt;span class="p"&gt;,&lt;/span&gt;
&lt;span class="w"&gt;                                   &lt;/span&gt;&lt;span class="nx"&gt;constant&lt;/span&gt;&lt;span class="o"&gt;:&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="mf"&gt;8.0&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="p"&gt;}),&lt;/span&gt;
&lt;span class="w"&gt;        &lt;/span&gt;&lt;span class="p"&gt;]);&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;A simple&amp;nbsp;grid&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/emeus-simple-grid.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;This obviously looks like a ton of code, which is why I added the ability to
describe constraints inside GtkBuilder &lt;span class="caps"&gt;XML&lt;/span&gt;:&lt;/p&gt;
&lt;figure class='code'&gt;
&lt;figcaption&gt;&lt;span class="liquid-tags-code-filename"&gt;centered.ui&lt;/span&gt;&lt;span class="liquid-tags-code-lines"&gt;[Lines 28-45]&lt;/span&gt;&lt;a href='/code/emeus/centered.ui'&gt;download&lt;/a&gt;&lt;/figcaption&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;constraints&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;constraint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;target-object=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;button_child&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;target-attr=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;center-x&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;relation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;eq&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;source-object=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;super&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;source-attr=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;center-x&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;strength=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;required&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;constraint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;target-object=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;button_child&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;target-attr=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;EMEUS_CONSTRAINT_ATTRIBUTE_CENTER_Y&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;relation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;eq&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;source-object=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;super&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;source-attr=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;center-y&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;              &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;constraint&lt;/span&gt;&lt;span class="w"&gt; &lt;/span&gt;&lt;span class="na"&gt;target-object=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;button_child&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;target-attr=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;width&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;relation=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;ge&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;constant=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;200&amp;quot;&lt;/span&gt;
&lt;span class="w"&gt;                          &lt;/span&gt;&lt;span class="na"&gt;strength=&lt;/span&gt;&lt;span class="s"&gt;&amp;quot;EMEUS_CONSTRAINT_STRENGTH_STRONG&amp;quot;&lt;/span&gt;&lt;span class="nt"&gt;/&amp;gt;&lt;/span&gt;
&lt;span class="w"&gt;            &lt;/span&gt;&lt;span class="nt"&gt;&amp;lt;/constraints&amp;gt;&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;/figure&gt;
&lt;p&gt;Additionally, I&amp;#8217;m writing a small parser for the Visual Format Language used
by Apple for their own auto layout implementation — even though it does look
like &lt;span class="caps"&gt;ASCII&lt;/span&gt; art of Perl format strings, it&amp;#8217;s easy to&amp;nbsp;grasp.&lt;/p&gt;
&lt;p&gt;The overall idea is to prototype UIs on top of this, and then take advantage
of &lt;span class="caps"&gt;GTK&lt;/span&gt;+&amp;#8217;s new development cycle to introduce something like this and see if
we can get people to migrate from&amp;nbsp;GtkFixed/GtkLayout.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="layout"></category><category term="gtk"></category><category term="constraints"></category><category term="solvers"></category></entry><entry><title>Who wrote GTK+ and more</title><link href="https://www.bassi.io/articles/2016/09/21/who-wrote-gtk-final/" rel="alternate"></link><published>2016-09-21T11:19:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-09-21:/articles/2016/09/21/who-wrote-gtk-final/</id><summary type="html">&lt;p&gt;a recap of the contributions to the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3.22 development&amp;nbsp;cycle&lt;/p&gt;</summary><content type="html">&lt;p&gt;I&amp;#8217;ve just posted on the &lt;a href="https://blog.gtk.org/2016/09/21/who-wrote-gtk-3-22/"&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+ development blog&lt;/a&gt; the latest
article in the &amp;#8220;who writes &lt;span class="caps"&gt;GTK&lt;/span&gt;+&amp;#8221; series. Now that we have a proper
development blog, this is the kind of content that should be present there
instead of my personal&amp;nbsp;blog.&lt;/p&gt;
&lt;p&gt;If you&amp;#8217;re not following the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ development blog, you really should do so
&lt;em&gt;now&lt;/em&gt;. Additionally, you should follow &lt;a href="https://twitter.com/GTKToolkit"&gt;@GTKToolkit&lt;/a&gt; on Twitter
and, if you&amp;#8217;re into niche social platforms, a kernel developer, or a Linus
groupie, there&amp;#8217;s the &lt;a href="https://plus.google.com/+GtkOrg"&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/a&gt; page on Google&amp;nbsp;Plus.&lt;/p&gt;
&lt;p&gt;Additionally, if you&amp;#8217;re contributing to &lt;span class="caps"&gt;GTK&lt;/span&gt;+, or using it, you should
consider writing an article for the developers blog; just contact me on &lt;span class="caps"&gt;IRC&lt;/span&gt;
(I&amp;#8217;m &lt;code&gt;ebassi&lt;/code&gt; on irc.gnome.org) or send me an email if you have an idea
about something you worked on, a new feature, some new &lt;span class="caps"&gt;API&lt;/span&gt;, or the internals
of the&amp;nbsp;platform.&lt;/p&gt;</content><category term="gnome"></category><category term="glib"></category><category term="gtk"></category><category term="development"></category><category term="gnome"></category><category term="who makes gnome"></category></entry><entry><title>GSK Demystified (III) — Interlude</title><link href="https://www.bassi.io/articles/2016/08/27/gsk-demystified-3/" rel="alternate"></link><published>2016-08-27T10:28:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-08-27:/articles/2016/08/27/gsk-demystified-3/</id><summary type="html">&lt;p&gt;In which we take a short pause and explain the current state of &lt;span class="caps"&gt;GSK&lt;/span&gt;&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;See the &lt;a href="https://www.bassi.io/tag/gsk-demystified/"&gt;the tag for the &lt;span class="caps"&gt;GSK&lt;/span&gt; demystified series&lt;/a&gt; for the
other articles in the&amp;nbsp;series.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;There have been multiple reports after &lt;a href="https://2016.guadec.org"&gt;&lt;span class="caps"&gt;GUADEC&lt;/span&gt;&lt;/a&gt; about the state
of &lt;span class="caps"&gt;GSK&lt;/span&gt;, so let&amp;#8217;s recap a bit by upholding the-long standing tradition of using
a &lt;span class="caps"&gt;FAQ&lt;/span&gt; format as a rhetorical&amp;nbsp;device.&lt;/p&gt;
&lt;hr&gt;
&lt;h3&gt;Q: Is &lt;span class="caps"&gt;GSK&lt;/span&gt; going to be merged in time for&amp;nbsp;3.22?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Short answer:&amp;nbsp;no.&lt;/p&gt;
&lt;p&gt;Long-ish answer: landing a rewrite of how &lt;span class="caps"&gt;GTK&lt;/span&gt; renders its widgets near the
end of a stable &lt;span class="caps"&gt;API&lt;/span&gt; cycle, when a bunch of applications that tend to eschew
&lt;span class="caps"&gt;GTK&lt;/span&gt;+ itself for rendering their content — like Firefox or LibreOffice —
finally, after many years, ported to &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3, seemed a bit sadistic on our&amp;nbsp;part.&lt;/p&gt;
&lt;p&gt;Additionally, &lt;span class="caps"&gt;GSK&lt;/span&gt; still has some performance issues when it comes to large
or constantly updating UIs; try running, for instance &lt;code&gt;gtk3-widget-factory&lt;/code&gt;
on HiDPI using the &lt;a href="https://git.gnome.org/browse/gtk+/log/?h=wip/ebassi/gsk-renderer"&gt;wip/ebassi/gsk-renderer&lt;/a&gt; branch and
marvel at the 10 fps we achieve&amp;nbsp;currently.&lt;/p&gt;
&lt;h3&gt;Q: Aside from performance, are there any other&amp;nbsp;concerns?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Performance is pretty much the biggest concern we found. We need to
reduce the amount of rasterizations we perform with Cairo, and we need
better ways to cache and reuse those rasterizations across frames; we really
want all buttons with the same &lt;span class="caps"&gt;CSS&lt;/span&gt; state and size to be rasterized once, for
instance, and just drawn multiple times in their right place. The same
applies to things like icons. Caching text runs and glyphs would also be a
nice&amp;nbsp;win.&lt;/p&gt;
&lt;p&gt;The nice bit is that, with a fully retained render tree, now we can actually
do&amp;nbsp;this.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;API&lt;/span&gt; seems to have survived contact with the widget drawing code inside
&lt;span class="caps"&gt;GTK&lt;/span&gt;+, so it&amp;#8217;s a matter of deciding how much we need to provide in terms of
convenience &lt;span class="caps"&gt;API&lt;/span&gt; for out-of-tree widgets and containers. The fallback code is
in place, right now, which means that porting widgets can proceed at its own&amp;nbsp;pace.&lt;/p&gt;
&lt;p&gt;There are a few bugs in the rendering code, like blend modes; and I still
want to have filters like blur and color conversions in the GskRenderNode
&lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;Finally, there&amp;#8217;s still the open question of the mid-level scene graph &lt;span class="caps"&gt;API&lt;/span&gt;,
or &lt;code&gt;GskLayer&lt;/code&gt;, that will replace Clutter and Clutter-&lt;span class="caps"&gt;GTK&lt;/span&gt;; the prototype is
roughly done, but things like animations are not set in stone due to lack of&amp;nbsp;users.&lt;/p&gt;
&lt;h3&gt;Q: Is there a plan for merging &lt;span class="caps"&gt;GSK&lt;/span&gt;?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; Yes, we do have a&amp;nbsp;plan.&lt;/p&gt;
&lt;p&gt;The merge window mostly hinges on when we&amp;#8217;re going to start with a new
development cycle for the next &lt;span class="caps"&gt;API&lt;/span&gt;, but we decided that as soon as the
window opens, &lt;span class="caps"&gt;GSK&lt;/span&gt; will land. Ideally we want to ensure that, by the time 4.0
rolls around, there won&amp;#8217;t be any users of &lt;code&gt;GtkWidget::draw&lt;/code&gt; left inside
&lt;span class="caps"&gt;GNOME&lt;/span&gt;, so we&amp;#8217;ll be able to deprecate its use, and applications targeting the
new stable &lt;span class="caps"&gt;API&lt;/span&gt; will be able to port away from&amp;nbsp;it.&lt;/p&gt;
&lt;p&gt;Having a faster, more featureful, and more optimized rendering pipeline
inside &lt;span class="caps"&gt;GTK&lt;/span&gt;+ is a pretty good new feature for the next &lt;span class="caps"&gt;API&lt;/span&gt; cycle, and we
think that the port is not going to be problematic, given the amount of
fallback code paths in&amp;nbsp;place.&lt;/p&gt;
&lt;p&gt;Additionaly, by the time we release &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 4.0, we&amp;#8217;ll have a more
battle-tested &lt;span class="caps"&gt;API&lt;/span&gt; to replace Clutter and Clutter-&lt;span class="caps"&gt;GTK&lt;/span&gt;, allowing applications
to drop a&amp;nbsp;dependency.&lt;/p&gt;
&lt;h3&gt;Q: How can I&amp;nbsp;help?&lt;/h3&gt;
&lt;p&gt;&lt;strong&gt;A:&lt;/strong&gt; If you&amp;#8217;re a maintainer of a &lt;span class="caps"&gt;GTK&lt;/span&gt;+ library or application, or if you
want to help out the development of &lt;span class="caps"&gt;GTK&lt;/span&gt;+ itself, then you can pick up my
&lt;a href="https://git.gnome.org/browse/gtk+/log/?h=wip/ebassi/gsk-renderer"&gt;&lt;span class="caps"&gt;GSK&lt;/span&gt; development branch&lt;/a&gt;, fork it off, and look at porting
widgets and containers. I&amp;#8217;m particularly interested in widgets using complex
drawing operations. See where the &lt;span class="caps"&gt;API&lt;/span&gt; is too bothersome, and look for
patterns we can wrap into convenience &lt;span class="caps"&gt;API&lt;/span&gt; provided by &lt;span class="caps"&gt;GTK&lt;/span&gt;+ itself. For
instance, the various &lt;code&gt;gtk_render_*&lt;/code&gt; family of functions are a prime
candidate for being replaced by equivalent functions that return a
&lt;code&gt;GskRenderNode&lt;/code&gt; instead.&lt;/p&gt;
&lt;p&gt;Testing is also welcome; for instance, look at missing widgets or fragments
of&amp;nbsp;rendering.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Hopefully, the answers above should have provided enough context for the
current state of &lt;span class="caps"&gt;GSK&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;The next time, we&amp;#8217;ll return to design and implementation notes of the &lt;span class="caps"&gt;API&lt;/span&gt;&amp;nbsp;itself.&lt;/p&gt;</content><category term="gnome"></category><category term="gtk"></category><category term="gsk"></category><category term="gsk demystified"></category><category term="development"></category><category term="welcome to the world of tomorrow"></category></entry><entry><title>GUADEC/2</title><link href="https://www.bassi.io/articles/2016/08/18/guadec-return/" rel="alternate"></link><published>2016-08-18T09:00:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-08-18:/articles/2016/08/18/guadec-return/</id><summary type="html">&lt;p&gt;And we&amp;#8217;re&amp;nbsp;back…&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;Writing this from my home office, while drinking the first coffee of the&amp;nbsp;day.&lt;/em&gt;&lt;/p&gt;
&lt;p&gt;Once again, &lt;span class="caps"&gt;GUADEC&lt;/span&gt; has come and&amp;nbsp;gone.&lt;/p&gt;
&lt;p&gt;Once again, it was impeccably organized by so many wonderful&amp;nbsp;volunteers.&lt;/p&gt;
&lt;p&gt;Once again, I feel my batteries&amp;nbsp;recharged.&lt;/p&gt;
&lt;p&gt;Once again, I&amp;#8217;ve had so many productive&amp;nbsp;conversations.&lt;/p&gt;
&lt;p&gt;Once again, I&amp;#8217;ve had many chances to&amp;nbsp;laugh.&lt;/p&gt;
&lt;p&gt;Once again, I&amp;#8217;ve met both new and long since&amp;nbsp;friends.&lt;/p&gt;
&lt;p&gt;Once again, I&amp;#8217;ve visited a new city, with interesting life, food, drinks,
and&amp;nbsp;locations.&lt;/p&gt;
&lt;p&gt;Once again, thanks to everybody who worked very hard to make this &lt;span class="caps"&gt;GUADEC&lt;/span&gt;
happen and be the success it&amp;nbsp;was.&lt;/p&gt;
&lt;p&gt;Once again, we&amp;nbsp;return.&lt;/p&gt;</content><category term="gnome"></category><category term="guadec"></category><category term="conference"></category><category term="gtk"></category><category term="gnome"></category></entry><entry><title>GUADEC</title><link href="https://www.bassi.io/articles/2016/08/10/guadec/" rel="alternate"></link><published>2016-08-10T15:40:00+01:00</published><updated>2023-05-22T10:26:26+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-08-10:/articles/2016/08/10/guadec/</id><summary type="html">&lt;p&gt;See you all in&amp;nbsp;Karlsruhe&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;img alt="Speaking at GUADEC 2016" src="https://www.bassi.io/images/guadec-2016-speaking-badge.png"&gt;&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to talk about &lt;a href="https://2016.guadec.org/schedule/#abstract-16-gtk_are_we_in_the_future_yet"&gt;the evolution of &lt;span class="caps"&gt;GTK&lt;/span&gt;+ rendering&lt;/a&gt;, from
its humble origins of X11 graphics contexts, to Cairo, to &lt;span class="caps"&gt;GSK&lt;/span&gt;. If you are
interested in this kind of stuff, you can either attend my presentation on
Saturday at 11 in the Grace Room, or you can just find me and have a&amp;nbsp;chat.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m also going to stick around during the BoF days — especially for the
usual &lt;span class="caps"&gt;GTK&lt;/span&gt;+ team meeting, which will be on the&amp;nbsp;15th.&lt;/p&gt;
&lt;p&gt;See you all in&amp;nbsp;Karlsruhe.&lt;/p&gt;</content><category term="gnome"></category><category term="guadec"></category><category term="conference"></category><category term="gtk"></category><category term="gnome"></category></entry><entry><title>GSK Demystified (II) — Rendering</title><link href="https://www.bassi.io/articles/2016/08/10/gsk-demystified-2/" rel="alternate"></link><published>2016-08-10T15:20:00+01:00</published><updated>2023-05-22T10:26:43+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-08-10:/articles/2016/08/10/gsk-demystified-2/</id><summary type="html">&lt;p&gt;In which rendering &lt;span class="caps"&gt;GTK&lt;/span&gt; with &lt;span class="caps"&gt;GSK&lt;/span&gt; is&amp;nbsp;explained&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;em&gt;See the &lt;a href="https://www.bassi.io/articles/2016/07/05/gsk-demystified-1/"&gt;previous article&lt;/a&gt; for an introduction to &lt;span class="caps"&gt;GSK&lt;/span&gt;.&lt;/em&gt;&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;In order to render with &lt;span class="caps"&gt;GSK&lt;/span&gt; we need to get acquainted with two&amp;nbsp;classes:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GskRenderNode&lt;/code&gt;, a single element in the rendering&amp;nbsp;tree&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GskRenderer&lt;/code&gt;, the object that effectively turns the rendering tree
   into rendering&amp;nbsp;commands&lt;/li&gt;
&lt;/ul&gt;
&lt;h3&gt;GskRenderNode&lt;/h3&gt;
&lt;p&gt;The usual way to put things on the screen involves asking the windowing
system to give us a memory region, filling it with something, and then
asking the windowing system to present it to the graphics hardware, in the
hope that everything ends up on the display. This is pretty much how every
windowing system works. The only difference lies in that &amp;#8220;filling it with&amp;nbsp;something&amp;#8221;.&lt;/p&gt;
&lt;p&gt;With Cairo you get a surface that represents that memory region, and a
(stateful) drawing context; every time you need to draw you set up your
state and emit a series of commands. This happens on every frame, starting
from the top level window down into every leaf object. At the end of the
frame, the content of the window is swapped with the content of the buffer.
Every frame is drawn while we&amp;#8217;re traversing the widget tree, and we have
no control on the rendering outside of the state of the drawing&amp;nbsp;context.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;A tree of &lt;span class="caps"&gt;GTK&lt;/span&gt;&amp;nbsp;widgets&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gtk-widget-tree.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;With &lt;span class="caps"&gt;GSK&lt;/span&gt; we change this process with a small layer of indirection; every
widget, from the top level to the leaves, creates a series of &lt;em&gt;render
nodes&lt;/em&gt;, small objects that each hold the drawing state for their contents.
Each node is, at its simplest, a collection&amp;nbsp;of:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a rectangle, representing the region used to draw the&amp;nbsp;contents&lt;/li&gt;
&lt;li&gt;a transformation matrix, representing the parent-relative set
   of transformations applied to the contents when&amp;nbsp;drawing&lt;/li&gt;
&lt;li&gt;the contents of the&amp;nbsp;node&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every frame, thus, is composed of a tree of render&amp;nbsp;nodes.&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;A tree of &lt;span class="caps"&gt;GTK&lt;/span&gt; widgets and &lt;span class="caps"&gt;GSK&lt;/span&gt; render&amp;nbsp;nodes&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gsk-render-tree.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;The important thing is that the render tree does not draw anything; it
describes what to draw (which can be a rasterization generated using Cairo)
and how and where to draw it. The actual drawing is deferred to the
&lt;code&gt;GskRenderer&lt;/code&gt; instance, and will happen only once the tree has been&amp;nbsp;built.&lt;/p&gt;
&lt;p&gt;After the rendering is complete we can discard the render tree. Since the
rendering is decoupled from the widget state, the widgets will hold all the
state across frames — as they already do. Each &lt;code&gt;GskRenderNode&lt;/code&gt; instance is,
thus, a very simple instance type instead of a full GObject, whose lifetime
is determined by the&amp;nbsp;renderer.&lt;/p&gt;
&lt;h3&gt;GskRenderer&lt;/h3&gt;
&lt;p&gt;The renderer is the object that turns a render tree into the actual draw
commands. At its most basic, it&amp;#8217;s a simple compositor, taking the content of
each node and its state and blending it on a rendering surface, which then
gets pushed to the windowing system. In practice, it&amp;#8217;s a tad more
complicated than&amp;nbsp;that.&lt;/p&gt;
&lt;p&gt;Each top-level has its own renderer instance, as it requires access to
windowing system resources, like a &lt;span class="caps"&gt;GL&lt;/span&gt; context. When the frame is started,
the renderer will take a render tree and a drawing context, and will proceed
to traverse the render tree in order to translate it into actual render&amp;nbsp;commands. &lt;/p&gt;
&lt;p&gt;As we want to offload the rendering and blending to the &lt;span class="caps"&gt;GPU&lt;/span&gt;, the
&lt;code&gt;GskRenderer&lt;/code&gt; instance you&amp;#8217;ll most likely get is one that uses OpenGL to
perform the rendering. The &lt;span class="caps"&gt;GL&lt;/span&gt; renderer will take the render tree and convert
it into a (mostly flat) list of data structures that represent the state to
be pushed on the state machine — the blending mode, the shading program, the
textures to sample, and the vertex buffer objects and attributes that
describe the rendering. This &amp;#8220;translation&amp;#8221; stage allows the renderer to
decide which render nodes should be used and which should be discarded; it
also allows us to create, or recycle, all the needed resources when the
frame starts, and minimize the state transitions when doing the actual&amp;nbsp;rendering.&lt;/p&gt;
&lt;h3&gt;Going from here to&amp;nbsp;there&lt;/h3&gt;
&lt;p&gt;Widgets provided by &lt;span class="caps"&gt;GTK&lt;/span&gt; will automatically start using render nodes
instead of rendering directly to a Cairo&amp;nbsp;context.&lt;/p&gt;
&lt;p&gt;There are various fallback code paths in place in the existing code, which
means that, luckily, we don&amp;#8217;t have to break any existing out of tree widget:
they will simply draw themselves (and their children) on an implicit render
node. If you want to port your custom widgets or containers, on the other
hand, you&amp;#8217;ll have to remove the &lt;code&gt;GtkWidget::draw&lt;/code&gt; virtual function
implementation or signal handler you use, and override the &lt;code&gt;GtkWidget::get_render_node()&lt;/code&gt;
virtual function&amp;nbsp;instead.&lt;/p&gt;
&lt;p&gt;Containers simply need to create a render node for their own background,
border, or custom drawing; then they will have to retrieve the render node
for each of their children. We&amp;#8217;ll provide convenience &lt;span class="caps"&gt;API&lt;/span&gt; for that, so the
chances of getting something wrong will be, hopefully, reduced to&amp;nbsp;zero.&lt;/p&gt;
&lt;p&gt;Leaf widgets can remain unported a bit longer, unless they are composed of
multiple rendering elements, in which case they simply need to create a new
render node for each&amp;nbsp;element.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll provide more example of porting widgets in a later article, as soon as
the &lt;span class="caps"&gt;API&lt;/span&gt; will have&amp;nbsp;stabilized.&lt;/p&gt;</content><category term="gnome"></category><category term="gtk"></category><category term="gsk"></category><category term="gsk demystified"></category><category term="development"></category><category term="welcome to the world of tomorrow"></category></entry><entry><title>GSK Demystified (I) — A GSK primer</title><link href="https://www.bassi.io/articles/2016/07/05/gsk-demystified-1/" rel="alternate"></link><published>2016-07-05T11:11:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-07-05:/articles/2016/07/05/gsk-demystified-1/</id><summary type="html">&lt;p&gt;In which I start explaining what &lt;span class="caps"&gt;GSK&lt;/span&gt; is, does, and where it&amp;#8217;s&amp;nbsp;at&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last month I published &lt;a href="https://blog.gtk.org/2016/06/15/drawing-in-gtk/"&gt;an article&lt;/a&gt; on how &lt;span class="caps"&gt;GTK&lt;/span&gt;+ draws widgets
on &lt;a href="https://blog.gtk.org"&gt;the toolkit development blog&lt;/a&gt;. The article should give you
some background on the current state of what &lt;span class="caps"&gt;GTK&lt;/span&gt; does when something asks it
to draw what you see on the screen — so it&amp;#8217;s probably a good idea to read
that first, and then come back here. Don&amp;#8217;t worry, I&amp;#8217;ll&amp;nbsp;wait…&lt;/p&gt;
&lt;hr&gt;
&lt;aside&gt;If you&amp;#8217;re running with X11 you may find some of the &lt;span class="caps"&gt;XRENDER&lt;/span&gt;
extension operations to be implemented with a modicum of hardware
acceleration; that does not imply that what you see has hit the right code
paths in the stack.&lt;/aside&gt;

&lt;p&gt;Welcome back! Now that we&amp;#8217;re on the same page… What I didn&amp;#8217;t say in that
article is that most of it happens on your &lt;span class="caps"&gt;CPU&lt;/span&gt;, rather than on your &lt;span class="caps"&gt;GPU&lt;/span&gt; —
except the very last step, when the compositor takes the contents of each
window and pushes them to the &lt;span class="caps"&gt;GPU&lt;/span&gt;, likely via the 3D pipeline provided by
your windowing system, to composite them into what you&amp;#8217;ll likely see on your&amp;nbsp;screen.&lt;/p&gt;
&lt;p&gt;The goal for &lt;span class="caps"&gt;GUI&lt;/span&gt; toolkits, for the past few years, has been to take
advantage of the &lt;span class="caps"&gt;GPU&lt;/span&gt; programmable pipeline as much as possible, as it allows
to use the right hardware for the job, while keeping your &lt;span class="caps"&gt;CPU&lt;/span&gt; free for
working on the application logic, or simply powered down and avoid polar
bears to squeeze on an ever reducing sheet of artic ice. It also allows to
improve the separation of jobs internally to the toolkit, with the potential
of splitting up the work across multiple &lt;span class="caps"&gt;CPU&lt;/span&gt;&amp;nbsp;cores.&lt;/p&gt;
&lt;aside&gt;Yes, we also have Vulkan. Or, at least, we&amp;#8217;re soon going to have
Vulkan. You can swap OpenGL with Vulkan throughout this article, if you
want, and you&amp;#8217;ll get pretty much the same results. Hopefully, internally,
we&amp;#8217;ll be able to do the same.&lt;/aside&gt;

&lt;p&gt;As toolkit developers, we currently have only one major &lt;span class="caps"&gt;API&lt;/span&gt; for talking to
the &lt;span class="caps"&gt;GPU&lt;/span&gt;, programming it, and using it to put the contents of a window on the
screen, and that&amp;#8217;s&amp;nbsp;OpenGL.&lt;/p&gt;
&lt;p&gt;You may think: &lt;em&gt;well, we use Cairo; Cairo has support for an OpenGL device.
Just enable that, and we&amp;#8217;re good to go, right?&lt;/em&gt; and you wouldn&amp;#8217;t be entirely
wrong — &lt;strong&gt;except&lt;/strong&gt; that you really don&amp;#8217;t want to use the OpenGL Cairo
device in production, as it&amp;#8217;s both a poor fit for the Cairo drawing model
&lt;em&gt;and&lt;/em&gt; it&amp;#8217;s basically unmaintained. Also, Cairo is pretty much 2D only, and
while you can fake some 3D transformations with it, it&amp;#8217;s definitely not up
to the task of implementing the full &lt;a href="https://www.w3.org/TR/css-transforms-1/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; transformation&lt;/a&gt;&amp;nbsp;specification.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Using OpenGL to generate pixel-perfect results is complicated, and in some
cases it just goes against the expectations of the &lt;span class="caps"&gt;GPU&lt;/span&gt; itself: reading back
data; minuscule fragments and tesselations; tons of state changes — those
are all pretty much no-go areas when dealing with a &lt;span class="caps"&gt;GPU&lt;/span&gt;.&lt;/p&gt;
&lt;aside&gt;If we could also move frame rendering to separate threads we could
have multiple frames scheduled on different cores running at the same time,
thus speeding up the whole drawing process.&lt;/aside&gt;

&lt;p&gt;On the other hand, we really want to stop relying so much on the &lt;span class="caps"&gt;CPU&lt;/span&gt; for
drawing; leaving your cores idle allows them to go into low power states,
preserving them and improving your battery life; additionally, any cycle
that is not spent inside the toolkit is a cycle available to your
application&amp;nbsp;logic.&lt;/p&gt;
&lt;p&gt;As you may know from the past few years, I&amp;#8217;ve been working on writing a new
&lt;span class="caps"&gt;API&lt;/span&gt; that lets &lt;span class="caps"&gt;GTK&lt;/span&gt; offload to the &lt;span class="caps"&gt;GPU&lt;/span&gt; what currently happens on the &lt;span class="caps"&gt;CPU&lt;/span&gt;; it&amp;#8217;s
called &lt;strong&gt;&lt;span class="caps"&gt;GSK&lt;/span&gt;&lt;/strong&gt; — short for &lt;em&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt; Scene Kit&lt;/em&gt; — and its meant to achieve two&amp;nbsp;things:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;render the contents of a &lt;span class="caps"&gt;GTK&lt;/span&gt; application more&amp;nbsp;efficiently&lt;/li&gt;
&lt;li&gt;provide a scene graph &lt;span class="caps"&gt;API&lt;/span&gt; to both the toolkit and&amp;nbsp;applications&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;With these two goals in mind, I want to give a quick overview on how &lt;span class="caps"&gt;GSK&lt;/span&gt;
works, and at which point we are in the&amp;nbsp;development.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;As &lt;span class="caps"&gt;GSK&lt;/span&gt; is meant to serve two purposes it makes sense to have two separate
layers of &lt;span class="caps"&gt;API&lt;/span&gt;. This is a design decision that solidified after various
discussions at &lt;span class="caps"&gt;GUADEC&lt;/span&gt; 2015. As such, it required a fair amount of rework
of the existing code base, but very much for the&amp;nbsp;better.&lt;/p&gt;
&lt;p&gt;At the lowest level we&amp;nbsp;have:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;&lt;code&gt;GskRenderNode&lt;/code&gt;, which is used to describe a tree of textures, blend
   modes, filters, and transformations; this tree is easily converted in
   render operations for graphics &lt;span class="caps"&gt;API&lt;/span&gt; like Cairo and OpenGL, and Vulkan in
   the near&amp;nbsp;future.&lt;/li&gt;
&lt;li&gt;&lt;code&gt;GskRenderer&lt;/code&gt;, an object that takes a tree of &lt;code&gt;GskRenderNode&lt;/code&gt; instances
   that describes the contents of a frame, and renders it on a given
   &lt;code&gt;GdkDrawingContext&lt;/code&gt;.&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Every time you wish to render something, you build a tree of render nodes;
specify their content; set up their transformations, opacity, and blending;
and, finally, you pass the tree to the renderer. After that, the renderer
owns the render nodes tree, so you can safely discard it after each&amp;nbsp;frame.&lt;/p&gt;
&lt;p&gt;On top of this lower level &lt;span class="caps"&gt;API&lt;/span&gt; we can implement both the higher level scene
graph &lt;span class="caps"&gt;API&lt;/span&gt; based on &lt;code&gt;GskLayer&lt;/code&gt; that I presented at &lt;span class="caps"&gt;GUADEC&lt;/span&gt;; and &lt;span class="caps"&gt;GTK&lt;/span&gt;+ itself,
which allows us to avoid reimplementing &lt;span class="caps"&gt;GTK&lt;/span&gt;+ widgets in terms of &lt;span class="caps"&gt;GSK&lt;/span&gt;&amp;nbsp;layers.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;m going to talk about &lt;code&gt;GskRenderer&lt;/code&gt; and &lt;code&gt;GskRenderNode&lt;/code&gt; more in depth in a
future blog post, but if you&amp;#8217;re looking for some form of prior art, you can
check the &lt;a href="https://developer.gnome.org/clutter/stable/ClutterPaintNode.html"&gt;&lt;code&gt;ClutterPaintNode&lt;/code&gt;&lt;/a&gt; &lt;span class="caps"&gt;API&lt;/span&gt; in&amp;nbsp;Clutter.&lt;/p&gt;
&lt;p&gt;Widgets in &lt;span class="caps"&gt;GTK&lt;/span&gt;+ would not really be required to use render nodes: ideally,
we want to get to a future where widgets &lt;strong&gt;are&lt;/strong&gt; a small, composable unit
whose appearances that can be described using &lt;span class="caps"&gt;CSS&lt;/span&gt;; while we build towards
that future, though, we can incrementally transition from the current
immediate more rendering model to a more structured tree of rendering
operations that can be reordered and optimized for the target graphics&amp;nbsp;layer.&lt;/p&gt;
&lt;p&gt;Additionally, by sharing the same rendering model between the more complex
widget &lt;span class="caps"&gt;API&lt;/span&gt; and the more freeform layers one, we only have to care about
optmizing a single set of&amp;nbsp;operations.&lt;/p&gt;
&lt;p&gt;&lt;em&gt;You can check the current progress of my work in the
&lt;a href="https://git.gnome.org/browse/gtk+/log/?h=wip/ebassi/gsk-renderer"&gt;gsk-renderer&lt;/a&gt; branch of the &lt;span class="caps"&gt;GTK&lt;/span&gt;+&amp;nbsp;repository.&lt;/em&gt;&lt;/p&gt;</content><category term="gnome"></category><category term="gtk"></category><category term="gsk"></category><category term="gsk demystified"></category><category term="development"></category><category term="welcome to the world of tomorrow"></category></entry><entry><title>Long term support for GTK+</title><link href="https://www.bassi.io/articles/2016/06/15/long-term-support-for-gtk/" rel="alternate"></link><published>2016-06-15T16:20:00+01:00</published><updated>2016-06-15T18:24:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-06-15:/articles/2016/06/15/long-term-support-for-gtk/</id><summary type="html">&lt;p&gt;In which I reply to Morten&amp;#8217;s latest unnecessary&amp;nbsp;rant&lt;/p&gt;</summary><content type="html">&lt;p&gt;&lt;a href="https://blogs.gnome.org/mortenw/2016/06/15/gtk-versioning/"&gt;Dear Morten&lt;/a&gt;,&lt;/p&gt;
&lt;blockquote&gt;
&lt;p&gt;A belief that achieving stability can be done after most of the paid
contributors have run off to play with new toys is delusional. The record
does not support&amp;nbsp;it.&lt;/p&gt;
&lt;/blockquote&gt;
&lt;p&gt;The record (in terms of commit history) seems to &lt;strong&gt;not&lt;/strong&gt; support your
position — as much as you think everyone else is &amp;#8220;delusional&amp;#8221; about it, the
commit log does not really&amp;nbsp;lie.&lt;/p&gt;
&lt;p&gt;The 2.24.0 release was cut in January, 2011 — five and half years ago. No
new features, no new &lt;span class="caps"&gt;API&lt;/span&gt;. Precisely what would happen with the new release
plan, except that the new plan would also give a much better cadence to this&amp;nbsp;behaviour.&lt;/p&gt;
&lt;p&gt;Since then, the 2.24 branch — i.e. the &amp;#8220;feature frozen&amp;#8221; branch has seen 873
commits (as of this afternoon, London time), and 30 additional&amp;nbsp;releases.&lt;/p&gt;
&lt;p&gt;Turns out that people &lt;em&gt;are&lt;/em&gt; being paid to maintain feature-frozen branches
because that&amp;#8217;s where the &amp;#8220;boring&amp;#8221; bits are — security issues, stability bugs,
etc. Volunteers are much more interested in getting the latest and greatest
feature that probably does not interest you now, but may be requested by
your users in two&amp;nbsp;years.&lt;/p&gt;
&lt;p&gt;Isn&amp;#8217;t it what you asked multiple times? A &amp;#8220;long term support&amp;#8221; release that
gives you time to port your application to a stable &lt;span class="caps"&gt;API&lt;/span&gt; that has seen most
of the bugs and uncertainty already&amp;nbsp;squashed?&lt;/p&gt;</content><category term="gnome"></category><category term="gtk"></category><category term="lts"></category></entry><entry><title>Experiments in Meson</title><link href="https://www.bassi.io/articles/2016/06/09/experiments-in-meson/" rel="alternate"></link><published>2016-06-09T00:00:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-06-09:/articles/2016/06/09/experiments-in-meson/</id><summary type="html">&lt;p&gt;in which I talk about using the Meson build system on a&amp;nbsp;project&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last &lt;a href="https://2015.guadec.org/"&gt;&lt;span class="caps"&gt;GUADEC&lt;/span&gt;&lt;/a&gt; I attended Jussi Pakkanen&amp;#8217;s talk about his build
system, &lt;a href="http://mesonbuild.com/"&gt;Meson&lt;/a&gt;; if you weren&amp;#8217;t there, I strongly recommend you
&lt;a href="https://www.youtube.com/watch?v=wTf0NjjNwTU&amp;amp;index=14&amp;amp;list=PLcb5uDX8FIoDeC6z7SeW0-KW3cHUKwIHU"&gt;watch the recording&lt;/a&gt;. I left the talk impressed, and I
wanted to give Meson a try. Cue 9 months later, and a really nice blog post
from &lt;a href="http://blog.nirbheek.in/2016/05/gstreamer-and-meson-new-hope.html"&gt;Nirbheek&lt;/a&gt; on how Centricular is porting GStreamer
from autotools to Meson, and I decided to spend some evening/weekend time on
learning&amp;nbsp;Meson.&lt;/p&gt;
&lt;p&gt;I decided to use the simplest project I maintain, the one with the minimal
amount of dependencies and with a fairly clean autotools set up — i.e.
&lt;a href="http://ebassi.github.io/graphene/"&gt;Graphene&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;Graphene has very little overhead in terms of build system by itself; all it
needs&amp;nbsp;are:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a way to check for compiler&amp;nbsp;flags&lt;/li&gt;
&lt;li&gt;a way to check for the existence of headers and&amp;nbsp;types&lt;/li&gt;
&lt;li&gt;a way to check for platform-specific extensions, like &lt;span class="caps"&gt;SSE&lt;/span&gt; or &lt;span class="caps"&gt;NEON&lt;/span&gt;&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;Additionally, it needs a way to generate documentation and introspection
data, but those are mostly hidden in weird incantations provided by other
projects, like gtk-doc and gobject-introspection, so most of the complexity
is hidden from the maintainer (and user) point of&amp;nbsp;view.&lt;/p&gt;
&lt;p&gt;Armed with little more than the &lt;a href="https://github.com/mesonbuild/meson/wiki"&gt;Meson documentation wiki&lt;/a&gt;
and the &lt;a href="https://github.com/centricular/gstreamer/tree/meson"&gt;GStreamer port&lt;/a&gt; as an example, I set
off towards the shining new future of a small, sane, fast build&amp;nbsp;system.&lt;/p&gt;
&lt;h2&gt;The&amp;nbsp;Good&lt;/h2&gt;
&lt;p&gt;Meson uses additional files, so I didn&amp;#8217;t have to drop the autotools set up
while working on the Meson one. Once I&amp;#8217;m sure that the results are the same,
I&amp;#8217;ll be able to remove the various &lt;code&gt;configure.ac&lt;/code&gt;, &lt;code&gt;Makefile.am&lt;/code&gt;, and
friends, and leave just the Meson&amp;nbsp;file.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Graphene generates two header files during its configuration&amp;nbsp;process:&lt;/p&gt;
&lt;ul&gt;
&lt;li&gt;a &lt;code&gt;config.h&lt;/code&gt; header file, for internal use; we use this file to check if
   a specific feature or header is available while building Graphene&amp;nbsp;itself&lt;/li&gt;
&lt;li&gt;a &lt;code&gt;graphene-config.h&lt;/code&gt; header file, for public use; we expose this file to
   Graphene users for build time detection of platform&amp;nbsp;features&lt;/li&gt;
&lt;/ul&gt;
&lt;p&gt;While the autotools code that generates &lt;code&gt;config.h&lt;/code&gt; is pretty much hidden
from the developer perspective, with autoconf creating a template file for
you by pre-parsing the build files, the part of the build system that
generates the &lt;code&gt;graphene-config.h&lt;/code&gt; one is pretty much a mess of shell script,
cacheable variables for cross-compilation, and random m4 escaping rules.
Meson, on the other hand, treats both files exactly the same way: generate a
&lt;code&gt;configuration&lt;/code&gt; object, set variables on it, then take the appropriate
configuration object and generate the header file — with or without a
template file as an&amp;nbsp;input:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="gh"&gt;#&lt;/span&gt; Internal configuration header
configure_file(input: &amp;#39;config.h.meson&amp;#39;,
               output: &amp;#39;config.h&amp;#39;,
               configuration: conf)

&lt;span class="gh"&gt;#&lt;/span&gt; External configuration header
configure_file(input: &amp;#39;graphene-config.h.meson&amp;#39;,
               output: &amp;#39;graphene-config.h&amp;#39;,
               configuration: graphene_conf,
               install: true,
               install_dir: &amp;#39;lib/graphene-1.0/include&amp;#39;)
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;hr&gt;
&lt;p&gt;While explicit is better than implicit, at least most of the time, having
things taken care for you avoids the boring bits and, more importantly,
avoids getting the boring bits &lt;em&gt;wrong&lt;/em&gt;. If I had a quid for every broken
invocation of the introspection scanner I&amp;#8217;ve ever seen or had to fix, I&amp;#8217;d
probably retire on a very small island. In Meson, this is taken care by a
function in the &lt;code&gt;gnome&lt;/code&gt; module:&lt;/p&gt;
&lt;pre&gt;
    import('gnome')

    # Build introspection only if we enabled building GObject types
    build_gir = build_gobject
    if build_gobject and get_option('enable-introspection')
      gir = find_program('g-ir-scanner', required: false)
      build_gir = gir.found() and not meson.is_cross_build()
    endif

    if build_gir
      gir_extra_args = [
        '--identifier-filter-cmd=' + meson.source_root() + '/src/identfilter.py',
        '--c-include=graphene-gobject.h',
        '--accept-unprefixed',
        '-DGRAPHENE_COMPILATION',
        '--cflags-begin',
        '-I' + meson.source_root() + '/src',
        '-I' + meson.build_root() + '/src',
        '--cflags-end'
      ]
      gnome.generate_gir(libgraphene,
                         sources: headers + sources,
                         namespace: 'Graphene',
                         nsversion: graphene_api_version,
                         identifier_prefix: 'Graphene',
                         symbol_prefix: 'graphene',
                         export_packages: 'graphene-gobject-1.0,
                         includes: [ 'GObject-2.0' ],
                         install: true,
                         extra_args: gir_extra_args)
    endif
&lt;/pre&gt;

&lt;hr&gt;
&lt;p&gt;Meson generates &lt;a href="https://ninja-build.org/"&gt;Ninja&lt;/a&gt; rules by default, and it&amp;#8217;s really fast at
that. I can get a fully configured Graphene build set up in less that a
couple of seconds. On top of that, Ninja is &lt;strong&gt;incredibly&lt;/strong&gt; fast. The whole
build of Graphene takes less than 5 seconds — and I&amp;#8217;m counting building the
tests and benchmarks, something that I had to move to be on demand for the
autotools set up because they added a noticeable delay to the build. Now I
always know if I&amp;#8217;ve just screwed up the build, and not just when I run &lt;code&gt;make
check&lt;/code&gt;.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Jussi is a very good maintainer, helpful and attentive at issues reported to
his project, and quick at reviewing patches. The terms for contributing to
Meson are fairly standard, and the barrier for entry is very low. For a
project like a build system, which interacts and enables other projects,
this is a very important&amp;nbsp;thing.&lt;/p&gt;
&lt;h3&gt;The&amp;nbsp;Ugly&lt;/h3&gt;
&lt;p&gt;As I said, Meson has some interesting automagic handling of the boring bits
of building software, like the introspection data. But there are other
boring bits that do not have convenience wrappers, and thus you get into
overly verbose section of your &lt;code&gt;meson.build&lt;/code&gt; — and while it&amp;#8217;s definitely
harder to get those wrong, compared to autoconf or automake, it can still&amp;nbsp;happen.&lt;/p&gt;
&lt;p&gt;Even in the case of automagic handling, though, there are cases when you
have to deal with some of the magic escaping from under the rug. Generally
it&amp;#8217;s not hard to understand what&amp;#8217;s missing or what&amp;#8217;s necessary, but it can
be a bit daunting when you&amp;#8217;re just staring at a Python exception barfed on
your&amp;nbsp;terminal.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;The documentation is kept in a wiki, which is generally fine for keeping it
up to date; but it&amp;#8217;s hard to search — as all wikis are — and hard to
visually scan. I&amp;#8217;ve lost count of the times I had to search for all the
methods on the &lt;code&gt;meson&lt;/code&gt; built-in object, and I never remember which page I
have to search for, or&amp;nbsp;in.&lt;/p&gt;
&lt;p&gt;The inheritance chain for some objects is mentioned in passing, but it&amp;#8217;s
hard to track; which methods does the &lt;code&gt;test&lt;/code&gt; object have? What kind of
arguments does the &lt;code&gt;compiler.compiles()&lt;/code&gt; method have? Are they positional or&amp;nbsp;named?&lt;/p&gt;
&lt;p&gt;The syntax and &lt;span class="caps"&gt;API&lt;/span&gt; reference documentation should probably be generated from
the code base, and look more like an &lt;span class="caps"&gt;API&lt;/span&gt; reference than a&amp;nbsp;wiki.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Examples are hard to come by. I looked at the GStreamer port, but I also had
to start looking at Meson&amp;#8217;s own test&amp;nbsp;suite.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Modules are all in tree, at least for the time being. This means that if I
want to add an &lt;em&gt;ad hoc&lt;/em&gt; module for a whole complex project like, say, &lt;span class="caps"&gt;GNOME&lt;/span&gt;,
I&amp;#8217;d have to submit it to upstream. Yeah, I know: bad example, Meson already
has a &lt;span class="caps"&gt;GNOME&lt;/span&gt; module; but the concept still&amp;nbsp;applies.&lt;/p&gt;
&lt;hr&gt;
&lt;p&gt;Meson does not do dist tarballs. I&amp;#8217;ve already heard people being skeptical
about this point, but I personally don&amp;#8217;t care that much. I can generate a
tarball from a Git tag, and while it won&amp;#8217;t be self-hosting, it&amp;#8217;s already
enough to get a distro going. Seriously, though: building from a Git tag is
a better option than building from a tarball, in&amp;nbsp;2016.&lt;/p&gt;
&lt;h3&gt;The&amp;nbsp;Bad&lt;/h3&gt;
&lt;p&gt;There shocking twist is that nothing stands out as &amp;#8220;bad&amp;#8221;. Mostly, it&amp;#8217;s just
ugly stuff — caused either by missing convenience functionality that will by
necessity appear once people start using Meson more; or by the mere fact
that all build systems are inherently&amp;nbsp;ugly.&lt;/p&gt;
&lt;p&gt;On the other hand, there&amp;#8217;s some badness in the tooling around project
building. For instance, Travis-&lt;span class="caps"&gt;CI&lt;/span&gt; does not support it, mostly because they
use an ancient version of Ubuntu &lt;span class="caps"&gt;LTS&lt;/span&gt; as the base environment. Jhbuild does
not have a Meson/Ninja build module, so we&amp;#8217;ll have to write that one; same
thing for &lt;span class="caps"&gt;GNOME&lt;/span&gt; Builder. While we wait, having a dummy &lt;code&gt;configure&lt;/code&gt; script
or a dummy &lt;code&gt;Makefile&lt;/code&gt; that would probably&amp;nbsp;help.&lt;/p&gt;
&lt;p&gt;These are not bad things per se, but they definitely block further&amp;nbsp;adoption.&lt;/p&gt;
&lt;h3&gt;tl;dr&lt;/h3&gt;
&lt;p&gt;I think Meson has great potential, and I&amp;#8217;d love to start using it more for
my projects. If you&amp;#8217;re looking for a better, faster, and more understandable
build system then you should grab Meson and explore&amp;nbsp;it.&lt;/p&gt;</content><category term="gnome"></category><category term="development"></category><category term="build systems"></category><category term="meson"></category></entry><entry><title>Reviving the GTK development blog</title><link href="https://www.bassi.io/articles/2016/05/16/reviving-the-gtk-dev-blog/" rel="alternate"></link><published>2016-05-16T00:00:00+01:00</published><updated>2016-05-16T19:38:00+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-05-16:/articles/2016/05/16/reviving-the-gtk-dev-blog/</id><summary type="html">&lt;p&gt;in which I talk about taking the old lady out for a&amp;nbsp;spin&lt;/p&gt;</summary><content type="html">&lt;p&gt;The &lt;span class="caps"&gt;GTK&lt;/span&gt;+ project has &lt;a href="https://blog.gtk.org"&gt;a development blog&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;I know it may come as a shock to many of you, and you&amp;#8217;d be completely
justified in thinking that I just made that link up — but the truth is, the
&lt;span class="caps"&gt;GTK&lt;/span&gt;+ project has had a development blog for a long&amp;nbsp;while.&lt;/p&gt;
&lt;p&gt;Sadly, the blog hasn&amp;#8217;t been updated in five years — mostly around the time
3.0 was released, and the &lt;a href="http://www.gtk.org"&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+ website&lt;/a&gt; was revamped; even before
that, the blog was mostly used for release announcements, which do not make
for very interesting&amp;nbsp;content.&lt;/p&gt;
&lt;p&gt;Like many free and open source software projects, &lt;span class="caps"&gt;GTK&lt;/span&gt;+ has various venues of
interaction between its contributors and its users; mailing lists, personal
blogs, &lt;span class="caps"&gt;IRC&lt;/span&gt;, Stack Overflow, reddit, and many, many other channels. In this
continuum of discussions it&amp;#8217;s both easy to get lost and to lose the sense of
having said things before — after all, if I repeat something at least three
times a week on three different websites for three years, how can people
still not know about it? Some users will always look at catching up after
three years, because their projects live on very different schedules that
the &lt;span class="caps"&gt;GTK&lt;/span&gt; releases one; others will try to look for official channels, even if
the free and open source software landscape has fragmented to such a degree
that any venue can be made &amp;#8220;official&amp;#8221; by the simple fact of having a
contributor on it; others again will look at the &lt;span class="caps"&gt;API&lt;/span&gt; reference for any
source of truth, forgetting, possibly, that if everything went into the &lt;span class="caps"&gt;API&lt;/span&gt;
reference then it would cease to be useful as a&amp;nbsp;reference.&lt;/p&gt;
&lt;p&gt;The &lt;span class="caps"&gt;GTK&lt;/span&gt;+ development blog is not meant to be the only source for truth, or
the only &amp;#8220;official&amp;#8221; channel; it&amp;#8217;s meant to be a place for interesting
content regarding the project, for developers using &lt;span class="caps"&gt;GTK&lt;/span&gt;+ or considering to
use it; a place that acts as a hub to let interested people discover what&amp;#8217;s
up with &lt;span class="caps"&gt;GTK&lt;/span&gt;+ itself but that don&amp;#8217;t want to subscribe to the commits list or
join &lt;span class="caps"&gt;IRC&lt;/span&gt;.&lt;/p&gt;
&lt;p&gt;From an editorial standpoint, I&amp;#8217;d like the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ development blog to be open
to contribution from people contributing to &lt;span class="caps"&gt;GTK&lt;/span&gt;+; using &lt;span class="caps"&gt;GTK&lt;/span&gt;+; and newcomers
to the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ code base and their experiences. What&amp;#8217;s a cool &lt;span class="caps"&gt;GTK&lt;/span&gt;+ feature that
you worked on? How did &lt;span class="caps"&gt;GTK&lt;/span&gt;+ help you in writing your application or
environment? How did you find contributing to &lt;span class="caps"&gt;GTK&lt;/span&gt;+ for the first time? If
you want to write an article for the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ blog talking about this, then feel
free to reach out to me with an outline, and I&amp;#8217;ll be happy to help&amp;nbsp;you.&lt;/p&gt;
&lt;p&gt;In the meantime, the &lt;a href="https://blog.gtk.org/2016/05/16/this-week-in-gtk-1/"&gt;first post&lt;/a&gt; in the &lt;em&gt;This Week in &lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/em&gt;
series has gone up; you&amp;#8217;ll get a new post about it every Monday, and if you
want to raise awareness on something that happened during a week, feel free
to point it out on &lt;a href="https://wiki.gnome.org/Projects/GTK+/TWIG"&gt;the wiki&lt;/a&gt;.&lt;/p&gt;</content><category term="gnome"></category><category term="glib"></category><category term="gtk"></category><category term="development"></category><category term="gnome"></category><category term="blag"></category></entry><entry><title>Who wrote GTK+ 3.20</title><link href="https://www.bassi.io/articles/2016/05/06/who-wrote-gtk-3-20/" rel="alternate"></link><published>2016-05-06T00:00:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2016-05-06:/articles/2016/05/06/who-wrote-gtk-3-20/</id><summary type="html">&lt;p&gt;a recap of the contributions to the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3.20 development&amp;nbsp;cycle&lt;/p&gt;</summary><content type="html">&lt;p&gt;Last time I tried to dispel the notion that &lt;span class="caps"&gt;GTK&lt;/span&gt;+ is dead or dying. Others
have also &lt;a href="https://csorianognome.wordpress.com/2016/05/04/nautilus-gtk-status-1-year-of-progress/"&gt;chimed in&lt;/a&gt;, and it seems that we&amp;#8217;re picking
up the pace into making &lt;span class="caps"&gt;GTK&lt;/span&gt; a more modern, more useful driving force into
the Linux desktop&amp;nbsp;ecosystem.&lt;/p&gt;
&lt;p&gt;Let&amp;#8217;s see how much has changed in the six months of the 3.20 development&amp;nbsp;cycle.&lt;/p&gt;
&lt;p&gt;Once again, to gather the data, I&amp;#8217;ve used the most excellent &lt;a href="http://repo.or.cz/w/git-dm.git"&gt;&lt;code&gt;git-dm&lt;/code&gt;&lt;/a&gt;
tool that Jonathan Corbet wrote for the &amp;#8220;Who wrote the Linux kernel&amp;#8221; columns
for &lt;span class="caps"&gt;LWN&lt;/span&gt;. As usual, I&amp;#8217;ve purposefully skipped the commits dealing with
translations, to avoid messing up the&amp;nbsp;statistics.&lt;/p&gt;
&lt;p&gt;You should look at my &lt;a href="https://www.bassi.io/articles/2015/09/15/who-wrote-gtk-3-18/"&gt;previous article&lt;/a&gt; as a comparison&amp;nbsp;point.&lt;/p&gt;
&lt;h3&gt;Activity&lt;/h3&gt;
&lt;p&gt;For the 3.20 cycle, the numbers&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines added&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines removed&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Delta&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Contributors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GLib&lt;/td&gt;
&lt;td&gt;2.48&lt;/td&gt;
&lt;td style="text-align: right;"&gt;20597&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7544&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13053&lt;/td&gt;
&lt;td style="text-align: right;"&gt;55&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/td&gt;
&lt;td&gt;3.20&lt;/td&gt;
&lt;td style="text-align: right;"&gt;158427&lt;/td&gt;
&lt;td style="text-align: right;"&gt;117823&lt;/td&gt;
&lt;td style="text-align: right;"&gt;40604&lt;/td&gt;
&lt;td style="text-align: right;"&gt;81&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;More or less stable in terms of contributors, but as you can see the number
of lines added and removed has doubled. This is definitely the result of the
changes in the &lt;span class="caps"&gt;CSS&lt;/span&gt; machinery that have (finally) brought it to a stable as
well as more featureful&amp;nbsp;state.&lt;/p&gt;
&lt;h3&gt;Contributors&lt;/h3&gt;
&lt;h4&gt;GLib&lt;/h4&gt;
&lt;p&gt;Of the 55 developers that contributed the 271 changesets of GLib during the
3.20 development cycle, the most active&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changed lines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ignacio Casal Quinteiro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;56 (20.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ignacio Casal Quinteiro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;8530 (39.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Philip Withnall&lt;/td&gt;
&lt;td style="text-align: right;"&gt;42 (15.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Philip Withnall&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5402 (25.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Allison Ryan Lortie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;27 (10.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3228 (15.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;22  (8.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1440  (6.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;18  (6.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Allison Ryan Lortie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1338  (6.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Dan Winship&lt;/td&gt;
&lt;td style="text-align: right;"&gt;9  (3.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Javier Jardón&lt;/td&gt;
&lt;td style="text-align: right;"&gt;565  (2.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Mikhail Zabaluev&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7  (2.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Iain Lane&lt;/td&gt;
&lt;td style="text-align: right;"&gt;149  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Marc-André Lureau&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (2.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ruslan Izhbulatov&lt;/td&gt;
&lt;td style="text-align: right;"&gt;147  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ruslan Izhbulatov&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (2.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Dan Winship&lt;/td&gt;
&lt;td style="text-align: right;"&gt;95  (0.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Rico Tzschichholz&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (2.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Lars Uebernickel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;79  (0.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Xavier Claessens&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (2.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Xavier Claessens&lt;/td&gt;
&lt;td style="text-align: right;"&gt;74  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Christian Hergert&lt;/td&gt;
&lt;td style="text-align: right;"&gt;71  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Iain Lane&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Mikhail Zabaluev&lt;/td&gt;
&lt;td style="text-align: right;"&gt;48  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Lars Uebernickel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (1.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Rico Tzschichholz&lt;/td&gt;
&lt;td style="text-align: right;"&gt;45  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Sébastien Wilmet&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (1.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Daiki Ueno&lt;/td&gt;
&lt;td style="text-align: right;"&gt;42  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Simon McVittie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (1.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Simon McVittie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;27  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Javier Jardón&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (1.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;25  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Christian Hergert&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (1.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Robert Ancell&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;coypu&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Marc-André Lureau&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Sebastian Geiger&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jan de Groot&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Ignacio has been hard at work, helped by Ruslan and Fan, in making 2.48 the
best GLib release ever in terms of supporting Windows — both for cross
and native compilation, using autotools and the Microsoft Visual C compiler
suite. If you can build an application for Windows as reliably as you can on
Linux, it&amp;#8217;s because of their&amp;nbsp;work.&lt;/p&gt;
&lt;h4&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/h4&gt;
&lt;p&gt;For &lt;span class="caps"&gt;GTK&lt;/span&gt;+, on the other hand, the most active of the 81 contributors&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changed lines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1220 (43.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;78960 (41.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Benjamin Otte&lt;/td&gt;
&lt;td style="text-align: right;"&gt;472 (16.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Benjamin Otte&lt;/td&gt;
&lt;td style="text-align: right;"&gt;35975 (18.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Lapo Calamandrei&lt;/td&gt;
&lt;td style="text-align: right;"&gt;203  (7.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Lapo Calamandrei&lt;/td&gt;
&lt;td style="text-align: right;"&gt;35352 (18.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Cosimo Cecchi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;167  (6.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Cosimo Cecchi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10408  (5.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Carlos Garnacho&lt;/td&gt;
&lt;td style="text-align: right;"&gt;147  (5.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jakub Steiner&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6927  (3.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Timm Bäder&lt;/td&gt;
&lt;td style="text-align: right;"&gt;107  (3.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Carlos Garnacho&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5334  (2.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3128  (1.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;39  (1.4%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2394  (1.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ruslan Izhbulatov&lt;/td&gt;
&lt;td style="text-align: right;"&gt;29  (1.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1771  (0.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Carlos Soriano&lt;/td&gt;
&lt;td style="text-align: right;"&gt;28  (1.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ruslan Izhbulatov&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1635  (0.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Jakub Steiner&lt;/td&gt;
&lt;td style="text-align: right;"&gt;26  (0.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Timm Bäder&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1326  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Olivier Fourdan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;26  (0.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Takao Fujiwara&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1269  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Jonas Ådahl&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23  (0.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jonas Ådahl&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1243  (0.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;22  (0.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;885  (0.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Piotr Drąg&lt;/td&gt;
&lt;td style="text-align: right;"&gt;18  (0.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Olivier Fourdan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;646  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ray Strode&lt;/td&gt;
&lt;td style="text-align: right;"&gt;18  (0.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ray Strode&lt;/td&gt;
&lt;td style="text-align: right;"&gt;570  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ignacio Casal Quinteiro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;16  (0.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Sébastien Wilmet&lt;/td&gt;
&lt;td style="text-align: right;"&gt;494  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;William Hua&lt;/td&gt;
&lt;td style="text-align: right;"&gt;16  (0.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Carlos Soriano&lt;/td&gt;
&lt;td style="text-align: right;"&gt;427  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14  (0.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ignacio Casal Quinteiro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;333  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Christoph Reiter&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10  (0.4%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;William Hua&lt;/td&gt;
&lt;td style="text-align: right;"&gt;321  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Benjamin has worked on the new &lt;a href="https://blogs.gnome.org/mclasen/2015/12/22/css-boxes-in-gtk/"&gt;&lt;span class="caps"&gt;CSS&lt;/span&gt; gadget&lt;/a&gt; internal
&lt;span class="caps"&gt;API&lt;/span&gt;; Matthias, Cosimo, and Timm have worked on porting existing widgets to
it, in order to validate the &lt;span class="caps"&gt;API&lt;/span&gt;. Lapo and Jakub have worked on updating
Adwaita and the other in tree themes to the new style&amp;nbsp;declarations.&lt;/p&gt;
&lt;p&gt;Carlos Soriano has worked on the widgets shared between the file chooser
dialog and&amp;nbsp;Nautilus.&lt;/p&gt;
&lt;p&gt;Carlos Garnacho has worked on the input layer in &lt;span class="caps"&gt;GDK&lt;/span&gt;, in order to make it
behave correctly under the new world order of Wayland; and speaking of
Wayland, Carlos, Jonas, and Olivier have worked really hard to implement
all the missing features in the Wayland backend, as well as the fallout of
the Wayland switch when it comes to window sizing and&amp;nbsp;positioning.&lt;/p&gt;
&lt;h3&gt;Affiliation&lt;/h3&gt;
&lt;h4&gt;GLib&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per lines&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per contributor (total 55)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;136 (50.2%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10942 (50.9%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;35 (60.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;49 (18.1%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5491 (25.6%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;9 (15.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41 (15.1%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3398 (15.8%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (8.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;36 (13.3%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1612  (7.5%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (6.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (2.2%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;34  (0.2%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (3.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (0.4%)&lt;/td&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (0.0%)&lt;/td&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (1.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (0.4%)&lt;/td&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.0%)&lt;/td&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (1.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Novell&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (0.4%)&lt;/td&gt;
&lt;td&gt;Novell&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (0.0%)&lt;/td&gt;
&lt;td&gt;Novell&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (1.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As usual, GLib is a little bit more diverse, in terms of employers, because
of its versatility and use in various&amp;nbsp;platforms.&lt;/p&gt;
&lt;h4&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per lines&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per contributor (total 81)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1940 (69.5%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;131833 (68.7%)&lt;/td&gt;
&lt;td&gt;(Unknown )&lt;/td&gt;
&lt;td style="text-align: right;"&gt;63 (75.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;796 (28.5%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;59204 (30.8%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;15 (18.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;41  (1.5%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;885  (0.5%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (4.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13  (0.5%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;104  (0.1%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (1.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Not many changes in these tables, but if your company uses the &lt;span class="caps"&gt;GNOME&lt;/span&gt; core
platform and you wish to have a voice in where the platform goes, you should
really consider contributing employee time to work&amp;nbsp;upstream.&lt;/p&gt;
&lt;p&gt;It is also very important to note that, while Red Hat still retains the
majority of commits, the vast majority of committers are&amp;nbsp;unaffiliated.&lt;/p&gt;
&lt;h3&gt;Methodology&lt;/h3&gt;
&lt;p&gt;The command line I used for &lt;code&gt;gitdm&lt;/code&gt; is:&lt;/p&gt;
&lt;div class="highlight"&gt;&lt;pre&gt;&lt;span&gt;&lt;/span&gt;&lt;code&gt;&lt;span class="n"&gt;git&lt;/span&gt; &lt;span class="n"&gt;log&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
 &lt;span class="o"&gt;--&lt;/span&gt;&lt;span class="n"&gt;numstat&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
 &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;M&lt;/span&gt; &lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="n"&gt;START&lt;/span&gt;&lt;span class="p"&gt;..&lt;/span&gt;&lt;span class="o"&gt;$&lt;/span&gt;&lt;span class="kr"&gt;END&lt;/span&gt; &lt;span class="p"&gt;|&lt;/span&gt; &lt;span class="err"&gt;\&lt;/span&gt;
 &lt;span class="n"&gt;gitdm&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;r&lt;/span&gt; &lt;span class="s"&gt;&amp;#39;.*(?&amp;lt;!po)$&amp;#39;&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;l&lt;/span&gt; &lt;span class="mi"&gt;20&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;u&lt;/span&gt; &lt;span class="o"&gt;-&lt;/span&gt;&lt;span class="n"&gt;n&lt;/span&gt;
&lt;/code&gt;&lt;/pre&gt;&lt;/div&gt;

&lt;p&gt;For GLib, I started from commit &lt;a href="https://git.gnome.org/browse/glib/commit/?id=37fcab17"&gt;37fcab17&lt;/a&gt;
which contains the version bump to 2.47, and ended on the 2.48.0&amp;nbsp;tag.&lt;/p&gt;
&lt;p&gt;For &lt;span class="caps"&gt;GTK&lt;/span&gt;+, I started from commit &lt;a href="https://git.gnome.org/browse/gtk+/commit/?id=2f0d4b68"&gt;2f0d4b68&lt;/a&gt;
which contains the first new &lt;span class="caps"&gt;API&lt;/span&gt; of the 3.19 cycle and precedes the version
bump, and ended on the 3.20.0&amp;nbsp;tag.&lt;/p&gt;
&lt;p&gt;The only changes to the &lt;code&gt;gitdm&lt;/code&gt; stock configuration are the addition of a
couple of email/name/employer association; I can publish them on&amp;nbsp;request.&lt;/p&gt;</content><category term="gnome"></category><category term="glib"></category><category term="gtk"></category><category term="development"></category><category term="gnome"></category><category term="who makes gnome"></category></entry><entry><title>Who wrote GTK+ (Reprise)</title><link href="https://www.bassi.io/articles/2015/09/16/who-wrote-gtk-reprise/" rel="alternate"></link><published>2015-09-16T00:00:00+01:00</published><updated>2023-05-22T10:26:59+01:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2015-09-16:/articles/2015/09/16/who-wrote-gtk-reprise/</id><summary type="html">&lt;p&gt;answering the question of who wrote past releases of &lt;span class="caps"&gt;GTK&lt;/span&gt;, one release at a&amp;nbsp;time&lt;/p&gt;</summary><content type="html">&lt;p&gt;As I&amp;#8217;ve been asked by different people about data from older releases of
&lt;span class="caps"&gt;GTK&lt;/span&gt;+, after the previous article on &lt;a href="https://www.bassi.io/articles/2015/09/15/who-wrote-gtk-3-18/"&gt;Who Wrote &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3.18&lt;/a&gt;, I ran the
&lt;code&gt;git-dm&lt;/code&gt; script on every release and generated some more&amp;nbsp;data:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines added&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines removed&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Delta&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Changesets&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Contributors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2.0&lt;sup id="fnref:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;666495&lt;/td&gt;
&lt;td style="text-align: right;"&gt;345348&lt;/td&gt;
&lt;td style="text-align: right;"&gt;321147&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2503&lt;/td&gt;
&lt;td style="text-align: right;"&gt;106&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td style="text-align: right;"&gt;301943&lt;/td&gt;
&lt;td style="text-align: right;"&gt;227762&lt;/td&gt;
&lt;td style="text-align: right;"&gt;74181&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1026&lt;/td&gt;
&lt;td style="text-align: right;"&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td style="text-align: right;"&gt;601707&lt;/td&gt;
&lt;td style="text-align: right;"&gt;116402&lt;/td&gt;
&lt;td style="text-align: right;"&gt;485305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2118&lt;/td&gt;
&lt;td style="text-align: right;"&gt;109&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.6&lt;/td&gt;
&lt;td style="text-align: right;"&gt;181478&lt;/td&gt;
&lt;td style="text-align: right;"&gt;88050&lt;/td&gt;
&lt;td style="text-align: right;"&gt;93428&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1421&lt;/td&gt;
&lt;td style="text-align: right;"&gt;101&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;td style="text-align: right;"&gt;93734&lt;/td&gt;
&lt;td style="text-align: right;"&gt;47609&lt;/td&gt;
&lt;td style="text-align: right;"&gt;46125&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1155&lt;/td&gt;
&lt;td style="text-align: right;"&gt;86&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.10&lt;/td&gt;
&lt;td style="text-align: right;"&gt;215734&lt;/td&gt;
&lt;td style="text-align: right;"&gt;54757&lt;/td&gt;
&lt;td style="text-align: right;"&gt;160977&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1614&lt;/td&gt;
&lt;td style="text-align: right;"&gt;110&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.12&lt;/td&gt;
&lt;td style="text-align: right;"&gt;232831&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43172&lt;/td&gt;
&lt;td style="text-align: right;"&gt;189659&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1966&lt;/td&gt;
&lt;td style="text-align: right;"&gt;148&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.14&lt;/td&gt;
&lt;td style="text-align: right;"&gt;215151&lt;/td&gt;
&lt;td style="text-align: right;"&gt;102888&lt;/td&gt;
&lt;td style="text-align: right;"&gt;112263&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1952&lt;/td&gt;
&lt;td style="text-align: right;"&gt;140&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.16&lt;/td&gt;
&lt;td style="text-align: right;"&gt;71335&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23272&lt;/td&gt;
&lt;td style="text-align: right;"&gt;48063&lt;/td&gt;
&lt;td style="text-align: right;"&gt;929&lt;/td&gt;
&lt;td style="text-align: right;"&gt;118&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;52228&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23490&lt;/td&gt;
&lt;td style="text-align: right;"&gt;28738&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1079&lt;/td&gt;
&lt;td style="text-align: right;"&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.20&lt;/td&gt;
&lt;td style="text-align: right;"&gt;80397&lt;/td&gt;
&lt;td style="text-align: right;"&gt;104504&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-24107&lt;/td&gt;
&lt;td style="text-align: right;"&gt;761&lt;/td&gt;
&lt;td style="text-align: right;"&gt;82&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.22&lt;/td&gt;
&lt;td style="text-align: right;"&gt;51115&lt;/td&gt;
&lt;td style="text-align: right;"&gt;71439&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-20324&lt;/td&gt;
&lt;td style="text-align: right;"&gt;438&lt;/td&gt;
&lt;td style="text-align: right;"&gt;70&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.24&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4984&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2168&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2816&lt;/td&gt;
&lt;td style="text-align: right;"&gt;184&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.0&lt;sup id="fnref2:1"&gt;&lt;a class="footnote-ref" href="#fn:1"&gt;1&lt;/a&gt;&lt;/sup&gt;&lt;/td&gt;
&lt;td style="text-align: right;"&gt;354665&lt;/td&gt;
&lt;td style="text-align: right;"&gt;580207&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-225542&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4792&lt;/td&gt;
&lt;td style="text-align: right;"&gt;115&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.2&lt;/td&gt;
&lt;td style="text-align: right;"&gt;227778&lt;/td&gt;
&lt;td style="text-align: right;"&gt;168616&lt;/td&gt;
&lt;td style="text-align: right;"&gt;59162&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2435&lt;/td&gt;
&lt;td style="text-align: right;"&gt;98&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.4&lt;/td&gt;
&lt;td style="text-align: right;"&gt;126934&lt;/td&gt;
&lt;td style="text-align: right;"&gt;83313&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43621&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2201&lt;/td&gt;
&lt;td style="text-align: right;"&gt;84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.6&lt;/td&gt;
&lt;td style="text-align: right;"&gt;206620&lt;/td&gt;
&lt;td style="text-align: right;"&gt;34965&lt;/td&gt;
&lt;td style="text-align: right;"&gt;171655&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1011&lt;/td&gt;
&lt;td style="text-align: right;"&gt;89&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.8&lt;/td&gt;
&lt;td style="text-align: right;"&gt;84693&lt;/td&gt;
&lt;td style="text-align: right;"&gt;34826&lt;/td&gt;
&lt;td style="text-align: right;"&gt;49867&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1105&lt;/td&gt;
&lt;td style="text-align: right;"&gt;90&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.10&lt;/td&gt;
&lt;td style="text-align: right;"&gt;143711&lt;/td&gt;
&lt;td style="text-align: right;"&gt;204684&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-60973&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1722&lt;/td&gt;
&lt;td style="text-align: right;"&gt;111&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.12&lt;/td&gt;
&lt;td style="text-align: right;"&gt;86342&lt;/td&gt;
&lt;td style="text-align: right;"&gt;54037&lt;/td&gt;
&lt;td style="text-align: right;"&gt;32305&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1453&lt;/td&gt;
&lt;td style="text-align: right;"&gt;92&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.14&lt;/td&gt;
&lt;td style="text-align: right;"&gt;130387&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144926&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-14539&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2553&lt;/td&gt;
&lt;td style="text-align: right;"&gt;84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.16&lt;/td&gt;
&lt;td style="text-align: right;"&gt;80321&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37037&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43284&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1725&lt;/td&gt;
&lt;td style="text-align: right;"&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;3.18*&lt;/td&gt;
&lt;td style="text-align: right;"&gt;78997&lt;/td&gt;
&lt;td style="text-align: right;"&gt;54614&lt;/td&gt;
&lt;td style="text-align: right;"&gt;24383&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1638&lt;/td&gt;
&lt;td style="text-align: right;"&gt;83&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Here you can see the history of the &lt;span class="caps"&gt;GTK&lt;/span&gt; releases, since&amp;nbsp;2.0.&lt;/p&gt;
&lt;p&gt;These numbers are to be taken with a &lt;strong&gt;truckload&lt;/strong&gt; of salt, especially the
ones from the 2.x era. During the early 2.x cycle, releases did not follow
the &lt;span class="caps"&gt;GNOME&lt;/span&gt; timed release schedule; instead, they were done whenever&amp;nbsp;needed:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Release&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Date&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;2.0&lt;/td&gt;
&lt;td style="text-align: left;"&gt;March 2002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.2&lt;/td&gt;
&lt;td style="text-align: left;"&gt;December 2002&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.4&lt;/td&gt;
&lt;td style="text-align: left;"&gt;March 2004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.6&lt;/td&gt;
&lt;td style="text-align: left;"&gt;December 2004&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.8&lt;/td&gt;
&lt;td style="text-align: left;"&gt;August 2005&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.10&lt;/td&gt;
&lt;td style="text-align: left;"&gt;July 2006&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.12&lt;/td&gt;
&lt;td style="text-align: left;"&gt;September 2007&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.14&lt;/td&gt;
&lt;td style="text-align: left;"&gt;September 2008&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.16&lt;/td&gt;
&lt;td style="text-align: left;"&gt;March 2009&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.18&lt;/td&gt;
&lt;td style="text-align: left;"&gt;September 2009&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.20&lt;/td&gt;
&lt;td style="text-align: left;"&gt;March 2010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.22&lt;/td&gt;
&lt;td style="text-align: left;"&gt;September 2010&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;2.24&lt;/td&gt;
&lt;td style="text-align: left;"&gt;January 2011&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Starting with 2.14, we settled to the same cycle as &lt;span class="caps"&gt;GNOME&lt;/span&gt;, as it made
releasing &lt;span class="caps"&gt;GNOME&lt;/span&gt; and packaging &lt;span class="caps"&gt;GTK&lt;/span&gt;+ on your favourite distribution a lot&amp;nbsp;easier.&lt;/p&gt;
&lt;p&gt;This disparity in the length of the development cycles explains why the 2.12
and 2.14 cycles, which lasted a year, represent an anomaly in terms of
contributors (148 and 140, respectively) and in terms of absolute lines&amp;nbsp;changed.&lt;/p&gt;
&lt;p&gt;The reduced activity between 2.20 and 2.24.0 is easily attributable to the
fact that people were working hard on the 2.90 branch that would become&amp;nbsp;3.0.&lt;/p&gt;
&lt;p&gt;In general, once you adjust by release time, it&amp;#8217;s easy to see that the
number of contributors is pretty much stable at around&amp;nbsp;90:&lt;/p&gt;
&lt;p&gt;&lt;figure&gt;
        &lt;figcaption class="image-caption"&gt;
          &lt;p&gt;The average is 94.5, which means we have an hobbit somewhere in the commit&amp;nbsp;log&lt;/p&gt;
        &lt;/figcaption&gt;
        &lt;div&gt;&lt;img src="https://www.bassi.io/images/gtk-contributors.png"/&gt;&lt;/div&gt;
      &lt;/figure&gt;&lt;/p&gt;
&lt;p&gt;Another interesting data point would be to look at the ecosystem of
companies spawned around &lt;span class="caps"&gt;GTK&lt;/span&gt;+ and &lt;span class="caps"&gt;GNOME&lt;/span&gt;, and how it has changed over the
years — but that&amp;#8217;s part of a larger discussion that would probably take more
than a couple of blog posts to&amp;nbsp;unpack.&lt;/p&gt;
&lt;p&gt;I guess the larger point is that &lt;span class="caps"&gt;GTK&lt;/span&gt;+ is definitely &lt;strong&gt;not&lt;/strong&gt; dying; it&amp;#8217;s pretty
much being worked on by the same &lt;em&gt;amount&lt;/em&gt; of people — which includes long
timers as well as newcomers — as it was during the 2.x&amp;nbsp;cycle.&lt;/p&gt;
&lt;div class="footnote"&gt;
&lt;hr&gt;
&lt;ol&gt;
&lt;li id="fn:1"&gt;
&lt;p&gt;Both 2.0 and 3.0 are not wholly accurate; I used, as a starting point
  for the changeset period, the previous &lt;em&gt;released&lt;/em&gt; branch point; for
  &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 2.0, I started from the &lt;code&gt;GTK_1_3_1&lt;/code&gt; tag, whereas for &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3.0
  I used the &lt;code&gt;2.90.0&lt;/code&gt; tag. There are commits preceding both tags, but
  not enough to skew the results.&amp;#160;&lt;a class="footnote-backref" href="#fnref:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;a class="footnote-backref" href="#fnref2:1" title="Jump back to footnote 1 in the text"&gt;&amp;#8617;&lt;/a&gt;&lt;/p&gt;
&lt;/li&gt;
&lt;/ol&gt;
&lt;/div&gt;</content><category term="gnome"></category><category term="glib"></category><category term="gtk"></category><category term="development"></category><category term="gnome"></category><category term="who makes gnome"></category></entry><entry><title>Who wrote GTK+ 3.18</title><link href="https://www.bassi.io/articles/2015/09/15/who-wrote-gtk-3-18/" rel="alternate"></link><published>2015-09-15T00:00:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2015-09-15:/articles/2015/09/15/who-wrote-gtk-3-18/</id><summary type="html">&lt;p&gt;a recap of the contributions to the &lt;span class="caps"&gt;GTK&lt;/span&gt;+ 3.18 development&amp;nbsp;cycle&lt;/p&gt;</summary><content type="html">&lt;p&gt;It&amp;#8217;s common &amp;#8220;knowledge&amp;#8221; in the Internet Peanut Gallery that &lt;span class="caps"&gt;GTK&lt;/span&gt;+ is &amp;#8220;dead&amp;#8221;
or &amp;#8220;dying&amp;#8221; — I assume in the same sense that NetCraft certified that &lt;span class="caps"&gt;BSD&lt;/span&gt; is
dead. It&amp;#8217;d be (and, in point of fact, it &lt;em&gt;is&lt;/em&gt;) easy to dismiss these rumors;
it&amp;#8217;s not like they come with actual numbers and trends, because the gods of
old never mentioned the requirement for comments on the Internet to be cogent,
let alone factually true, when they laid down the various&amp;nbsp;RFCs.&lt;/p&gt;
&lt;p&gt;On the other hand, not having an actual answer is a bit of a self-serving
argument on the side of people, like me, that actually contribute to &lt;span class="caps"&gt;GTK&lt;/span&gt;+ and
to the &lt;span class="caps"&gt;GNOME&lt;/span&gt; core platform; it allows a bit of leeway when we ask for help,
contributions, or simply for decent bug reports — &amp;#8220;we don&amp;#8217;t have enough
resources, so if you want your pet bug fixed, or feature implemented, you&amp;#8217;ll
have to help us help you&amp;#8221;. Not that having actual numbers would change that;
after all, resources are not infinite, and there are a ton of bugs that need
to be fixed — including ones that require &lt;a href="https://bugzilla.gnome.org/show_bug.cgi?id=171940"&gt;a time machine&lt;/a&gt;.&lt;/p&gt;
&lt;p&gt;As much as I wanted to dispel the rumors about the impending death of &lt;span class="caps"&gt;GTK&lt;/span&gt;+,
my goal was definitely to provide numbers on how much gets done every six
months in the core &lt;span class="caps"&gt;GNOME&lt;/span&gt; platform, thus honoring the people that work hard
on it. Having numbers also allows us to quantify what kind of help we need, so
that, the next time somebody complains that we don&amp;#8217;t work hard enough on fixing
&lt;em&gt;&lt;span class="caps"&gt;ALL&lt;/span&gt;&lt;/em&gt; the bugs, at least we&amp;#8217;ll have a handy way to point out how much we work&amp;nbsp;already.&lt;/p&gt;
&lt;p&gt;To gather the data, I&amp;#8217;ve used the most excellent &lt;a href="http://repo.or.cz/w/git-dm.git"&gt;&lt;code&gt;git-dm&lt;/code&gt;&lt;/a&gt; tool that Jonathan
Corbet wrote for the &amp;#8220;Who wrote the Linux kernel&amp;#8221; columns for &lt;span class="caps"&gt;LWN&lt;/span&gt;.&lt;/p&gt;
&lt;h3&gt;Activity&lt;/h3&gt;
&lt;p&gt;To provide a baseline, this is how the development activity looked like during
the &lt;span class="caps"&gt;GNOME&lt;/span&gt; 3.14 and 3.16 cycles, i.e. during the past&amp;nbsp;year:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines added&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines removed&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Delta&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Contributors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GLib&lt;/td&gt;
&lt;td&gt;2.42&lt;/td&gt;
&lt;td style="text-align: right;"&gt;17195&lt;/td&gt;
&lt;td style="text-align: right;"&gt;9934&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7261&lt;/td&gt;
&lt;td style="text-align: right;"&gt;61&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;GLib&lt;/td&gt;
&lt;td&gt;2.44&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12504&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2240&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10264&lt;/td&gt;
&lt;td style="text-align: right;"&gt;49&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/td&gt;
&lt;td&gt;3.14&lt;/td&gt;
&lt;td style="text-align: right;"&gt;130387&lt;/td&gt;
&lt;td style="text-align: right;"&gt;144945&lt;/td&gt;
&lt;td style="text-align: right;"&gt;-14558&lt;/td&gt;
&lt;td style="text-align: right;"&gt;84&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/td&gt;
&lt;td&gt;3.16&lt;/td&gt;
&lt;td style="text-align: right;"&gt;80321&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37043&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43278&lt;/td&gt;
&lt;td style="text-align: right;"&gt;94&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;&lt;em&gt;Note&lt;/em&gt;: the numbers do not include the translation work; as much as
translations are an important part of our stack, they tend to skew any
statistic, given the sheer size of lines&amp;nbsp;touched.&lt;/p&gt;
&lt;p&gt;The 3.14 cycle is an outlier for &lt;span class="caps"&gt;GTK&lt;/span&gt;+ because of the move of Adwaita in tree,
as well as the &lt;span class="caps"&gt;GTK&lt;/span&gt;+&amp;nbsp;Inspector.&lt;/p&gt;
&lt;p&gt;For the 3.18 cycle, the numbers up to September 15th&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;&lt;/th&gt;
&lt;th&gt;Version&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines added&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Lines removed&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Delta&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Contributors&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;GLib&lt;/td&gt;
&lt;td&gt;2.46&lt;/td&gt;
&lt;td style="text-align: right;"&gt;19763&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12437&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7326&lt;/td&gt;
&lt;td style="text-align: right;"&gt;50&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/td&gt;
&lt;td&gt;3.18&lt;/td&gt;
&lt;td style="text-align: right;"&gt;78676&lt;/td&gt;
&lt;td style="text-align: right;"&gt;54508&lt;/td&gt;
&lt;td style="text-align: right;"&gt;24168&lt;/td&gt;
&lt;td style="text-align: right;"&gt;83&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;As you can see, the numbers are mostly stable, in terms for code changes and
number of&amp;nbsp;developers.&lt;/p&gt;
&lt;h3&gt;Contributors&lt;/h3&gt;
&lt;p&gt;Of the 50 developers that contributed the 355 changesets of GLib during the
3.18 cycle, the most active&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changed lines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;89 (25.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Руслан Ижбулатов&lt;/td&gt;
&lt;td style="text-align: right;"&gt;7337 (27.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Philip Withnall&lt;/td&gt;
&lt;td style="text-align: right;"&gt;50 (14.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ryan Lortie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5709 (21.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ryan Lortie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;31  (9.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3426 (12.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Dan Winship&lt;/td&gt;
&lt;td style="text-align: right;"&gt;29  (8.4%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2881 (10.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Simon McVittie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;19  (5.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Philip Withnall&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1729  (6.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14  (4.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Dan Winship&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1590  (6.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Руслан Ижбулатов&lt;/td&gt;
&lt;td style="text-align: right;"&gt;11  (3.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Simon McVittie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;867  (3.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Mikhail Zabaluev&lt;/td&gt;
&lt;td style="text-align: right;"&gt;8  (2.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;648  (2.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Ting-Wei Lan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;8  (2.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;588  (2.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Garrett Regier&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (1.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Patrick Griffis&lt;/td&gt;
&lt;td style="text-align: right;"&gt;358  (1.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Janusz Lewandowski&lt;/td&gt;
&lt;td style="text-align: right;"&gt;313  (1.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Michael Catanzaro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Mikhail Zabaluev&lt;/td&gt;
&lt;td style="text-align: right;"&gt;256  (1.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Iain Lane&lt;/td&gt;
&lt;td style="text-align: right;"&gt;130  (0.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Christophe Fergeau&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Garrett Regier&lt;/td&gt;
&lt;td style="text-align: right;"&gt;128  (0.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Michael Catanzaro&lt;/td&gt;
&lt;td style="text-align: right;"&gt;106  (0.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Piotr Drąg&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (1.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Richard Hughes&lt;/td&gt;
&lt;td style="text-align: right;"&gt;97  (0.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Kalev Lember&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (1.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;70  (0.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Iain Lane&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (1.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Xavier Claessens&lt;/td&gt;
&lt;td style="text-align: right;"&gt;48  (0.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Patrick Griffis&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4  (1.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ross Lagerwall&lt;/td&gt;
&lt;td style="text-align: right;"&gt;35  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Rico Tzschichholz&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (0.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ting-Wei Lan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;32  (0.1%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;Руслан Ижбулатов has been working on the Windows support, ensuring that the
library and test suites work correctly there. Chun-wei Fan has been fixing
the project files for building GLib (and &lt;span class="caps"&gt;GTK&lt;/span&gt;+, as well as a lot of libraries
in the &lt;span class="caps"&gt;GNOME&lt;/span&gt; stack) with Microsoft Visual Studio and the Microsoft Visual C
Compiler. Philip Withnall has been hard at work on the &lt;span class="caps"&gt;API&lt;/span&gt; reference and
GObject tutorial, incorporating the feedback he got from clients at Collabora.
Dan Winship and Michael Catanzaro have been working on the certificate &lt;span class="caps"&gt;API&lt;/span&gt;
inside &lt;span class="caps"&gt;GIO&lt;/span&gt;, even though the bulk of the work has been going on inside the
external glib-networking module. Simon McVittie has been working on GDBus; on
the testing &lt;span class="caps"&gt;API&lt;/span&gt;; and has been incorporating patches coming from the Debian&amp;nbsp;project.&lt;/p&gt;
&lt;p&gt;For &lt;span class="caps"&gt;GTK&lt;/span&gt;+, on the other hand, the most active of the 83 contributors&amp;nbsp;are:&lt;/p&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th style="text-align: left;"&gt;Name&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changed lines&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;811 (49.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Matthias Clasen&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37393 (37.3%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Benjamin Otte&lt;/td&gt;
&lt;td style="text-align: right;"&gt;184 (11.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;22644 (22.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Carlos Garnacho&lt;/td&gt;
&lt;td style="text-align: right;"&gt;107  (6.6%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Benjamin Otte&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10991 (11.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Cosimo Cecchi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;40  (2.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jakub Steiner&lt;/td&gt;
&lt;td style="text-align: right;"&gt;4762  (4.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Jakub Steiner&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37  (2.3%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Georges Basile Stavracas Neto&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3879  (3.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Lapo Calamandrei&lt;/td&gt;
&lt;td style="text-align: right;"&gt;35  (2.1%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Carlos Soriano&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3827  (3.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;33  (2.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Lapo Calamandrei&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3208  (3.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Carlos Soriano&lt;/td&gt;
&lt;td style="text-align: right;"&gt;30  (1.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Carlos Garnacho&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2690  (2.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Timm Bäder&lt;/td&gt;
&lt;td style="text-align: right;"&gt;29  (1.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Руслан Ижбулатов&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1480  (1.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Chun-wei Fan&lt;/td&gt;
&lt;td style="text-align: right;"&gt;24  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1001  (1.0%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;William Hua&lt;/td&gt;
&lt;td style="text-align: right;"&gt;24  (1.5%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;William Hua&lt;/td&gt;
&lt;td style="text-align: right;"&gt;947  (0.9%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Alexander Larsson&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23  (1.4%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Cosimo Cecchi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;704  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Georges Basile Stavracas Neto&lt;/td&gt;
&lt;td style="text-align: right;"&gt;23  (1.4%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;671  (0.7%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Jonas Ådahl&lt;/td&gt;
&lt;td style="text-align: right;"&gt;19  (1.2%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jasper St. Pierre&lt;/td&gt;
&lt;td style="text-align: right;"&gt;627  (0.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Christian Hergert&lt;/td&gt;
&lt;td style="text-align: right;"&gt;17  (1.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Christian Hergert&lt;/td&gt;
&lt;td style="text-align: right;"&gt;592  (0.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Piotr Drąg&lt;/td&gt;
&lt;td style="text-align: right;"&gt;17  (1.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Sebastien Lafargue&lt;/td&gt;
&lt;td style="text-align: right;"&gt;570  (0.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Paolo Borelli&lt;/td&gt;
&lt;td style="text-align: right;"&gt;17  (1.0%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Emmanuele Bassi&lt;/td&gt;
&lt;td style="text-align: right;"&gt;556  (0.6%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Christoph Reiter&lt;/td&gt;
&lt;td style="text-align: right;"&gt;14  (0.9%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Jonas Ådahl&lt;/td&gt;
&lt;td style="text-align: right;"&gt;543  (0.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Руслан Ижбулатов&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13  (0.8%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Christoph Reiter&lt;/td&gt;
&lt;td style="text-align: right;"&gt;488  (0.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td style="text-align: left;"&gt;Jasper St. Pierre&lt;/td&gt;
&lt;td style="text-align: right;"&gt;11  (0.7%)&lt;/td&gt;
&lt;td style="text-align: left;"&gt;Ryan Lortie&lt;/td&gt;
&lt;td style="text-align: right;"&gt;424  (0.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;p&gt;While Benjamin is hard at work at improving the correctness and performance of
the style machinery inside &lt;span class="caps"&gt;GTK&lt;/span&gt;+, Jakub and Lapo are constantly trying to find
ways to make Adwaita and the High Constrast themes push the boundaries of the
same style machinery. Carlos Soriano and Georges Basile Stavracas Neto have
been working on the components of the file selection dialog following the new
designs from Allan Day, for the Google Summer of Code; the code is going to be
shared between &lt;span class="caps"&gt;GTK&lt;/span&gt;+ and Nautilus, to improve consistency between Nautilus and
the &lt;code&gt;GtkFileChooser&lt;/code&gt; widget, and keep bugs to a minimum. Carlos Garnacho has
worked on input — mostly the support for touchpad on Wayland. Also on Wayland,
Jonas Ådahl has been working on bug fixing and feature parity in &lt;span class="caps"&gt;GDK&lt;/span&gt; between
Wayland and&amp;nbsp;X11.&lt;/p&gt;
&lt;p&gt;From a company perspective, Red Hat still dominates, as it employs many of the
more prolific contributors; nevertheless, it&amp;#8217;s important to note that a larger
number of developers are unaffiliated, or contribute to GLib and &lt;span class="caps"&gt;GTK&lt;/span&gt;+ in their
own&amp;nbsp;time:&lt;/p&gt;
&lt;h4&gt;GLib&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per lines&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per contributor (total 52)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;138 (40.1%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;12892 (48.5%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;32 (61.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;95 (27.6%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5794 (21.8%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;10 (19.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;65 (18.9%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;5222 (19.6%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (5.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;37 (10.8%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2574  (9.7%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (3.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;6  (1.7%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;72  (0.3%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (3.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.6%)&lt;/td&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;28  (0.1%)&lt;/td&gt;
&lt;td&gt;Centricular&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (3.8%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h4&gt;&lt;span class="caps"&gt;GTK&lt;/span&gt;+&lt;/h4&gt;
&lt;table&gt;
&lt;thead&gt;
&lt;tr&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per changeset&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per lines&lt;/th&gt;
&lt;th&gt;Affiliation&lt;/th&gt;
&lt;th style="text-align: right;"&gt;Per contributor (total 85)&lt;/th&gt;
&lt;/tr&gt;
&lt;/thead&gt;
&lt;tbody&gt;
&lt;tr&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1230 (75.5%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;61725 (61.6%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;58 (68.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;340 (20.9%)&lt;/td&gt;
&lt;td&gt;(Unknown)&lt;/td&gt;
&lt;td style="text-align: right;"&gt;36845 (36.7%)&lt;/td&gt;
&lt;td&gt;Red Hat&lt;/td&gt;
&lt;td style="text-align: right;"&gt;19 (22.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;43  (2.6%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1181  (1.2%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;3  (3.5%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;13  (0.8%)&lt;/td&gt;
&lt;td&gt;Canonical&lt;/td&gt;
&lt;td style="text-align: right;"&gt;491  (0.5%)&lt;/td&gt;
&lt;td&gt;Endless&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (2.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.1%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;19  (0.0%)&lt;/td&gt;
&lt;td&gt;Collabora&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (2.4%)&lt;/td&gt;
&lt;/tr&gt;
&lt;tr&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (0.1%)&lt;/td&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;2  (0.0%)&lt;/td&gt;
&lt;td&gt;Intel&lt;/td&gt;
&lt;td style="text-align: right;"&gt;1  (1.2%)&lt;/td&gt;
&lt;/tr&gt;
&lt;/tbody&gt;
&lt;/table&gt;
&lt;h3&gt;Conclusions&lt;/h3&gt;
&lt;p&gt;One of the most obvious conclusions that I can draw from these numbers is that
GLib and &lt;span class="caps"&gt;GTK&lt;/span&gt;+ are definitely capable of retaining existing contributors — you
just need to look at the names in the top committers and check how many GUADECs
they have attended; what&amp;#8217;s less obvious is the capacity of acquiring and
retaining new contributors. For the latter, the Summer of Code and Outreachy
programs are definitely a great resource. Carlos and Georges have been working
their way down the stack at an impressive speed, and are now responsible for
core&amp;nbsp;functionality.&lt;/p&gt;
&lt;p&gt;In terms of contributions, I think the code base has long since reached a point
where it cannot be increased without also increasing the number of stable
contributors. This is not a bad thing, per se; GLib and &lt;span class="caps"&gt;GTK&lt;/span&gt;+ are not the Linux
kernel; we cannot add widgets like the kernel adds drivers, or file systems. It
is mostly clear, though, that new functionality must come with new people that
take responsibility for it, or at the expense of deprecating old &lt;span class="caps"&gt;API&lt;/span&gt;.&lt;/p&gt;</content><category term="gnome"></category><category term="glib"></category><category term="gtk"></category><category term="development"></category><category term="gnome"></category><category term="who makes gnome"></category></entry><entry><title>PyClutter Reborn</title><link href="https://www.bassi.io/articles/2015/05/29/pyclutter-reborn/" rel="alternate"></link><published>2015-05-29T12:00:00+01:00</published><updated>2016-11-18T23:09:18+00:00</updated><author><name>ebassi</name></author><id>tag:www.bassi.io,2015-05-29:/articles/2015/05/29/pyclutter-reborn/</id><summary type="html">&lt;p&gt;The Python bindings for Clutter have finally seen an update in the brave new world of&amp;nbsp;introspection&lt;/p&gt;</summary><content type="html">&lt;p&gt;Back when I started hacking on Clutter, the Python bindings were the first
thing that I was tasked to write. In order to make them happen, I had to
understand the intent of the library, and fix up the &lt;span class="caps"&gt;API&lt;/span&gt; to be
binding-friendly. It was another time — a time before introspection made
possible to have run-time bindings that automatically acquired support for
new &lt;span class="caps"&gt;API&lt;/span&gt; once the underlying shared library changed. I had to learn the
CPython &lt;span class="caps"&gt;API&lt;/span&gt;; the code generation utilities that turned C header files into
defs files, and defs files into C code; I also had to fix those utilities,
whenever they lied about what they did, or whenever they were pretty much ad
hoc code supporting &lt;span class="caps"&gt;GTK&lt;/span&gt;+ quirks; and, finally, I had to understand the build
system used by PyGTK that ate all this stuff on one end, blended it all, and
spat out a Python C module on the&amp;nbsp;other.&lt;/p&gt;
&lt;p&gt;For a long while, the &lt;a href="https://git.gnome.org/browse/pyclutter"&gt;Python bindings for Clutter&lt;/a&gt; have been
based on that particular brand on insanity; people were able to switch to
the introspection-based ones and drop PyClutter entirely, but the &lt;span class="caps"&gt;API&lt;/span&gt; was
not as nice to use, and you&amp;#8217;d be missing out on some niceties provided by
both Python and&amp;nbsp;Clutter.&lt;/p&gt;
&lt;p&gt;In 2011, Bastian Winkler started porting the whole infrastructure to the
overrides mechanism provided by PyGObject; instead of just loading the
Clutter introspection data, you&amp;#8217;d load a pure Python module that wrapped
specific bits of the exposed &lt;span class="caps"&gt;API&lt;/span&gt;, and made it nicer to&amp;nbsp;use.&lt;/p&gt;
&lt;p&gt;For various reasons — mostly lack of time on my side and lack of testing —
that work has been bitrotting in a branch of the Git repository. Well, no
more. The &lt;code&gt;master&lt;/code&gt; branch of the PyClutter repository is now providing
introspection overrides similar to the ones for &lt;span class="caps"&gt;GTK&lt;/span&gt;+. I also added a bunch
of examples, ported from their C equivalent, to show the idiomatic use of
Clutter in a Python&amp;nbsp;context.&lt;/p&gt;
&lt;p&gt;I&amp;#8217;ll probably do a release, but I&amp;#8217;d be happy if somebody wanted to pick up
the bindings and run with them — I&amp;#8217;m not much of a Python programmer&amp;nbsp;myself.&lt;/p&gt;
&lt;h3&gt;Resources&lt;/h3&gt;
&lt;ul&gt;
&lt;li&gt;&lt;a href="https://git.gnome.org/browse/pyclutter"&gt;PyClutter&lt;/a&gt; Git repository on&amp;nbsp;git.gnome.org&lt;/li&gt;
&lt;li&gt;&lt;a href="https://git.gnome.org/browse/pyclutter/tree/examples"&gt;PyClutter&amp;nbsp;examples&lt;/a&gt;&lt;/li&gt;
&lt;/ul&gt;</content><category term="gnome"></category><category term="development"></category><category term="python"></category><category term="clutter"></category></entry></feed>