You are here

Planet GNOME

Subscribe to Feed Planet GNOME
Planet GNOME - https://planet.gnome.org/
Përditësimi: 12 orë 44 min më parë

Laureen Caliman: Extending Libipuz

Enj, 11/06/2026 - 10:49md

From white-boarding my ideas on a Google Doc, to writing a formal design document in Crosswords, my ability to communicate technical ideas clearly is being put to the test.

Writing documentation is critical to guide others’ understanding of the code and choices made on a particular codebase. Especially when several developers are introduced to the system, a way to reference material leads to more preparedness to contribute to the codebase.

I wrote a design document introducing the concepts I would like to implement towards creating a way to generate a dynamic grid. Critique is welcome.

Standard libipuz crosswords currently rely on using an existing dictionary to fill a static box of X length x Y width. However, the implementation of vocab puzzles goes against this logic and instead generates a new grid of N length x M width based on a list of 0 <= W <= 30 words of 1 <= L <= 25 characters long.

I reconsidered the idea of using a GArray to store unplaced words because I want something idempotent. To avoid unwanted time complexity bloat, the backend should not carry the memory of unplaced words. Instead, the frontend will compare the generated grid against the original list to manage words that couldn’t be placed.

Integrating this new feature will be a fascinating technical challenge.

I created a new IpuzVocab class which inherits from IpuzCrossword. I learned how GNOME manages its developer documentation by writing a file myself to introduce this class. Writing this document made me think about the whole picture: how vocab puzzles handle grids, clues, and guesses, comparing it to standard crossword puzzles. I wrote the support to display a vocab puzzle in light and dark mode, with my next goal to integrate them via gi-docgen.

GNOME Foundation News: Announcing Our First Fellows

Enj, 11/06/2026 - 10:49pd

The GNOME Foundation has selected the first recipients who will receive funding through its new Fellowship program, and is delighted to announce that Peter Eisenmann and Sophie Herold will begin work as our first Fellows in July.

Sophie and Peter are both long-running GNOME contributors, with many significant contributions as members of the GNOME community. Sophie is known as developer of apps, libraries, and websites, including Loupe, Pika Backup, Glycin, and welcome.gnome.org. Peter is a long-standing Nautilus maintainer (officially known as the Files app), as well as an experienced contributor to platform libraries, including GTK and GLib.

Both Fellows will spend time working to enhance the long-term sustainability and health of the GNOME project. Sophie will be working to establish a new RFC process for GNOME, which will enhance our project-level governance. She will also be working on more maintainable and secure libraries through Rust adoption. Peter will work to modernize many aspects of the Files app, including thumbnailing, user directory localization, and the use of modern GNOME platform conventions.

Congratulations to Peter and Sophie – we’re genuinely excited to see what you’ll achieve as our first Fellows, and proud to be supporting your work.

We’d also like to take this opportunity to thank everyone who submitted applications to the first round of the Fellowship. We received some genuinely excellent proposals, and would strongly encourage unsuccessful applicants to apply again in future rounds.

Peter and Sophie’s work is made possible by the generosity of GNOME’s supporters. If you’d like to help fund future rounds and support contributors like them, please consider donating.

Jakub Steiner: Welcome to the Icon Designer Webring!

Mër, 10/06/2026 - 2:00pd

Terry Godier wrote a beautiful essay "The Boring Internet". The internet isn't dying, he argues, just the commercial veneer glued on top of it is. Underneath all the engagement metrics and algorithmic feeds, there's still an older, slower, more federated web. One built on protocols nobody owns. RSS feeds still work (thank you, Aaron), people can set up websites and blogs.

Lets start a webring in 2026

Don't worry, I haven't pushed too many pixels and gone a little cuckoo. But it's a fun exercise to remind what the web once was. We'll silently skip over the fact that I actually started using gopher first, but even web surfing didn't begin on a search engine back in the day. It was web rings, later followed by index sites.

Start

Not long ago I posted about designing app icons for 3rd party GNOME app developers. The post generated quite some buzz and some old and new faces started showing up to help with the backlog. So obviously I'd like to take you on a webring tour of all the designers responsible for making the GNOME app ecosystem a little less awkward to browse on Flathub.

Let me introduce you to Brage. He's been around for a couple of years now, helping to tame the flames of the reddit community, helping with the GNOME Circle project to improve the quality of GNOME apps in the wild, creating illustrations for initial states in apps, authoring some noteworthy apps himself. So thank you, Brage, welcome to the 90s!

Next Up: Brage Fuglseth

Christian Hergert: A Data Layer for GTK applications

Mar, 09/06/2026 - 9:48md

Gom is a very old object mapper I wrote to bridge GObject to SQLite. It made a lot of assumptions about the world based on when it was prototyped.

The past couple years had me using it again for the documentation search in Manuals. Typically, I would have just built Manuals to parse all the XML files on disk and hold them in memory. That’s how both Devhelp and Builder always did things. Once we started supporting Flatpak SDKs that was no longer realistic. You could have numerous SDKs all with copies of the overlapping data and it just became easier to have a query model.

One of the more performance critical limitations was the locking model. When gom-1.0 was written, it was not common for distributions to compile SQLite with locking support. So you just created a single thread and did your work over there.

Bolting fulltext search and many other missing features onto the old ABI just wasn’t realistic. Especially when I’ve wanted to make the thing properly async for years. One of my other projects, Libdex is just right over there and perfect for this sort of problem.

The landscape changed and so do our horizons.

A new informed ABI

In the years after Gom was prototyped, I worked at a commercial database company and learned a great deal about implementing the internals of both that database and more traditional RDBMS. That left a certain cringe on my mouth whenever looking at my code predating it. Knowing how things get done inside the database allows for building better APIs to interact with it.

This time everything is async. Queries are modeled like you do with a compiler. Lowered into the back-end specific implementation. There can be an entity map and real transactions which allows you to read back the same instance despite which query inflated it.

The Center

Your early stage objects are the GomRepository, GomDriver, and GomRegistry.

The registry describes the entities that can exist within the repository. This is handy because it allows us to pre-compile information into a model that is both immutable and fast at runtime. Compare that to methods like g_object_class_list_properties() which is a performance bottleneck of its own.

The driver is very obvious. It is our abstraction layer for the database engines. Currently we have support for SQLite and PostgreSQL.

The repository is the center of the center. It is how you query, insert, update, delete, transact, and more. It is likely your application instance owns one of these unless of course you use Gom as your file format in which case you’ll have one per “document”.

Two Access Models

This new version of Gom can support either the entity mapping you’re used to or; optionally, raw access to relations/projections via the GomCursor.

As the cursor moves through the resulting rows you will have access to all the projections requested in the query. Though it holds enough information to allow you to gom_cursor_materialize() the row into an GomEntity subclass.

If you want a snapshot of that cursor row without materializing, you can use GomRecord which can also conveniently be used in GListModel for integration into GTK applications.

Most of the time, you’ll use materialization. And even then it is likely to happen through automated collections rather than with a cursor directly. More on that later.

Sessions

As I mentioned, there was no concept of transactions previously.

In this iteration we have GomSession. It is your standard identity-map layer with transaction-scoping. If you perform multiple queries for the same record, the session will ensure you get the same instance back. hat is essential when you do local mutations on an instance and what to see that reflected in followup queries.

Additionally, it makes it nice to have multiple views of an object with an editor or listview and needing them to stay in sync.

Relationship Modeling

Support for relationships was adhoc previously. We had some functions named in ways that made you think you could, but I assure you, they were not well tested.

This time around you can model your GomEntity with 1:1, 1:M, M:M, inverse, self-referencing, all while handling proper delete rules. Combing this with the session support mentioned previously is crucial.

So now you should be able to show related models easily in GtkListView while keeping the paginated-and-lazy model beneath it transactional.

Migrations

In the previous version migrations were dynamic, but largely controlled by Gom itself. Very inflexible.

This time around we have things broken down into Migrator and Migration.

You can use built-in implementations like the EntityMigrator or implement your own. CustomMigrator makes that easy. Especially since you can inject your own migrations at just the right point.

Internally, libgom-2 can snapshot your GomRegistry at specific versions based on the provided metadata. Then it performs a diff between two versions of the registry to determine what migration work must be done.

You can just as easily use a SqlMigration with custom SQL scripts. This stuff is all highly composable now to get exactly what you need.

Live List Models

I’ve written many ways to get live SQLite results into GTK over the past two decades. I think one of the first was a GtkTreeModel implementation for GTK 2 which could do it. With that in mind, it was still rather annoying when making Manuals so I set off to make that convenient.

We have GomRecordListModel, GomEntityListModel, GomRelatedListModel, GomQueryModel all of which have practical uses based on application needs.

But in short, most of those are lazy and support transaction-backed stable identities for entities. Very useful when you have a list of items and an editor loaded in another frame, both of which must reflect the same data.

Expression Trees

This time around I implemented proper expression trees. They model the query, relations, and projections in a manner that allows the driver to lower into a query much more accurately.

You can model things like function-calls cleanly all of which required writing manual SQL before. If you did anything outside of what gom could generate previously, it became madness to maintain.

Vectors

This version of libgom embeds the vec1 extension for SQLite. That means we can store vectors in your records and query them. GomVector makes that easier to manage as a property within your application entity.

I can think of a few things this will be useful for, maybe you can too.

Profiling

This version of libgom has profiling support with another project of mine, Sysprof. The whole library emits profiler marks about what is going on so that it is easy for you to figure out why something might be slow in your application.

Since we’ve already done the integration of Sysprof into GLib/GObject, GTK, Pango, Libdex, and GNOME Shell/Mutter you can very quickly get an idea with details of what is going on in your application. Click record, select the problem area, zoom, and it is often pretty clear. You can have flamegraphs, callgraphs, and timing marks all in one place.

Local First with Sync Coordination

One of my personal motivations for this is around building a native sync protocol for applications I’m building. I wrote numerous SQLite-based sync protocols for the now defuct catch.com before they were acquired by apple. That means I know multiple wrong ways to do it.

This time around, I want to put it right in the data-mapper at the point where you have the most insight. So libgom has the right abstractions in place to build that. The GomSyncCoordinator manages the process and GomSyncTransport is the abstraction-point for service integration.

You work with GomDelta at this layer. The application can provide you with a GomMergePolicy to help make decisions which allow for contextually doing the right thing.

This part is still very new. I’m still building the other side of it but landing the shape early allows me to mock and test things comprehensively before committing to the ABI.

My goal is building a practical, robust, and correct implementation for personal local first features.

A small personal note: as I wrote in my recent update from France, I am no longer employed by Red Hat. Work like this is currently self-funded, out of pocket, while my family and I settle into a new chapter. If you find it useful, a note of encouragement or a contribution means a lot right now. It helps make it possible to keep improving the free software infrastructure many of us rely on.

Michael Catanzaro: Please Do Not Ban AI-Assisted Issue Reports

Hën, 08/06/2026 - 11:30md

Many GNOME projects have adopted a policy banning all contributions generated by LLMs. This policy was originally developed by Sophie for Loupe, but is now used in many other notable places:

This project does not allow contributions generated by large languages models (LLMs) and chatbots. This ban includes, but is not limited to, tools like ChatGPT, Claude, Copilot, DeepSeek, and Devin AI. We are taking these steps as precaution due to the potential negative influence of AI generated content on quality, as well as likely copyright violations.

This ban of AI generated content applies to all parts of the projects, including, but not limited to, code, documentation, issues, and artworks. An exception applies for purely translating texts for issues and comments to English.

AI tools can be used to answer questions and find information. However, we encourage contributors to avoid them in favor of using existing documentation and our chats and forums. Since AI generated information is frequently misleading or false, we cannot supply support on anything referencing AI output.

I won’t attempt to argue that you should allow use of AI for writing code. If you wish to ban LLM-generated code, fine. That’s probably inadvisable, but I am not going to object.

But this policy is far stricter than that. Notably, it strictly prohibits AI-generated content in issue reports (except to translate text). Don’t do this! Prohibiting bug reports is stupid and just makes your software worse. Please make sure your project’s AI policy allows for at least AI-generated static analysis results and AI-generated vulnerability reports. Otherwise, you prohibit entirely unobjectionable problem reports.

It’s hard to imagine what could possibly be the value of prohibiting valid bug reports. AI-generated static analysis works well: the AI is able to think about your code, follow execution paths, and automatically discard most false positives to avoid bothering you with them, and the quality of reports is generally pretty high. They are far from perfect, but the same is true of humans.

Here is a typical example of an AI-generated static analysis finding:

2. Resource leak in update_credentials_cb on gnutls_credentials_set failure

File: tls/gnutls/gtlsconnection-gnutls.c:169-172

When gnutls_credentials_set() fails, the function returns without calling g_gnutls_certificate_credentials_unref(credentials). The credentials was either freshly allocated or ref-bumped, so it leaks.

Pasting this into an issue report clearly violates the ban on AI-generated content. And yet, why would you not want to receive a clear and concrete bug report for memory leak?

I understand not all maintainers are fond of AI, but is your dislike really so extreme that you would choose to ignore valid problems and intentionally make your software worse? If not, then your AI policy should thoughtfully consider how to handle AI-generated content in issue reports. Certainly do not adopt a policy that outright bans all AI-generated content in issue reports.

As an issue reporter, you could theoretically take the problem found by the AI and rephrase all the words, then claim that it is no longer AI-generated content because it is rewritten it. This is a waste of time and usually results in a lower-quality, less-detailed result, but you could plausibly do that. Or, if you want to go above and beyond, you could just jump ahead to creating a merge request. But realistically, if your project does not allow any use of AI in issue reports, it’s more likely that either (a) you won’t receive the issue report in the first place, or (b) you won’t receive such issue reports from experienced developers who read and respect your policy, while users who do not read your policy will continue to submit them.

What about security vulnerability reports? Since the start of this year, I have reviewed well over 100 vulnerability reports that I strongly suspect were generated by AI. To reach the “over 100” claim, I sadly only considered vulnerability reports submitted during a particularly heavy four week period, so this is an extremely loose lower bound. Suffice to say, I have seen a lot of them. The quality varies dramatically. Vulnerability reports are now often better or worse than before: better because an experienced human working with a good AI is able to find vulnerabilities that would have surely gone unnoticed without AI, and worse because an inexperienced human with a bad AI might create some pretty terrible issue reports, a significant proportion of which are just outright spam. Low-quality reports remain a problem, but nowadays most AI-generated issue reports are quite good.

Maintainers do not need to tolerate spammy vulnerability reports. If an issue report is bad, of course go ahead and close it. If it’s really bad, then I sometimes don’t even bother replying. But banning good vulnerability reports solely because some portion of the report was generated by AI is unacceptable. AI-assisted vulnerability reports are the new industry standard, and this is not likely to change. Prohibiting issue reports reduces the quality and safety of your software, punishing your users. This is too extreme.

Christian Hergert: Stackless Coroutines in Libdex

Hën, 08/06/2026 - 3:05md

Fibers are always a nice way to keep your async C code clean while using Libdex. However, occasionally you may want a lighter option which doesn’t require a stack or saving registers for work doing little more than coordinating futures.

I’ve added Stackless Coroutines for this which still allows writing future-coordinating code. Though this will suspend/resume your coroutine by re-entering the function and jumping to the next position. Your threads stack is reused. State is saved in your closure state.

This isn’t a new concept. It is really old just like fibers. What is useful is that this style of continuation passing may still be represented as a DexFuture and therefore composed like the others.

You can place these stackless coroutines in DexTaskGroup alongside fibers, threadpool work, and others. Cancellation will propagate to a clean exit point of the coroutine just like it would with a fiber.

Overhead is a bit lower than fibers in synthetic benchmarks depending on use. I was actually impressed our fiber implementation performed as well as it did head-to-head.

To make building your coroutine continuation easier, libdex provides a handy macro to create your typedef struct, _new(), and _free() helpers in a single macro expansion using DEX_DEFINE_CLOSURE_TYPE().

You use it like this:

DEX_DEFINE_CLOSURE_TYPE (MyTaskState, my_task_state, DEX_DEFINE_CLOSURE_VALUE (gsize, bytes), DEX_DEFINE_CLOSURE_POINTER (GBytes *, bytes_obj, g_bytes_unref), DEX_DEFINE_CLOSURE_OBJECT (GSocketConnection, conn))

Coroutines cannot use the exact syntax that fibers do for awaiting, which is a bummer, but a side-effect of trying to make something that works across Linux, Windows, FreeBSD, Solaris, macOS, etc. Particularly because the implementation must use switch/case to stay portable without address-of-label support on MSVC nor clang-cl.exe.

So awaiting is a bit more clear you’re suspending/resuming the stackless coroutine.

DEX_DEFINE_CLOSURE_TYPE (LoadState, load_state, DEX_DEFINE_CLOSURE_OBJECT (GFile, file), DEX_DEFINE_CLOSURE_OBJECT (GFileInputStream, input), DEX_DEFINE_CLOSURE_OBJECT (GFileInfo, info), DEX_DEFINE_CLOSURE_VALUE (int, io_priority)) static DexFuture * do_something (DexCoroutineContext *context, gpointer user_data) { LoadState *state = user_data; g_autoptr(GError) error = NULL; DEX_COROUTINE_BEGIN (context); DEX_COROUTINE_SUSPEND_OBJECT ( &state->input, &error, dex_file_read (state->file, state->io_priority)); if (error != NULL) return dex_future_new_for_error (g_steal_pointer (&error)); DEX_COROUTINE_SUSPEND_OBJECT ( &state->info, &error, dex_file_input_stream_query_info ( state->input, G_FILE_ATTRIBUTE_STANDARD_SIZE, state->io_priority)); if (error != NULL) return dex_future_new_for_error (g_steal_pointer (&error)); /* maybe do something useful here */ return dex_future_new_int64 (g_file_info_get_size (state->info)); DEX_COROUTINE_END; }

You do need to be careful about placing things on the stack, because they wont be there on the other side of that DEX_COROUTINE_SUSPEND_* macro expansion. That is because when the scheduler jumps back into your stackless coroutine, it will use a switch/case to jump to the next bit of code. Don’t fear though, just add your state to your continuation which we’ve established is easy to do now.

If you don’t like these macros, you can do things the manual way using dex_coroutine_context_suspend() and dex_coroutine_context_resume() who’s APIs are not terrible either. They do require you make up your own program-counter regime though which for the macro case is basically just __COUNTER__.

You can spawn your coroutine using dex_scheduler_spawn_coroutine() or as part of a work-queue in DexLimiter with dex_limiter_run_coroutine().

dex_scheduler_spawn_coroutine ( dex_thread_pool_scheduler_get_default (), my_coroutine, my_coroutine_new (), (GDestroyNotify) my_coroutine_free);

I hope you've enjoyed this attempt to make another 1970s technology useful in a modern world.

Jussi Pakkanen: Faking keyword arguments to functions in C++

Hën, 08/06/2026 - 2:09md

One of the many nice language features in Python are keyword arguments. They make some types of APIs  concise and readable. Like so:

Unfortunately C does not have keyword arguments and, by extension, neither does C++. Adding them as a language feature would take 15-20 years of effort, most of which would consist of trying to convince people via email that such a feature is important and should be added.

There have been attempts to implement this via macros and template magic (link), but they have not seen widespread usage probably because they are using macros and template magic. However it turns out that with modern language features you can fake keyword arguments fairly convincingly. Like so:

The add_argument method takes a single argument which is a struct. The extra curly braces inside the parentheses boil down to "whatever the underlying argument is, construct it in place with these parameters". The dotted names are designated initializers, so those fields get the specified value whereas other fields get their default values.

And there you go, keyword arguments in C++. You just have to squint a bit and pretend not to see the extra curly braces.