This feed does not validate.
line 121, column 83: (50 occurrences) [help]
... /div></description><author>Andy Wingo</author><dc:creator>Andy Wingo< ...
^
In addition, interoperability with the widest range of feed readers could be improved by implementing the following recommendations.
line 121, column 92: (50 occurrences) [help]
... /description><author>Andy Wingo</author><dc:creator>Andy Wingo</dc:creat ...
^
line 765, column 0: (11 occurrences) [help]
<p><video controls="controls"><source src="https://thisweek.g ...
line 836, column 0: (3 occurrences) [help]
<video class="wp-video-shortcode" controls="controls" height="478" id="vi ...
<video class="image full" controls="" loop="" poster="https://blog.jimmac ...
... and-of-ai-and-open-source/</guid></item></channel></rss>
^
<?xml version="1.0" encoding="UTF-8"?><rss version="2.0" xmlns:dc="http://purl.org/dc/elements/1.1/"><channel><title>Planet GNOME</title><link>https://planet.gnome.org/</link><description>Planet GNOME - https://planet.gnome.org/</description><language>en</language><generator>rfeed v1.1.1</generator><docs>https://github.com/svpino/rfeed/blob/master/README.md</docs><item><title>Andy Wingo: wastrel, a profligate implementation of webassembly</title><link>https://wingolog.org/archives/2025/10/30/wastrel-a-profligate-implementation-of-webassembly</link><description><div><p>Hey hey hey good evening!  Tonight a quick note on<a href="https://codeberg.org/andywingo/wastrel">wastrel</a>, a new WebAssemblyimplementation.</p><h3>a wasm-to-native compiler that goes through c</h3><p>Wastrel compiles Wasm modules to standalone binaries.  It does so byemitting C and then compiling that C.</p><p>Compiling Wasm to C isn’t new: <a href="https://binji.github.io/">Ben Smith</a>wrote <a href="https://github.com/WebAssembly/wabt/tree/main/wasm2c">wasm2c</a>back in the day and these days most people in this space use <a href="https://turbolent.com/">BastienMüller</a>‘s <a href="https://github.com/turbolent">w2c2</a>.These are great projects!  </p><p>Wastrel has two or three minor differences from these projects.  Let’slead with the most important one, despite the fact that it’s as yetvaporware: Wastrel aims to support automatic memory managment via<a href="https://v8.dev/blog/wasm-gc-porting">WasmGC</a>, by embedding the <a href="https://github.com/wingo/whippet">Whippetgarbage collection library</a>.  (For thewingolog faithful, you can think of Wastrel as a<a href="https://wingolog.org/archives/2023/11/13/i-accidentally-a-scheme">Whiffle</a>for Wasm.)  This is the whole point!  But let’s come back to it.</p><p>The other differences are minor.  Firstly, the CLI is more like<a href="https://wasmtime.dev">wasmtime</a>: instead of privileging the productionof C, which you then incorporate into your project, Wastrel alsocompiles the C (by default), and even runs it, like <tt>wasmtime run</tt>.</p><p>Unlike wasm2c (but like w2c2), Wastrel implements<a href="https://wasi.dev">WASI</a>.  Specifically, WASI 0.1, sometimes known as“WASI preview 1”.  It’s nice to be able to take the<a href="https://github.com/WebAssembly/wasi-sdk">wasi-sdk</a>‘s C compiler,compile your program to a binary that uses WASI imports, and then run itdirectly.</p><p>In a past life, I once took a week-long sailing course on a 12-meteryacht.  One thing that comes back to me often is the way the instructorwould insist on taking in the bumpers immediately as we left port, thatto sail with them was <i>no muy marinero</i>, not very seamanlike.  Well onething about Wastrel is that it emits nice C: nice in the sense that itavoids many useless temporaries.  It does so with a lightweight <a href="https://wingolog.org/archives/2014/05/18/effects-analysis-in-guile">effectsanalysis</a>,in which as temporaries are produced, they record which bits of theworld they depend on, in a coarse way: one bit for the contents of allglobal state (memories, tables, globals), and one bit for each local.When compiling an operation that writes to state, we flush alltemporaries that read from that state (but only that state).  It’s asmall thing, and I am sure it has very little or zero impact after<a href="https://llvm.org/doxygen/SROA_8cpp_source.html">SROA</a> turns locals intoSSA values, but we are vessels of the divine, and it is important forvessels to be C worthy.</p><p>Finally, w2c2 at least is built in such a way that you can instantiate amodule multiple times.  Wastrel doesn’t do that: the Wasm instance isstatically allocated, once.  It’s a restriction, but that’s the use caseI’m going for.</p><h3>on performance</h3><p>Oh buddy, who knows?!?  What is real anyway?  I would love to haveproper perf tests, but in the meantime, I compiled<a href="https://github.com/eembc/coremark">coremark</a> using my GCC on x86-64(-02, no other options), then also compiled it with the current wasi-sdkand then ran with w2c2, wastrel, and wasmtime.  I am well aware of themany pitfalls of benchmarking, and so I should not say anything becauseit is irresponsible to make conclusions from useless microbenchmarks.However, we’re all friends here, and I am a dude with hubris who alsobelieves blogs are better out than in, and so I will give some smallindications.  Please obtain your own salt.</p><p>So on coremark, Wastrel is some 2-5% percent slower than native, andw2c2 is some 2-5% slower than that.  Wasmtime is 30-40% slower than GCC.Voilà.</p><p>My conclusion is, Wastrel provides state-of-the-art performance.  Likew2c2.  It’s no wonder, these are simple translators that use industrialcompilers underneath.  But it’s neat to see that performance is close tonative.</p><h3>on wasi</h3><p>OK this is going to sound incredibly arrogant but here it is: writingWastrel was easy.  I have worked on Wasm for a while, and on <a href="https://wingolog.org/archives/2020/03/25/firefoxs-low-latency-webassembly-compiler">Firefox’sbaselinecompiler</a>,and Wastrel is kinda like a baseline compiler in shape: it just has toavoid emitting boneheaded code, and can leave the serious work tosomeone else (Ion in the case of Firefox, GCC in the case of Wastrel).I just had to use the <a href="https://codeberg.org/spritely/hoot/src/branch/main/module/wasm">Wasm libraries I alreadyhad</a> andmake it emit some C for each instruction.  It took 2 days.</p><p>WASI, though, took two and a half weeks of agony.  Three reasons: One,you can be sloppy when implementing just wasm, but when you do WASI youhave to implement an ABI using sticks and glue, but you have no glue,it’s all just <tt>i32</tt>.  Truly excruciating, it makes you doubt everything,and I had to refactor Wastrel to use C’s meager type system to the max.(Basically, structs-as-values to avoid type confusion, but via inlinefunctions to avoid overhead.)</p><p>Two, WASI is not huge but not tiny either.  Implementing<a href="https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#poll_oneoff"><tt>poll_oneoff</tt></a>is annoying.  And so on.  Wastrel’s <a href="https://codeberg.org/andywingo/wastrel/src/branch/main/resource/wasip1.h">WASIimplementation</a>is thin but it’s still a couple thousand lines of code.</p><p>Three, WASI is underspecified, and in practice what is “conforming” is afunction of what the Rust and C toolchains produce.  I used<a href="https://github.com/WebAssembly/wasi-testsuite">wasi-testsuite</a> to burndown most of the issues, but it was a slog.  I neglected email andimportant things but now things pass so it was worth it maybe?  Maybe?</p><h3>on wasi’s filesystem sandboxing</h3><p>WASI preview 1 has this<a href="https://github.com/WebAssembly/WASI/blob/main/legacy/preview1/docs.md#rights">“rights”</a>interface that associated capabilities with file descriptors.  I thinkit was an attempt at replacing and expanding file permissions with acapabilities-oriented security approach to sandboxing, but it was only aveneer.  In practice most WASI implementations effectively implement thesandbox via a permissions layer: for example the process hascapabilities to access the parents of preopened directories via <tt>..</tt>,but the WASI implementation has to actively prevent this capability fromleaking to the compiled module via run-time checks.</p><p>Wastrel takes a different approach, which is to use Linux’s filesystemnamespaces to build a tree in which only the exposed files areaccessible.  No run-time checks are necessary; the system is secure byconstruction.  He says.  It’s very hard to be categorical in this domainbut a true capabilities-based approach is the only way I can have anyconfidence in the results, and that’s what I did.</p><p>The upshot is that Wastrel is only for Linux.  And honestly, if you areon MacOS or Windows, what are you doing with your life?  I get that it’simportant to meet users where they are but it’s just gross to build on acorporate-controlled platform.</p><p>The current versions of WASI keep a vestigial capabilities-based API,but given that the goal is to compile POSIX programs, I would prefer if<a href="https://github.com/WebAssembly/wasi-filesystem">wasi-filesystem</a> leanedinto the approach of WASI just having access to a filesystem instead ofa small set of descriptors plus scoped <tt>openat</tt>, <tt>linkat</tt>, and so onAPIs.  The security properties would be the same, except with fewer bugpossibilities and with a more conventional interface.</p><h3>on wtf</h3><p>So Wastrel is Wasm to native via C, but with an as-yet-unbuilt GC aim.Why?</p><p>This is hard to explain and I am still workshopping it.</p><p>Firstly I am annoyed at the WASI working group’s focus on shared-nothingarchitectures as a principle of composition.  Yes, it works, but garbagecollection also works; we could be building different, simpler systemsif we leaned in to a more capable virtual machine.  Many of the problemsthat WASI is currently addressing are ownership-related, and would becomprehensively avoided with automatic memory management.  Nobody isreally pushing for GC in this space and I would like for people to beable to build out counterfactuals to the shared-nothing orthodoxy.</p><p>Secondly there are quite a number of languages that are targettingWasmGC these days, and it would be nice for them to have a good run-timeoutside the browser.  I know that Wasmtime is working on GC, but itneeds competition :)</p><p>Finally, and selfishly, <a href="https://github.com/wingo/whippet">I have a GC library</a>!  I would love to spend moretime on it.  One way that can happen is for it to prove itself useful,and maybe a Wasm implementation is a way to do that.  Could Wastrel on<a href="https://github.com/ocaml-wasm/wasm_of_ocaml"><tt>wasm_of_ocaml</tt></a> output beat<tt>ocamlopt</tt>?  I don’t know but it would be worth it to find out!  And Iwould love to get Guile programs compiled to native, and perhaps with<a href="https://codeberg.org/spritely/hoot">Hoot</a> and Whippet and Wastrel that is apossibility.</p><p>Welp, there we go, blog out, dude to bed.  Hack at y’all later andwonderful wasming to you all!</p></div></description><author>Andy Wingo</author><dc:creator>Andy Wingo</dc:creator><pubDate>Thu, 30 Oct 2025 22:19:33 GMT</pubDate><guid isPermaLink="true">https://wingolog.org/archives/2025/10/30/wastrel-a-profligate-implementation-of-webassembly</guid></item><item><title>Michael Meeks: 2025-10-29 Wednesday</title><link>https://meeksfamily.uk/~michael/blog/2025-10-29.html</link><description><ul> <!-- --> 	<li>		Call with Dave, catch up with Gerald &amp; Matthias,	sync with Thorsten, then Pedro.	</li>	<li>		Published the next strip with one approach for how (not)	to get free maintenance:		<center>		<a href="https://www.collaboraonline.com/torf/torf41"><img alt="The Open Road to Freedom - strip#41 - Free maintenance ?" src="https://meeksfamily.uk/~michael/images/torf41-thumb.png" /></a>		</center>	</li>	<li>		Snatched lunch, call with Quikee - chat with an	old friend, sync with Philippe, got to a quick code-fix.	</li></ul></description><author>Michael Meeks</author><dc:creator>Michael Meeks</dc:creator><pubDate>Wed, 29 Oct 2025 18:47:25 GMT</pubDate><guid isPermaLink="true">https://meeksfamily.uk/~michael/blog/2025-10-29.html</guid></item><item><title>Thibault Martin: From VS Code to Helix</title><link>https://ergaster.org/posts/2025/10/29-vscode-to-helix/</link><description><p>I created the website you're reading with VS Code. Behind the scenes I use Astro, a static site generator that gets out of the way while providing nice conveniences.</p><p>Using VS Code was a no-brainer: everyone in the industry seems to at least be familiar with it, every project can be opened with it, and most projects can get enhancements and syntactic helpers in a few clicks. In short: VS Code is free, easy to use, and widely adopted.</p><p>A Rustacean colleague kept singing <a href="https://helix-editor.com/">Helix</a>'s praises. I discarded it because he's much smarter than I am, and I only ever use vim when I need to fiddle with files on a server. I like when things "Just Work" and didn't want to bother learning how to use Helix nor how to configure it.</p><p>Today it has become my daily driver. Why did I change my mind? What was preventing me from using it before? And how difficult was it to get there?</p><h2>Automation is a double-edged sword</h2><p>Automation and technology make work easier, this is why we produce technology in the first place. But it also means you grow more dependent on the tech you use. If the tech is produced transparently by an international team or a team you trust, it's fine. But if it's produced by a single large entity that can screw you over, it's dangerous.</p><p>VS Code might be open source, but in practice it's produced by Microsoft. Microsoft has a problematic relationship to consent and is shoving AI products down everyone's throat. I'd rather use tools that respect me and my decisions, and I'd rather not get my tools produced by already monopolistic organizations.</p><p>Microsoft is also based in the USA, and the political climate over there makes me want to depend as little as possible on American tools. I know that's a long, uphill battle, but we have to start somewhere.</p><p>I'm not advocating for a ban against American tech in general, but for more balance in our supply chain. I'm also not advocating for European tech either: I'd rather get open source tools from international teams competing in a race to the top, rather than from teams in a single jurisdiction. What is happening in the USA could happen in Europe too.</p><h2>Why I feared using Helix</h2><p>I've never found vim particularly pleasant to use but it's everywhere, so I figured I might just get used to it. But one of the things I never liked about vim is the number of moving pieces. By default, vim and neovim are very bare bones. They can be extended and completely modified with plugins, but I really don't like the idea of having extremely customize tools.</p><p>I'd rather have the same editor as everyone else, with a few knobs for minor preferences. I am subject to choice paralysis, so making me configure an editor before I've even started editing is the best way to tank my productivity.</p><p>When my colleague told me about Helix, two things struck me as improvements over vim.</p><ol><li><strong>Helix's philosophy is that everything should work out of the box.</strong> There are a few configs and themes, but everything should work similarly from one Helix to another. All the language-specific logic is handled in Language Servers that implement the <a href="https://en.wikipedia.org/wiki/Language_Server_Protocol">Language Server Protocol</a> standard.</li><li><strong>In Helix, first you select text, and then you perform operations onto it.</strong> So you can visually tell what is going to be changed before you apply the change. It fits my mental model much better.</li></ol><p>But there are major drawbacks to Helix too:</p><ol><li><strong>After decades of vim, I was scared to re-learn everything.</strong> In practice this wasn't a problem at all because of the very visual way Helix works.</li><li><strong>VS Code "Just Works", and Helix sounded like more work than the few clicks from VS Code's extension store.</strong> This is true, but not as bad as I had anticipated.</li></ol><p>After a single week of usage, Helix was already very comfortable to navigate. After a few weeks, most of the wrinkles have been ironed out and I use it as my primary editor. So how did I overcome those fears?</p><h2>What Helped</h2><h3>Just Do It</h3><p><strong>I tried Helix.</strong> It can sound silly, but the very first step to get into Helix was not to overthink it. I just installed it on my mac with <code>brew install helix</code> and gave it a go. I was not too familiar with it, so I looked up <a href="https://docs.helix-editor.com/usage.html">the official documentation</a> and noticed there was a tutorial.</p><p>This tutorial alone is what convinced me to try harder. It's an interactive and well written way to learn how to move and perform basic operations in Helix. I quickly learned how to move around, select things, surround them with braces or parenthesis. I could <em>see</em> what I was about to do before doing it. This has been epiphany. Helix just worked the way I wanted.</p><p></p><p>Better: I could get things done faster than in VS Code after a few minutes of learning. Being a lazy person, I never bothered looking up VS Code shortcuts. Because the learning curve for Helix is slightly steeper, you <em>have</em> to learn those shortcuts that make moving around feel so easy.</p><p>Not only did I quickly get used to Helix key bindings: my vim muscle-memory didn't get in the way at all!</p><h3>Better docs</h3><p>The built-in tutorial is a very pragmatic way to get started. You get results fast, you learn hands on, and it's not that long. But if you want to go further, you have to look for docs. Helix <a href="https://docs.helix-editor.com/">has officials docs</a>. They seem to be fairly complete, but they're also impenetrable as a new user. They focus on what the editor supports and not on what I will want to do with it.</p><p>After a bit of browsing online, I've stumbled upon <a href="https://helix-nikita-revencos-projects.vercel.app/start-here/basics">this third-party documentation website</a>. The domain didn't inspire me a lot of confidence, but the docs are really good. They are clearly laid out, use-case oriented, and they make the most of Astro Starlight to provide a great reading experience. The author <a href="https://github.com/helix-editor/helix/pull/12127#issuecomment-2525902615">tried to upstream these docs, but that won't happen</a>. It looks like they are upstreaming their docs to the current website. I hope this will improve the quality of upstream docs eventually.</p><p>After learning the basics and finding my way through the docs, it was time to ensure Helix was set up to help me where I needed it most.</p><h2>Getting the most of Markdown and Astro in Helix</h2><p>In my free time, I mostly use my editor for three things:</p><ol><li>Write notes in markdown</li><li>Tweak my website with Astro</li><li>Edit yaml to faff around my Kubernetes cluster</li></ol><p>Helix is a "stupid" text editor. It doesn't know much about what you're typing. But it supports Language Servers that implement the Language Server Protocol. Language Servers understand the document you're editing. They explain to Helix what you're editing, whether you're in a TypeScript function, typing a markdown link, etc. With that information, Helix and the Language Server can provide code completion hints, errors &amp; warnings, and easier navigation in your code.</p><p>In addition to Language Servers, Helix also supports plugging code formatters. Those are pieces of software that will read the document and ensure that it is consistently formatted. It will check that all indentations use spaces and not tabs, that there is a consistent number of space when indenting, that brackets are on the same line as the function, etc. In short: it will make the code pretty.</p><h3>Markdown</h3><p>Markdown is not really a programming language, so it might seem surprising to configure a Language Server for it. But if you remember what we said earlier, Language Servers can provide code completion, which is useful when creating links for example. <a href="https://github.com/artempyanykh/marksman">Marksman</a> does exactly that!</p><p>Since Helix <a href="https://docs.helix-editor.com/lang-support.html">is pre-configured to use marksman for markdown files</a> we only need to install marksman and make sure it's in our <code>PATH</code>. Installing it with homebrew is enough.</p><pre><code>$ brew install marksman</code></pre><p>We can check that Helix is happy with it with the following command</p><pre><code>$ hx --health markdownConfigured language servers:  ✓ marksman: /opt/homebrew/bin/marksmanConfigured debug adapter: NoneConfigured formatter: NoneTree-sitter parser: ✓Highlight queries: ✓Textobject queries: ✘Indent queries: ✘</code></pre><p>But Language Servers can also help Helix display errors and warnings, and "code suggestions" to help fix the issues. It means Language Servers are a perfect fit for... grammar checkers! Several grammar checkers exist. The most notable are:</p><ul><li><a href="https://ltex-plus.github.io/ltex-plus/">LTEX+</a>, the Language Server used by <a href="https://languagetool.org/">Language Tool</a>. It supports several languages must is quite resource hungry.</li><li><a href="https://writewithharper.com/">Harper</a>, a grammar checker Language Server developed by Automattic, the people behind WordPress, Tumblr, WooCommerce, Beeper and more. Harper only support English and its variants, but they intend to support more languages in the future.</li></ul><p>I mostly write in English and want to keep a minimalistic setup. Automattic is well funded, and I'm confident they will keep working on Harper to improve it. Since grammar checker LSPs can easily be changed, I've decided to go with Harper for now.</p><p></p><p>To install it, homebrew does the job as always:</p><pre><code>$ brew install harper</code></pre><p>Then I edited my <code>~/.config/helix/languages.toml</code> to add Harper as a secondary Language Server in addition to marksman</p><pre><code>[language-server.harper-ls]command = "harper-ls"args = ["--stdio"]  [[language]]name = "markdown"language-servers = ["marksman", "harper-ls"]</code></pre><p>Finally I can add a markdown linter to ensure my markdown is formatted properly. Several options exist, and <a href="https://github.com/DavidAnson/markdownlint">markdownlint</a> is one of the most popular. My colleagues recommended the new kid on the block, a <em>Blazing Fast</em> equivalent: <a href="https://github.com/rvben/rumdl">rumdl</a>.</p><p>Installing rumdl was pretty simple on my mac. I only had to add the repository of the maintainer, and install rumdl from it.</p><pre><code>$ brew tap rvben/rumdl$ brew install rumdl</code></pre><p>After that I added a new <code>language-server</code> to my <code>~/.config/helix/languages.toml</code> and added it to the language servers to use for the markdown <code>language</code>.</p><pre><code>[language-server.rumdl]command = "rumdl"args = ["server"] [...]  [[language]]name = "markdown"language-servers = ["marksman", "harper-ls", "rumdl"]soft-wrap.enable = truetext-width = 80soft-wrap.wrap-at-text-width = true</code></pre><p>Since my website already contained a <code>.markdownlint.yaml</code> I could import it to the rumdl format with</p><pre><code>$ rumdl import .markdownlint.yamlConverted markdownlint config from '.markdownlint.yaml' to '.rumdl.toml'You can now use: rumdl check --config .rumdl.toml .</code></pre><p>You might have noticed that I've added a little quality of life improvement: soft-wrap at 80 characters.</p><p>Now if you add this to your own <code>config.toml</code> you will notice that the text is completely left aligned. This is not a problem on small screens, but it rapidly gets annoying on wider screens.</p><p>Helix doesn't support centering the editor. There is <a href="https://github.com/helix-editor/helix/pull/9838">a PR tackling the problem</a> but it has been stale for most of the year. The maintainers are overwhelmed by the number of PRs making it their way, and it's not clear if or when this PR will be merged.</p><p>In the meantime, a workaround exists, with a few caveats. It is possible to add spaces to the left gutter (the column with the line numbers) so it pushes the content towards the center of the screen.</p><p></p><p>To figure out how many spaces are needed, you need to get your terminal width with <code>stty</code></p><pre><code>$ stty size82 243</code></pre><p>In my case, when in full screen, my terminal is 243 characters wide. I need to remove the content column with from it, and divide everything by 2 to get the space needed on each side. In my case for a 243 character wide terminal with a text width of 80 characters:</p><pre><code>(243 - 80) / 2 = 81</code></pre><p>As is, I would add 203 spaces to my left gutter to push the rest of the gutter and the content to the right. But the gutter itself has a width of 4 characters, that I need to remove from the total. So I need to subtract them from the total, which leaves me with <code>76</code> characters to add.</p><p>I can open my <code>~/.config/helix/config.toml</code> to add a new key binding that will automatically add or remove those spaces from the left gutter when needed, to shift the content towards the center.</p><pre><code>[keys.normal.space.t]z = ":toggle gutters.line-numbers.min-width 76 3"</code></pre><p>Now when in normal mode, pressing &lt;kbd&gt;Space&lt;/kbd&gt; then &lt;kbd&gt;t&lt;/kbd&gt; then &lt;kbd&gt;z&lt;/kbd&gt; will add/remove the spaces. Of course this workaround only works when the terminal runs in full screen mode.</p><h3>Astro</h3><p>Astro works like a charm in VS Code. The team behind it provides <a href="https://github.com/withastro/language-tools?tab=readme-ov-file#astrojslanguage-server">a Language Server</a> and a <a href="https://github.com/withastro/language-tools?tab=readme-ov-file#astrojsts-plugin">TypeScript plugin</a> to enable code completion and syntax highlighting.</p><p>I only had to install those globally with</p><pre><code>$ pnpm install -g @astrojs/language-server typescript @astrojs/ts-plugin</code></pre><p>Now we need to add a few lines to our <code>~/.config/helix/languages.toml</code> to tell it how to use the language server</p><pre><code>[language-server.astro-ls]command = "astro-ls"args = ["--stdio"]config = { typescript = { tsdk = "/Users/thibaultmartin/Library/pnpm/global/5/node_modules/typescript/lib" }} [[language]]name = "astro"scope = "source.astro"injection-regex = "astro"file-types = ["astro"]language-servers = ["astro-ls"]</code></pre><p>We can check that the Astro Language Server can be used by helix with</p><pre><code>$ hx --health astroConfigured language servers:  ✓ astro-ls: /Users/thibaultmartin/Library/pnpm/astro-lsConfigured debug adapter: NoneConfigured formatter: NoneTree-sitter parser: ✓Highlight queries: ✓Textobject queries: ✘Indent queries: ✘</code></pre><p>I also like to get a formatter to automatically make my code consistent and pretty for me when I save a file. One of the most popular code formaters out there is <a href="https://prettier.io/">Prettier</a>. I've decided to go with the fast and easy formatter <a href="https://dprint.dev/">dprint</a> instead.</p><p>I installed it with</p><pre><code>$ brew install dprint</code></pre><p>Then in the projects I want to use dprint in, I do</p><pre><code>$ dprint init</code></pre><p>I might edit the <code>dprint.json</code> file to my liking. Finally, I configure Helix to use dprint globally for all Astro projects by appending a few lines in my <code>~/.config/helix/languages.toml</code>.</p><pre><code>[[language]]name = "astro"scope = "source.astro"injection-regex = "astro"file-types = ["astro"]language-servers = ["astro-ls"]formatter = { command = "dprint", args = ["fmt", "--stdin", "astro"]}auto-format = true</code></pre><p>One final check, and I can see that Helix is ready to use the formatter as well</p><pre><code>$ hx --health astroConfigured language servers:  ✓ astro-ls: /Users/thibaultmartin/Library/pnpm/astro-lsConfigured debug adapter: NoneConfigured formatter:  ✓ /opt/homebrew/bin/dprintTree-sitter parser: ✓Highlight queries: ✓Textobject queries: ✘Indent queries: ✘</code></pre><h3>YAML</h3><p>For yaml, it's simple and straightforward: Helix is preconfigured to use <code>yaml-language-server</code> as soon as it's in the PATH. I just need to install it with</p><pre><code>$ brew install yaml-language-server</code></pre><h2>Is it worth it?</h2><p><strong>Helix really grew on me. I find it particularly easy and fast to edit code with it.</strong> It takes a tiny bit more work to get the language support than it does in VS Code, but it's nothing insurmountable. There is a slightly steeper learning curve than for VS Code, but I consider it to be a good thing. It forced me to learn how to move around and edit efficiently, because there is no way to do it inefficiently. Helix remains intuitive once you've learned the basics.</p><p>I am a GNOME enthusiast, and I adhere to the same principles: <strong>I like when my apps work out of the box, and when I have little to do to configure them.</strong> This is a strong stance that often attracts a vocal opposition. I like products that follow those principles better than those who don't.</p><p>With that said, Helix sometimes feels like it is maintained by one or two people who have a strong vision, but who struggle to onboard more maintainers. As of writing, Helix has more than 350 PRs open. Quite a few bring interesting features, but the maintainers don't have enough time to review them.</p><p>Those 350 PRs mean there is a lot of energy and goodwill around the project. <strong>People are willing to contribute. Right now, all that energy is gated, resulting in frustration</strong> both from the contributors who feel like they're working in the void, and the maintainers who feel like there at the receiving end of a fire hose.</p><p><strong>A solution to make everyone happier without sacrificing the quality of the project would be to work on a Contributor Ladder.</strong> CHAOSS' Dr Dawn Foster published <a href="https://fastwonderblog.com/2025/08/12/governance-part-3-new-contributors-and-pathways-to-leadership/">a blog post about it</a>, listing interesting resources at the end.</p></description><author>Thibault Martin</author><dc:creator>Thibault Martin</dc:creator><pubDate>Wed, 29 Oct 2025 12:00:00 GMT</pubDate><guid isPermaLink="true">https://ergaster.org/posts/2025/10/29-vscode-to-helix/</guid></item><item><title>Felipe Borges: Google Summer of Code Mentor Summit 2025</title><link>https://blogs.gnome.org/feborges/gsoc-mentor-summit-2025/</link><description><p>Last week, I took a lovely train ride to Munich, Germany, to represent GNOME at the Google Summer of Code Mentor Summit 2025. This was my first time attending the event, as previous editions were held in the US, which was always a bit too hard to travel.</p><p>This was also my first time at an event with the &#8220;unconference&#8221; format, which I found to be quite interesting and engaging. I was able to contribute to a few discussions and hear a variety of different perspectives from other contributors. It seems that when done well, this format can lead to much richer conversations than our usual, pre-scheduled &#8220;one-to-many&#8221; talks.</p><p>The event was attended by a variety of free and open-source communities from all over the world. These groups are building open solutions for everything from cloud software and climate applications to programming languages, academia, and of course, AI. This diversity was a great opportunity to learn about the challenges other software communities face and their unique circumstances.</p><p>There was a nice discussion with the people behind MusicBrainz. I was happy and surprised to find out that they are the largest database of music metadata in the world, and that pretty much all popular music streaming services, record labels, and similar groups consume their data in some way.</p><p>Funding the project is a constant challenge for them, given that they offer a public API that everyone can consume. They’ve managed over the years by making direct contact with these large companies, developing relationships with the decision-makers inside, and even sometimes publicly highlighting how these highly profitable businesses rely on FOSS projects that struggle with funding. Interesting stories. <img alt="🙂" class="wp-smiley" src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" style="height: 1em;" /></p><p>There was a large discussion about &#8220;AI slop,&#8221; particularly in GSoC applications. This is a struggle we’ve faced in GNOME as well, with a flood of AI-generated proposals. The Google Open Source team was firm that it&#8217;s up to each organization to set its own criteria for accepting interns, including rules for contributions. Many communities shared their experiences, and the common solution seems to be reducing the importance of the GSoC proposal document. Instead, organizations are focusing on requiring a history of small, &#8220;first-timer&#8221; contributions and conducting short video interviews to discuss that work. This gives us more confidence that the applicant truly understands what they are doing.</p><p>GSoC is not a &#8220;pay-for-feature&#8221; initiative, neither for Google nor for GNOME. We see this as an opportunity to empower newcomers to become long-term GNOME contributors. Funding free and open-source work is hard, especially for people in less privileged places of the world, and initiatives like GSoC and Outreachy allow these people to participate and find career opportunities in our spaces. We have a large number of GSoC interns who have become long-term maintainers and contributors to GNOME. Many others have joined different industries, bringing their GNOME expertise and tech with them. It&#8217;s been a net-positive experience for Google, GNOME, and the contributors over the past decades.</p><p>Our very own Karen Sandler was there and organized a discussion around diversity. This topic is as relevant as ever, especially given recent challenges to these initiatives in the US. We discussed ideas on how to make communities more diverse and better support the existing diverse members of our communities.</p><p>It was quite inspiring. Communities from various other projects shared their stories and results, and to me, it just confirmed my perception: while diverse communities are hard to build, they can achieve much more than non-diverse ones in the long run. It is always worth investing in people.</p><p>As always, the &#8220;hallway track&#8221; was incredibly fruitful. I had great chats with Carl Schwan (from KDE) about event organizing (comparing notes on GUADEC, Akademy, and LAS) and cross-community collaboration around technologies like Flathub and Flatpak. I also caught up with Claudio Wunder, who did engagement work for GNOME in the past and has always been a great supporter of our project. His insights into the dynamics of other non-profit foundations sparked some interesting discussions about the challenges we face in our foundation.</p><p>I also had a great conversation with Till Kamppeter (from OpenPrinting) about the future of printing in xdg-desktop-portals. We focused on agreeing on a direction for new dialog features, like print preview and other custom app-embedded settings. This was the third time I&#8217;ve run into Till at a conference this year! <img alt="🙂" class="wp-smiley" src="https://s.w.org/images/core/emoji/16.0.1/72x72/1f642.png" style="height: 1em;" /></p><p>I met plenty of new people and had various off-topic chats as well. The event was only two days long, but thanks to the unconference format, I ended up engaging far more with participants than I usually do in that amount of time.</p><p>I also had the chance to give a lightning talk about GNOME&#8217;s long history with Google Summer of Code and how the program has helped us build our community. It was a great opportunity to also share our wider goals, like building a desktop for everyone and our focus on being a people-centric community.</p><p>Finally, I&#8217;d like to thank Google for sponsoring my trip, and for providing the space for us all to talk about our communities and learn from so many others.</p></description><author>Felipe Borges</author><dc:creator>Felipe Borges</dc:creator><pubDate>Wed, 29 Oct 2025 11:05:09 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/feborges/gsoc-mentor-summit-2025/</guid></item><item><title>Michael Meeks: 2025-10-28 Tuesday</title><link>https://meeksfamily.uk/~michael/blog/2025-10-28.html</link><description><ul> <!-- ljm --> 	<li>		Up early, chat with boiler man - new gas-valve ordered	and fetched by J. for fitting this evening - house: cold.	</li>	<li>		Planning call, lunch with M&amp;D <!-- funeral bits -->	bid a fond farewell, and drove home with J.	</li>	<li>		Lovely to see M. and H. and E. - the nest is refilling	temporarily it seems.	</li></ul></description><author>Michael Meeks</author><dc:creator>Michael Meeks</dc:creator><pubDate>Tue, 28 Oct 2025 21:00:00 GMT</pubDate><guid isPermaLink="true">https://meeksfamily.uk/~michael/blog/2025-10-28.html</guid></item><item><title>Jakub Steiner: USB MIDI Controllers on the M8</title><link>https://blog.jimmac.eu/2025/usb-midi-m8/</link><description><p>The M8 has extensive USB audio and MIDI capabilities, but it cannot be a USB MIDI host. So you can control other devices through USB MIDI, but cannot sent to it over USB.</p> <h1 id="control-surface--pots-for-m8">Control Surface &amp; Pots for M8</h1> <p>Controlling things via USB devices has to be done through the old TRS (A) jacks. There’s two devices that can aid in that. I’ve used the <a href="https://retrokits.com/shop/rk006/">RK06</a> which is very featureful, but in a very clumsy plastic case and USB micro cable that has a splitter for the HOST part and USB Power in. It also sometimes doesn’t reset properly when having multiple USB devices attached through a hub. The last bit is why I even bother with this setup.</p> <p>The Dirtywave M8 has amazing support for the <a href="https://novationmusic.com/products/launchpad-pro-mk3">Novation Launchpad Pro MK3</a>. Majority of peolpe hook it up directly to the M8 using the TRS MIDI cables. The Launchpad lacks any sort of pots or encoders though. Thus the need to fuss with USB dongles. What you need is to use the Launchpad Pro as a USB controller and shun at the reliable MIDI connection. The RK06 allows to combine multiple USB devices attached through an unpowered USB hub. Because I am flabbergasted how I did things here’s a schema that works.</p> <p><img alt="Retrokits RK06 schema" src="https://blog.jimmac.eu/2025/usb-midi-m8/schema.svg" /></p> <p>If it doesn’t work, unplug the RK06 and turn LPPro off and on in the M8. I hate this setup but it is the only compact one that works (after some fiddling that you absolutely hate when doing a gig).</p> <p><img alt="Launchpar Pro and Intech PO16 via USB handled by RK06" src="https://blog.jimmac.eu/2025/usb-midi-m8/m8-po16-lpp-mk3.webp" /></p> <h1 id="intech-knot">Intech Knot</h1> <p>The Hungarians behind the Grid USB controlles (with first class Linux support) have a USB&gt;MIDI device called <a href="https://intech.studio/landing/shop/knot">Knot</a>. It has one great feature of a switch between TRS A/B for the non-standard devices.</p> <p><img alt="Clean setup with Knot&amp;Grid" src="https://blog.jimmac.eu/2025/usb-midi-m8/knot.webp" /></p> <p>It is way less fiddly than the RK06, uses nice aluminium housing and is sturdier. Hoewer it doesn’t seem to work with the Launchpad Pro via USB and it seems to be completely confused by a USB hub, so it’s not useful for my use case of multiple USB controllers.</p> <h1 id="non-compact-but-reliable">Non-compact but Reliable</h1> <p>Novation came out with the <a href="https://novationmusic.com/products/launch-control-xl">Launch Control XL</a>, which sadly replaced pots in the old one with encoders (absolute vs relative movement), but added midi in/ou/through with a MIDI mixer even. That way you can avoid USB altogether and get a reliable setup with control surfaces and encoders and sliders.</p> <p>One day someone comes up with a compact midi capable pots to play along with Launchpad Pro ;) This post has been brought to you by an old man who forgets things.</p></description><author>Jakub Steiner</author><dc:creator>Jakub Steiner</dc:creator><pubDate>Tue, 28 Oct 2025 11:04:00 GMT</pubDate><guid isPermaLink="true">https://blog.jimmac.eu/2025/usb-midi-m8/</guid></item><item><title>Colin Walters: Thoughts on agentic AI coding as of Oct 2025</title><link>https://blog.verbum.org/2025/10/27/thoughts-on-agentic-ai-coding-as-of-oct-2025/</link><description><div class="wp-block-jetpack-markdown"><h1>Sandboxed, reviewed parallel agents make sense</h1><p>For coding and software engineering, I’ve used and experimented with variousfrontends (FOSS and proprietary) to multiple foundation models(mostly proprietary) trying to keep up with the state of the art.I’ve come to strongly believe in a few things:</p><ul><li>Agentic AI for coding needs strongly sandboxed, reproducible environments</li><li>It makes sense to run multiple agents at once</li><li>AI output definitely needs human review</li></ul><h2>Why human review is necessary</h2><h3>Prompt injection is a serious risk at scale</h3><p>All AI is at risk of <a href="https://simonwillison.net/2025/Jun/13/prompt-injection-design-patterns/">prompt injection</a>to some degree, but it’s particularly dangerous with agentic coding. All the state of the arttoday knows how to do is mitigate it at best. I don’t think it’s a reasonto avoid AI, but it’s one of the top reasons to use AI thoughtfully andcarefully for products that have any level of criticality.</p><p><a href="https://developers.openai.com/codex/cloud/internet-access#risks-of-agent-internet-access">OpenAI’s Codex documentation</a>has a simple and good example of this.</p><h3>Disabling the tests and claiming success</h3><p>Beyond that, I’ve experienced multiple times different models happilydisabling the tests or adding a <code>println!(&quot;TODO add testing here&quot;)</code> andclaim success. At least this one is easier to mitigate with a secondagent doing code review before it gets to human review.</p><h2>Sandboxing</h2><p>The “can I do X” prompting model that various interfaces default to isseriously flawed. Anthropic has a <a href="https://www.anthropic.com/engineering/claude-code-sandboxing">recent blog post on Claude Code changes</a>in this area.</p><p>My take here is that sandboxing is only part of the problem; theother part is ensuring the agent has a reproducible environment,and especially one that can be run in IaaS environments. I think<a href="https://containers.dev/">devcontainers</a> are a good fit.</p><p>I don’t agree with the statement from Anthropic’s blog</p><blockquote><p>without the overhead of spinning up and managing a container.</p></blockquote><p>I don’t think this is overhead for most projects becauseWhere it feels like it has overhead,we should be working to mitigate it.</p><h3>Running code as separate login users</h3><p>In fact, one thing I think we should popularize more on Linuxis the concept of running multiple unprivileged login users.Personally for the tasks <em>I</em> work on, it often involves buildingcontainers or launching local VMs, and isolating that worksreally well with a full separate “user” identity. An experimentI did was basically <code>useradd ai</code> and running delegated tasksthere instead. To log in I added <code>%wheel ALL=NOPASSWD: /usr/bin/machinectl shell ai@</code>to <code>/etc/sudoers.d/ai-login</code> so that my regular humanuser could easily get a shell in the <code>ai</code> user’s context.</p><p>I haven’t truly “operationalized” this one as juggling separategit repository clones was a bit painful, but I think I couldautomate it more. I’m interested in hearing from folkswho are doing something similar.</p><h2>Parallel, IaaS-ready agents…with review</h2><p>I’m today often running 2-3 agents in parallel on different tasks(with different levels of success, but that’s its own story).</p><p>It makes total sense to support delegating some of these agentsto work off my local system and into cloud infrastructure.</p><p>In looking around in this space, there’s quite a lot of stuff.One of them is <a href="https://ona.com/">Ona</a> (formerly Gitpod). Igave it a quick try and I like where they’re going, but more on thisbelow.</p><p><a href="https://github.com/features/copilot">Github Copilot</a> can also do something similar to this, butwhat I don’t like about it is that it pushes a modelwhere all of one’s interaction is in the PR. That’s goingto be seriously noisy for some repositories, and interactionwith LLMs can feel too “personal” sometimes to have permanentlyrecorded.</p><h2>Credentials should be on demand and fine grained for tasks</h2><p>To me a huge flaw with Ona and one shared with other things like<a href="https://github.com/langchain-ai/open-swe">Langchain Open-SWE</a> isbasically this:</p></div>   <figure class="wp-block-image size-large"><a href="https://blog.verbum.org/wp-content/uploads/2025/10/ona-permissions.png"><img alt="" class="wp-image-1908" height="770" src="https://blog.verbum.org/wp-content/uploads/2025/10/ona-permissions.png?w=765" width="765" /></a></figure>   <div class="wp-block-jetpack-markdown"><p>Sorry but: no way I’m clicking OK on that button. I need a strong and clearlydelineated barrier between tooling/AI agents acting “as me”and <em>my</em> ability to approve and push codeor even do basic things like edit existing pull requests.</p><p>Github’s Copilot gets this more right because its bot runs asa distinct identity. I haven’t dug into what it’s authorizedto do. I may play with it more, but I also want to use agentsoutside of Github and I also am not a fan of deepening dependenceon a single proprietary forge either.</p><p>So I think a key thing agent frontends should help do hereis in granting fine-grained ephemeral credentials for dedicated write accessas an agent is working on a task. This “credential handling”should be a clearly distinct component. (This goes beyond justgit forges of course but also other issue trackers or datasources that may be in context).</p><h2>Conclusion</h2><p>There’s so much out there on this, I can barely keep trackwhile trying to do my real job. I’m sure I’m not alone &#8211;but I’m interested in other’s thoughts on this!</p></div></description><author>Colin Walters</author><dc:creator>Colin Walters</dc:creator><pubDate>Mon, 27 Oct 2025 21:08:31 GMT</pubDate><guid isPermaLink="true">https://blog.verbum.org/2025/10/27/thoughts-on-agentic-ai-coding-as-of-oct-2025/</guid></item><item><title>Christian Hergert: Status Week 43</title><link>https://blogs.gnome.org/chergert/2025/10/27/status-week-43/</link><description><p>Got a bit side-tracked with life stuff but lets try to get back to it this week.</p><h2>Libdex</h2><ul><li><p>D-Bus signal abstraction iteration from swick</p></li><li><p>Merge documentation improvements for libdex</p></li><li><p>I got an email from the Bazaar author about a crash they&#8217;re    seeing when loading textures into the GPU for this app-store.</p><p>Almost every crash I&#8217;ve seen from libdex has been from forgetting    to transfer ownership. I tried hard to make things ergonomic but    sometimes it happens.</p><p>I didn&#8217;t have any cycles to really donate so I just downloaded the    project and told my local agent to scan the project and look for    improper ownership transfer of DexFuture.</p><p>It found a few candidates which I looked at in detail over about    five minutes. Passed it along to the upstream developer and    that-was-that. Their fixu-ps seem to resolve the issue. Considering how bad agents are at using the proper ownership transfer its interesting it can also be used to discover them.</p></li><li><p>Add some more tests to the testsuite for future just to give myself    some more certainty over incoming issue reports.</p></li></ul><h2>Foundry</h2><ul><li><p>Added a new Gir parser as FoundryGir so that we can have access to    the reflected, but not compiled or loaded into memory, version of    Gir files. This will mean that we could have completion providers    or documentation sub-system able to provide documentation for the    code-base even if the documentation is not being generated.</p><p>It would also mean that we can perhaps get access to the markdown    specific documentation w/o HTML so that it may be loaded into the    completion accessory window using Pango markup instead of a    <code>WebKitWebView</code> shoved into a <code>GtkPopover</code>.</p><p>Not terribly different from what Builder used to do in the Python    plugin for code completion of GObject Introspection.</p></li><li><p>Expanding on the Gir parser to locate gir files in the build,    system, and installation prefix for the project. That allows trying    to discover the documentation for a keyword (type, identifier, etc),    which we can generate as something markdowny.        My prime motivation here is to have Shift+K working in Vim for real    documentation without having to jump to a browser, but it obviously    is beneficial in other areas like completion systems. This is    starting to work but needs more template improvements.</p></li><li><p>Make FoundryForgeListing be able to simplify the process of pulling    pages from the remote service in order. Automatically populates a    larger listmodel as individual pages are fetched.</p></li><li><p>Start on Gitlab forge implementation for querying issues.</p><p>Quickly ran into an issue where gitlab.gnome.org is not servicing    requests for the API due to Anubis. Bart thankfully updated things    to allow our API requests with <code>PRIVATE-TOKEN</code> to pass through.</p><p>Since validating API authorization tokens is one of the most    optimized things in web APIs, this is probably of little concern to    the blocking of AI scrapers.</p></li><li><p>Gitlab user, project, issues abstractions</p></li><li><p>Start loading GitlabProject after querying API system for the actual    project-id from the primary git remote path part.</p></li><li><p>Support finding current project</p></li><li><p>Support listing issues for current project</p></li><li><p>Storage of API keys in a generic fashion using libsecret. Forges    will take advantage of this to set a key for host/service pair.</p></li><li><p>Start on translate API for files in/out of SDKs/build environments.    Flatpak and Podman still need implementations.</p></li><li><p>PluginGitlabListing can now pre-fetch pages when the last item has    been queries from the list model. This will allow GtkListView to    keep populating in the background while you scroll.</p></li><li><p><code>mdoc</code> command helper to prototype discover of markdown docs for    use in interesting places. Also prototyped some markdown-&gt;ansi    conversion for nice man-like replacement in console.</p></li><li><p>Work on a new file search API for Foundry which matches a lot of    what Builder will need for its search panel. Grep as a service    basically with lots of GListModel and thread-pool trickery.</p></li><li><p>Add <code>foundry grep</code> which uses the <code>foundry_file_manager_search()</code>    API for testing. Use it to try to improve the non-UTF-8 support    you can run into when searching files/disks where that isn&#8217;t used.</p></li><li><p>Cleanup build system for plugins to make it obvious what is happening</p></li><li><p>Setup include/exclude globing for file searches (backed by grep)</p></li><li><p>Add abstraction for search providers in <code>FoundryFileSearchProvider</code>    with the default fallback implementation being GNU grep. This will    allow for future expansion into tooling like <code>rg</code> (ripgrep) which    provides some nice performance and tooling like <code>--json</code> output.        One of the more annoying parts of using grep is that it is so    different per-platform. For example, we really want <code>--null</code> from    GNU grep so that we get a <code>\0</code> between the file path and the content    as any other character could potentially fall within the possible    filename and/or encoding of files on disk.</p><p>Where as with ripgrep we can just get JSON and make each search    result point to the parsed <code>JsonNode</code> and inflate properties from    that as necessary.</p></li><li><p>Add a new IntentManager, IntentHandler, and Intent system so that    we can allow applications to handle policy differently with a plugin    model w/ priorities. This also allows for a single system to be able    to dispatch differently when opening directories vs files to edit.</p><p>This turned out quite nice and might be a candidate to have lower    in the platform for writing applications.</p></li><li><p>Add a FoundrySourceBuffer comment/uncomment API to make this easily    available to editors using Foundry. Maybe this belongs in GSV    someday.</p></li></ul><h2>Ptyxis</h2><ul><li><p>Fix shortcuts window issue where it could potentially be shown again    after being destroyed. Backport to 48/49.</p></li><li><p>Fix issue with background cursor blink causing transparency to break.</p></li></ul><h2>Builder</h2><ul><li><p>Various prototype work to allow further implementation of Foundry    APIs for the on-foundry rewrite. New directory listing, forge    issue list, intent handlers.</p></li></ul><h2>Other</h2><ul><li><p>Write up the situation with Libpeas and GObject Introspection for    GNOME/Fedora.</p></li></ul><h2>Research</h2><ul><li><p>Started looking into various JMAP protocols. I&#8217;d really like to get    myself off my current email configuration but it&#8217;s been around for    decades and that&#8217;s a hard transition.</p></li></ul></description><author>Christian Hergert</author><dc:creator>Christian Hergert</dc:creator><pubDate>Mon, 27 Oct 2025 20:40:26 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/chergert/2025/10/27/status-week-43/</guid></item><item><title>Sam Thursfield: Slow Fedora VMs</title><link>https://samthursfield.wordpress.com/2025/10/27/avoid-the-fedora-kernel-6-16-8-200-fc42-x86_64/</link><description><p>Good morning!</p>   <p>I spent some time figuring out why my build PC was running so slowly today. Thanks to some help from my very smart colleagues I came up with this testcase in Nushell to measure CPU performance:<br /><br /></p>   <pre class="wp-block-code"><code>~: dd if=/dev/random of=./test.in bs=(1024 * 1024) count=1010+0 records in10+0 records out10485760 bytes (10 MB, 10 MiB) copied, 0.0111184 s, 943 MB/s~: time bzip2 test.in0.55user 0.00system 0:00.55elapsed 99%CPU (0avgtext+0avgdata 8044maxresident)k112inputs+20576outputs (0major+1706minor)pagefaults 0swap</code></pre>   <p>We are copying 10MB of random data into a file and compressing it with bzip2. 0.55 seconds is a pretty good time to compress 10MB of data with bzip2.</p>   <p>But! As soon as I ran a virtual machine, this same test started to take 4 or 5 seconds, both on the host and in the virtual machine.</p>   <p>There is already a new Fedora kernel available and with that version (6.17.4-200.fc42.x86_64) I don&#8217;t see any problems. I guess some issue affecting AMD Ryzen virtualization that got fixed already.</p>   <p>Have a fun day!</p>   <p><em>edit: The problem came back with the new kernel</em> <em>as well. I guess this not going to be a fun day.</em></p></description><author>Sam Thursfield</author><dc:creator>Sam Thursfield</dc:creator><pubDate>Mon, 27 Oct 2025 11:00:17 GMT</pubDate><guid isPermaLink="true">https://samthursfield.wordpress.com/2025/10/27/avoid-the-fedora-kernel-6-16-8-200-fc42-x86_64/</guid></item><item><title>Cassidy James Blaede: I’ve Joined ROOST</title><link>https://cassidyjames.com/blog/ive-joined-roost-oss-community-open-online-safety/</link><description><img src="https://cassidyjames.com/images/blog/chick.jpg" />                                       <p>A couple of months ago I shared that I was <a href="https://cassidyjames.com/blog/heres-to-whats-next/">looking for what was next</a> for me, and I’m thrilled to report that I’ve found it: I’m joining <a href="https://roost.tools">ROOST</a> as OSS Community Manager!</p> <p><img alt="Baby chick being held in a hand" class="card" src="https://cassidyjames.com/images/blog/chick.jpg" /></p> <h3 id="what-is-roost">What is ROOST?</h3> <p>I’ll let <a href="https://roost.tools">our website</a> do most of the talking, but I can add some context based on my conversations with the rest of the incredible ROOSTers over the past few weeks. In a nutshell, ROOST is a relatively new nonprofit focused on building, distributing, and maintaining the open source building blocks for online trust and safety. It was founded by tech industry veterans who saw the need for truly open source tools in the space, and were sick of rebuilding the exact same internal tools across multiple orgs and teams.</p> <p>The way I like to frame it is how you wouldn’t roll your own encryption; why would you roll your own trust and safety tooling? It turns out that <em>currently</em> every platform, service, and community has to reinvent all of the hard work to ensure people are safe and harmful content doesn’t spread. ROOST is teaming up with industry partners to release existing trust and safety tooling as open source and to build the missing pieces together, in the open. The result is that teams will no longer have to start from scratch and take on all of the effort (and risk!) of rolling their own trust and safety tools; instead, they can reach for the open source projects from ROOST to integrate into their own products and systems. And we know open source is the right approach for critical tooling: the tools themselves must be transparent and auditable, while organizations can customize and even help improve this suite of online safety tools to benefit everyone.</p> <!--_Alternatively: back in the day every e-commerce website would manually implement payments, taking debit/credit card numbers and ensuring PCI compliance—which was a massive amount of work and prone to serious issues if they got it wrong. Then, this little startup called [Stripe](https://stripe.com) came along and made it stupidly simple to accept payments while massively improving the security and compliance story for developers—and now they're just _the way_ that 90% of sites accept payments. Now imagine if Stripe was actually open source, and it's similar to the idea of ROOST when it comes to trust and safety!_--> <p>This <a href="https://www.platformer.news/roost-open-source-trust-safety/">Platformer article</a> does a great job of digging into more detail; give it a read. :) Oh, and why the baby chick? ROOST has a habit of naming things after birds—and I’m a baby ROOSTer. :D</p> <h3 id="what-is-trust-and-safety">What is trust and safety?</h3> <p>I’ve used the term “trust and safety” a ton in this post; I’m no expert (I’m rapidly learning!), but think about protecting users from harm including unwanted sexual content, misinformation, violent/extremist content, etc. It’s a field that’s much larger in scope and scale than most people probably realize, and is becoming ever more important as it becomes easier to generate massive amounts of text and graphic content using LLMs and related generative “AI” technologies. Add in that those generative technologies are largely trained using opaque data sources that can themselves include harmful content, and you can imagine how we’re at a flash point for trust and safety; robust open online safety tools like those that ROOST is helping to build and maintain are needed more than ever.</p> <h3 id="what-ill-be-doing">What I’ll be doing</h3> <p>My role is officially “OSS Community Manager,” but “community manager” can mean ten different things to ten different people (which is why people in the role often don’t survive long at a company…). At ROOST, I feel like the team knows exactly what they need me to do—and importantly, they have a nice onramp and initial roadmap for me to take on! My work will mostly focus on building and supporting an active and sustainable contributor community around our tools, as well as helping improve the discourse and understanding of open source in the trust and safety world. It’s an exciting challenge to take on with an amazing team from ROOST as well as partner organizations.</p> <h3 id="my-work-with-gnome">My work with GNOME</h3> <p>I’ll continue to serve on the GNOME Foundation board of directors and contribute to both GNOME and Flathub as much as I can; there may be a bit of a transition time as I get settled into this role, but my open source contributions—both to trust and safety <em>and</em> the desktop Linux world—are super important to me. I’ll see you around!</p></description><author>Cassidy James Blaede</author><dc:creator>Cassidy James Blaede</dc:creator><pubDate>Mon, 27 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://cassidyjames.com/blog/ive-joined-roost-oss-community-open-online-safety/</guid></item><item><title>Aryan Kaushik: Balancing Work and Open Source</title><link>https://www.aryank.in/posts/2025-10-25-balancing-work-and-open-source/</link><description><h1>Work pressure + Burnout == Low contributions?</h1><p>Over the past few months, I’ve been struggling with a tough question. How do I balance my work commitments and personal life while still contributing to open source?</p><p>On the surface, it looks like a weird question. Like I really enjoy contributing and working with contributors, and when I was in college, I always thought... &quot;Why do people ever step back? It is so fun!&quot;. It was the thing that brought a smile to my face and took off any &quot;stress&quot;. But now that I have graduated, things have taken a turn.</p><p>It is now that when work pressure mounts, you use the little time you get to not focus on writing code and instead perform some kind of hobby, learn something new or spend time with family. Or, just endless video scroll and sleep.</p><p>This has led me to be on my lowest contributions streak and not able to work on all those cool things I imagined, like reworking the Pitivi timeline in Rust, finishing that one MR in GNOME Settings that is stuck for ages, or fixing some issues in GNOME Extensions website, or work on my own extension's feature request, or contributing to the committees I am a part of.</p><p>It’s reached a point where I’m genuinely unsure how to balance things anymore, and hence wanted to give all whom I might not have been able to reply to or have not seen me for a long time an update, that I'm there but just in a dilemma of how to return.</p><p>I believe I'm not the only one who faces this. After guiding my juniors for a long while on how to contribute and study at the same time and still manage time for other things, I now am at a road where I am in the same situation. So, if anyone has any insights on how they manage their time, or keep up the motivation and juggle between tasks, do let me know (akaushik [at] gnome [dot] org), I'd really appreciate any insights :)</p><p>One of them would probably be to take fewer things on my plate?</p><p>Perhaps this is just a new phase of learning? Not about code, but about balance.</p></description><author>Aryan Kaushik</author><dc:creator>Aryan Kaushik</dc:creator><pubDate>Sat, 25 Oct 2025 23:00:00 GMT</pubDate><guid isPermaLink="true">https://www.aryank.in/posts/2025-10-25-balancing-work-and-open-source/</guid></item><item><title>Christian Hergert: Libpeas and Introspection</title><link>https://blogs.gnome.org/chergert/2025/10/24/libpeas-and-introspection/</link><description><p>One of the unintended side-effects of writing applications using language bindings is that you inherit the dependencies of the binding.</p><p>This made things a bit complicated when <code>GIRepository</code> moved from <code>gobject-introspection-1.0</code> to <code>girepository-2.0</code> as we very much want language bindings to move to the new API.</p><p>Where this adds great difficulty on maintainers is in projects like <strong>Libpeas</strong> which provides plug-in capabilities for GTK application developers across multiple programming languages.</p><p>In practice this has allowed applications like Gedit, Rhythmbox, and GNOME Builder to be written in C but load plugins from languages such as Python, Lua, JavaScript, Rust, C, C++, Vala, or any other language capable of producing a <code>.so</code>/<code>.dylib</code>/<code>.dll</code>.</p><p>A very early version of Libpeas, years before I took over maintaining the library, had support for GObject Introspection baked in. This allowed really interesting (at the time) tooling to perform dynamic method call dispatching using a sort of proxy object implemented at runtime. Practically nobody is using this feature from what I can tell.</p><p>But maintaining ABI being what it is, the support for it has long been part of the <code>libpeas-1.x</code> ABI.</p><p>A couple years ago I finally released a fresh <code>libpeas-2.x</code> ABI which removed a lot of legacy API. With objects implementing <code>GListModel</code> and <code>PleasPluginInfo</code> becoming a <code>GObject</code>, the need for <code>libpeas-gtk</code> dwindled. It&#8217;s extremely easy for your application to do everything provided by the library. Additionally, I removed the unused GObject Introspection support which means that <code>libpeas-2.x</code> no longer needs to link against <code>gobject-introspection-1.0</code> (nor <code>girepository-2.0</code>).</p><p>One area where those are still used is the testsuite. This can complicate testing because we want to make sure that APIs work across language bindings but if the language binding uses a specific version of GObject Introspection that does not align with what the <code>libpeas</code> project is using for tests, it will of course lead to runtime disasters.</p><p>Such is the case with some language bindings. The Lua LGI project is scarcely maintained right now and still uses <code>gobject-introspection-1.0</code> instead of <code>girepository-2.0</code>. I submitted patches upstream to port it over, but without an official maintainer well versed in C and language bindings there isn&#8217;t anyone to review and say &#8220;yes merge this&#8221;.</p><blockquote><p>There is a fork now that includes some of the patches I submitted upstream, but the namespace is different so it isn&#8217;t a 1:1 replacement.</p></blockquote><p>The PyGObject project has moved to <code>girepository-2.0</code> upstream and that caused some breakage with applications in Fedora 42 that were still using the legacy <code>libpeas-1.x</code> ABI. For that reason, I believe the older PyGObject was released With Fedora 42.</p><p>If you are using <code>libpeas-2.x</code> in your application, you have nothing to fear with any of the language runtimes integrated with libpeas. Since libpeas doesn&#8217;t link against either introspection libraries, it can&#8217;t hurt you. Just make sure your dependencies and language bindings are all in sync and you should be fine.</p><p>If you are using <code>libpeas-1.x</code> still (2.x was released a little over 2 years ago) then you are in a much worse shape. Language bindings are moving (or have moved) to <code>girepository-2.0</code> while libpeas cannot realistically be ported and maintain ABI. Too much is exposed as part of the library itself.</p><p>It is imperative that if you want to keep your application working that you are either on <code>libpeas-2.x</code> or you&#8217;re bundling your application in such a way that you can guarantee your dependencies are all on the same version of GObject Introspection.</p><h3>Halfway ABI</h3><p>There exists a sort of &#8220;half-way-ABI&#8221; that someone could work on with enough motivation which is to break ABI as a sort of <code>libpeas-1.38</code>. It would move to <code>girepository-2.0</code> and all the ABI side-effects that come with it. Since the introspection support in <code>libpeas-1.x</code> is rarely used there should be little side-effects other than recompiling against the new ABI (and the build system transitions that go along with that).</p><p>In my experience maintaining the largest application using libpeas (being Builder), that is really a lot more effort than porting your applications to <code>libpeas-2.x</code>.</p><h3>Is my app effected?</h3><p>So in short, here are a few questions to ask yourself to know if you&#8217;re affected by this.</p><ul><li>Does my application only use embedded plug-ins or plug-ins from shared-modules such as <code>*.so</code>? If so, then you are all set!</li><li>Do I use libpeas-1.x? If no, then great!</li><li>Does my libpeas-1.x project use Python for plug-ins? If yes, port to libpeas-2.x (or alternatively work suggested halfway-ABI for libpeas).</li><li>Does my libpeas-1.x or libpeas-2.x project use Lua for plug-ins? If yes, make sure all your dependencies are using <code>gobject-introspection-1.0</code> only. Any use of <code>girepository-2.0</code> will end in doom.</li></ul><p>Since JavaScript support with <code>GJS/MozJS</code> was added in <code>libpeas-2.x</code>, if you&#8217;re using JavaScript plug-ins you&#8217;re already good. GJS recently transitioned to <code>girepository-2.0</code> already and continues to integrate well with libpeas. But do make sure your other dependencies have made the transition.</p><h3>How this could have been avoided?</h3><p>Without a time machine there are only three options besides what was done and they all create their own painful side-effects for the ecosystem.</p><ol><li>Never break ABI even if your library was a stop gap, never change dependencies, never let dependencies change dependencies, never fix anything.</li><li>When pulling GObject Introspection into the GLib project, rename all symbols to a new namespace so that both libraries may co-exist in process at the same time. Symbol multi-versioning can&#8217;t fix overlapping type name registration in GType.</li><li>Don&#8217;t fix any of the glaring issues or inconsistencies when pulling GObject Introspection into GLib. Make <code>gobject-introspection-1.0</code> map to the same thing that <code>girepository-2.0</code> does.</li></ol><p>All of those have serious side-effects that are equal to if not worse than the status-quo.</p><p>Those that want to &#8220;<em>do nothing</em>&#8221; as maintainers of their applications can really just keep shipping them on Flatpak but with the Runtime pinned to their golden age of choice.</p><p>Moral of the story is that ABI&#8217;s are hard even when you&#8217;re good at it. Doubly so if your library does anything non-trivial.</p></description><author>Christian Hergert</author><dc:creator>Christian Hergert</dc:creator><pubDate>Fri, 24 Oct 2025 23:14:43 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/chergert/2025/10/24/libpeas-and-introspection/</guid></item><item><title>Allan Day: GNOME Foundation Update, 2025-10-24</title><link>https://blogs.gnome.org/aday/2025/10/24/gnome-foundation-update-2025-10-24/</link><description><p>It&#8217;s Friday, so it&#8217;s time for a GNOME Foundation update, and there are some exciting items to share. As ever, these are just the highlights: there&#8217;s plenty more happening in the background that I&#8217;m not covering.</p><h2>Fundraising progress</h2><p>I&#8217;m pleased to be able to report that, in recent weeks, the number of donors in our <a class="external" href="https://donate.gnome.org/">Friends of GNOME program</a> has been increasing. These new regular donations are already adding up to a non-trivial rise in income for the Foundation, which is already making a significant difference to us as an organization.</p><p>I&#8217;d like to take this moment to thank every person who has signed up with a regular donation. You are all making a major difference to the GNOME Foundation and the future of the GNOME project. Thank you! We appreciate every single donation.</p><p>The new contributions we are receiving are vital, but we want to go further, and we are working on our plans for both fundraising and future investments in the GNOME project.</p><h2>New accountant</h2><p>This week we secured the services of a new accountant, <a class="external" href="https://www.parenthesesconsulting.com/">Dawn Matlak</a>. Dawn is extremely knowledgeable, and comes with a huge amount of relevant experience, particularly around fiscal hosting. She&#8217;s also great to work with, and we&#8217;re looking forward to collaborating with her.</p><p>Dawn is going to be doing a fair amount of work for us in the coming months. In addition to helping us to prepare for our upcoming audit, she is also going to be overhauling some of our finance systems, in order to reduce workloads, increase reliability, and speed up processing.</p><h2>GNOME.Asia</h2><p>In other news, <a class="external" href="https://events.gnome.org/event/303/">GNOME.Asia 2025</a> is happening in Tokyo on 13-15 December, and it&#8217;s approaching fast! Talk submissions have been reviewed and accepted, and the schedule is starting to come together. Information is being added to the website, and social activities are being planned. It&#8217;s shaping up to be a great event.</p><p>Registration for attendees isn&#8217;t open just yet, but it isn&#8217;t far off &#8211; look out for the announcement.</p><p>That&#8217;s it from me this week. I am on vacation next week, so I&#8217;ll be skipping next week&#8217;s post. See you in two weeks!</p></description><author>Allan Day</author><dc:creator>Allan Day</dc:creator><pubDate>Fri, 24 Oct 2025 18:26:46 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/aday/2025/10/24/gnome-foundation-update-2025-10-24/</guid></item><item><title>Flathub Blog: Enhanced License Compliance Tools for Flathub</title><link>https://docs.flathub.org/blog/enhanced-license-compliance-tools</link><description><p><em><strong>tl;dr:</strong></em> Flathub has improved tooling to make license compliance easier for developers. Distros should rebuild OS images with updated runtimes from Flathub; app developers should ensure they're using up-to-date runtimes and verify that licenses and copyright notices are properly included.</p><p>In early August, a concerned community member brought to our attention that copyright notices and license files were being omitted when software was bundled as Flatpaks and distributed via Flathub. This was a genuine oversight across multiple projects, and we're glad we've been able to take the opportunity to correct and improve this for runtimes and apps across the Flatpak ecosystem.</p><p>Over the past few months, we've been working to enhance our tooling and infrastructure to better support license compliance. With the support of the Flatpak, freedesktop-sdk, GNOME, and KDE teams, we've developed and deployed significant improvements that make it easier than ever for developers to ensure their applications properly include license and copyright notices.</p><h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="whats-new">What's New<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#whats-new" title="Direct link to What's New"></a></h2><p>In coordination with maintainers of the <a class="" href="https://gitlab.com/freedesktop-sdk/freedesktop-sdk/-/merge_requests/27806" rel="noopener noreferrer" target="_blank">freedesktop-sdk</a>, <a class="" href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/4056" rel="noopener noreferrer" target="_blank">GNOME</a>, and <a class="" href="https://invent.kde.org/packaging/flatpak-kde-runtime/-/merge_requests/264" rel="noopener noreferrer" target="_blank">KDE</a> runtimes, we've implemented enhanced license handling that automatically includes license and copyright notice files in the runtimes themselves, deduplicated to be as space-efficient as possible. This improvement has been applied to all supported freedesktop-sdk, GNOME, and KDE runtimes, plus backported to freedesktop-sdk 22.08 and newer, GNOME 45 and newer, KDE 5.15-22.08 and newer, and KDE 6.6 and newer. These updated runtimes cover over 90% of apps on Flathub and have already rolled out to users as regular Flatpak updates.</p><p>We've also worked with the Flatpak developers to add new functionality to <a class="" href="https://github.com/flatpak/flatpak-builder/pull/655" rel="noopener noreferrer" target="_blank">flatpak-builder 1.4.5</a> that automatically recognizes and includes common license files. This enhancement, now deployed to the Flathub build service, helps ensure apps' own licenses as well as the licenses of any bundled libraries are retained and shipped to users along with the app itself.</p><p>These improvements represent an important milestone in the maturity of the Flatpak ecosystem, making license compliance easier and more automatic for the entire community.</p><h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="recommended-actions">Recommended Actions<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#recommended-actions" title="Direct link to Recommended Actions"></a></h2><h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="app-developers">App Developers<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#app-developers" title="Direct link to App Developers"></a></h3><p>We encourage you to rebuild your apps with flatpak-builder 1.4.5 or newer to take advantage of the new automatic license detection. You can verify that license and copyright notices are properly included in your Flatpak's <code>/app/share/licenses</code>, both for your app and any included dependencies. In most cases, simply rebuilding your app will automatically include the necessary licenses, but you can also fine-tune which license files are included using the license-files key in your app's Flatpak manifest if needed.</p><p>For apps with binary sources (e.g. debs or rpms), we encourage app maintainers to explicitly include relevant license files in the Flatpak itself for consistency and auditability.</p><p><strong>End-of-life runtime transition:</strong> To focus our resources on maintaining high-quality, up-to-date runtimes, we'll be completing the removal of several end-of-life runtimes in January 2026. Apps using runtimes older than freedesktop-sdk 22.08, GNOME 45, KDE 5.15-22.08 or KDE 6.6 will be marked as EOL shortly. Once these older runtimes are removed, the apps will need to be updated to use a supported runtime to remain available on Flathub. While this won't affect existing app installations, after this date, new users will be unable to install these apps from Flathub until they're rebuilt against a current runtime. Flatpak manifests of any affected apps will remain on the Flathub GitHub organization to enable developers to update them at any time.</p><p>If your app currently targets an end-of-life runtime that did receive the backported license improvements, we still strongly encourage you to upgrade to a newer, supported runtime to benefit from ongoing security updates and platform improvements.</p><h3 class="anchor anchorTargetStickyNavbar_Vzrq" id="distributors">Distributors<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#distributors" title="Direct link to Distributors"></a></h3><p>If you redistribute binaries from Flathub, such as pre-installed runtimes or apps, you should rebuild your distributed images (ISOs, containers, etc.) with the updated runtimes and apps from Flathub. You can verify that appropriate licenses are included with the Flatpaks in the runtime filesystem at <code>/usr/share/licenses</code> inside each runtime.</p><h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="get-in-touch">Get in Touch<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#get-in-touch" title="Direct link to Get in Touch"></a></h2><p>App developers, distributors, and community members are encouraged to connect with the team and other members of the community in our <a class="" href="https://discourse.flathub.org/" rel="noopener noreferrer" target="_blank">Discourse forum</a> and <a class="" href="https://matrix.to/#/#flathub:matrix.org" rel="noopener noreferrer" target="_blank">Matrix chat room</a>. If you are an app developer or distributor and have any questions or concerns, you may also reach out to us at <a class="" href="mailto:admins@flathub.org" rel="noopener noreferrer" target="_blank">admins@flathub.org</a>.</p><h2 class="anchor anchorTargetStickyNavbar_Vzrq" id="thank-you">Thank You!<a class="hash-link" href="https://docs.flathub.org/blog/enhanced-license-compliance-tools#thank-you" title="Direct link to Thank You!"></a></h2><p>We are grateful to Jef Spaleta from Fedora for his care and confidentiality in bringing this to our attention and working with us collaboratively throughout the process. Special thanks to Boudhayan Bhattcharya (bbhtt) for his tireless work across Flathub, Flatpak and freedesktop-sdk, on this as well as many other important areas. And thank you to Abderrahim Kitouni (akitouni), Adrian Vovk (AdrianVovk), Aleix Pol Gonzalez (apol), Bart Piotrowski (barthalion), Ben Cooksley (bcooksley), Javier Jardón (jjardon), Jordan Petridis (alatiera), Matthias Clasen (matthiasc), Rob McQueen (ramcq), Sebastian Wick (swick), Timothée Ravier (travier), and any others behind the scenes for their hard work and timely collaboration across multiple projects to deliver these improvements.</p><p>Our Linux app ecosystem is truly strongest when individuals from across companies and projects come together to collaborate and work towards shared goals. We look forward to continuing to work together to ensure app developers can easily ship their apps to users across all Linux distributions and desktop environments. ♥</p></description><author>Flathub Blog</author><dc:creator>Flathub Blog</dc:creator><pubDate>Fri, 24 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://docs.flathub.org/blog/enhanced-license-compliance-tools</guid></item><item><title>This Week in GNOME: #222 Trip Notifications</title><link>https://thisweek.gnome.org/posts/2025/10/twig-222/</link><description><p>Update on what happened across the GNOME project in the week from October 17 to October 24.<!--more--></p><h2 id="gnome-circle-apps-and-libraries">GNOME Circle Apps and Libraries</h2><h3 id="railway">Railway <a href="https://gitlab.com/schmiddi-on-mobile/railway">↗</a></h3><p>Travel with all your train information in one place.</p><p><a href="https://thisweek.gnome.org/reporters/2d6bfa52eff97725a6197c0937e602046fe2a6569a3e73f54fe0124496ec618f">schmiddi</a> announces</p><blockquote><p>Railway version 2.9.0 was released. This release allows you to get notifications about the current status of the trip, including for example when you will need to transition to the next train, when a train is running late, or when a departure platform changes. It also fixes an error with DB not working anymore. We also updated to the GNOME 49 runtime.</p><p><img height="650" src="https://thisweek.gnome.org/_astro/railway.nAtXhnTX_24P7Ue.webp" width="1050" /></p><p><img height="106" src="https://thisweek.gnome.org/_astro/railway-notification.BoceOkSk_Z21GQn0.webp" width="532" /></p></blockquote><h2 id="third-party-projects">Third Party Projects</h2><p><a href="https://thisweek.gnome.org/reporters/eff749b25ef6105b7c8ab1bd6cb8cd0ca5fe07250842f605721d84939b539c29">ranfdev</a> reports</p><blockquote><p>A new release of DistroShelf has been published!As always, you can get it from <a href="https://flathub.org/en/apps/com.ranfdev.DistroShelf">flathub</a></p><ul><li>Added support for exporting binaries: You can just type the command and DistroShelf will resolve the binary path inside the container, then make it available on your host system.This is great if you have an immutable OS. You can install all your terminal utilities in a distrobox and export them from here</li><li>Save and restore main window size between sessions</li><li>Added keyboard shortcuts for common actions</li><li>Added qterminal and deepin terminal support</li><li>Fixed issues regarding distrobox creation, where some switches weren’t working</li><li>Many other small quality of life changes and bugfixes</li></ul><p><img height="1644" src="https://thisweek.gnome.org/_astro/DistroShelf.CPi36ncB_1hrUkS.webp" width="2014" /></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/992cf0ff8f56c50a96ef32d01f88efeb8fa8a9a6fd409a193bc341adcb6ec1f3">lo</a> announces</p><blockquote><p>I have released Nucleus version 2! This update brings translation support for the periodic table info, support for radioactivity, some info fixes for Vanadium, Cadmium and Promethium, as well as the ability to search elements by symbol. The app has also been updated to GNOME 49 and ported to the new shortcuts dialog so you can see the newly added search shortcut.</p><p>Get the app and see the full changelog on Flathub: <a href="https://flathub.org/en/apps/page.codeberg.lo_vely.Nucleus">https://flathub.org/en/apps/page.codeberg.lo_vely.Nucleus</a></p></blockquote><h3 id="crosswords">Crosswords <a href="https://gitlab.gnome.org/jrb/crosswords">↗</a></h3><p>A crossword puzzle game and creator.</p><p><a href="https://thisweek.gnome.org/reporters/23c83f6f7894b45274925cff086b988be7986f73caa4f793cae28b1efbfbc853">jrb</a> says</p><blockquote><p>GNOME Crosswords 0.3.16 was released! Read the details at the <a href="https://blogs.gnome.org/jrb/2025/10/23/crosswords-0-3-16-2025-internship-results/">release announcement</a>.</p><p>This version contains the culmination of the hard work our GSoC and Outreachy students have done over the summer. There are two notable end-user features in this release. First, the game now has printing support. This feature involved a major reworking of the rendering system and hundreds of changes across the code base, resulting in a high-quality printed puzzle.</p><p>In addition, the Editor now has a significantly improved word suggestion widget. This updated widget will only recommend words that fit with existing letters in an area.</p><p>You can get it at <a href="https://flathub.org/en/apps/org.gnome.Crosswords">flathub</a> (<a href="https://flathub.org/en/apps/org.gnome.Crosswords.Editor">editor</a>)</p><p></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-222/crosswords-printing.webm" type="video/webm" /></video></p></blockquote><h2 id="shell-extensions">Shell Extensions</h2><p><a href="https://thisweek.gnome.org/reporters/4768f0b15941925ebb1d9a771d351a380dbfa9efe132d23597e020c4653d0558">Ravener</a> reports</p><blockquote><p>Hey everyone!</p><p>I’ve just published my first GNOME Shell extension: 1440 <a href="https://extensions.gnome.org/extension/8696/1440/">https://extensions.gnome.org/extension/8696/1440/</a></p><p>This extension is inspired by the macOS app <a href="https://1440app.com/">https://1440app.com/</a>It shows an indicator in the panel, counting down the minutes until the day is over, by default, that’s until midnight, but you can change that time to suit your schedule.</p><p>The extension supports GNOME 45 to 49</p></blockquote><p><a href="https://thisweek.gnome.org/reporters/74a485bf0823b741b52074ba377aec7823544b7c05f9bea3966c7e88f50b883e">CodeMonkeyIsland</a> announces</p><blockquote><p>Hello EveryonePublished my first gnome extension: minimized-windows-buttons!Especially Microsoft Windows users get confused in gnome, when they minimzie a window, and it just “disappears”. To help those poor souls a bit, here is an extension to make them feel less lost. It creates a Button on the bottom of the main screen for each minimized window and “maximizes” it again on click.</p><p>link: <a href="https://extensions.gnome.org/extension/8657/minimized-windows-buttons/">https://extensions.gnome.org/extension/8657/minimized-windows-buttons/</a></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/d961c1282cd0f3c3f36f83f19c1617e23d4f841771bcb7b8d0517bf6fc90368c">pendagtp</a> announces</p><blockquote><p>Hi everyone!</p><p>I’ve create a GNOME Shell extension: <strong>Hide dash in Overview</strong>This is a lightweight extension with no configuration needed - just enable or disable it.As the name suggests, it does only one thing: it hides the Dash (also often called the Deck in the Overview.</p><p>This extension supports versions starting <strong>v45</strong></p><p>I originally made this for myself, but I hope it will be useful to others as well</p><p>Other similar extensions and why I made mine:</p><ul><li><a href="https://extensions.gnome.org/extension/6195/hide-the-dock-in-overview/">Hide-dock-in-overview</a> - Archived</li><li><a href="https://extensions.gnome.org/extension/79/hide-dash/">Hide Dash</a> - Only works with v3.x</li><li><a href="https://extensions.gnome.org/extension/307/dash-to-dock/">Dash to Dock</a> - Great, but to many features and need customization, idk if it’s possible but I suppose</li></ul><p>Link: <a href="https://extensions.gnome.org/extension/8693/hide-dash-in-overview/">hide-dash-in-overview</a></p><p><img height="1198" src="https://thisweek.gnome.org/_astro/demo.BO-sxHEr_144efx.webp" width="3166" /></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/1db91d8f334f57b451851b2a78801e012beab6af2565c9eeefbdb6c3da11ce6c">Filip Rund</a> announces</p><blockquote><p>Hi everyone!I’m super excited to have my first GNOME Extension published. I called it <strong>In Picture</strong>, because it moves and resizes Picture-in-Picture windows according to preferences, optionally keeping them always on top. I initially made it for myself, because PiP windows kept spawning in the middle of the screen and not “always above” (average Wayland experience 😁). And since it works, I figured why not share it with others?You can check it out <a href="https://extensions.gnome.org/extension/8692/in-picture/">here</a>.</p></blockquote><p><a href="https://thisweek.gnome.org/reporters/9480bc4138a2bb99fb9f1d496fee26544befe78f8f8bc1fa1efb2e8832e5445b">V</a> says</p><blockquote><p>Hi everyone! 👋</p><p>I just released <strong>Ordo</strong>, a GNOME 48 Shell extension that moves the window control buttons (minimize, maximize, close) from each window’s titlebar to a single location on the top panel. It keeps the buttons minimal, always at the top-right, and works well with tiling extensions like <strong>Forge</strong>.</p><p>You can find it on GNOME Extensions here: <a href="https://extensions.gnome.org/extension/8686/ordo/">https://extensions.gnome.org/extension/8686/ordo/</a></p><p><img height="163" src="https://thisweek.gnome.org/_astro/Ordo@Vibudh_screenshot.DM_KvQwi_ZpB2b0.webp" width="420" /></p></blockquote><h2 id="gnome-foundation">GNOME Foundation</h2><p><a href="https://thisweek.gnome.org/reporters/c3370cae2e550d4d7f879eecbe1ccbad891c52b77cb2b7cab17d9d30f31088bb">Allan Day</a> says</p><blockquote><p>Another <a href="https://blogs.gnome.org/aday/2025/10/24/gnome-foundation-update-2025-10-24/">GNOME Foundation update</a> is available this week, with news items from the last week. These include an increase in donations, a new accountant, and GNOME.Asia 2025 preparations.</p></blockquote><h2 id="thats-all-for-this-week">That’s all for this week!</h2><p>See you next week, and be sure to stop by <a href="https://matrix.to/#/#thisweek:gnome.org">#thisweek:gnome.org</a> with updates on your own projects!</p></description><author>This Week in GNOME</author><dc:creator>This Week in GNOME</dc:creator><pubDate>Fri, 24 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://thisweek.gnome.org/posts/2025/10/twig-222/</guid></item><item><title>Matthias Clasen: SVG in GTK</title><link>https://blogs.gnome.org/gtk/2025/10/23/svg-in-gtk/</link><description><p>GTK has been using SVG for symbolic icons since essentially forever. It hasn&#8217;t been a perfect relationship, though.</p><h3>Pre-History</h3><p>For the longest time (all through the GTK 3 era, and until recently), we&#8217;ve used librsvg indirectly, through gdk-pixbuf, to obtain rendered icons, and then we used some pixel tricks to recolor the resulting image according to the theme.</p><p><a href="https://blogs.gnome.org/gtk/files/2025/10/Screenshot-From-2025-10-22-21-20-23.png"><img alt="Symbolic icon, with success color" class="aligncenter wp-image-10577 size-medium" height="283" src="https://blogs.gnome.org/gtk/files/2025/10/Screenshot-From-2025-10-22-21-20-23-300x283.png" width="300" /></a></p><p>This works, but it gives up on the defining feature of SVG: <em>its scalability.</em></p><p>Once you&#8217;ve rasterized your icon at a given size, all you&#8217;re left with is pixels. In the GTK 3 era, this wasn&#8217;t a problem, but in GTK 4, we have a scene graph and fractional scaling, so we could do *much* better if we don&#8217;t rasterize early.</p><p><a href="https://blogs.gnome.org/gtk/files/2025/10/Screenshot-From-2025-10-22-21-22-58.png"><img alt="Symbolic icon, pixellated" class="aligncenter wp-image-10578 size-medium" height="300" src="https://blogs.gnome.org/gtk/files/2025/10/Screenshot-From-2025-10-22-21-22-58-295x300.png" width="295" /></a></p><p>Unfortunately, librsvg&#8217;s API isn&#8217;t set up to let us easily translate SVG into our own render nodes. And its rust nature makes for an inconvenient dependency, so we held off on depending on it for a long time.</p><h3>History</h3><p>Early this year, I grew tired of this situation, and decided to improve our story for icons, and symbolic ones in particular.</p><p>So I set out to see how hard it would be to parse the very limited subset of SVG used in symbolic icons myself. It turned out to be <em>relatively</em> <em>easy</em>. I quickly managed to parse 99% of the Adwaita symbolic icons, so I decided to merge this work for GTK 4.20.</p><p>There were some detours and complications along the way. Since my simple parser couldn&#8217;t handle 100% of Adwaita (let alone all of the SVGs out there), a fallback to a proper SVG parser was needed. So we added a librsvg dependency after all. Since our new Android backend has an even more difficult time with rust than our other backends, we needed to arrange for a non-rust librsvg branch to be used when necessary.</p><p>One thing that this hand-rolled SVG parser improved upon is that it allows stroking, in addition to filling. I documented the format for symbolic icons <a class="external" href="https://gitlab.gnome.org/GNOME/gtk/-/blob/gtk-4-20/docs/symbolic-icons.md?ref_type=heads">here</a>.</p><h3>Starting over</h3><p>A bit later, I was inspired by Apple&#8217;s <a class="external" href="https://developer.apple.com/videos/play/wwdc2025/337/"><em>SF Symbols</em></a> work to look into how hard it would be to extend my SVG parser with a few custom attributes to enable dynamic strokes.</p><p>It turned out to be <em>easy</em> <em>again</em>. With a <a class="external" href="https://docs.gtk.org/gtk4/icon-format.html">handful of attributes</a>, I could create plausible-looking animations and transitions. And it was <a class="external" href="https://gitlab.gnome.org/GNOME/gtk/-/issues/7655">fun</a> to play with. When I showed this work to Jakub and Lapo at GUADEC, they were intrigued, so I decided to keep pushing this forward, and it landed in early GTK 4.21, as <a class="external" href="https://gitlab.gnome.org/GNOME/gtk/-/merge_requests/8892">GtkPathPaintable</a>.</p><div class="wp-video" style="width: 542px;"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]--><video class="wp-video-shortcode" controls="controls" height="478" id="video-10576-1" preload="metadata" width="542"><source src="https://blogs.gnome.org/gtk/files/2025/10/path-anim5.webm?_=1" type="video/webm" /><a href="https://blogs.gnome.org/gtk/files/2025/10/path-anim5.webm">https://blogs.gnome.org/gtk/files/2025/10/path-anim5.webm</a></video></div><p>To make experimenting with this easier, I made a quick editor.  It was invaluable to have Jakub as an early adopter play with the editor while I was improving the implementation. Some very good ideas came out of this rapid feedback cycle, for example dynamic stroke width.</p><p>You can get some impression of the new stroke-based icons Jakub has been working on <a class="external" href="https://teams.pages.gitlab.gnome.org/Design/icon-development-kit/index.html">here</a>.</p><h3>Recent happenings</h3><p>As summer was turning to fall, I felt that I should attempt to support SVG more completely, including grouping and animations. GTK&#8217;s rendering infrastructure has most of the pieces that are required for SVG after all: transforms, filters, clips, paths, gradients are all supported.</p><p>This was *not* easy.</p><p>But eventually, things started to fall into place. And this week, I&#8217;ve replaced  GtkPathPaintable with <a class="external" href="https://docs.gtk.org/gtk4/class.Svg.html">GtkSvg</a>, which is a GdkPaintable that supports SVG. At least, the subset of SVG that is most relevant for icons. And that includes animations.</p><div class="wp-video" style="width: 720px;"><video class="wp-video-shortcode" controls="controls" height="618" id="video-10576-2" preload="metadata" width="720"><source src="https://blogs.gnome.org/gtk/files/2025/10/Screencast-From-2025-10-22-18-13-02.webm?_=2" type="video/webm" /><a href="https://blogs.gnome.org/gtk/files/2025/10/Screencast-From-2025-10-22-18-13-02.webm">https://blogs.gnome.org/gtk/files/2025/10/Screencast-From-2025-10-22-18-13-02.webm</a></video></div><p>&nbsp;</p><p>This is still a subset of full SVG, but converting a few random lottie files to SVG animations gave me a decent success rate for getting things to display mostly ok.</p><p>The details are spelled out <a class="external" href="https://docs.gtk.org/gtk4/class.Svg.html#the-supported-subset-of-svg">here</a>.</p><h3>Summary</h3><p>GTK 4.22 will natively support SVG, including SVG animations.</p><p>If you&#8217;d like to help improve this further, here are some some <a class="external" href="https://gitlab.gnome.org/GNOME/gtk/-/issues/7834">suggestions.</a></p><p>If you would like to support the GNOME foundation, who&#8217;s infrastructure and hosting GTK relies on, please <a class="external" href="https://donate.gnome.org/">donate</a>.</p><p><img alt="❤" class="wp-smiley" src="https://s.w.org/images/core/emoji/16.0.1/72x72/2764.png" style="height: 1em;" /></p></description><author>Matthias Clasen</author><dc:creator>Matthias Clasen</dc:creator><pubDate>Thu, 23 Oct 2025 10:34:17 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/gtk/2025/10/23/svg-in-gtk/</guid></item><item><title>Jonathan Blandford: Crosswords 0.3.16: 2025 Internship Results</title><link>https://blogs.gnome.org/jrb/2025/10/23/crosswords-0-3-16-2025-internship-results/</link><description><p>Time for another GNOME Crosswords release! This one highlights the features our interns did this past summer. We had three fabulous interns — two through GSoC and one through Outreachy. While this release really only has three big features — one from each — they were all fantastic.</p><p>Thanks goes to to my fellow GSoC mentors Federico and Tanmay. In addition, Tilda and the folks at Outreachy were extremely helpful. Mentorship is a lot of work, but it&#8217;s also super-rewarding. If you&#8217;re interested in participating as a mentor in the future and have any questions about the process, let me know. I&#8217;ll be happy to speak with you about them.</p><h2>Dictionary pipeline improvements</h2><p>First, our Outreachy intern Nancy spent the summer improving the build pipeline to generate the internal dictionaries we use. These dictionaries are used to provide autofill capabilities and add definitions to the Editor, as well as providing near-instant completions for both the Editor and Player. The old pipeline was buggy and hard to maintain. Once we had a cleaned it up, Nancy was able to use it to effortlessly produce a dictionary in her native tongue: Swahili.</p><figure class="wp-caption aligncenter" id="attachment_7637" style="width: 300px;"><a href="https://blogs.gnome.org/jrb/files/2025/10/swahili.png"><img alt="" class="size-medium wp-image-7637" height="300" src="https://blogs.gnome.org/jrb/files/2025/10/swahili-300x300.png" width="300" /></a><figcaption class="wp-caption-text" id="caption-attachment-7637">A Grid in swahili</figcaption></figure><p>We have no distribution story yet, but it&#8217;s exciting to have it so much easier to create dictionaries in other languages. It opens the door to the Editor being more universally useful (and fulfills a core GNOME tenet).</p><p>You can read about it more details in <a class="external" href="https://nancyenos.github.io/nancy.github.io/2025/09/15/swahili-dictionary.html">Nancy&#8217;s final report</a>.</p><h2>Word List</h2><p><a class="external" href="https://victorma.ca/">Victor</a> did a ton of research for Crosswords, almost acting like a Product Manager. He installed every crossword editor he could find and did <a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/wikis/survey-editors">a competitive analysis</a>, noting possible areas for improvement. One of the areas he flagged was the word list in our editor. This list suggests words that could be used in a given spot in the grid. We started with a simplistic implementation that listed every possible word in our dictionary that could fit. This approach— while fast — provided a lot of dead words that would make the grid unsolvable. So he set about trying to narrow down that list.</p><figure class="wp-caption aligncenter" id="attachment_7639" style="width: 300px;"><a href="https://blogs.gnome.org/jrb/files/2025/10/Screenshot-From-2025-10-21-23-33-32.png"><img alt="" class="size-medium wp-image-7639" height="233" src="https://blogs.gnome.org/jrb/files/2025/10/Screenshot-From-2025-10-21-23-33-32-300x233.png" width="300" /></a><figcaption class="wp-caption-text" id="caption-attachment-7639">New Word List showing possible options</figcaption></figure><p>It turns out that there&#8217;s a lot of tradeoffs to be made here (<a class="external" href="https://victorma.ca/posts/gsoc-6/">Victor&#8217;s post</a>). It&#8217;s possible to find a really good set of words, at the cost of a lot of computational power. A much simpler list is quick but has dead words. In the end, we found a happy medium that let us get results fast and had a stable list across a clue. He&#8217;ll be blogging about this shortly.</p><p>Victor also cleaned up our <a class="external" href="https://jrb.pages.gitlab.gnome.org/crosswords/devel-docs/index.html">development docs</a>, and researched satsolve algorithms for the grid. He&#8217;s working on a <a class="external" href="https://pad.gnome.org/s/vNYCDoL5S#">lovely doc</a> on the AC-3 algorithm, and we can use it to add additional functionality to the editor in the future.</p><h2>Printing</h2><p>Toluwaleke implemented printing support for GNOME Crosswords.</p><p>This was a tour de force, and a phenomenal addition to the Crosswords codebase. When I proposed it for a GSoC project, I had no idea how much work this project could involve. We already had code to produce an svg of the grid — I thought that we could just quickly add support for the clues and call it a day. Instead, we ended up going on a wild ride resulting in a significantly stronger feature and code base than we had going in.</p><p>His blog has more detail and it&#8217;s really quite cool (<a href="https://blogs.gnome.org/anonymoux47/2025/10/22/gsoc-final-report-printing-in-gnome-crosswords/">go read it!</a>). But from my perspective, we ended up with a flexible and fast rendering system that can be used in a lot more places. Take a look:</p><div class="wp-video" style="width: 840px;"><!--[if lt IE 9]><script>document.createElement('video');</script><![endif]--><video class="wp-video-shortcode" controls="controls" height="457" id="video-7636-1" preload="metadata" width="840"><source src="https://blogs.gnome.org/jrb/files/2025/10/output_video.webm?_=1" type="video/webm" /><a href="https://blogs.gnome.org/jrb/files/2025/10/output_video.webm">https://blogs.gnome.org/jrb/files/2025/10/output_video.webm</a></video></div><p>The resulting PDFs are really high quality — they seem to look better than some of the newspaper puzzles I&#8217;ve seen. We&#8217;ll keep tweaking them as there are still a lot of improvements we&#8217;d like to add, such as taking the High Contrast / Large Text A11Y options into account. But it&#8217;s a tremendous basis for future work.</p><h2>Increased Polish</h2><p>There were a few other small things that happened</p><ul><li>I hooked Crosswords up to <a class="external" href="https://l10n.gnome.org/module/Crosswords/">Damned Lies</a>. This led to an increase in our translation quality and count</li><li>This included a Polish translation, which came with a new <a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/issues/274">downloader!</a></li><li>I ported all the dialogs to AdwDialog, and moved on from (most) of the deprecated Gtk4 widgets</li><li>A lot of code cleanups and small fixes</li></ul><p>Now that these big changes have landed, it&#8217;s time to go back to working on the rest of the changes proposed for GNOME Circle.</p><p>Until next time, happy puzzling!</p></description><author>Jonathan Blandford</author><dc:creator>Jonathan Blandford</dc:creator><pubDate>Thu, 23 Oct 2025 06:00:48 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/jrb/2025/10/23/crosswords-0-3-16-2025-internship-results/</guid></item><item><title>Toluwaleke Ogundipe: GSoC Final Report: Printing in GNOME Crosswords</title><link>https://blogs.gnome.org/anonymoux47/2025/10/22/gsoc-final-report-printing-in-gnome-crosswords/</link><description><p>A few months ago, I <a href="https://blogs.gnome.org/anonymoux47/2025/06/14/hello-gnome-and-gsoc">introduced my GSoC project</a>: <em>Adding Printing Support to </em><a class="external" href="https://gitlab.gnome.org/jrb/crosswords"><em>GNOME Crosswords</em></a>. Since June, I’ve been working hard on it, and I’m happy to share that printing puzzles is finally possible!</p>   <h2 class="wp-block-heading">The Result</h2>   <p>GNOME Crosswords now includes a <strong>Print</strong> option in its menu, which opens the system’s print dialog. After adjusting printer settings and page setup, the user is shown a <strong>preview dialog</strong> with a few crossword-specific options, such as ink-saving mode and whether (and how) to include the solution. The options are intentionally minimal, keeping the focus on a clean and straightforward printing experience.</p>   <p>Below is a short clip showing the feature in action:</p>   <figure class="wp-block-video aligncenter"><video controls="controls" src="https://blogs.gnome.org/anonymoux47/files/2025/10/print_demo.webm"></video></figure>   <p></p>   <p>The resulting file: <strong><a href="https://blogs.gnome.org/anonymoux47/files/2025/10/output.pdf" rel="noreferrer noopener" target="_blank">output.pdf</a></strong></p>   <div class="wp-block-file"></div>   <p>Crosswords now also ships with a standalone command-line tool, <code><strong>ipuz2pdf</strong></code>, which converts any IPUZ puzzle file into a print-ready PDF. It offers a similarly minimal set of layout and crossword-specific options.</p>   <h2 class="wp-block-heading">The Process</h2>   <ul class="wp-block-list"><li>Studied and profiled the existing code and came up with an overall approach for the project.</li>   <li>Built a new <strong>grid rendering framework</strong>, resulting in a <strong>10× speedup</strong> in rendering. Dealt with a ton of details around text placement and rendering, colouring, shapes, and more.</li>   <li>Designed and implemented a <strong>print layout engine with a templating system</strong>, adjusted to work with different puzzle kinds, grid sizes, and paper sizes.</li>   <li>Integrated the layout engine with the <strong>print dialog</strong> and added a <strong>live print preview</strong>.</li>   <li><strong>Bonus:</strong> Created <strong><code>ipuz2pdf</code></strong>, a standalone command-line utility (originally for testing) that converts an IPUZ file into a printable PDF.</li></ul>   <h2 class="wp-block-heading">The Challenges</h2>   <p>Working on a feature of this scale came with plenty of challenges. Getting familiar with a large codebase took patience, and understanding how everything fit together often meant careful study and experimentation. Balancing ideas with the project timeline and navigating code reviews pushed me to grow both technically and collaboratively.</p>   <p>On the technical side, rendering and layout had their own hurdles. Handling text metrics, scaling, and coordinate transformations required a mix of technical knowledge, critical thinking, and experimentation. Even small visual glitches could lead to hours of debugging. One notably difficult part was implementing the box layout system that powers the dynamic print layout engine.</p>   <h2 class="wp-block-heading">The Lessons</h2>   <p>This project taught me a lot about patience, focus, and iteration. I learned to approach large problems by breaking them into small, testable pieces, and to value clarity and simplicity in both code and design. Code reviews taught me to communicate ideas better, accept feedback gracefully, and appreciate different perspectives on problem-solving.</p>   <p>On the technical side, working with rendering and layout systems deepened my understanding of graphics programming. I also learned how small design choices can ripple through an entire codebase, and how careful abstraction and modularity can make complex systems easier to evolve.</p>   <p>Above all, I learned the value of collaboration, and that progress in open source often comes from many small, consistent improvements rather than big leaps.</p>   <h2 class="wp-block-heading">The Conclusion</h2>   <p>In the end, I achieved all the goals set out for the project, and even more. It was a long and taxing journey, but absolutely worth it.</p>   <h2 class="wp-block-heading">The Gratitude</h2>   <p>I’m deeply grateful to my mentors, <a class="external" href="https://gitlab.gnome.org/jrb">Jonathan Blandford</a> and <a class="external" href="https://gitlab.gnome.org/federico">Federico Mena Quintero</a>, for their guidance, patience, and support throughout this project. I’ve learned so much from working with them. I’m also grateful to the GNOME community and Google Summer of Code for making this opportunity possible and for creating such a welcoming environment for new contributors.</p>   <h2 class="wp-block-heading">What Comes After</h2>   <p>No project is ever truly finished, and this one is no exception. There’s still plenty to be done, and some already have <a class="external" href="https://gitlab.gnome.org/jrb/crosswords/-/issues?sort=created_date&amp;state=opened&amp;label_name%5B%5D=Printing&amp;first_page_size=20">tracking issues</a>. I plan to keep improving the printing system and related features in GNOME Crosswords.</p>   <p>I also hope to stay involved in the GNOME ecosystem and open-source development in general. I’m especially interested in projects that combine design, performance, and system-level programming. More importantly, I’m a recent CS graduate <strong>looking for a full-time role</strong> in the field of interest stated earlier. If you have or know of any opportunities, please reach out at <a href="mailto:feyidab01@gmail.com">feyidab01@gmail.com</a>.</p>   <p>Finally, I plan to write a couple of follow-up posts diving into interesting parts of the process in more detail. Stay tuned!</p>   <h2 class="wp-block-heading"><strong>Thank you!</strong></h2></description><author>Toluwaleke Ogundipe</author><dc:creator>Toluwaleke Ogundipe</dc:creator><pubDate>Wed, 22 Oct 2025 22:50:41 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/anonymoux47/2025/10/22/gsoc-final-report-printing-in-gnome-crosswords/</guid></item><item><title>Jussi Pakkanen: CapyPDF 1.8.0 released</title><link>https://nibblestew.blogspot.com/2025/10/capypdf-180-released.html</link><description><p>I have just released CapyPDF 1.8. It's mostly minor fixes and tweaks but there are two notable things. The first one is that CapyPDF now supports variable axis fonts. The other one is that CapyPDF will now produce PDF version 2.0 files instead of 1.7 by default. This might seem like a big leap but really isn't. PDF 2.0 is pretty much the same as 1.7, just with documentation updates and deprecating (but not removing) a bunch of things. People using PDF have a tendency to be quite conservative in their versions, but PDF 2.0 has been out since 2017 with most of it being PDF 1.7 from 2008.</p><p>It is still possible to create version with older PDF specs. If you specify, say, PDF/X3, CapyPDF will output PDF 1.3 as the spec requires that version and no other even though, for example, Adobe's PDF tools accept PDF/X3 whose version later than 1.3.</p><p>The PDF specification is currently undergoing major changes and future versions are expected to have backwards incompatible features such as HDR imaging. But 2.0 does not have those yet.</p><h1 style="text-align: left;">Things CapyPDF supports</h1><p>CapyPDF has implemented a fair chunk of the various PDF specs:</p><p></p><ul style="text-align: left;"><li>All paint and text operations</li><li>Color management</li><li>Optional content groups</li><li>PDF/X and PDF/A support</li><li>Tagged PDF (i.e. document structure and semantic information)</li><li>TTF, OTF, TTC and CFF fonts</li><li>Forms (preliminary)</li><li>Annotations</li><li>File attachments</li><li>Outlines</li><li>Page naming</li></ul>In theory this should be enough to support things like <a href="https://de.wikipedia.org/wiki/XRechnung">XRechnung</a>&nbsp;and documents with full accessibility information as per <a href="https://en.wikipedia.org/wiki/PDF/UA">PDF/UA</a>. These have not been actually tested as I don't have personal experience in German electronic invoicing or document accessibility.<p></p></description><author>Jussi Pakkanen</author><dc:creator>Jussi Pakkanen</dc:creator><pubDate>Tue, 21 Oct 2025 22:27:00 GMT</pubDate><guid isPermaLink="true">https://nibblestew.blogspot.com/2025/10/capypdf-180-released.html</guid></item><item><title>Dorothy Kabarozi: Laravel Mix “Unable to Locate Mix File” Error: Causes and Fixes</title><link>https://dorothykabarozi.wordpress.com/2025/10/21/laravel-mix-unable-to-locate-mix-file-error-causes-and-fixes/</link><description><hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading"><strong>Laravel Mix “Unable to Locate Mix File” Error: Causes and Fixes</strong></h2>   <p>If you’re working with <strong>Laravel</strong> and using <strong>Laravel Mix</strong> to manage your CSS and JavaScript assets, you may have come across an error like this:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">Spatie\LaravelIgnition\Exceptions\ViewException  Message: Unable to locate Mix file: /assets/vendor/css/rtl/core.css </pre></div>  <p>Or in some cases:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">Illuminate\Foundation\MixFileNotFoundExceptionUnable to locate Mix file: /assets/vendor/fonts/boxicons.css </pre></div>  <p>This error can be frustrating, especially when your project works perfectly on one machine but fails on another. Let’s break down what’s happening and how to solve it.</p>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h3 class="wp-block-heading"><strong>What Causes This Error?</strong></h3>   <p>Laravel Mix is a wrapper around <strong>Webpack</strong>, designed to compile your <code>resources/</code> assets (CSS, JS, images) into the <code>public/</code> directory. The <code>mix()</code> helper in Blade templates references these compiled assets using a special file: <code>mix-manifest.json</code>.</p>   <p>This error occurs when <strong>Laravel cannot find the compiled asset</strong>. Common reasons include:</p>   <ol class="wp-block-list"><li><strong>Assets are not compiled yet</strong><br />If you’ve just cloned a project, the <code>public/assets</code> folder might be empty. Laravel is looking for files that do not exist yet.</li>   <li><strong><code>mix-manifest.json</code> is missing or outdated</strong><br />This file maps original asset paths to compiled paths. If it’s missing, Laravel Mix won’t know where to find your assets.</li>   <li><strong>Incorrect paths in Blade templates</strong><br />If your code is like: <code>&lt;link rel="stylesheet" href="{{ asset(mix('assets/vendor/css/rtl/core.css')) }}" /&gt;</code> but the RTL folder or the file doesn’t exist, Mix will throw an exception.</li>   <li><strong>Wrong configuration</strong><br />Some themes use variables like <code>$configData['rtlSupport']</code> to toggle right-to-left CSS. If it’s set incorrectly, Laravel will try to load files that don’t exist.</li></ol>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h3 class="wp-block-heading"><strong>How to Fix It</strong></h3>   <p>Here’s a step-by-step solution:</p>   <h4 class="wp-block-heading"><strong>1. Install NPM dependencies</strong></h4>   <p>Make sure you have Node.js installed, then run:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">npm install </pre></div>  <h4 class="wp-block-heading"><strong>2. Compile your assets</strong></h4>   <ul class="wp-block-list"><li><strong>Development mode (fast, unminified):</strong></li></ul>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">npm run dev </pre></div>  <ul class="wp-block-list"><li><strong>Production mode (optimized, minified):</strong></li></ul>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">npm run build </pre></div>  <p>This will generate your CSS and JS files in the <code>public</code> folder and update <code>mix-manifest.json</code>.</p>   <h4 class="wp-block-heading"><strong>3. Check <code>mix-manifest.json</code></strong></h4>   <p>Ensure the manifest contains the file Laravel is looking for:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">"/assets/vendor/css/rtl/core.css": "/assets/vendor/css/rtl/core.css" </pre></div>  <h4 class="wp-block-heading"><strong>4. Adjust Blade template paths</strong></h4>   <p>If you don’t use RTL, you can set:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">$configData&#91;'rtlSupport'] = ''; </pre></div>  <p>so the code doesn’t try to load <code>/rtl/core.css</code> unnecessarily.</p>   <h4 class="wp-block-heading"><strong>5. Clear caches</strong></h4>   <p>Laravel may cache old views and configs. Clear them:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">php artisan view:clearphp artisan config:clearphp artisan cache:clear </pre></div>  <hr class="wp-block-separator has-alpha-channel-opacity" />   <h3 class="wp-block-heading"><strong>Pro Tips</strong></h3>   <ul class="wp-block-list"><li>Always check if the file exists in <code>public/assets/...</code> after compiling.</li>   <li>If you move your project to another machine or server, you must run <code>npm install</code> and <code>npm run dev</code> again.</li>   <li>For production, make sure your server has <strong>Node.js and NPM installed</strong>, otherwise Laravel Mix cannot build the assets.</li></ul>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h3 class="wp-block-heading"><strong>Conclusion</strong></h3>   <p>The “Unable to locate Mix file” error is <strong>not a bug in Laravel</strong>, but a result of missing compiled assets or misconfigured paths. Once you:</p>   <ol class="wp-block-list"><li>Install dependencies.</li>   <li>Compile assets,</li>   <li>Correct Blade paths, and</li>   <li>Clear caches; your Laravel project should load CSS and JS files without issues.</li></ol>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <p></p>   <p></p></description><author>Dorothy Kabarozi</author><dc:creator>Dorothy Kabarozi</dc:creator><pubDate>Tue, 21 Oct 2025 16:40:58 GMT</pubDate><guid isPermaLink="true">https://dorothykabarozi.wordpress.com/2025/10/21/laravel-mix-unable-to-locate-mix-file-error-causes-and-fixes/</guid></item><item><title>Daniel García Moreno: GNOME Tour in openSUSE and welcome app</title><link>https://danigm.net/gnome-tour-opensuse.html</link><description><p>As a follow up of the <a href="https://danigm.net/hackweek24.html">Hackweek 24 project</a>, I've continued workingon the gnome-tour fork for openSUSE with custom pages to replace thewelcome application for openSUSE distributions.</p><h2>GNOME Tour modifications</h2><p>All the modifications are on top of <a href="https://gitlab.gnome.org/GNOME/gnome-tour/">upstream gnome-tour</a> andstored in the <a href="https://github.com/openSUSE/gnome-tour">openSUSE/gnome-tour repo</a></p><ul><li>Custom <strong>initial page</strong></li></ul><p class="img">  <img src="https://danigm.net/pictures/gnome-tour-opensuse.png" /></p> <ul><li><strong>A new donations page</strong>. In openSUSE we remove the popup from GNOME   shell for donations, so it's fair to add it in this place.</li></ul><p class="img">  <img src="https://danigm.net/pictures/gnome-tour-donation.png" /></p> <ul><li><strong>Last page with custom openSUSE links</strong>, this one is the used for   opensuse-welcome app.</li></ul><h2>opensuse-welcome package</h2><p>The <a href="https://danigm.net/feeds/tags/github.com/openSUSE/openSUSE-welcome">original opensuse-welcome</a> is a qt application, and this oneis used for all desktop environments, but it's more or lessunmaintained and looking for a replacement, we can use the gnome-tourfork as the default welcome app for all desktop without a custom app.</p><p>To do a minimal desktop agnostic opensuse-welcome application, I'vemodified the gnome-tour to also generate a second binary but just withthe last page.</p><p>The new opensuse-welcome rpm package is built as a subpackage of<a href="https://src.opensuse.org/pool/gnome-tour">gnome-tour</a>. This new application is minimal and it doesn't havelots of requirements, but as it's a gtk4 application, it requires gtkand libadwaita, and also depends on gnome-tour-data to get theresoures of the app.</p><p class="img">  <img src="https://danigm.net/pictures/opensuse-welcome.png" /></p> <p>To improve this welcome app we need to review the translations,because I added three new pages to the gnome-tour and that specificpages are not translated, so I should regenerate the .po files for alllanguages and upload to <a href="https://l10n.opensuse.org/">openSUSE Weblate</a> for translations.</p></description><author>Daniel García Moreno</author><dc:creator>Daniel García Moreno</dc:creator><pubDate>Tue, 21 Oct 2025 12:00:00 GMT</pubDate><guid isPermaLink="true">https://danigm.net/gnome-tour-opensuse.html</guid></item><item><title>Matthew Garrett: Where are we on X Chat security?</title><link>https://mjg59.dreamwidth.org/73625.html</link><description>AWS had an outage today and Signal was unavailable for some users for a while. This has confused some people, including Elon Musk, who are concerned that having a dependency on AWS means that Signal could somehow be compromised by anyone with sufficient influence over AWS (it can't). Which means we're back to the richest man in the world recommending his own "X Chat", saying <q>The messages are fully encrypted with no advertising hooks or strange “AWS dependencies” such that I can’t read your messages even if someone put a gun to my head</q>.<br /><br />Elon is either uninformed about his own product, lying, or both.<br /><br />As I wrote <a href="https://mjg59.dreamwidth.org/71646.html">back in June</a>, X Chat genuinely end-to-end encrypted, but ownership of the keys is complicated. The encryption key is stored using the <a href="https://juicebox.xyz/">Juicebox</a> protocol, sharded between multiple backends. Two of these are asserted to be HSM backed - a discussion of the commissioning ceremony was recently posted <a href="https://x.com/XEng/status/1971739456857145574">here</a>. I have not watched the almost 7 hours of video to verify that this was performed correctly, and I also haven't been able to verify that the public keys included in the post were the keys generated during the ceremony, although that may be down to me just not finding the appropriate point in the video (sorry, Twitter's video hosting doesn't appear to have any skip feature and would frequently just sit spinning if I tried to seek to far and I should probably just download them and figure it out but I'm not doing that now). With enough effort it would probably also have been possible to fake the entire thing - I have no reason to believe that this has happened, but it's not externally verifiable.<br /><br />But let's assume these published public keys are legitimately the ones used in the HSM Juicebox realms[1] and that everything was done correctly. Does that prevent Elon from obtaining your key and decrypting your messages? No.<br /><br />On startup, the X Chat client makes an API call called GetPublicKeysResult, and the public keys of the realms are returned. Right now when I make that call I get the public keys listed above, so there's at least some indication that I'm going to be communicating with actual HSMs. But what if that API call returned different keys? Could Elon stick a proxy in front of the HSMs and grab a cleartext portion of the key shards? Yes, he absolutely could, and then he'd be able to decrypt your messages.<br /><br />(I will accept that there is a plausible argument that Elon is telling the truth in that even if you held a gun to his head he's not smart enough to be able to do this himself, but that'd be true even if there were no security whatsoever, so it still says nothing about the security of his product)<br /><br />The solution to this is remote attestation - a process where the device you're speaking to proves its identity to you. In theory the endpoint could attest that it's an HSM running this specific code, and we could look at the Juicebox repo and verify that it's that code and hasn't been tampered with, and then we'd know that our communication channel was secure. Elon hasn't done that, despite it being table stakes for this sort of thing (Signal uses remote attestation to verify the enclave code used for private contact discovery, for instance, which ensures that the client will refuse to hand over any data until it's verified the identity and state of the enclave). There's no excuse whatsoever to build a new end-to-end encrypted messenger which relies on a network service for security without providing a trustworthy mechanism to verify you're speaking to the real service.<br /><br />We know how to do this properly. We have done for years. Launching without it is unforgivable.<br /><br />[1] There are three Juicebox realms overall, one of which doesn't appear to use HSMs, but you need at least two in order to obtain the key so at least part of the key will always be held in HSMs<br /><br /><img alt="comment count unavailable" height="12" src="https://www.dreamwidth.org/tools/commentcount?user=mjg59&amp;ditemid=73625" style="vertical-align: middle;" width="30" /> comments</description><author>Matthew Garrett</author><dc:creator>Matthew Garrett</dc:creator><pubDate>Mon, 20 Oct 2025 23:36:19 GMT</pubDate><guid isPermaLink="true">https://mjg59.dreamwidth.org/73625.html</guid></item><item><title>Dorothy Kabarozi: Deploying a Simple HTML Project on Linode Using Nginx</title><link>https://dorothykabarozi.wordpress.com/2025/10/18/deploying-a-simple-html-project-on-linode-using-nginx/</link><description><hr class="wp-block-separator has-alpha-channel-opacity" />   <h1 class="wp-block-heading">Deploying a Simple HTML Project on Linode Using Nginx: My Journey and Lessons Learned</h1>   <p>Deploying web projects can seem intimidating at first, especially when working with a remote server like Linode. Recently, I decided to deploy a simple HTML project (<code>index.html</code>) on a Linode server using Nginx. Here’s a detailed account of the steps I took, the challenges I faced, and the solutions I applied.</p>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 1: Accessing the Linode Server</h2>   <p>The first step was to connect to my Linode server via SSH:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">ssh root@&lt;your-linode-ip&gt; </pre></div>  <p>Initially, I encountered a <strong>timeout issue</strong>, which reminded me to check network settings and ensure SSH access was enabled for my Linode instance. Once connected, I had access to the server terminal and could manage files and services.</p>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 2: Preparing the Project</h2>   <p>My project was simple—it only contained an <code>index.html</code> file. I uploaded it to the server under:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">/var/www/hng13-stage0-devops </pre></div>  <p>I verified the project folder structure with:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">ls -l /var/www/hng13-stage0-devops </pre></div>  <p>Since there was no <code>public</code> folder or PHP files, I knew I needed to adjust the Nginx configuration to serve directly from this folder.</p>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 3: Setting Up Nginx</h2>   <p>I opened the Nginx configuration for my site:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo nano /etc/nginx/sites-available/hng13 </pre></div>  <p>Initially, I mistakenly pointed <code>root</code> to a non-existent folder (<code>public</code>), which caused a <strong>404 Not Found</strong> error. The correct configuration looked like this:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">server {    listen 80;    server_name &lt;your_linode-ip&gt;;     root /var/www/hng13-stage0-devops;  # points to folder containing index.html    index index.html index.htm;     location / {        try_files $uri $uri/ =404;    }} </pre></div>  <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 4: Enabling the Site and Testing</h2>   <p>After creating the configuration file, I enabled the site:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo ln -s /etc/nginx/sites-available/hng13 /etc/nginx/sites-enabled/ </pre></div>  <p>I also removed the default site to avoid conflicts:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo rm /etc/nginx/sites-enabled/default </pre></div>  <p>Then I tested the configuration:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo nginx -t </pre></div>  <p>If the syntax was OK, I reloaded Nginx:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo systemctl reload nginx </pre></div>  <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 5: Checking Permissions</h2>   <p>Nginx must have access to the project files. I ensured the correct permissions:</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">sudo chown -R www-data:www-data /var/www/hng13-stage0-devopssudo chmod -R 755 /var/www/hng13-stage0-devops </pre></div>  <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Step 6: Viewing the Site</h2>   <p>Finally, I opened my browser and navigated to</p>  <div class="wp-block-syntaxhighlighter-code "><pre class="brush: plain; title: ; notranslate">http://&lt;your-linode-ip&gt; </pre></div>  <p>And there it was—my <code>index.html</code> page served perfectly via Nginx. <img alt="✅" class="wp-smiley" src="https://s0.wp.com/wp-content/mu-plugins/wpcom-smileys/twemoji/2/72x72/2705.png" style="height: 1em;" /></p>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Challenges and Lessons Learned</h2>   <ol class="wp-block-list"><li><strong>Nginx <code>server_name</code> Error</strong><ul class="wp-block-list"><li>Error: <code>"server_name" directive is not allowed here</code></li>   <li>Lesson: Always place <code>server_name</code> inside a <code>server { ... }</code> block.</li></ul></li>   <li><strong>404 Not Found</strong><ul class="wp-block-list"><li>Cause: Nginx was pointing to a <code>public</code> folder that didn’t exist.</li>   <li>Solution: Update <code>root</code> to the folder containing <code>index.html</code>.</li></ul></li>   <li><strong>Permissions Issues</strong><ul class="wp-block-list"><li>Nginx could not read files initially.</li>   <li>Solution: Ensure ownership by <code>www-data</code> and proper read/execute permissions.</li></ul></li>   <li><strong>SSH Timeout / Connection Issues</strong><ul class="wp-block-list"><li>Double-check firewall rules and Linode network settings.</li></ul></li></ol>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <h2 class="wp-block-heading">Key Takeaways</h2>   <ul class="wp-block-list"><li>For static HTML projects, Nginx is simple and effective.</li>   <li>Always check the <strong>root folder</strong> matches your project structure.</li>   <li>Testing the Nginx config (<code>nginx -t</code>) before reload saves headaches.</li>   <li>Proper permissions are crucial for serving files correctly.</li></ul>   <hr class="wp-block-separator has-alpha-channel-opacity" />   <p>Deploying my project was a learning experience. Even small mistakes like pointing to the wrong folder or placing directives in the wrong context can break the site—but step-by-step debugging and understanding the errors helped me fix everything quickly.This has kick started my devOps journey and I truly loved the challenge</p></description><author>Dorothy Kabarozi</author><dc:creator>Dorothy Kabarozi</dc:creator><pubDate>Sat, 18 Oct 2025 16:14:37 GMT</pubDate><guid isPermaLink="true">https://dorothykabarozi.wordpress.com/2025/10/18/deploying-a-simple-html-project-on-linode-using-nginx/</guid></item><item><title>Allan Day: GNOME Foundation Update, 2025-10-17</title><link>https://blogs.gnome.org/aday/2025/10/17/gnome-foundation-update-2025-10-17/</link><description><p>It&#8217;s the end of the working week, the weekend is calling, and it&#8217;s time for another weekly GNOME Foundation update. As always, there&#8217;s plenty going on at the GNOME Foundation, and this post just covers the highlights that are easy to share. Let&#8217;s get started.</p><h2>Board meeting</h2><p>The Board of Directors had a regular meeting on Tuesday this week (the meeting was regular in the sense that it is regularly scheduled for the 2nd Tuesday of the month). </p><p>We were extremely pleased to approve the addition of two new members to the <a class="external" href="https://handbook.gnome.org/foundation/committees/circle.html">Circle Committee</a>: welcome to Alireza and Ignacy, who will be helping out with the fantastic <a class="external" href="https://circle.gnome.org/">Circle initiative</a>!</p><p>For those who don&#8217;t know, the Circle Committee is the team that is responsible for reviewing app submissions, as well as doing regular maintenance on the list of member apps. It&#8217;s valuable work.</p><p>The main item on the agenda for this week&#8217;s Board meeting was the 2025-26 budget, which we finalized and approved. Our financial year runs from October to September, so the budget approval was slightly late, but a delay this small doesn&#8217;t have any practical consequence for our operations. We&#8217;ll provide a separate post on the budget itself, to provide more details on our plans and financial position.</p><h2>GIMP grants</h2><p>Some news which I can share now, even though it isn&#8217;t technically from this week: last week the Foundation finished the long process of awarding the GIMP project&#8217;s first two development grants. I&#8217;m really excited for the GIMP project now that we have reached this milestone, and I&#8217;m sure that the grants will give their development efforts a major boost.</p><p>More specifics about the grants are coming in a dedicated announcement, so I won&#8217;t go into too many details now. However, I will say that a fair amount of work was required on the Foundation side to implement the grants in a compliant manner, including the creation and roll out of a new conflict of interest policy. The nice thing about this is that, with the necessary frameworks in place, it will be relatively easy to award additional grants in the future.</p><h2>Fundraising Committee</h2><p>The new Fundraising Committee had its first meeting this week, and I hear that its members have started working through a list of tasks, which is great news. I&#8217;m very appreciative of this effort, and especial thanks has to go to Maria Majadas who has pushed it forward.</p><p>The committee isn&#8217;t an official committee just yet &#8211; this is something that the Board will hopefully look at during its next meeting.</p><h2>Message ends</h2><p>That&#8217;s it for this week! Thanks for reading, and see you next week.</p></description><author>Allan Day</author><dc:creator>Allan Day</dc:creator><pubDate>Fri, 17 Oct 2025 16:25:09 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/aday/2025/10/17/gnome-foundation-update-2025-10-17/</guid></item><item><title>Sam Thursfield: Status update, 17/10/2025</title><link>https://samthursfield.wordpress.com/2025/10/17/status-update-17-10-2025/</link><description><p>Greetings readers. I&#8217;m writing to you from a hotel room in Manchester which I&#8217;m currently sharing with a variant of COVID 19. We are listening to disco funk music.</p>   <p>This virus prevents me from working or socializing, but I at least I have time to do some cyber-janitorial tasks like updating my &#8220;dotfiles&#8221; (which holds configuration for all the programs i use on Linux, stored in Git&#8230; for those who aren&#8217;t yet converts).</p>   <p>I also caught up with some big upcoming changes in the GNOME 50 release cycle &#8212; more on that below.</p>   <h2 class="wp-block-heading">nvim</h2>   <p>I picked up Vim as my text editor ten years ago while working on a very boring project. This article by Jon Beltran de Heredia, <a href="http://www.viemu.com/a-why-vi-vim.html">&#8220;Why, oh WHY, do those #?@! nutheads use vi?&#8221;</a> sold me on the key ideas: you use &#8220;normal mode&#8221; for everything, which gives you powerful and composable edit operations. I printed out this <a href="https://michaelgoerz.net/refcards/vimqrc.pdf">Vim quick reference card by Michael Goerz</a> and resolved to learn one new operation every day.</p>   <p>It worked and I&#8217;ve been a convert ever since. Doing consultancy work makes you a nomad: often working via SSH or WSL on other people&#8217;s computers. So I never had the luxury of setting up an IDE like GNOME Builder, or using something that isn&#8217;t packaged in 99% of distros. Luckily Vim is everywhere.</p>   <p>Over the years, I read a newletter named <a href="https://vimtricks.com/">Vimtricks</a> and I picked up various Vim plugins like <a href="https://github.com/dmerejkowsky/vim-ale">ALE</a>, <a href="https://github.com/ctrlpvim/ctrlp.vim">ctrlp</a>, and <a href="https://github.com/AndrewRadev/sideways.vim">sideways</a>. But there&#8217;s a problem: some of these depend on extra Vim features like Python support. If a required feature is missing, you get an error message that appears on like&#8230; <em>every keystroke</em>:</p>   <figure class="wp-block-image size-large"><a href="https://samthursfield.wordpress.com/wp-content/uploads/2025/10/image.png"><img alt="" class="wp-image-3106" height="306" src="https://samthursfield.wordpress.com/wp-content/uploads/2025/10/image.png?w=798" width="798" /></a></figure>   <p>In this case, on a Debian 12 build machine, I could work around by installing the <code>vim-gtk3</code> package. But it&#8217;s frustrating enough that I decided it was time to try Neovim.</p>   <p>The <a href="https://neovim.io/">Neovim</a> project began around the time I was switching to Vim, and is based on the premise that <a href="https://geoff.greer.fm/2015/01/15/why-neovim-is-better-than-vim/">&#8220;Vim is, without question, the worst C codebase I have seen.&#8221;</a>. </p>   <p>So far its been painless to switch and everything works a little better. The <a href="https://neovim.io/doc/user/terminal.html">:terminal</a> feels better integrated. I didn&#8217;t need to immediately disable <a href="https://neovim.io/doc/user/options.html#'mouse'">mouse mode</a>. I can link to online documentation! The ALE plugin (which provides language server integration) is even <a href="https://packages.fedoraproject.org/pkgs/vim-ale/neovim-ale/">ready packaged in Fedora</a>.</p>   <p>I&#8217;d send a screenshot but my editor looks&#8230; exactly the same as before. Boring!</p>   <figure class="wp-block-image size-large"><a href="https://samthursfield.wordpress.com/wp-content/uploads/2025/10/image-1.png"><img alt="" class="wp-image-3109" height="269" src="https://samthursfield.wordpress.com/wp-content/uploads/2025/10/image-1.png?w=790" width="790" /></a></figure>   <p></p>   <p>I also briefly tried out <a href="http://www.helix-editor.com">Helix</a>, which appears to take the good bits of Vim (modal editing) and run in a different direction (visible selection and multiple cursors). I need a more boring project before I&#8217;ll be able to learn a completely new editor. Give me 10 years.</p>   <h2 class="wp-block-heading">Endless OS 7</h2>   <p>I&#8217;ve been working flat out on <a href="https://github.com/endlessm/eos-build-meta/">Endless OS 7</a>, as last month. Now that the basics work and the system boots, we were mainly looking at integrating Endless-specific Pay as you Go functionality that they use for <a href="https://www.endlessglobal.com/foundation/access/laptop-program">affordable laptop programs</a>. </p>   <p>I learned more than I wanted to about Linux early boot process, particularly the <a href="https://dracut-ng.github.io/dracut-ng/">dracut-ng initramfs generator</a> (one of many Linux components that seems to be named after a town in Massachusetts).</p>   <p>GNOME OS actually dropped Dracut altogether, in <a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/2512">&#8220;vm-secure: Get rid of dracut and use systemd&#8217;s ukify&#8221;</a> by Valentin David, and now uses a simple Python script. A lot of Dracut&#8217;s features aren&#8217;t necessary for building atomic, image-based distros. For EOS we decided to stick with Dracut, at least for now.</p>   <p>So we get to deal with fun changes such as the initramfs growing from 90MB to 390MB after we updated to latest Dracut. Something which is affecting Fedora too (LWN: <a href="https://lwn.net/Articles/1041078/">&#8220;Last-minute /boot boost for Fedora 43&#8221;</a>).</p>   <p>I requested time after the contract finishes to write up a technical article on the work we did, so I won&#8217;t go into more details yet. Watch this space!</p>   <h2 class="wp-block-heading">GNOME 50</h2>   <p>I haven&#8217;t had a minute to look at upstream GNOME this month, but there are some interesting things cooking there.</p>   <p>Jordan <a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/3949">merged the GNOME OS openQA tests into the main gnome-build-meta repo</a>. This is a simple solution to a number of basic questions we had around testing, such as, &#8220;how do we target tests to specific versions of GNOME?&#8221;. </p>   <p>We separated the tests <em>out</em> of gnome-build-meta because, at the time, each new CI pipeline would track new versions of each GNOME module. This meant, firstly that pipelines could take anywhere from 10 minutes to 4 hours rebuilding a disk image before the tests even started, and secondly that the system under test would change every time you ran the pipeline.</p>   <p>While that sounds dumb, it worked this way for historical reasons: GNOME OS has been an under-resourced ad-hoc project ongoing since 2011, whose original goal was simply to continuously build: already a huge challenge if you remember GNOME in the early 2010s. Of course, such as CI pipeline is highly counterproductive if you&#8217;re trying to develop and review changes to the <em>tests</em>, and not the system: so the separate <a href="https://gitlab.gnome.org/GNOME/openqa-tests">openqa-tests repo</a> was a necessary step.</p>   <p>Thanks to Abderrahim&#8217;s work in 2022 (<a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/1795">&#8220;Commit refs to the repository&#8221;</a> and <a href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/merge_requests/1796">&#8220;Add script to update refs&#8221;</a>), plus my work on a tool to run the openQA tests locally before pushing to CI (<a href="https://gitlab.gnome.org/sthursfield/ssam_openqa/">ssam_openqa</a>), I hope we&#8217;re not going to have those kinds of problems any more. We enter a brave new world of testing!</p>   <p>The next thing the openQA tests need, in my opinion, is dedicated test infrastructure. The shared Gitlab CI runners we have are in high demand. The openQA tests have timeouts, as they ultimately are doing this in a loop:</p>   <ul class="wp-block-list"><li>Send an input event</li>   <li>Wait for the system under test to react</li></ul>   <p>If a VM is running on a test runner with overloaded CPU or IO then tests will start to time out in unhelpful ways. So, if you want to have better testing for GNOME, finding some dedicated hardware to run tests would be a significant help.</p>   <p>There are also some changes cooking in Localsearch thanks to Carlos Garnacho:</p>   <ul class="wp-block-list"><li><a href="https://gitlab.gnome.org/GNOME/localsearch/-/merge_requests/629">Per removeable device databases</a></li>   <li><a href="https://gitlab.gnome.org/GNOME/localsearch/-/merge_requests/630">Index homedir recursively</a></li></ul>   <p>The first of these is a nicely engineered way to allow searching files on removable disks like external HDs. This should be opt-in: so you can opt in to indexing your external hard drive full of music, but your machine wouldn&#8217;t be vulnerable to an attack where someone connects a malicious USB stick while your back is turned. (The sandboxing in localsearch makes it non-trivial to construct such an attack, but it would require a significantly greater level of security auditing before I&#8217;d make any <em>guarantees</em> about that).</p>   <p>The second of these changes is pretty big: in GNOME 50, localsearch will now consider everything in your homedir for indexing.</p>   <p>As Carlos notes in the commit message, he has spent years working on performance optimisations and bug fixes in localsearch to get to a point where he considers it reasonable to enable by default. From a design point of view, discussed in the issue &#8220;<a href="https://gitlab.gnome.org/GNOME/localsearch/-/issues/336#top">Be more encompassing about what get indexed</a>&#8220;, it&#8217;s hard to justify a search feature that only surfaces a <em>subset </em>of your files.</p>   <p>I don&#8217;t know if it&#8217;s a great time to do this, but nothing is perfect and sometimes you have to take a few risks to move forwards.</p>   <p>There&#8217;s a design, testing and user support element to all of this, and it&#8217;s going to require help from the GNOME community and our various downstream distributors, particularly around:</p>   <ul class="wp-block-list"><li>Widely testing the new feature before the GNOME 50 release.</li>   <li>Making sure users are aware of the change and how to manage the search config.</li>   <li>Handling an expected increase in bug reports and support requests.</li>   <li>Highlighting how privacy-focused localsearch is.</li></ul>   <p>I never got time to extend the openQA tests to <a href="https://gitlab.gnome.org/GNOME/openqa-tests/-/issues/8">cover media indexing</a>; it&#8217;s not a trivial job. We will rely on volunteers and downstream testers to try out the config change as widely as possible<em> </em>over the next 6 months.</p>   <p>One thing that makes me support this change is that the indexer in Android devices already works like this: everything is scanned into a local cache, unless there&#8217;s a <code>.nomedia</code> file.  Unfortunately Google don&#8217;t document how the Android media scanner works. But it&#8217;s not like this is GNOME treading a radical new path. </p>   <p>The localsearch index lives in the same filesystem as the data, and never leaves your PC. In a world where <a href="https://www.bbc.co.uk/news/articles/cj3xjrj7v78o">Microsoft Windows can now send your boss screenshots of everything you looked at</a>, GNOME is still very much on <em>your</em> side. Let&#8217;s see if we can tell that story.</p></description><author>Sam Thursfield</author><dc:creator>Sam Thursfield</dc:creator><pubDate>Fri, 17 Oct 2025 16:16:16 GMT</pubDate><guid isPermaLink="true">https://samthursfield.wordpress.com/2025/10/17/status-update-17-10-2025/</guid></item><item><title>This Week in GNOME: #221 Virus Season</title><link>https://thisweek.gnome.org/posts/2025/10/twig-221/</link><description><p>Update on what happened across the GNOME project in the week from October 10 to October 17.<!--more--></p><h2 id="gnome-circle-apps-and-libraries">GNOME Circle Apps and Libraries</h2><h3 id="podcasts">Podcasts <a href="https://gitlab.gnome.org/World/podcasts">↗</a></h3><p>Podcast app for GNOME.</p><p><a href="https://thisweek.gnome.org/reporters/7c4a7f876686de5e08468568f47eabc632cddce0a28ef7f73a116e8fd1cedade">alatiera</a> reports</p><blockquote><p>A new release of Podcasts is out! Version 25.3 Introduces the long awaited episode chapters! Additionally it includes performance improvements and interface polish, especially for mobile devices.</p><p>Available now only on <a href="https://flathub.org/en/apps/org.gnome.Podcasts">Flathub</a></p><p><img height="1500" src="https://thisweek.gnome.org/_astro/episooe-chapters.De-Vg7Pc_Z1o2pe0.webp" width="2100" /></p></blockquote><h2 id="third-party-projects">Third Party Projects</h2><p><a href="https://thisweek.gnome.org/reporters/061d41eb80a43440bf9447406e072b686064bc0a68d55d07a985bc5822f385ef">Alain</a> reports</p><blockquote><p>Planify 4.15.1 — A smoother, more focused experience</p><p>Planify 4.15.1 introduces a brand-new Markdown editor, Focus Mode, animated progress bars, improved keyboard navigation, and better translation management through Weblate. This release also brings numerous stability fixes and UI refinements that make task management faster, more fluid, and delightful.</p><p><a href="https://useplanify.com/blog/#planify-4151-a-smoother-more-focused-experience">Read the full release notes</a></p><p></p><p></p><p></p><p></p><p><img height="624" src="https://thisweek.gnome.org/_astro/inbox-page.iLuQhufO_Z1xOL11.webp" width="479" /></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-221/circular-progress.mp4" type="video/mp4" /></video></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-221/focus-mode.mp4" type="video/mp4" /></video></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-221/markdown-editor.mp4" type="video/mp4" /></video></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-221/scroll-animation.mp4" type="video/mp4" /></video></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/a76f6e3bdd3e274da222b1e597e8da5a174db85da2dbaf4f7269416d16181e21">Vladimir Kosolapov</a> announces</p><blockquote><p>This week I released <a href="https://flathub.org/apps/details/io.github.vmkspv.lenspect">Lenspect</a> — a lightweight security threat scanner powered by VirusTotal.</p><p>In almost 11 years, this is the first native GUI VirusTotal client developed specifically for Linux platform and using a modern GNOME technology stack. Stay tuned for updates to try out new features in the next versions.</p><p>Check out the project on <a href="https://github.com/vmkspv/lenspect">GitHub</a></p><p><img height="1542" src="https://thisweek.gnome.org/_astro/Lenspect.CgieQvVE_swCl1.webp" width="1744" /></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/3f7e56fd3e07a5d293b680946eb734c590035ba39d4a7db7ddfc048c9d97aad6">Alexander Vanhee</a> reports</p><blockquote><p>Bazaar got a pretty big update this week. I added the in-app screenshot viewer (featuring zoom) and the featured apps carousel, as seen on the Flathub site. Kolumni worked on a custom rendering engine for app descriptions, featuring a nicer multi-line list item experience. She also added a custom animated pending state for the Global Progress Bar, shown whenever the current task has no associated percentage.</p><p>Please check out these changes on <a href="https://flathub.org/en/apps/io.github.kolunmi.Bazaar">Flathub</a></p><p><img height="807" src="https://thisweek.gnome.org/_astro/bazaar-carousel.DgCiSrL4_ZBilQw.webp" width="1123" /> </p><p></p><p><img height="829" src="https://thisweek.gnome.org/_astro/bazaar-description-renderer.C6Yg_lu-_ZD7kfz.webp" width="834" /></p><p><img height="864" src="https://thisweek.gnome.org/_astro/bazaar-image-viewer.qpYS3XZn_28mYB7.webp" width="1179" /></p><p><video controls="controls"><source src="https://thisweek.gnome.org/posts/2025/10/twig-221/bazaar-pending-state.mp4" type="video/mp4" /></video></p></blockquote><p><a href="https://thisweek.gnome.org/reporters/1cbcc511e6ca919ad647ad976ae4438db064eda941fbb2882a21d6e13044d34a">Bilal Elmoussaoui</a> reports</p><blockquote><p>Today I have finished all the remaining missing bits of the Rust re-implementation of gnome-keyring to be spec compatible. It is only missing PAM integration for automatically unlocking the keyring when you log in, otherwise most of the features should just work.  The code source is available at <a href="https://github.com/bilelmoussaoui/oo7/tree/main/server">https://github.com/bilelmoussaoui/oo7/tree/main/server</a>, any help with testing would be appreciated. Thanks!</p></blockquote><h3 id="quadrapassel">Quadrapassel <a href="https://gitlab.gnome.org/GNOME/quadrapassel">↗</a></h3><p>Fit falling blocks together.</p><p><a href="https://thisweek.gnome.org/reporters/9d1ec84ce44929354b3a4ae336781b776cf26af387dbb7983b76a1143cb8d10d">Will Warner</a> reports</p><blockquote><p>Quadrapassel 49.1 is out!This release improves upon 49.0 by updating some of its dependencies, fixing bugs, and polishing the UI.New in 49.1:</p><ul><li>Updated translations: Occitan, Chinese (China), Brazilian Portuguese, Slovenian, Ukrainian, Georgian</li><li>Improved controller support and controller mappings</li><li>Replaced the theme dialog with one that is easier to use</li><li>Improved the scores dialogYou can check it out on <a href="https://flathub.org/apps/org.gnome.Quadrapassel">Flathub</a>!</li></ul></blockquote><h3 id="pipeline">Pipeline <a href="https://flathub.org/apps/de.schmidhuberj.tubefeeder">↗</a></h3><p>Follow your favorite video creators.</p><p><a href="https://thisweek.gnome.org/reporters/2d6bfa52eff97725a6197c0937e602046fe2a6569a3e73f54fe0124496ec618f">schmiddi</a> reports</p><blockquote><p>I’ve released version 3.1.0 of Pipeline. Starting with this release, Pipeline now fetches data about YouTube videos directly from YouTube instead of proxying over Piped. This is due to pretty much no public Piped instances working anymore. If you have a private Piped instance you want to use, you can still switch back to using Piped in the settings. This change also speeds up fetching the feed of videos a lot, for my personal feed by a factor of about 20.</p></blockquote><h3 id="fractal">Fractal <a href="https://gitlab.gnome.org/World/fractal">↗</a></h3><p>Matrix messaging app for GNOME written in Rust.</p><p><a href="https://thisweek.gnome.org/reporters/cb8ebb1826d577060c92faada43d4ec4c2dff3628749a1dfc63866b2747e19b3">Kévin Commaille</a> reports</p><blockquote><p>Ah, Autumn… The trees are wearing their warmest colors, the wine harvest is ending, developers are preparing to hibernate… and Fractal 13.rc is here!</p><p>Our repository has been relatively quiet since the beta release, with mostly work on bug fixes for our new audio player, and a bit of code refactoring.</p><p>As usual, this release includes other improvements, fixes and new translations thanks to all our contributors, and our upstream projects.</p><p>It is available to install via Flathub Beta, see the <a href="https://gitlab.gnome.org/World/fractal#installation-instructions">instructions in our README</a>.</p><p>As the version implies, it should be mostly stable and we expect to only include minor improvements until the release of Fractal 13.</p><p>If you want to join the fun, you can try to fix one of our <a href="https://gitlab.gnome.org/World/fractal/-/issues/?label_name%5B%5D=4.%20Newcomers">newcomers issues</a>. We are always looking for new contributors!</p></blockquote><h2 id="gnome-foundation">GNOME Foundation</h2><p><a href="https://thisweek.gnome.org/reporters/c3370cae2e550d4d7f879eecbe1ccbad891c52b77cb2b7cab17d9d30f31088bb">Allan Day</a> reports</p><blockquote><p>Another weekly <a href="https://blogs.gnome.org/aday/2025/10/17/gnome-foundation-update-2025-10-17/">GNOME Foundation update is available</a>! Highlights this week include a new budget, new Circle Committee members, GIMP development grants, and more.</p></blockquote><h2 id="thats-all-for-this-week">That’s all for this week!</h2><p>See you next week, and be sure to stop by <a href="https://matrix.to/#/#thisweek:gnome.org">#thisweek:gnome.org</a> with updates on your own projects!</p></description><author>This Week in GNOME</author><dc:creator>This Week in GNOME</dc:creator><pubDate>Fri, 17 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://thisweek.gnome.org/posts/2025/10/twig-221/</guid></item><item><title>Jussi Pakkanen: Building Android apps with native code using Meson</title><link>https://nibblestew.blogspot.com/2025/10/building-android-apps-with-native-code.html</link><description><p>Building code for Android with Meson has long been possible, but a bit hacky and not particularly well documented. Recently some new features have landed in Meson main, which make the experience quite a bit nicer. To demonstrate, I have updated the <a href="https://github.com/jpakkane/platypus">Platypus sample project</a> to build and run on Android. The project itself aims demonstrate how you'd build a GUI application with shared native code on multiple platforms using native widget toolkits on each of them. Currently it supports GTK, Win32, Cocoa, WASM and Android. In addition to building the code it also generates native packages and installers.</p><p>It would be nice if you could build full Android applications with just a toolchain directly from the command line. As you start looking into how Android builds work you realize that this is not really the way to go if you want to preserve your sanity. Google has tied app building very tightly into Android Studio. Thus the simple way is to build the native code with Meson, Java/Kotlin code with Android Studio and then merge the two together.</p><p>The Platypus repo has a script called <span style="font-family: courier;">build_android.py</span>, which does exactly this. The steps needed to get a working build are the following:</p><p></p><ol style="text-align: left;"><li>Use Meson's <span style="font-family: courier;">env2mfile</span> to introspect the current Android Studio installation and create cross files for all discovered Android toolchains</li><li>Set up a build directory for the toolchain version/ABI/CPU combination given, defaulting to the newest toolchain and arm64-v8a</li><li>Compile the code.</li><li>Install the generated shared library in the source tree under <span style="font-family: courier;">&lt;app source dir&gt;/jniLibs/&lt;cpu&gt;</span>.</li><li>Android Studio will then automatically install the built libs when deploying the project.</li></ol><p></p><p>Here is a picture of the end result. The same application is running both in an emulator (x86_64) and a physical device (arm64-v8a).</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAT_oB2C0NJkFLdO_qH0AnUi6zBNuNQw-iuGJXWLnBTFRBRdrnOnHh1Jynjevj7ZjoFyhHIqMYNuXgomE8oBeBm_lF1_6lCUuPo5tuwxWx0en8akXHZAoL-UMSC4UYQIZ1nHwEaZXTqrYXrXZcZw5kN0uEDvlhZBeeY7Xaje9or8NWTSb5mF3oLxkUOpo/s1024/meson_android.jpg" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="300" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhAT_oB2C0NJkFLdO_qH0AnUi6zBNuNQw-iuGJXWLnBTFRBRdrnOnHh1Jynjevj7ZjoFyhHIqMYNuXgomE8oBeBm_lF1_6lCUuPo5tuwxWx0en8akXHZAoL-UMSC4UYQIZ1nHwEaZXTqrYXrXZcZw5kN0uEDvlhZBeeY7Xaje9or8NWTSb5mF3oLxkUOpo/w400-h300/meson_android.jpg" width="400" /></a></div><p>The main downside is that you have to run the native build step by hand. It should be possible to make this a custom build step in Gradle but I've never actually written Gradle code so I don't know how to do it.</p></description><author>Jussi Pakkanen</author><dc:creator>Jussi Pakkanen</dc:creator><pubDate>Wed, 15 Oct 2025 23:32:00 GMT</pubDate><guid isPermaLink="true">https://nibblestew.blogspot.com/2025/10/building-android-apps-with-native-code.html</guid></item><item><title>Gedit Technology blog: Mid-October News</title><link>https://gedit-text-editor.org/blog/2025-10-15-mid-october-news.html</link><description><p>  Misc news about the  <a href="https://gedit-text-editor.org/" target="_blank">gedit text editor</a>,  mid-October edition! (Some sections are a bit technical).</p> <h3>Rework of the file loading and saving (continued)</h3><p>  The refactoring continues in the libgedit-gtksourceview module, this time to  tackle a big class that takes too much responsibilities. A utility is in  development which will permit to delegate a part of the work.</p><p>  The utility is about character encoding conversion, with support of invalid  bytes. It takes as input a single GBytes (the file content), and transforms it  into a list of chunks. A chunk contains either valid (successfully converted)  bytes, or invalid bytes. The output format - the "list of chunks" - is subject  to change to improve memory consumption and performances.</p><p>  Note that invalid bytes are allowed, to be able to open really any kind of  files with gedit.</p><p>  I must also note that this is quite sensitive work, at the heart of document  loading for gedit. Normally all these refactorings and improvements will be  worth it!</p> <h3>Progress in other modules</h3><p>  There has been some progress on other modules:</p><ul>  <li>    <strong>gedit:</strong> version 48.1.1 has been released with a few minor    updates.  </li>  <li>    <strong>The Flatpak</strong> on Flathub: update to gedit 48.1.1 and the    GNOME 49 runtime.  </li>  <li>    <strong>gspell:</strong> version 1.14.1 has been released, mainly to pick up    the updated translations.  </li></ul> <h3>GitHub Sponsors</h3><p>  In addition to Liberapay, you can now support the work that I do on  GitHub Sponsors. See the  <a href="https://gedit-text-editor.org/donations.html" target="_blank">gedit donations</a>  page.</p><p>  Thank you ❤️</p></description><author>Gedit Technology blog</author><dc:creator>Gedit Technology blog</dc:creator><pubDate>Wed, 15 Oct 2025 10:00:00 GMT</pubDate><guid isPermaLink="true">https://gedit-text-editor.org/blog/2025-10-15-mid-october-news.html</guid></item><item><title>Victor Ma: This is a test post</title><link>https://victorma.ca/posts/gsoc-8/</link><description><p>Over the past few weeks, I&rsquo;ve been working on improving some test code that I had written.</p><h2 id="refactoring-time">Refactoring time!</h2><p>My first order of business was to refactor the test code. There was a lot of boilerplate, which made it difficult to add new tests, and also created visual clutter.</p><p>For example, have a look at this test case:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span></span></span><span style="display: flex;"><span><span style="color: #a6e22e;">test_egg_ipuz</span> (<span style="color: #66d9ef;">void</span>)</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_autoptr</span> (WordList) word_list <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span> IpuzGrid <span style="color: #f92672;">*</span>grid;</span></span><span style="display: flex;"><span> g_autofree IpuzClue <span style="color: #f92672;">*</span>clue <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_autoptr</span> (WordArray) clue_matches <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span> word_list <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_broda_word_list</span> ();</span></span><span style="display: flex;"><span> grid <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">create_grid</span> (EGG_IPUZ_FILE_PATH);</span></span><span style="display: flex;"><span> clue <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_clue</span> (grid, IPUZ_CLUE_DIRECTION_ACROSS, <span style="color: #ae81ff;">2</span>);</span></span><span style="display: flex;"><span> clue_matches <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">word_list_find_clue_matches</span> (word_list, clue, grid);</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_assert_cmpint</span> (<span style="color: #a6e22e;">word_array_len</span> (clue_matches), <span style="color: #f92672;">==</span>, <span style="color: #ae81ff;">3</span>);</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_assert_cmpstr</span> (<span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">0</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGS"</span>);</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_assert_cmpstr</span> (</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">1</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGO"</span>);</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_assert_cmpstr</span> (</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">2</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGY"</span>);</span></span><span style="display: flex;"><span>}</span></span></code></pre></div><p>That&rsquo;s an awful lot of code just to say:</p><ol><li>Use the <code>EGG_IPUZ_FILE_PATH</code> file.</li><li>Run the <code>word_list_find_clue_matches()</code> function on the 2-Across clue.</li><li>Assert that the results are <code>[&quot;EGGS&quot;, &quot;EGGO&quot;, &quot;EGGY&quot;]</code>.</li></ol><p>And this was repeated in every test case, and needed to be repeated in every new test case I added. So, I knew that I had to refactor my code.</p><h3 id="fixtures-and-functions">Fixtures and functions</h3><p>My first step was to extract all of this setup code:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #a6e22e;">g_autoptr</span> (WordList) word_list <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span>IpuzGrid <span style="color: #f92672;">*</span>grid;</span></span><span style="display: flex;"><span>g_autofree IpuzClue <span style="color: #f92672;">*</span>clue <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span><span style="color: #a6e22e;">g_autoptr</span> (WordArray) clue_matches <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span>word_list <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_broda_word_list</span> ();</span></span><span style="display: flex;"><span>grid <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">create_grid</span> (EGG_IPUZ_FILE_PATH);</span></span><span style="display: flex;"><span>clue <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_clue</span> (grid, IPUZ_CLUE_DIRECTION_ACROSS, <span style="color: #ae81ff;">2</span>);</span></span><span style="display: flex;"><span>clue_matches <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">word_list_find_clue_matches</span> (word_list, clue, grid);</span></span></code></pre></div><p>To do this, I used a fixture:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #66d9ef;">typedef</span> <span style="color: #66d9ef;">struct</span> {</span></span><span style="display: flex;"><span> WordList <span style="color: #f92672;">*</span>word_list;</span></span><span style="display: flex;"><span> IpuzGrid <span style="color: #f92672;">*</span>grid;</span></span><span style="display: flex;"><span>} Fixture;</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span> <span style="color: #a6e22e;">fixture_set_up</span> (Fixture <span style="color: #f92672;">*</span>fixture, gconstpointer user_data)</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #66d9ef;">const</span> gchar <span style="color: #f92672;">*</span>ipuz_file_path <span style="color: #f92672;">=</span> (<span style="color: #66d9ef;">const</span> gchar <span style="color: #f92672;">*</span>) user_data;</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span> fixture<span style="color: #f92672;">-&gt;</span>word_list <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_broda_word_list</span> ();</span></span><span style="display: flex;"><span> fixture<span style="color: #f92672;">-&gt;</span>grid <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">create_grid</span> (ipuz_file_path);</span></span><span style="display: flex;"><span>}</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span> <span style="color: #a6e22e;">fixture_tear_down</span> (Fixture <span style="color: #f92672;">*</span>fixture, gconstpointer user_data)</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_object_unref</span> (fixture<span style="color: #f92672;">-&gt;</span>word_list);</span></span><span style="display: flex;"><span>}</span></span></code></pre></div><p>My next step was to extract all of this assertion code:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #a6e22e;">g_assert_cmpint</span> (<span style="color: #a6e22e;">word_array_len</span> (clue_matches), <span style="color: #f92672;">==</span>, <span style="color: #ae81ff;">3</span>);</span></span><span style="display: flex;"><span><span style="color: #a6e22e;">g_assert_cmpstr</span> (<span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">0</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGS"</span>);</span></span><span style="display: flex;"><span><span style="color: #a6e22e;">g_assert_cmpstr</span> (</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">1</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGO"</span>);</span></span><span style="display: flex;"><span><span style="color: #a6e22e;">g_assert_cmpstr</span> (</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_list_get_indexed_word</span> (word_list,</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">word_array_index</span> (clue_matches, <span style="color: #ae81ff;">2</span>)),</span></span><span style="display: flex;"><span> <span style="color: #f92672;">==</span>,</span></span><span style="display: flex;"><span> <span style="color: #e6db74;">"EGGY"</span>);</span></span></code></pre></div><p>To do this, I created a new function that runs <code>word_list_find_clue_matches()</code> and asserts that the result equals an <code>expected_words</code> parameter.</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span></span></span><span style="display: flex;"><span><span style="color: #a6e22e;">test_clue_matches</span> (WordList <span style="color: #f92672;">*</span>word_list,</span></span><span style="display: flex;"><span> IpuzGrid <span style="color: #f92672;">*</span>grid,</span></span><span style="display: flex;"><span> IpuzClueDirection clue_direction,</span></span><span style="display: flex;"><span> guint clue_index,</span></span><span style="display: flex;"><span> <span style="color: #66d9ef;">const</span> gchar <span style="color: #f92672;">*</span>expected_words[])</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #66d9ef;">const</span> IpuzClue <span style="color: #f92672;">*</span>clue <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_autoptr</span> (WordArray) clue_matches <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_autoptr</span> (WordArray) expected_word_array <span style="color: #f92672;">=</span> NULL;</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span> clue <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">get_clue</span> (grid, clue_direction, clue_index);</span></span><span style="display: flex;"><span> clue_matches <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">word_list_find_clue_matches</span> (word_list, clue, grid);</span></span><span style="display: flex;"><span> expected_word_array <span style="color: #f92672;">=</span> <span style="color: #a6e22e;">str_array_to_word_array</span> (expected_words, word_list);</span></span><span style="display: flex;"><span></span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">g_assert_true</span> (<span style="color: #a6e22e;">word_array_equals</span> (clue_matches, expected_word_array));</span></span><span style="display: flex;"><span>}</span></span></code></pre></div><p>After all that, here&rsquo;s what my test case looked like:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span></span></span><span style="display: flex;"><span><span style="color: #a6e22e;">test_egg_ipuz</span> (Fixture <span style="color: #f92672;">*</span>fixture, gconstpointer user_data)</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">test_clue_matches</span> (fixture<span style="color: #f92672;">-&gt;</span>word_list,</span></span><span style="display: flex;"><span> fixture<span style="color: #f92672;">-&gt;</span>grid,</span></span><span style="display: flex;"><span> IPUZ_CLUE_DIRECTION_ACROSS,</span></span><span style="display: flex;"><span> <span style="color: #ae81ff;">2</span>,</span></span><span style="display: flex;"><span> (<span style="color: #66d9ef;">const</span> gchar<span style="color: #f92672;">*</span>[]){<span style="color: #e6db74;">"EGGS"</span>, <span style="color: #e6db74;">"EGGO"</span>, <span style="color: #e6db74;">"EGGY"</span>, NULL});</span></span><span style="display: flex;"><span>}</span></span></code></pre></div><p>Much better!</p><h3 id="macro-functions">Macro functions</h3><p>But as great as that was, I knew that I could take it even further, with macro functions.</p><p>I created a macro function to simplify test case definitions:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #75715e;">#define ASSERT_CLUE_MATCHES(DIRECTION, INDEX, ...) \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> test_clue_matches (fixture-&gt;word_list, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> fixture-&gt;grid, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> DIRECTION, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> INDEX, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> (const gchar*[]){__VA_ARGS__, NULL})</span></span></span></code></pre></div><p>Now, <code>test_egg_ipuz()</code> looked like this:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #66d9ef;">static</span> <span style="color: #66d9ef;">void</span></span></span><span style="display: flex;"><span><span style="color: #a6e22e;">test_egg_ipuz</span> (Fixture <span style="color: #f92672;">*</span>fixture, gconstpointer user_data)</span></span><span style="display: flex;"><span>{</span></span><span style="display: flex;"><span> <span style="color: #a6e22e;">ASSERT_CLUE_MATCHES</span> (IPUZ_CLUE_DIRECTION_ACROSS, <span style="color: #ae81ff;">2</span>, <span style="color: #e6db74;">"EGGS"</span>, <span style="color: #e6db74;">"EGGO"</span>, <span style="color: #e6db74;">"EGGY"</span>);</span></span><span style="display: flex;"><span>}</span></span></code></pre></div><p>I also made a macro function for the test case declarations:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #75715e;">#define ADD_IPUZ_TEST(test_name, file_name) \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> g_test_add ("/clue_matches/" #test_name, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> Fixture, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> "tests/clue-matches/" #file_name, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> fixture_set_up, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> test_name, \</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"> fixture_tear_down)</span></span></span></code></pre></div><p>Which turned this:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #a6e22e;">g_test_add</span> (<span style="color: #e6db74;">"/clue_matches/test_egg_ipuz"</span>,</span></span><span style="display: flex;"><span> Fixture,</span></span><span style="display: flex;"><span> EGG_IPUZ,</span></span><span style="display: flex;"><span> fixture_set_up,</span></span><span style="display: flex;"><span> test_egg_ipuz,</span></span><span style="display: flex;"><span> fixture_tear_down);</span></span></code></pre></div><p>Into this:</p><div class="highlight"><pre tabindex="0"><code class="language-c"><span style="display: flex;"><span><span style="color: #a6e22e;">ADD_IPUZ_TEST</span> (test_egg_ipuz, egg.ipuz);</span></span></code></pre></div><h2 id="an-unfortunate-bug">An unfortunate bug</h2><p>So, picture this: You&rsquo;ve just finished refactoring your test code. You add some finishing touches, do a final test run, look over the diff one last time&hellip;and everything seems good. So, you open up an MR and start working on other things.</p><p>But then, the unthinkable happens&mdash;the CI pipeline fails! And apparently, it&rsquo;s due to a test failure? But you ran your tests locally, and everything worked just fine. (You run them again just to be sure, and yup, they still pass.) And what&rsquo;s more, it&rsquo;s only the Flatpak CI tests that failed. The <em>native</em> CI tests succeeded.</p><p>So&hellip;what, then? What could be the cause of this? I mean, how do you even begin debugging a test failure that only happens in a particular CI job and nowhere else? Well, let&rsquo;s just try running the CI pipeline again and see what happens. Maybe the problem will go away. Hopefully, the problem goes away.</p><p>&hellip;</p><p>Nope. Still fails.</p><p>&hellip;</p><p>Rats.</p><p>Well, I&rsquo;ll spare you the gory details that it took for me to finally figure this one out. But the cause of the bug was me accidentally freeing an object that I should never have freed.</p><p>This meant that the corresponding memory segment <em>could be</em>&mdash;but, importantly, <em>did not necessarily have to be</em>&mdash;filled with garbage data. And this is why only the Flatpak job&rsquo;s test run failed&hellip;well, at first, anyway. By changing around some of the test cases, I was able to get the native CI tests and local tests to fail. And this is what eventually clued me into the true nature of this bug.</p><p>So, after spending the better part of two weeks, here is the fix I ended up with:</p><div class="highlight"><pre tabindex="0"><code class="language-diff"><span style="display: flex;"><span><span style="color: #75715e;">@@ -94,7 +94,7 @@ test_clue_matches (WordList *word_list,</span></span></span><span style="display: flex;"><span><span style="color: #75715e;"></span> guint clue_index,</span></span><span style="display: flex;"><span> const gchar *expected_words[])</span></span><span style="display: flex;"><span> {</span></span><span style="display: flex;"><span><span style="color: #f92672;">- g_autofree IpuzClue *clue = NULL;</span></span></span><span style="display: flex;"><span><span style="color: #f92672;"></span><span style="color: #a6e22e;">+ const IpuzClue *clue = NULL;</span></span></span><span style="display: flex;"><span><span style="color: #a6e22e;"></span> g_autoptr (WordArray) clue_matches = NULL;</span></span><span style="display: flex;"><span> g_autoptr (WordArray) expected_word_array = NULL;</span></span></code></pre></div></description><author>Victor Ma</author><dc:creator>Victor Ma</dc:creator><pubDate>Wed, 15 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://victorma.ca/posts/gsoc-8/</guid></item><item><title>Jordan Petridis: Nightly Flatpak CI gets a cache</title><link>https://blogs.gnome.org/alatiera/2025/10/14/nightly-flatpak-ci-gets-a-cache/</link><description><p>Recently I got around tackling a long standing issue for good. There were multiple attempts in the past 6 years to cache <a class="external" href="https://github.com/flatpak/flatpak-builder">flatpak-builder</a> artifacts with Gitlab but none had worked so far.</p><p>On the technical side of things, flatpak-builder relies heavily on <a class="external" href="https://en.wikipedia.org/wiki/Extended_file_attributes">extended attributes</a> (xattrs) on files to do cache validation. Using gitlab’s built-in cache or artifacts mechanisms results in a plain zip archive which strips all the attributes from the files, causing the cache to always be invalid once restored. Additionally the hardlinks/symlinks in the cache break. One workaround for this is to always tar the directories and then manually extract them after they are restored.</p><p>On the infrastructure of things we stumble once again into Gitlab. When a cache or artifact is created, it’s uploaded into the Gitlab’s instance storage so it can later be reused/redownloaded into any runner. While this is great, it also quickly ramps up the network egress bill we have to pay along with storage.
 And since its a public gitlab instance that anyone can make request against repositories, it gets out of hand fast.</p><p>Couple weeks ago Bart pointed me out to <a class="external" href="https://flathub.org/">Flathub</a>’s workaround for this same problem. It comes down to making it someone else problem, and ideally one someone who is willing to fund FOSS infrastructure. We can use <a class="external" href="https://oras.land/">ORAS</a> to wrap files and directories into an OCI wrapper and publish it to public registries. And it worked. Quite handy! OCI images are the new tarballs.</p><p>Now when a pipeline run against your default branch (and assuming it’s protected) it will create a cache artifact and upload to the currently configured OCI registry. Afterwards, any build, including Merge Request pipelines, will download the image, extract the artifacts and check how much of it is still valid.</p><p>From some quick tests and numbers, <a class="external" href="https://gitlab.gnome.org/GNOME/gnome-builder">GNOME Builder</a> went from a ~16 minute build to 6 minutes for our x86_64 runners. While on the AArch64 runner the impact was even bigger, going from 50 minutes to 16 minutes. Not bad. The more modules you are building in your manifest, the more noticeable it is.</p><p>Unlike <a class="external" href="https://www.buildstream.build/">Buildstream</a>, there is no Content Addressable Server and flatpak-builder itself isn’t aware of the artifacts we publish or can associate them with the cache keys. The OCI/ORAS cache artifacts are manual and a bit hacky of a solution but works well in practice and until we have better tooling. To optimize a bit better for less cache-misses consider building modules from pinned commits/tags/tarballs and building modules from moving branches as late as possible.</p><p>If you are curious in the details, take a look at the <a class="external" href="https://gitlab.gnome.org/GNOME/citemplates/-/merge_requests/128">related Merge Request</a> in the templates repository and the follow up commits.</p><p>Free Palestine <img alt="✊" class="wp-smiley" src="https://s.w.org/images/core/emoji/16.0.1/72x72/270a.png" style="height: 1em;" /></p></description><author>Jordan Petridis</author><dc:creator>Jordan Petridis</dc:creator><pubDate>Tue, 14 Oct 2025 18:00:17 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/alatiera/2025/10/14/nightly-flatpak-ci-gets-a-cache/</guid></item><item><title>Jordan Petridis: The Flatpak Runtime drops the 32-bit compatibility extension</title><link>https://blogs.gnome.org/alatiera/2025/10/13/flatpak-32bit/</link><description><p>Last month GNOME 49 was <a class="external" href="https://release.gnome.org/49/">released</a>, very smooth overall, especially given the amount of changes <a href="https://blogs.gnome.org/sophieh/2025/06/13/making-gnomes-gdkpixbuf-image-loading-safer/">across</a> <a href="https://blogs.gnome.org/alatiera/2025/06/08/the-x11-session-removal/">the entire</a> <a href="https://blogs.gnome.org/adrianvovk/2025/06/10/gnome-systemd-dependencies/">stack</a> that we shipped.</p><p>One thing that is missing and that flew under the radar however, is that 32 bit Compatibility extension (org.gnome.Platform.i386.Compat) of the GNOME Flatpak Runtime is now gone. We were planning on making an announcement earlier but life got in the way.</p><p>That extension is a 32-bit version of the Runtime that applications could request to use. This is mostly helpful so <a class="external" href="https://www.winehq.org/">Wine</a> can use a 32 bit environment to run against. However your wine or legacy applications most likely don’t require a 32 bit build of GTK 4, libadwaita or WebkitGTK.</p><p>We rebuild all of GNOME from the latest commits in git in each module, at least twice a day. This includes 2 builds of WebkitGTK, a build of mozjs and a couple of rust libraries and applications. Multiplied for each architecture we support. This is no small task for our CI machines to handle. There were also a couple of updates that were blocked on 32-bit specific build failures, as projects rarely test for that before merging the code. Suffice to say that supporting builds that almost nobody used or needed was a universal annoyance across developers and projects.</p><p>When we lost our main pool of donated CI machines and builders, the first thing in the <a class="external" href="https://gitlab.gnome.org/GNOME/gnome-build-meta/-/commit/2e6283f75f0d61d365590c0bd8cb050854655b6b">chopping block</a> was the 32-bit build of the runtime. It affected no applications, as none are relying on the Nightly version of the extension but it would affect some applications on Flathub once released.</p><p>In order to keep the applications working, and to avoid having to overload our runners again, we thought about another approach. In theory it would be possible to make the runtime compatible with the org.Freedesktop.i386.Compat extension point instead. We already use freedesktop-sdk as the base for the runtime so we did not expect many issues.</p><p>There were exactly 4 applications that made use of the gnome specific extension, 2 in Flathub, 1 in Flathub Beta and 1 archived.</p><p>Abderrahim and I worked on porting all the application to the GNOME 49 runtime and have Pull Requests open. The developers of <a class="external" href="https://github.com/flathub/com.usebottles.bottles/pull/506">Bottles</a> were great help in our <a class="external" href="https://github.com/flathub/com.usebottles.bottles/pull/495">testing</a> and the subsequent PR is almost <a class="external" href="https://github.com/flathub/com.usebottles.bottles/pull/506">ready</a> to be merged. <a class="external" href="https://github.com/flathub/net.lutris.Lutris/pull/497">Lutris</a> and <a class="external" href="https://github.com/flathub/io.github.sharkwouter.Minigalaxy/pull/96">Minigalaxy</a> need some extra work to upgrade the runtime but its for unrelated reasons.</p><p>Since everything was working we never re-published the i386 GNOME compatibility extension again in Nightly, and thus we also didn’t for GNOME 49. As a result, the GNOME Runtime is only available for x86_64 and AArch64.</p><p>Couple years ago we dropped the normal armv7 and i386 build as of the Runtime. With the i386 compatibility extension also gone, it means that we no longer have any 32 bit targets we QA before releasing GNOME as a whole. Previously, all modules we released would be guaranteed to at least compile for i386/x86 but going forward that will not be the case.</p><p>Some projects, for example glib, have their own CI specifically for 32 bit architectures. What was a project-wide guarantee before, is now a per-project opt-in. While many maintainers will no longer go out of their way to fix 32 bit specific issues anymore, they will most likely still review and merge any patches sent their way.</p><p>If you are a distributor, relying on 32 bit builds of GNOME, you will now be expected to debug and fix issues on your own for the majority of the projects. Alternatively you could also get involved upstream and help avoid further bit rot of 32 bit builds.</p><p>Free Palestine <img alt="✊" class="wp-smiley" src="https://s.w.org/images/core/emoji/16.0.1/72x72/270a.png" style="height: 1em;" /></p></description><author>Jordan Petridis</author><dc:creator>Jordan Petridis</dc:creator><pubDate>Mon, 13 Oct 2025 06:00:20 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/alatiera/2025/10/13/flatpak-32bit/</guid></item><item><title>Bilal Elmoussaoui: Testing a Rust library - Code Coverage</title><link>https://belmoussaoui.com/blog/22-testing-rust-lib-coverage/</link><description><p>It has been a couple of years since I started working on a Rust library called <a href="https://lib.rs/crates/oo7" rel="nofollow noreferrer">oo7</a> as a Secret Service client implementation.The library ended up also having support for per-sandboxed app keyring using the Secret portal with a seamless API for end-users that makes usage from the application side straightforward.</p><p>The project, with time, grew support for various components:</p><ul><li><a href="https://github.com/bilelmoussaoui/oo7/tree/main/cli" rel="nofollow noreferrer">oo7-cli</a>: A secret-tool replacement but much better, as it allows not only interacting with the Secret service on the DBus session bus but also with any keyring.<code>oo7-cli --app-id com.belmoussaoui.Authenticator list</code>, for example, allows you to read the sandboxed app with app-id <code>com.belmoussaoui.Authenticator</code>'s keyring and list its contents, something that is not possible with secret-tool.</li><li><a href="https://github.com/bilelmoussaoui/oo7/tree/main/portal" rel="nofollow noreferrer">oo7-portal</a>: A server-side implementation of the Secret portal mentioned above. Straightforward, thanks to my other library ASHPD.</li><li><a href="https://github.com/bilelmoussaoui/oo7/tree/main/cargo-credential" rel="nofollow noreferrer">cargo-credential-oo7</a>: A <a href="https://doc.rust-lang.org/stable/cargo/reference/registry-authentication.html#registry-authentication" rel="nofollow noreferrer">cargo credential provider</a> built using oo7 instead of <a href="https://github.com/rust-lang/cargo/tree/master/credential/cargo-credential-libsecret" rel="nofollow noreferrer">libsecret</a>.</li><li><a href="https://github.com/bilelmoussaoui/oo7/tree/main/server" rel="nofollow noreferrer">oo7-daemon</a>: A server-side implementation of the Secret service.</li></ul><p>The last component was kickstarted by <a href="https://github.com/warusadura" rel="nofollow noreferrer">Dhanuka Warusadura</a>, as we already had the foundation for that in the client library, especially the file backend reimplementation of gnome-keyring. The project is slowly progressing, but it is almost there!</p><p>The problem with replacing such a very sensitive component like gnome-keyring-daemon is that you have to make sure the very sensitive user data is not corrupted, lost, or inaccessible. For that, we need to ensure that both the file backend implementation in the <code>oo7</code> library and the daemon implementation itself are well tested.</p><p>That is why I spent my weekend, as well as a whole day off, working on improving the test suite of the wannabe core component of the Linux desktop.</p><h2 id="coverage-report">Coverage Report</h2><p>One metric that can give the developer some insight into which lines of code or functions of the codebase are executed when running the test suite is code coverage.</p><p>In order to get the coverage of a Rust project, you can use a project like <a href="https://github.com/xd009642/tarpaulin/" rel="nofollow noreferrer">Tarpaulin</a>, which integrates with the Cargo build system.For a simple project, a command like this, after installing Tarpaulin, can give you an HTML report:</p><pre class="language-bash " style="background-color: #2e3440; color: #d8dee9;"><code class="language-bash"><span style="color: #88c0d0;">cargo</span><span> tarpaulin </span><span style="color: #81a1c1;">\</span><span>  --package oo7 </span><span style="color: #81a1c1;">\</span><span>  --lib </span><span style="color: #81a1c1;">\</span><span>  --no-default-features </span><span style="color: #81a1c1;">\</span><span>  --features </span><span style="color: #a3be8c;">&quot;tracing,tokio,native_crypto&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore-panics </span><span style="color: #81a1c1;">\</span><span>  --out Html </span><span style="color: #81a1c1;">\</span><span>  --output-dir coverage</span></code></pre><p>Except in our use case, it is slightly more complicated. The client library supports switching between Rust native cryptographic primitives crates or using OpenSSL. We must ensure that both are tested.</p><p>For that, we can export our report in LCOV for native crypto and do the same for OpenSSL, then combine the results using a tool like <a href="https://crates.io/crates/grcov" rel="nofollow noreferrer">grcov</a>.</p><pre class="language-bash " style="background-color: #2e3440; color: #d8dee9;"><code class="language-bash"><span style="color: #88c0d0;">mkdir</span><span> -p coverage-raw</span><span style="color: #88c0d0;">cargo</span><span> tarpaulin </span><span style="color: #81a1c1;">\</span><span>  --package oo7 </span><span style="color: #81a1c1;">\</span><span>  --lib </span><span style="color: #81a1c1;">\</span><span>  --no-default-features </span><span style="color: #81a1c1;">\</span><span>  --features </span><span style="color: #a3be8c;">&quot;tracing,tokio,native_crypto&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore-panics </span><span style="color: #81a1c1;">\</span><span>  --out Lcov </span><span style="color: #81a1c1;">\</span><span>  --output-dir coverage-raw</span><span style="color: #88c0d0;">mv</span><span> coverage-raw/lcov.info coverage-raw/native-tokio.info</span><span></span><span style="color: #88c0d0;">cargo</span><span> tarpaulin </span><span style="color: #81a1c1;">\</span><span>  --package oo7 </span><span style="color: #81a1c1;">\</span><span>  --lib </span><span style="color: #81a1c1;">\</span><span>  --no-default-features </span><span style="color: #81a1c1;">\</span><span>  --features </span><span style="color: #a3be8c;">&quot;tracing,tokio,openssl_crypto&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore-panics </span><span style="color: #81a1c1;">\</span><span>  --out Lcov </span><span style="color: #81a1c1;">\</span><span>  --output-dir coverage-raw</span><span style="color: #88c0d0;">mv</span><span> coverage-raw/lcov.info coverage-raw/openssl-tokio.info</span></code></pre><p>and then combine the results with</p><pre class="language-bash " style="background-color: #2e3440; color: #d8dee9;"><code class="language-bash"><span style="color: #88c0d0;">cat</span><span> coverage-raw/</span><span style="color: #81a1c1;">*</span><span>.info </span><span style="color: #81a1c1;">&gt;</span><span> coverage-raw/combined.info</span><span></span><span style="color: #88c0d0;">grcov</span><span> coverage-raw/combined.info </span><span style="color: #81a1c1;">\</span><span>  --binary-path target/debug/ </span><span style="color: #81a1c1;">\</span><span>  --source-dir . </span><span style="color: #81a1c1;">\</span><span>  --output-type html </span><span style="color: #81a1c1;">\</span><span>  --output-path coverage </span><span style="color: #81a1c1;">\</span><span>  --branch </span><span style="color: #81a1c1;">\</span><span>  --ignore-not-existing </span><span style="color: #81a1c1;">\</span><span>  --ignore </span><span style="color: #a3be8c;">&quot;**/portal/*&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore </span><span style="color: #a3be8c;">&quot;**/cli/*&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore </span><span style="color: #a3be8c;">&quot;**/tests/*&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore </span><span style="color: #a3be8c;">&quot;**/examples/*&quot; </span><span style="color: #81a1c1;">\</span><span>  --ignore </span><span style="color: #a3be8c;">&quot;**/target/*&quot;</span></code></pre><p>To make things easier, I added a bash script to the project repository that generates coverage for both the client library and the server implementation, as both are very sensitive and require intensive testing.</p><p>With that script in place, I also used it on CI to generate and upload the coverage reports at <a href="https://bilelmoussaoui.github.io/oo7/coverage/" rel="nofollow noreferrer">https://bilelmoussaoui.github.io/oo7/coverage/</a>. The results were pretty bad when I started.</p><h2 id="testing">Testing</h2><p>For the client side, most of the tests are straightforward to write; you just need to have a secret service implementation running on the DBus session bus. Things get quite complicated when the methods you have to test require a Prompt, a mechanism used in the spec to define a way for the user to be prompted for a password to unlock the keyring, create a new collection, and so on. The prompter is usually provided by a system component. For now, we just skipped those tests.</p><p>For the server side, it was mostly about setting up a peer-to-peer connection between the server and the client:</p><pre class="language-rust " style="background-color: #2e3440; color: #d8dee9;"><code class="language-rust"><span style="color: #81a1c1;">let</span><span> guid </span><span style="color: #81a1c1;">= </span><span>zbus</span><span style="color: #81a1c1;">::</span><span>Guid</span><span style="color: #81a1c1;">::</span><span>generate()</span><span style="color: #eceff4;">;</span><span style="color: #81a1c1;">let </span><span>(p0</span><span style="color: #eceff4;">,</span><span> p1) </span><span style="color: #81a1c1;">= </span><span>tokio</span><span style="color: #81a1c1;">::</span><span>net</span><span style="color: #81a1c1;">::</span><span>UnixStream</span><span style="color: #81a1c1;">::</span><span>pair()</span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">unwrap</span><span>()</span><span style="color: #eceff4;">;</span><span></span><span style="color: #81a1c1;">let </span><span>(client_conn</span><span style="color: #eceff4;">,</span><span> server_conn) </span><span style="color: #81a1c1;">= </span><span>tokio</span><span style="color: #81a1c1;">::</span><span>try_join</span><span style="color: #81a1c1;">!</span><span>(</span><span>    </span><span style="color: #616e88;">// Client</span><span>    zbus</span><span style="color: #81a1c1;">::</span><span>connection</span><span style="color: #81a1c1;">::</span><span>Builder</span><span style="color: #81a1c1;">::</span><span>unix_stream(p0)</span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">p2p</span><span>()</span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">build</span><span>()</span><span style="color: #eceff4;">,</span><span>    </span><span style="color: #616e88;">// Server</span><span>    zbus</span><span style="color: #81a1c1;">::</span><span>connection</span><span style="color: #81a1c1;">::</span><span>Builder</span><span style="color: #81a1c1;">::</span><span>unix_stream(p1)</span><span>        </span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">server</span><span>(guid)</span><span>        </span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">unwrap</span><span>()</span><span>        </span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">p2p</span><span>()</span><span>        </span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">build</span><span>()</span><span style="color: #eceff4;">,</span><span>)</span><span style="color: #81a1c1;">.</span><span style="color: #88c0d0;">unwrap</span><span>()</span><span style="color: #eceff4;">;</span></code></pre><p>Thanks to the design of the client library, we keep the low-level APIs under <code>oo7::dbus::api</code>, which allowed me to straightforwardly write a bunch of server-side tests already.</p><p>There are still a lot of tests that need to be written and a few missing bits to ensure oo7-daemon is in an acceptable shape to be proposed as an alternative to gnome-keyring.</p><h2 id="don-t-overdo-it">Don't overdo it</h2><p>The coverage report is not meant to be targeted at 100%. It’s not a video game. You should focus only on the critical parts of your code that must be tested. Testing a <code>Debug</code> impl or a <code>From</code> trait (if it is straightforward) is not really useful, other than giving you a small dose of dopamine from "achieving" something.</p><p>Till then, may your coverage never reach 100%.</p></description><author>Bilal Elmoussaoui</author><dc:creator>Bilal Elmoussaoui</dc:creator><pubDate>Mon, 13 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://belmoussaoui.com/blog/22-testing-rust-lib-coverage/</guid></item><item><title>Hubert Figuière: Dev Log September 2025</title><link>https://www.figuiere.net/hub/wlog/dev-log-september-2025/</link><description><p>Not as much as I wanted to do was done in September.</p><h2 id="libopenraw">libopenraw</h2><p>Extracting more of the calibration values for colour correction onDNG. Currently work on fixing the purple colour cast.</p><p>Added Nikon ZR and EOS C50.</p><h2 id="exiftool">ExifTool</h2><p>Submitted some metadata updates to ExifTool. Because it nice to have,and also because libopenraw uses some of these autogenerated: I have aPerl script to generate Rust code from it (it used to do C++).</p><h2 id="niepce">Niepce</h2><p>Finally merged the develop branch with all the import dialog workafter having requested that it be removed from Damned Lies to notstrain the translator is there is a long way to go before we canfreeze the strings.</p><h2 id="supporting-cast">Supporting cast</h2><p>Among the number of packages I maintain / update on flathub, LightZoneis a digital photo editing application written inJava<sup class="footnote-reference"><a href="https://www.figuiere.net/hub/wlog/atom.xml#java">1</a></sup>. Updating to the latest runtime 25.08 cause it to ignorethe HiDPI setting. It will honour <code>GDK_SCALE</code> environment but thisisn't set. So I wrote the small command line too <code>gdk-scale</code> to outputthe value. See <a href="https://gitlab.com/hfiguiere/gdk-scale">gdk-scale ongitlab</a>. And another patch inthe wrapper script.</p><p>HiDPI support remains a mess across the board. Fltk just recentlygained support for it (it's used by a few audio plugins).</p><div class="footnote-definition" id="java"><sup class="footnote-definition-label">1</sup><p>Don't try this at home.</p></div></description><author>Hubert Figuière</author><dc:creator>Hubert Figuière</dc:creator><pubDate>Sat, 11 Oct 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://www.figuiere.net/hub/wlog/dev-log-september-2025/</guid></item><item><title>Sebastian Wick: SO_PEERPIDFD Gets More Useful</title><link>https://blog.sebastianwick.net/posts/so-peerpidfd-gets-more-useful/</link><description><p>A while ago I wrote about <a href="https://blog.sebastianwick.net/posts/so-peerpidfd-usefulness/">the limited usefulness of SO_PEERPIDFD</a>. for authenticating sandboxed applications. The core problem was simple: while pidfds gave us a race-free way to identify a process, we still had no standardized way to figure out what that process actually <em>was</em> - which sandbox it ran in, what application it represented, or what permissions it should have.</p><p>The situation has improved considerably since then.</p><h2 id="cgroup-xattrs">cgroup xattrs</h2><p>Cgroups now support user extended attributes. This feature allows arbitrary metadata to be attached to cgroup inodes using standard xattr calls.</p><p>We can change flatpak (or snap, or any other container engine) to create a cgroup for application instances it launches, and attach metadata to it using xattrs. This metadata can include the sandboxing engine, application ID, instance ID, and any other information the compositor or D-Bus service might need.</p><p>Every process belongs to a cgroup, and you can query which cgroup a process belongs to through its pidfd - completely race-free.</p><h2 id="standardized-authentication">Standardized Authentication</h2><p>Remember the complexity from the original post? Services had to implement different lookup mechanisms for different sandbox technologies:</p><ul><li>For flatpak: look in <code>/proc/$PID/root/.flatpak-info</code></li><li>For snap: shell out to <code>snap routine portal-info</code></li><li>For firejail: no solution</li><li>&hellip;</li></ul><p>All of this goes away. Now there&rsquo;s a single path:</p><ol><li>Accept a connection on a socket</li><li>Use <code>SO_PEERPIDFD</code> to get a pidfd for the client</li><li>Query the client&rsquo;s cgroup using the pidfd</li><li>Read the cgroup&rsquo;s user xattrs to get the sandbox metadata</li></ol><p>This works the same way regardless of which sandbox engine launched the application.</p><h2 id="a-kernel-feature-not-a-systemd-one">A Kernel Feature, Not a systemd One</h2><p>It&rsquo;s worth emphasizing: cgroups are a Linux kernel feature. They have no dependency on systemd or any other userspace component. Any process can manage cgroups and attach xattrs to them. The process only needs appropriate permissions and is restricted to a subtree determined by the cgroup namespace it is in. This makes the approach universally applicable across different init systems and distributions.</p><p>To support non-Linux systems, we might even be able to abstract away the cgroup details, by providing a varlink service to register and query running applications. On Linux, this service would use cgroups and xattrs internally.</p><h2 id="replacing-socket-per-app">Replacing Socket-Per-App</h2><p>The old approach - creating dedicated wayland, D-Bus, etc. sockets for each app instance and attaching metadata to the service which gets mapped to connections on that socket - can now be retired. The pidfd + cgroup xattr approach is simpler: one standardized lookup path instead of mounting special sockets. It works everywhere: any service can authenticate any client without special socket setup. And it&rsquo;s more flexible: metadata can be updated after process creation if needed.</p><p>For compositor and D-Bus service developers, this means you can finally implement proper sandboxed client authentication without needing to understand the internals of every container engine. For sandbox developers, it means you have a standardized way to communicate application identity without implementing custom socket mounting schemes.</p></description><author>Sebastian Wick</author><dc:creator>Sebastian Wick</dc:creator><pubDate>Fri, 10 Oct 2025 17:04:34 GMT</pubDate><guid isPermaLink="true">https://blog.sebastianwick.net/posts/so-peerpidfd-gets-more-useful/</guid></item><item><title>Jiri Eischmann: Fedora & CentOS at LinuxDays 2025</title><link>https://enblog.eischmann.cz/2025/10/07/fedora-centos-at-linuxdays-2025/</link><description><p>Another edition of <a href="https://www.linuxdays.cz/">LinuxDays</a> took place in Prague last weekend &#8211; the country&#8217;s largest Linux event drawing more than 1200 attendees and as every yearm we had a Fedora booth there &#8211; this time we also representing CentOS.</p>   <p>I was really glad that <a href="https://fedoraproject.org/wiki/User:Humaton">Tomáš Hrčka</a> helped me staff the booth. I&#8217;m focused on the desktop part of Fedora and don&#8217;t follow the rest of the project in such detail. As a member of FESCo and Fedora infra team he has a great overview of what is going on in the project and our knowledge complemented each other very well when answering visitors&#8217; questions. I&#8217;d also like to thank Adellaide Mikova who helped us tremendously despite not being a technical person.</p>   <figure class="wp-block-image size-large has-custom-border"><img alt="" class="wp-image-1976" height="768" src="https://enblog.eischmann.cz/wp-content/uploads/2025/10/linuxdays-2025-1024x768.webp" style="border-width: 1px;" width="1024" /></figure>   <p>This year I took our heavy 4K HDR display and showcased HDR support in Fedora Linux whose implementation was a multi-year effort for our team. I played HDR videos in two different video players (one that supports HDR and one that doesn&#8217;t), so that people could see a difference, and explained what needed to be implemented to make it work.</p>   <p>Another highlight of our booth were the laptops that run Fedora exceptionally well: Slimbook and especially Framework Laptop. Visitors were checking them out and we spoke about how the Fedora community works with the vendors to make sure Fedora Linux runs flawlessly on their laptops.</p>   <figure class="wp-block-image size-large has-custom-border"><img alt="" class="wp-image-1977" height="768" src="https://enblog.eischmann.cz/wp-content/uploads/2025/10/linuxdays-2025-1-1024x768.webp" style="border-width: 1px;" width="1024" /></figure>   <p>We also got a lot of questions about CentOS. We met quite a few people who were surprised that CentOS still exists. We explained to them that it lives on in the form of CentOS Stream and tried to dispel some of common misconceptions surrounding it.</p>   <p>Exhausting as it is, I really enjoy going to LinuxDays, but it&#8217;s also a great opportunity to explain things and get direct feedback from the community.</p>   <p></p></description><author>Jiri Eischmann</author><dc:creator>Jiri Eischmann</dc:creator><pubDate>Tue, 07 Oct 2025 16:23:54 GMT</pubDate><guid isPermaLink="true">https://enblog.eischmann.cz/2025/10/07/fedora-centos-at-linuxdays-2025/</guid></item><item><title>Ignacio Casal Quinteiro: Servo GTK</title><link>https://blogs.gnome.org/nacho/2025/10/01/servo-gtk/</link><description><p>I just checked and it seems that it has been 9 years since my last post in this blog :O</p><p>As part of my job at Amazon I started working in a GTK widget which will allow embedding a Servo Webview inside a GTK application. This was mostly a research project just to understand the current state of Servo and whether it was at a good enough state to migrate from WebkitGTK to it. I have to admit that it is always a pleasure to work with Rust and the great gtk-rs bindings. Instead, Servo while it is not yet ready for production, or at least not for what we need in our product, it was simple to embed and to get something running in just a few days. The community is also amazing, I had some problems along the way and they were providing good suggestions to get me unblocked in no time.</p><p>This project can be found in the following git repo: <a class="external" href="https://github.com/nacho/servo-gtk">https://github.com/nacho/servo-gtk</a></p><p>I also created some Issues with some tasks that can be done to improve the project in case that anyone is interested.</p><p>Finally I leave you here a the usual mandatory screenshot:</p><p><a href="https://blogs.gnome.org/nacho/files/2025/10/Screenshot-from-2025-10-01-15-46-00.png"><img alt="" class="aligncenter size-large wp-image-6849" height="623" src="https://blogs.gnome.org/nacho/files/2025/10/Screenshot-from-2025-10-01-15-46-00-1024x996.png" width="640" /></a></p></description><author>Ignacio Casal Quinteiro</author><dc:creator>Ignacio Casal Quinteiro</dc:creator><pubDate>Wed, 01 Oct 2025 13:49:15 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/nacho/2025/10/01/servo-gtk/</guid></item><item><title>Debarshi Ray: Ollama on Fedora Silverblue</title><link>https://debarshiray.wordpress.com/2025/10/01/ollama-on-fedora-silverblue/</link><description><p><em>I found myself dealing with various rough edges and questions around running <a href="https://ollama.com/">Ollama</a> on <a href="https://fedoraproject.org/silverblue/">Fedora Silverblue</a> for the past few months.  These arise from the fact that there are a few different ways of installing Ollama, <code>/usr</code> is a read-only mount point on Silverblue, people have different kinds of GPUs or none at all, the program that&#8217;s using Ollama might be a graphical application in a Flatpak or part of the operating system image, and so on.  So, I thought I&#8217;ll document a few different use-cases in one place for future reference or maybe someone will find it useful.</em></p>   <h3 class="wp-block-heading"><strong>Different ways of installing Ollama</strong></h3>   <p>There are at least three different ways of installing Ollama on Fedora Silverblue.  Each of those have their own nuances and trade-offs that we will explore later.</p>   <p>First, there&#8217;s the popular single command POSIX <a href="https://ollama.com/download/linux">shell script installer</a>:</p>   <pre class="wp-block-code"><code>$ curl -fsSL https://ollama.com/install.sh | sh</code></pre>   <p></p>   <p>There is a <a href="https://github.com/ollama/ollama/blob/main/docs/linux.md">manual step by step</a> variant for those who are uncomfortable with running a script straight off the Internet.  They both install Ollama in the operating system&#8217;s <code>/usr/local</code> or <code>/usr</code> or <code>/</code> prefix, depending on which one comes first in the <code>PATH</code> environment variable, and attempts to enable and activate a systemd service unit that runs <code>ollama serve</code>.</p>   <p>Second, there&#8217;s a <a href="https://hub.docker.com/r/ollama/ollama">docker.io/ollama/ollama</a> OCI <a href="https://ollama.com/blog/ollama-is-now-available-as-an-official-docker-image">image</a> that can be used to put Ollama in a container.  The container runs <code>ollama serve</code> by default.</p>   <p>Finally, there&#8217;s Fedora&#8217;s <a href="https://src.fedoraproject.org/rpms/ollama/">ollama</a> RPM.</p>   <h3 class="wp-block-heading"><strong>Surprise</strong></h3>   <p>Astute readers might be wondering why I mentioned the shell script installer in the context of Fedora Silverblue, because <code>/usr</code> is a read-only mount point.  Won&#8217;t it break the script?  Not really, or the script breaks but not in the way one might expect.</p>   <p>Even though, <code>/usr</code> is read-only on Silverblue, <code>/usr/local</code> is not, because it&#8217;s a symbolic link to /var/usrlocal, and Fedora defaults to putting /usr/local/bin earlier in the PATH environment variable than the other prefixes that the installer attempts to use, as long as <code>pkexec(1)</code> isn&#8217;t being used.  This happy coincidence allows the installer to place the Ollama binaries in their right places.</p>   <p>The script <a href="https://github.com/ollama/ollama/pull/12455">does fail</a> eventually when attempting to create the systemd service unit to run <code>ollama serve</code>, because it tries to create an ollama user with <code>/usr/share/ollama</code> as its home directory.  However, this half-baked installation works surprisingly well as long as nobody is trying to use an AMD GPU.</p>   <p>NVIDIA GPUs work, if the proprietary driver and <code>nvidia-smi(1)</code> are present in the operating system, which are provided by the <code>kmod-nvidia</code> and <code>xorg-x11-drv-nvidia-cuda</code> packages from <a href="https://rpmfusion.org/">RPM Fusion</a>; and so does CPU fallback.</p>   <p>Unfortunately, the results would be the same if the shell script installer is used inside a <a href="https://containertoolbx.org/">Toolbx</a> container.  It will fail to create the systemd service unit because it can&#8217;t connect to the system-wide instance of systemd.</p>   <p>Using AMD GPUs with Ollama is an important use-case.  So, let&#8217;s see if we can do better than trying to manually work around the hurdles faced by the script.</p>   <h3 class="wp-block-heading"><strong>OCI image</strong></h3>   <p>The <code>docker.io/ollama/ollama</code> <a href="https://opencontainers.org/">OCI</a> image requires the user to know what processing hardware they have or want to use.  To use it only with the CPU without any GPU acceleration:</p>   <pre class="wp-block-code"><code>$ podman run \    --name ollama \    --publish 11434:11434 \    --rm \    --security-opt label=disable \    --volume ~/.ollama:/root/.ollama \    docker.io/ollama/ollama:latest</code></pre>   <p></p>   <p>This will be used as the baseline to enable different kinds of GPUs.  Port 11434 is the default port on which the Ollama server listens, and <code>~/.ollama</code> is the default directory where it stores its SSH keys and artificial intelligence models.</p>   <p>To enable NVIDIA GPUs, the proprietary driver and <code>nvidia-smi(1)</code> must be present on the host operating system, as provided by the <code>kmod-nvidia</code> and <code>xorg-x11-drv-nvidia-cuda</code> packages from <a href="https://rpmfusion.org/">RPM Fusion</a>.  The user space driver has to be injected into the container from the host using <a href="https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/latest/index.html">NVIDIA Container Toolkit</a>, provided by the <a href="https://src.fedoraproject.org/rpms/golang-github-nvidia-container-toolkit">nvidia-container-toolkit</a> package from Fedora, for Ollama to be able to use the GPUs.</p>   <p>The first step is to generate a <a href="https://github.com/cncf-tags/container-device-interface">Container Device Interface</a> (or CDI) specification for the user space driver:</p>   <pre class="wp-block-code"><code>$ sudo nvidia-ctk cdi generate --output /etc/cdi/nvidia.yaml……</code></pre>   <p></p>   <p>Then the container needs to be run with access to the GPUs, by adding the <code>--gpus</code> option to the baseline command above:</p>   <pre class="wp-block-code"><code>$ podman run \    --gpus all \    --name ollama \    --publish 11434:11434 \    --rm \    --security-opt label=disable \    --volume ~/.ollama:/root/.ollama \    docker.io/ollama/ollama:latest</code></pre>   <p></p>   <p>AMD GPUs don&#8217;t need the driver to be injected into the container from the host, because it can be bundled with the OCI image.  Therefore, instead of generating a CDI specification for them, an image that bundles the driver must be used.  This is done by using the <code>rocm</code> tag for the <code>docker.io/ollama/ollama</code> image.</p>   <p>Then container needs to be run with access to the GPUs.  However, the <code>--gpus</code> option only works for NVIDIA GPUs.  So, the specific devices need to be spelled out by adding the <code>--devices</code> option to the baseline command above:</p>   <pre class="wp-block-code"><code>$ podman run \    --device /dev/dri \    --device /dev/kfd \    --name ollama \    --publish 11434:11434 \    --rm \    --security-opt label=disable \    --volume ~/.ollama:/root/.ollama \    docker.io/ollama/ollama:rocm</code></pre>   <p></p>   <p>However, because of how AMD GPUs are programmed with <a href="https://en.wikipedia.org/wiki/ROCm">ROCm</a>, it&#8217;s possible that some decent GPUs might not be supported by the <code>docker.io/ollama/ollama:rocm</code> image.  The ROCm compiler needs to explicitly support the GPU in question, and Ollama needs to be built with such a compiler.  Unfortunately, the binaries in the image leave out support for some GPUs that would otherwise work.  For example, my AMD Radeon RX 6700 XT isn&#8217;t supported.</p>   <p>This can be verified with <a href="https://github.com/Syllo/nvtop">nvtop(1)</a> in a Toolbx container.  If there&#8217;s no spike in the GPU and its memory then its not being used.</p>   <p>It will be good to support as many AMD GPUs as possible with Ollama.  So, let&#8217;s see if we can do better.</p>   <h3 class="wp-block-heading"><strong>Fedora&#8217;s ollama RPM</strong></h3>   <p>Fedora offers a very capable <code>ollama</code> RPM, as far as AMD GPUs are concerned, because Fedora&#8217;s ROCm stack supports a lot more GPUs than other builds out there.  It&#8217;s possible to check if a GPU is supported either by using the RPM and keeping an eye on <code>nvtop(1)</code>, or by comparing the name of the GPU shown by rocminfo with those listed in the <a href="https://src.fedoraproject.org/rpms/rocm-rpm-macros/">rocm-rpm-macros</a> RPM.</p>   <p>For example, according to <code>rocminfo</code>, the name for my AMD Radeon RX 6700 XT is <code>gfx1031</code>, which is listed in <code>rocm-rpm-macros</code>:</p>   <pre class="wp-block-code"><code>$ rocminfoROCk module is loaded=====================    HSA System Attributes    =====================    Runtime Version:         1.1Runtime Ext Version:     1.6System Timestamp Freq.:  1000.000000MHzSig. Max Wait Duration:  18446744073709551615 (0xFFFFFFFFFFFFFFFF) (timestamp count)Machine Model:           LARGE                              System Endianness:       LITTLE                             Mwaitx:                  DISABLEDDMAbuf Support:          YES ==========               HSA Agents               ==========               *******                  Agent 1                  *******                    Name:                    AMD Ryzen 7 5800X 8-Core Processor   Uuid:                    CPU-XX                               Marketing Name:          AMD Ryzen 7 5800X 8-Core Processor   Vendor Name:             CPU                                  Feature:                 None specified                       Profile:                 FULL_PROFILE                         Float Round Mode:        NEAR                                 Max Queue Number:        0(0x0)                               Queue Min Size:          0(0x0)                               Queue Max Size:          0(0x0)                               Queue Type:              MULTI                                Node:                    0                                    Device Type:             CPU                                ……*******                  Agent 2                  *******                    Name:                    gfx1031                              Uuid:                    GPU-XX                               Marketing Name:          AMD Radeon RX 6700 XT                Vendor Name:             AMD                                  Feature:                 KERNEL_DISPATCH                      Profile:                 BASE_PROFILE                         Float Round Mode:        NEAR                                 Max Queue Number:        128(0x80)                            Queue Min Size:          64(0x40)                             Queue Max Size:          131072(0x20000)                      Queue Type:              MULTI                                Node:                    1                                    Device Type:             GPU……</code></pre>   <p></p>   <p>The <code>ollama</code> RPM can be installed inside a Toolbx container, or it can be layered on top of the base <a href="https://quay.io/repository/fedora/fedora">registry.fedoraproject.org/fedora</a> image to replace the <code>docker.io/ollama/ollama:rocm</code> image:</p>   <pre class="wp-block-code"><code>FROM registry.fedoraproject.org/fedora:42RUN dnf --assumeyes upgradeRUN dnf --assumeyes install ollamaRUN dnf clean allENV OLLAMA_HOST=0.0.0.0:11434EXPOSE 11434ENTRYPOINT &#091;"/usr/bin/ollama"]CMD &#091;"serve"]</code></pre>   <p></p>   <p>Unfortunately, for obvious reasons, Fedora&#8217;s <code>ollama</code> RPM doesn&#8217;t support NVIDIA GPUs.</p>   <h3 class="wp-block-heading"><strong>Conclusion</strong></h3>   <p>From the puristic perspective of not touching the operating system&#8217;s OSTree image, and being able to easily remove or upgrade Ollama, using an OCI container is the best option for using Ollama on Fedora Silverblue.  Tools like <a href="https://podman.io/">Podman</a> offer a suite of features to manage OCI containers and images that are far beyond what the POSIX shell script installer can hope to offer.</p>   <p>It seems that the realities of GPUs from AMD and NVIDIA prevent the use of the same OCI image, if we want to maximize our hardware support, and force the use of slightly different Podman commands and associated set-up.  We have to create our own image using Fedora&#8217;s <code>ollama</code> RPM for AMD, and the <code>docker.io/ollama/ollama:latest</code> image with NVIDIA Container Toolkit for NVIDIA.</p></description><author>Debarshi Ray</author><dc:creator>Debarshi Ray</dc:creator><pubDate>Wed, 01 Oct 2025 00:30:09 GMT</pubDate><guid isPermaLink="true">https://debarshiray.wordpress.com/2025/10/01/ollama-on-fedora-silverblue/</guid></item><item><title>Hans de Goede: Fedora 43 will ship with FOSS Meteor, Lunar and Arrow Lake MIPI camera support</title><link>https://hansdegoede.dreamwidth.org/31089.html</link><description>Good news the just released 6.17 kernel has support for the IPU7 CSI2 receiver and the missing USBIO drivers have recently landed in linux-next. I have <a href="https://gitlab.com/cki-project/kernel-ark/-/merge_requests/4105">backported</a> the USBIO drivers + a few other camera fixes to the <a href="https://bodhi.fedoraproject.org/updates/FEDORA-2025-a2b653cff6">Fedora 6.17 kernel</a>.<br /><br />I've also prepared an <a href="https://bodhi.fedoraproject.org/updates/FEDORA-2025-bdeff04027">updated libcamera-0.5.2</a> Fedora package with support for IPU7 (Lunar Lake) CSI2 receivers as well as backporting a set of upstream SwStats and AGC fixes, fixing various crashes as well as the bad flicker MIPI camera users have been hitting with libcamera 0.5.2.<br /><br />Together these 2 updates should make Fedora 43's FOSS MIPI camera support work on most Meteor Lake, Lunar Lake and Arrow Lake laptops!<br /><br />If you want to give this a try, install / upgrade to Fedora 43 beta and install all updates. If you've installed rpmfusion's binary IPU6 stack please run: <br /><br /><em>sudo dnf remove akmod-intel-ipu6 'kmod-intel-ipu6*'</em><br /><br />to remove it as it may interfere with the FOSS stack and finally reboot. Please first try with qcam:<br /><br /><em>sudo dnf install libcamera-qcam<br />qcam<br /></em><br />which only tests libcamera and after that give apps which use the camera through pipewire a try like gnome's &quot;Camera&quot; app (snapshot) or video-conferencing in Firefox.<br /><br />Note snapshot on Lunar Lake triggers a bug in the LNL Vulkan code, to avoid this start snapshot from a terminal with:<br /><br /><em>GSK_RENDERER=gl snapshot<br /></em><br />If you have a MIPI camera which still does not work please file a bug <a href="https://fedoraproject.org/wiki/Changes/X86_MIPI_CameraHwEnablement#How_To_Test">following these instructions</a>&nbsp;and drop me an email with the bugzilla link at hansg@kernel.org.<br /><br /><img alt="comment count unavailable" height="12" src="https://www.dreamwidth.org/tools/commentcount?user=hansdegoede&amp;ditemid=31089" style="vertical-align: middle;" width="30" /> comments</description><author>Hans de Goede</author><dc:creator>Hans de Goede</dc:creator><pubDate>Tue, 30 Sep 2025 18:55:09 GMT</pubDate><guid isPermaLink="true">https://hansdegoede.dreamwidth.org/31089.html</guid></item><item><title>Matthew Garrett: Investigating a forged PDF</title><link>https://mjg59.dreamwidth.org/73317.html</link><description>I had to rent a house for a couple of months recently, which is long enough in California that it pushes you into proper tenant protection law. As landlords tend to do, they failed to return my security deposit within the 21 days <a href="https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=1950.5&amp;lawCode=CIV">required by law</a>, having already failed to provide the required notification that I was entitled to an inspection before moving out. Cue some tedious argumentation with the letting agency, and eventually me threatening to take them to small claims court.<br /><br />This post is not about that.<br /><br />Now, under Californian law, the onus is on the <em>landlord</em> to hold and return the security deposit - the agency has no role in this. The only reason I was talking to them is that my lease didn't mention the name or address of the landlord (another <a href="https://leginfo.legislature.ca.gov/faces/codes_displaySection.xhtml?sectionNum=1962&amp;lawCode=CIV">legal violation</a>, but the outcome is just that you get to serve the landlord via the agency). So it was a bit surprising when I received an email from the owner of the agency informing me that they did not hold the deposit and so were not liable - I already knew this.<br /><br />The odd bit about this, though, is that they sent me another copy of the contract, asserting that it made it clear that the landlord held the deposit. I read it, and instead found a clause reading <q>SECURITY: The security deposit will secure the performance of Tenant’s obligations. IER may, but will not be obligated to, apply all portions of said deposit on account of Tenant’s obligations. Any balance remaining upon termination will be returned to Tenant. Tenant will not have the right to apply the security deposit in payment of the last month’s rent. Security deposit held at IER Trust Account.</q>, where IER is <a href="https://www.iersf.com/">International Executive Rentals</a>, the agency in question. Why send me a contract that says you hold the money while you're telling me you don't? And then I read further down and found this:<br /><img alt="Text reading ENTIRE AGREEMENT: The foregoing constitutes the entire agreement between the parties and may bemodified only in writing signed by all parties. This agreement and any modifications, including anyphotocopy or facsimile, may be signed in one or more counterparts, each of which will be deemed anoriginal and all of which taken together will constitute one and the same instrument. The followingexhibits, if checked, have been made a part of this Agreement before the parties’ execution:۞Exhibit 1:Lead-Based Paint Disclosure (Required by Law for Rental Property Built Prior to 1978)۞Addendum 1 The security deposit will be held by (name removed) and applied, refunded, or forfeited in accordance with the terms of this lease agreement." src="https://codon.org.uk/~mjg59/pictures/addendum.png" style="width: 60vw;" /><br />Ok, fair enough, there's an addendum that says the landlord has it (I've removed the landlord's name, it's present in the original).<br /><br />Except. I had no recollection of that addendum. I went back to the copy of the contract I had and discovered:<br /><img alt="The same text as the previous picture, but addendum 1 is empty" src="https://codon.org.uk/~mjg59/pictures/no-addendum.png" style="width: 60vw;" /><br />Huh! But obviously I could just have edited that to remove it (there's no obvious reason for me to, but whatever), and then it'd be my word against theirs. However, I'd been sent the document via <a href="https://www.sharefile.com/rightsignature">RightSignature</a>, an online document signing platform, and they'd added a certification page that looked like this:<br /><img alt="A Signature Certificate, containing a bunch of data about the document including a checksum or the original" src="https://codon.org.uk/~mjg59/pictures/contract-certificate.png" style="width: 60vw;" /><br />Interestingly, the certificate page was identical in both documents, including the checksums, despite the content being different. So, how do I show which one is legitimate? You'd think given this certificate page this would be trivial, but RightSignature provides no documented mechanism whatsoever for anyone to verify any of the fields in the certificate, which is annoying but let's see what we can do anyway.<br /><br />First up, let's look at the PDF metadata. <a href="https://www.pdflabs.com/tools/pdftk-the-pdf-toolkit/"><tt>pdftk</tt></a> has a <tt>dump_data</tt> command that dumps the metadata in the document, including the creation date and the modification date. My file had both set to identical timestamps in June, both listed in UTC, corresponding to the time I'd signed the document. The file containing the addendum? The same creation time, but a modification time of this Monday, shortly before it was sent to me. This time, the modification timestamp was in Pacific Daylight Time, the timezone currently observed in California. In addition, the data included two ID fields, ID0 and ID1. In my document both were identical, in the one with the addendum ID0 matched mine but ID1 was different.<br /><br />These ID tags are intended to be some form of representation (such as a hash) of the document. ID0 is set when the document is created and should not be modified afterwards - ID1 initially identical to ID0, but changes when the document is modified. This is intended to allow tooling to identify whether two documents are modified versions of the same document. The identical ID0 indicated that the document with the addendum was originally identical to mine, and the different ID1 that it had been modified.<br /><br />Well, ok, that seems like a pretty strong demonstration. I had the "I have a very particular set of skills" conversation with the agency and pointed these facts out, that they were an extremely strong indication that my copy was authentic and their one wasn't, and they responded that the document was "re-sealed" every time it was downloaded from RightSignature and that would explain the modifications. This doesn't seem plausible, but it's an argument. Let's go further.<br /><br />My next move was <a href="https://pypi.org/project/pdfalyzer/">pdfalyzer</a>, which allows you to pull a PDF apart into its component pieces. This revealed that the documents were identical, other than page 3, the one with the addendum. This page included tags entitled "touchUp_TextEdit", evidence that the page had been modified using Acrobat. But in itself, that doesn't prove anything - obviously it had been edited at some point to insert the landlord's name, it doesn't prove whether it happened before or after the signing.<br /><br />But in the process of editing, Acrobat appeared to have renamed all the font references on that page into a different format. Every other page had a consistent naming scheme for the fonts, and they matched the scheme in the page 3 I had. Again, that doesn't tell us whether the renaming happened before or after the signing. Or does it?<br /><br />You see, when I completed my signing, RightSignature inserted my name into the document, and did so using a font that wasn't otherwise present in the document (Courier, in this case). That font was named identically throughout the document, except on page 3, where it was named in the same manner as every other font that Acrobat had renamed. Given the font wasn't present in the document until after I'd signed it, this is proof that the page was edited <em>after</em> signing.<br /><br />But eh this is all very convoluted. Surely there's an easier way? Thankfully yes, although I hate it. RightSignature had sent me a link to view my signed copy of the document. When I went there it presented it to me as the original PDF with my signature overlaid on top. Hitting F12 gave me the network tab, and I could see a reference to a <tt>base.pdf</tt>. Downloading that gave me the original PDF, pre-signature. Running <tt>sha256sum</tt> on it gave me an identical hash to the "Original checksum" field. Needless to say, it did not contain the addendum.<br /><br />Why do this? The only explanation I can come up with (and I am obviously guessing here, I may be incorrect!) is that International Executive Rentals realised that they'd sent me a contract which could mean that they <em>were</em> liable for the return of my deposit, even though they'd already given it to my landlord, and after realising this added the addendum, sent it to me, and assumed that I just wouldn't notice (or that, if I did, I wouldn't be able to prove anything). In the process they went from an extremely unlikely possibility of having civil liability for a few thousand dollars (even if they were holding the deposit it's still the landlord's legal duty to return it, as far as I can tell) to doing something that looks extremely like <a href="https://leginfo.legislature.ca.gov/faces/codes_displayText.xhtml?lawCode=PEN&amp;division=&amp;title=13.&amp;part=1.&amp;chapter=4.&amp;article=">forgery</a>.<br /><br />There's a hilarious followup. After this happened, the agency offered to do a screenshare with me showing them logging into RightSignature and showing the signed file with the addendum, and then proceeded to do so. One minor problem - the "Send for signature" button was still there, just below a field saying "Uploaded: 09/22/25". I asked them to search for my name, and it popped up two hits - one marked draft, one marked completed. The one marked completed? Didn't contain the addendum.<br /><br /><img alt="comment count unavailable" height="12" src="https://www.dreamwidth.org/tools/commentcount?user=mjg59&amp;ditemid=73317" style="vertical-align: middle;" width="30" /> comments</description><author>Matthew Garrett</author><dc:creator>Matthew Garrett</dc:creator><pubDate>Wed, 24 Sep 2025 22:22:34 GMT</pubDate><guid isPermaLink="true">https://mjg59.dreamwidth.org/73317.html</guid></item><item><title>Arun Raghavan: Asymptotic on hiatus</title><link>https://arunraghavan.net/2025/09/asymptotic-on-hiatus/</link><description><div class="wp-block-jetpack-markdown"><p>Asymptotic was started 6 years ago, when I wanted to build something that would be larger than just myself.</p><p>We’ve worked with some <a href="https://asymptotic.io/work/">incredible clients</a> in this time, on a wide range of projects. I would be remiss to not thank all the teams that put their trust in us.</p><p>In addition to working on interesting challenges, our goal was to make sure we were making a positive impact on the open source projects that we are part of. I think we truly punched above our weight class (pardon the boxing metaphor), on this front – all the <a href="https://asymptotic.io/work/#talks">upstream work</a> we have done stands testament to that.</p><p>Of course, the biggest single contributor to what we were able to achieve is our team. My partner, Deepa, was instrumental in shaping how the company was formed and run. <a href="https://sanchayanmaity.net/about/">Sanchayan</a> (who took a leap of faith in joining us first), and <a href="https://github.com/tkanakamalla">Taruntej</a> were stellar colleagues and friends on this journey.</p><p>It’s been an incredibly rewarding experience, but the time has come to move on to other things, and we have now paused operations. I’ll soon write about some recent work and what’s next.</p></div></description><author>Arun Raghavan</author><dc:creator>Arun Raghavan</dc:creator><pubDate>Wed, 24 Sep 2025 18:14:58 GMT</pubDate><guid isPermaLink="true">https://arunraghavan.net/2025/09/asymptotic-on-hiatus/</guid></item><item><title>Sebastian Wick: XDG Intents Updates</title><link>https://blog.sebastianwick.net/posts/xdg-intents-update/</link><description><p>Andy Holmes wrote an excellent overview of XDG Intents in his <a href="https://andyholmes.ca/posts/best-intentions/">&ldquo;Best Intentions&rdquo;</a> blog post, covering the foundational concepts and early proposals. Unfortunately, due to GNOME Foundation issues, this work never fully materialized. As I have been running into more and more cases where this would provide a useful primitive for other features, I tried to continue the work.</p><p>The specifications have evolved as I worked on implementing them in glib, desktop-file-utils and ptyxis. Here&rsquo;s what&rsquo;s changed:</p><h2 id="intent-apps-specification">Intent-Apps Specification</h2><p>Andy showed this hypothetical syntax for scoped preferences:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-ini"><span class="line"><span class="cl"><span class="k">[Default Applications]</span></span></span><span class="line"><span class="cl"><span class="na">org.freedesktop.Thumbnailer</span><span class="o">=</span><span class="s">org.gimp.GIMP</span></span></span><span class="line"><span class="cl"><span class="na">org.freedesktop.Thumbnailer[image/svg+xml]</span><span class="o">=</span><span class="s">org.gnome.Loupe;org.gimp.GIMP</span></span></span></code></pre></div><p>We now use separate groups instead:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-ini"><span class="line"><span class="cl"><span class="k">[Default Applications]</span></span></span><span class="line"><span class="cl"><span class="na">org.freedesktop.Thumbnailer</span><span class="o">=</span><span class="s">org.gimp.GIMP</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="k">[org.freedesktop.Thumbnailer]</span></span></span><span class="line"><span class="cl"><span class="na">image/svg+xml</span><span class="o">=</span><span class="s">org.gnome.Loupe;org.gimp.GIMP</span></span></span></code></pre></div><p>This approach creates a dedicated group for each intent, with keys representing the scopes. This way, we do not have to abuse the square brackets which were meant for translatable keys and allow only very limited values.</p><p>The updated specification also adds support for <code>intent.cache</code> files to improve performance, containing up-to-date lists of applications supporting particular intents and scopes. This is very similar to the already existing cache for MIME types. The <code>update-desktop-database</code> tool is responsible for keeping the cache up-to-date.</p><p>This is implemented in <a href="https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4797">glib!4797</a>, <a href="https://gitlab.freedesktop.org/xdg/desktop-file-utils/-/merge_requests/27">desktop-file-utils!27</a>, and the updated specification is in <a href="https://gitlab.freedesktop.org/xdg/xdg-specs/-/merge_requests/106">xdg-specs!106</a>.</p><h2 id="terminal-intent-specification">Terminal Intent Specification</h2><p>While Andy mentioned the terminal intent as a use case, Zander Brown tried to upstream the intent in <a href="https://gitlab.freedesktop.org/xdg/xdg-specs/-/merge_requests/46">xdg-specs!46</a> multiple years ago. However, because it depended on the intent-apps specification, it unfortunately never went anywhere. With the fleshed-out version of the intent-apps specification, and an implementation in glib, I was able to implement the terminal-intent specification in glib as well. With some help from Christian, we also added support for the intent in the ptyxis terminal.</p><p>This revealed some shortcomings in the proposed D-Bus interface. In particular, when a desktop file gets activated with multiple URIs, and the <code>Exec</code> line in the desktop entry only indicates support for a limited number of URIs, multiple commands need to be launched. To support opening those commands in a single window but in multiple tabs in the terminal emulator, for example, those multiple commands must be part of a single D-Bus method call. The resulting D-Bus interface looks like this:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-xml"><span class="line"><span class="cl"><span class="nt">&lt;interface</span> <span class="na">name=</span><span class="s">"org.freedesktop.Terminal1"</span><span class="nt">&gt;</span></span></span><span class="line"><span class="cl">  <span class="nt">&lt;method</span> <span class="na">name=</span><span class="s">"LaunchCommand"</span><span class="nt">&gt;</span></span></span><span class="line"><span class="cl">    <span class="nt">&lt;arg</span> <span class="na">type=</span><span class="s">'aa{sv}'</span> <span class="na">name=</span><span class="s">'commands'</span> <span class="na">direction=</span><span class="s">'in'</span> <span class="nt">/&gt;</span></span></span><span class="line"><span class="cl">    <span class="nt">&lt;arg</span> <span class="na">type=</span><span class="s">'ay'</span> <span class="na">name=</span><span class="s">'desktop_entry'</span> <span class="na">direction=</span><span class="s">'in'</span> <span class="nt">/&gt;</span></span></span><span class="line"><span class="cl">    <span class="nt">&lt;arg</span> <span class="na">type=</span><span class="s">'a{sv}'</span> <span class="na">name=</span><span class="s">'options'</span> <span class="na">direction=</span><span class="s">'in'</span> <span class="nt">/&gt;</span></span></span><span class="line"><span class="cl">    <span class="nt">&lt;arg</span> <span class="na">type=</span><span class="s">'a{sv}'</span> <span class="na">name=</span><span class="s">'platform_data'</span> <span class="na">direction=</span><span class="s">'in'</span> <span class="nt">/&gt;</span></span></span><span class="line"><span class="cl">  <span class="nt">&lt;/method&gt;</span></span></span><span class="line"><span class="cl"><span class="nt">&lt;/interface&gt;</span></span></span></code></pre></div><p>This is implemented in <a href="https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4797">glib!4797</a>, <a href="https://gitlab.gnome.org/chergert/ptyxis/-/merge_requests/119">ptyxis!119</a> and the updated specification is in <a href="https://gitlab.freedesktop.org/xdg/xdg-specs/-/merge_requests/107">xdg-specs!107</a>.</p><h2 id="deeplink-intent">Deeplink Intent</h2><p>Andy&rsquo;s post discussed a generic &ldquo;org.freedesktop.UriHandler&rdquo; with this example:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-ini"><span class="line"><span class="cl"><span class="k">[org.freedesktop.UriHandler]</span></span></span><span class="line"><span class="cl"><span class="na">Supports</span><span class="o">=</span><span class="s">wise.com;</span></span></span><span class="line"><span class="cl"><span class="na">Patterns</span><span class="o">=</span><span class="s">https://*.wise.com/link?urn=urn%3Awise%3Atransfers;</span></span></span></code></pre></div><p>The updated specification introduces a specific <code>org.freedesktop.handler.Deeplink1</code> intent where the scheme is implicitly <code>http</code> or <code>https</code> and the host comes from the scope (i.e., the <code>Supports</code> part). The pattern matching is done on the path alone:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-ini"><span class="line"><span class="cl"><span class="k">[org.freedesktop.handler.Deeplink1]</span></span></span><span class="line"><span class="cl"><span class="na">Supports</span><span class="o">=</span><span class="s">example.org;extensions.gnome.org</span></span></span><span class="line"><span class="cl"><span class="na">example.org</span><span class="o">=</span><span class="s">/login;/test/a?a</span></span></span><span class="line"><span class="cl"><span class="na">extensions.gnome.org</span><span class="o">=</span><span class="s">/extension/*/*/install;/extension/*/*/uninstall</span></span></span></code></pre></div><p>This allows us to focus on deeplinking alone and allows the user to set the order of handlers for specific hosts.</p><p>In this example, the app would handle the URIs <code>http://example.org/login</code>, <code>http://example.org/test/aba</code>, <code>http://extensions.gnome.org/extension/123456/BestExtension/install</code> and so on.</p><p>There is a draft implementation in <a href="https://gitlab.gnome.org/GNOME/glib/-/merge_requests/4833">glib!4833</a> and the specification is in <a href="https://gitlab.freedesktop.org/xdg/xdg-specs/-/merge_requests/109">xdg-specs!109</a>.</p><h2 id="deeplinking-issues-and-other-handlers">Deeplinking Issues and Other Handlers</h2><p>I am still unsure about the Deeplink1 intent. Does it make sense to allow schemes other than <code>http</code> and <code>https</code>? If yes, how should the priority of applications be determined when opening a URI? How complex does the pattern matching need to be?</p><p>Similarly, should we add an <code>org.freedesktop.handler.Scheme1</code> intent? We currently abuse MIME handlers for this, so it seems like a good idea, but then we need to take backwards compatibility into account. Maybe we can modify <code>update-desktop-database</code> to add entries from <code>org.freedesktop.handler.Scheme1</code> to <code>mimeapps.list</code> for that?</p><p>If we go down that route, is there a reason not to also do the same for MIME handlers and add an <code>org.freedesktop.handler.Mime1</code> intent for that purpose with the same backwards compatibility mechanism?</p><h2 id="deeplinking-to-app-locations">Deeplinking to App Locations</h2><p>While working on this, I noticed that we are not great at allowing linking to locations in our apps. For example, most email clients do not have a way to link to a specific email. Most calendars do not allow referencing a specific event. Some apps do support this. For example, Zotero allows linking to items in the app with URIs of the form <code>zotero://select/items/0_USN95MJC</code>.</p><p>Maybe we can improve on this? If all our apps used a consistent scheme and queries (for example <code>xdg-app-org.example.appid:/some/path/in/the/app?name=Example</code>), we could render those links differently and finally have a nice way to link to an email in our calendar.</p><p>This definitely needs more thought, but I do like the idea.</p><h2 id="security-considerations">Security Considerations</h2><p>Allowing apps to describe more thoroughly which URIs they can handle is great, but we also live in a world where security has to be taken into account. If an app wants to handle the URI <code>https://bank.example.org</code>, we better be sure that this app actually is the correct banking app. This unfortunately is not a trivial issue, so I will leave it for the next time.</p></description><author>Sebastian Wick</author><dc:creator>Sebastian Wick</dc:creator><pubDate>Wed, 24 Sep 2025 18:57:45 GMT</pubDate><guid isPermaLink="true">https://blog.sebastianwick.net/posts/xdg-intents-update/</guid></item><item><title>Jakub Steiner: HDR Wallpapers</title><link>https://blog.jimmac.eu/2025/wallpapers/</link><description><p>GNOME 49 brought another round of <a href="https://release.gnome.org/49/#wallpapers">changes to the default wallpaper set</a> — some new additions, and a few removals too. Not just to keep the old <em>GNOME Design loves to delete things trope</em> alive, but to make room for fresh work and reduce stylistic overlap.</p> <p>Our goal has always been to provide a varied collection of abstract wallpapers. (Light/dark photographic sets are still on the wish list — we’ll get there, promise! 😉). When we introduce new designs, some of the older ones naturally have to step aside.</p> <p>We’ve actually been shipping wallpapers in high bit depth formats for quite a while, even back when the GNOME display pipeline (based on gdk-pixbuf) was limited to 8-bit output. That changed in GNOME 49. Thanks to Sophie’s Glycin, we now have a color-managed pipeline that makes full use of modern hardware — even if you’re still on an SDR display.</p> <p>So what does that mean for wallpapers? Well, with HDR displays (using OLED or Mini-LED panels), you can push brightness and contrast to extremes — bright enough to feel like a flashlight in your face. That’s great for games and movies, but it’s not something you want staring back at you from the desktop all day. With wallpapers, subtlety matters.</p> <p>The new set takes advantage of wider color gamuts (Display P3 instead of sRGB) and higher precision (16-bit per channel instead of 8-bit). That translates to smoother gradients, richer tones, and more depth — without the blinding highlights. Think of it as HDR done tastefully: more range to play with, but in service of calm, everyday visuals rather than spectacle.</p> <video class="image full" controls="" loop="" poster="https://blog.jimmac.eu/2025/wallpapers/timelapse.webp"><source src="https://blog.jimmac.eu/2025/wallpapers/timelapse.webm" type="video/webm" /><source src="https://blog.jimmac.eu/2025/wallpapers/timelapse.mp4" type="video/mp4" /></video> <p>Personally, I still think HDR makes the most sense today in games, videos, and fullscreen photography, where those deep contrasts and bright highlights can really shine. On the desktop, apps and creative tools still need to catch up. Blender, for instance, already shows it’s colormanaged HDR preview pipeline on macOS, and HDR display support is expected to land for Wayland in Blender 5.0.</p></description><author>Jakub Steiner</author><dc:creator>Jakub Steiner</dc:creator><pubDate>Wed, 17 Sep 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://blog.jimmac.eu/2025/wallpapers/</guid></item><item><title>Gedit Technology blog: Mid-September News</title><link>https://gedit-text-editor.org/blog/2025-09-15-mid-september-news.html</link><description><p>  Misc news about the  <a href="https://gedit-text-editor.org/" target="_blank">gedit</a>  text editor, mid-September edition! (Some sections are a bit technical).</p> <h3>Next version will be released when Ready</h3><p>  While the release of GNOME 49.0 was approaching (it's this week!), I came to  the conclusion that it's best for gedit to wait more, and to follow the Debian  way of releasing software: when it's Ready. "Ready" with an uppercase letter  'R'!</p><p>  So the question is: what is <em>not</em> ready? Two main things:</p><ul>  <li>    The rework of the file loading and saving: it is something that takes time,    and I prefer to be sure that it'll be a solid solution.  </li>  <li>    The question about the Python support for implementing plugins. Time will    tell what is the answer.  </li></ul> <h3>Rework of the file loading and saving (next steps)</h3><p>  Work continues to refactor that part of the code, both in  libgedit-gtksourceview and gedit.</p><p>  I won't go into too much technical details this time. But what the previous  developer (Ignacio Casal Quinteiro, aka nacho)  <a href="https://gitlab.gnome.org/World/gedit/gedit/-/commit/89fe90084cfa3c727589fafa969a9678208a8652" target="_blank">wrote</a>  (in 2011) in a comment at the top of a class is  <em>"welcome to a really big headache."</em></p><p>  And naturally, I want to improve the situation. For a long time this class was  used as a black box, using only its interface. Time has come to change things!  It takes time, but I already see the end of the tunnel and I have good hopes  that the code will be better structured. I intend to write about it more once  finished.</p><p>  But I can reveal that there is already a visible improvement: loading a big  file (e.g. 200 MB) is now super fast! Previously, it could take one minute to  load such file, with a progress bar shown and a Cancel button. Now there is  not enough time to even click on (or to see) the Cancel button! (I'm talking  about local files, for remote files with a slow network connection, the  progress bar is still useful).</p><p>  To be continued...</p> <p><small>  If you appreciate the work that I do, you can send  <a href="https://gedit-text-editor.org/donations.html" target="_blank">a thank-you donation</a>.  Your support is much appreciated! For years to come, it will be useful for the  project.</small></p></description><author>Gedit Technology blog</author><dc:creator>Gedit Technology blog</dc:creator><pubDate>Mon, 15 Sep 2025 10:00:00 GMT</pubDate><guid isPermaLink="true">https://gedit-text-editor.org/blog/2025-09-15-mid-september-news.html</guid></item><item><title>Alley Chaggar: Final Report</title><link>https://alleych.github.io/gnome/final-report/</link><description><h1 id="intro">Intro:</h1><p>Hi everyone, it’s the end of GSoc! I had a great experience throughout this whole process. I’ve learned so much. This is essentially the ‘final report’ for GSoC, but not my final report for this project in general by a long shot. I still have so much more I want to do, but here is what I’ve done so far.</p> <h1 id="project">Project:</h1><p>JSON, YAML, and/or XML emitting and parsing integration into Vala’s compiler.</p> <h1 id="mentor">Mentor:</h1><p>I would like to thank <a href="https://mastodon.social/@lw64@chaos.social">Lorenz Wildberg</a> for being my mentor for this project, as well as the <a href="https://mastodon.social/@vala_lang">Vala community</a>.</p> <h1 id="description">Description:</h1><p>The main objective of this project is to integrate direct syntax support for parsing and emitting JSON, XML, and/or YAML formats in Vala.  This will cut back the boilerplate code, making it more user-friendly and efficient for developers working with these formatting languages.</p> <h1 id="what-ive-done">What I’ve done:</h1><h2 id="research">Research</h2><ul>  <li>I’ve done significant research in both JSON and YAML parsing and emitting in various languages like C#, Java, Rust and Python.</li>  <li>Looked into how Vala currently handles JSON using JSON GLib classes, and I then modelled the C code after the examples I collected.</li>  <li>Modelled the JSON module after other modules in the codegen, specifically, mainly after Dbus, Gvariant, GObject, and GTK.</li></ul> <h2 id="custom-json-overrides-and-attribute">Custom JSON Overrides and Attribute</h2><ul>  <li>Created Vala syntax sugar specifically making a [JSON] attribute to do serialization.</li>  <li>Built support for custom overrides as in mapping JSON keys to differently named fields/properties.</li>  <li>Reduced boilerplate by generating C code behind the scenes.</li></ul> <h2 id="structs">Structs</h2><ul>  <li>I’ve created both Vala functions to deserialize and serialize structs using JSON boxed functions.</li>  <li>I created a Vala  <code class="language-vala highlighter-rouge"><span class="n">generate_struct_serialize_func</span></code> function to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_</span><span class="p">%</span><span class="n">s_serialize_func</span></code> to serialize fields.</li>  <li>    <p>I then created a Vala function  <code class="language-vala highlighter-rouge"><span class="n">generate_struct_to_json</span></code> to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_json_</span><span class="p">%</span><span class="n">s_serialize_mystruct</span></code> to fully serialize the struct by using boxed serialize functions.<br /></p>  </li>  <li>I created a Vala  <code class="language-vala highlighter-rouge"><span class="n">generate_struct_deserialize_func</span></code> function to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_</span><span class="p">%</span><span class="n">s_deserialize_func</span></code> to deserialize fields.</li>  <li>I then created a Vala function  <code class="language-vala highlighter-rouge"><span class="n">generate_struct_to_json</span></code> to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_json_</span><span class="p">%</span><span class="n">s_deserialize_mystruct</span></code> to fully deserialize the struct by using boxed deserialized functions.</li></ul> <h2 id="gobjects">GObjects</h2><ul>  <li>I’ve created both Vala functions to deserialize and serialize GObjects using json_gobject_serialize and JSON generator.</li>  <li>    <p>I then created a Vala function  <code class="language-vala highlighter-rouge"><span class="n">generate_gclass_to_json</span></code> to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_json_</span><span class="p">%</span><span class="n">s_serialize_gobject_myclass</span></code> to fully serialize GObjects.<br /></p>  </li>  <li>I created a Vala  <code class="language-vala highlighter-rouge"><span class="n">generate_gclass_from_json</span></code> function to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_json_</span><span class="p">%</span><span class="n">s_deserialize_class</span></code> to deserialize fields.</li></ul> <h2 id="non-gobjects">Non-GObjects</h2><ul>  <li>I’ve done serializing of non-GObjects using JSON GLib’s builder functions.</li>  <li>I then created a Vala function  <code class="language-vala highlighter-rouge"><span class="n">generate_class_to_json</span></code> to create a C code function called  <code class="language-vala highlighter-rouge"><span class="n">_json_</span><span class="p">%</span><span class="n">s_serialize_myclass</span></code> to fully serialize non-objects that aren’tinheriting from Object or Json.Serializable.</li></ul> <h1 id="future-work">Future Work:</h1><h2 id="research-1">Research</h2><ul>  <li>Research still needs to be put into integrating XML and determining which library to use.</li>  <li>The integration of YAML and other formatting languages not only JSON, YAML, or XML.</li></ul> <h2 id="custom-overrides-and-attributes">Custom Overrides and Attributes</h2><ul>  <li>I want to create more specialized attributes for JSON that only do serialization or deserialization. Such as [JsonDeserialize] and [JsonSerialize] or something similar.</li>  <li>[JSON] attribute needs to do both deserializing and serializing, and at the moment, the deserializing code has problems.</li>  <li>XML, YAML, and other formating languages will follow very similar attribute patterns:  <code class="language-vala highlighter-rouge"><span class="na">[Yaml]</span><span class="p">,</span> <span class="p">[</span><span class="n">Xml</span><span class="p">],</span> <span class="p">[</span><span class="n">Json</span><span class="p">]</span></code>.</li></ul> <h2 id="bugs">Bugs</h2><ul>  <li>unref c code functions are calling nulls, which shouldn’t be the cause. They need proper types going through.</li>  <li>Deserializing prompts a redefinition that needs to be corrected.</li>  <li>Overridden GObject properties need to have setters made to be able to get the values.</li></ul> <h1 id="links">Links</h1><ul>  <li>Here is the <a href="https://gitlab.gnome.org/AlleyChaggar/vala/-/blob/098c51eb28c99d4d9fa4786d84109782fe8cf2c3/codegen/valajsonmodule.vala">JSON module</a> that has majority of the code.</li>  <li>Here is the <a href="https://gitlab.gnome.org/GNOME/vala/-/merge_requests/468">merge request</a>.</li></ul></description><author>Alley Chaggar</author><dc:creator>Alley Chaggar</dc:creator><pubDate>Sat, 13 Sep 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://alleych.github.io/gnome/final-report/</guid></item><item><title>Alice Mikhaylenko: Libadwaita 1.8</title><link>https://nyaa.place/blog/libadwaita-1-8</link><description><source media="(prefers-color-scheme: dark)" />  <img alt="Screenshot of Fractal with the new .document style class, and Elastic and Papers with the new shortcuts dialogs" src="https://nyaa.place/blog/libadwaita-1-8/header.png" /> <p>Another six months have passed, and with that comes another libadwaita release to go with GNOME 49.</p><p>This cycle doesn't have a lot of changes due to numerous IRL circumstances I've been dealing with, but let's look at them anyway.</p><h1 id="shortcuts-dialog">Shortcuts dialog</h1>   <source media="(prefers-color-scheme: dark)" />  <img alt="Screenshot of the shortcuts dialog in libadwaita demo" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts.png" /> <p>Last cycle GTK deprecated <code>GtkShortcutsWindow</code> and all of the related classes. Unfortunately, this left it with no replacement, despite being widely used. So, now there is a replacement: <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ShortcutsDialog.html"><code>AdwShortcutsDialog</code></a>. Same as shortcuts window, it has very minimal API and is intended to be static and constructed from UI files.</p><h2 id="structure">Structure</h2><p>While the new dialog has a similar feature set to the old one, it has a very different organization, and is not a drop-in replacement.</p><p>The old dialog was structured as: <a href="https://docs.gtk.org/gtk4/class.ShortcutsWindow.html"><code>GtkShortcutsWindow</code></a> → <a href="https://docs.gtk.org/gtk4/class.ShortcutsSection.html"><code>GtkShortcutsSection</code></a>  → <a href="https://docs.gtk.org/gtk4/class.ShortcutsGroup.html"><code>GtkShortcutsGroup</code></a> → <a href="https://docs.gtk.org/gtk4/class.ShortcutsShortcut.html"><code>GtkShortcutsShortcut</code></a>.</p><p>Most apps only have a single shortcuts section, but those that have multiple would have them shown in a dropdown in the dialog's header bar, as seen in Builder:</p>   <source media="(prefers-color-scheme: dark)" />  <img alt="Screenshot of the shortcuts window in Builder" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-builder.png" /> <p>Each section would have one or more shortcuts groups. When a section has too many groups, it would be paginated. Each group has a title and optionally a view, we'll talk about that a bit later.</p><p>Finally each groups contains shortcuts. Or shortcuts shortcuts, I suppose - which describe the actual shortcuts.</p><p>When sections and groups specify a view, the dialog can be launched while only showing a subset of shortcuts. This can be seen in Clocks, but was never very widely used. And specifically in Clocks it was also a bit silly, since the dialog actually becomes <em>shorter</em> when the button is clicked.</p><div class="gallery large">      <source media="(prefers-color-scheme: dark)" />    <img alt="Screenshot of the shortcuts window in Clocks, with a Show All button and only General and World Clocks sections" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-clocks.png" />        <source media="(prefers-color-scheme: dark)" />    <img alt="Screenshot of the shortcuts window in Clocks, with that button gone and all sections visible" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-clocks-all.png" />  </div><p>The new dialog drops the rarely used sections and views, so it has a simpler structure: <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ShortcutsDialog.html"><code>AdwShortcutsDialog</code></a> → <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ShortcutsSection.html"><code>AdwShortcutsSection</code></a> → <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ShortcutsItem.html"><code>AdwShortcutsItem</code></a>.</p><p>Sections here are closer to the old groups, but are slightly different. Their titles are optional, and sections without titles behave as if they were a part of the previous section with an extra gap. This allows to subdivide the sections further, without adding an extra level of hierarchy when it's not necessary.</p>   <source media="(prefers-color-scheme: dark)" />  <img alt="Screenshot of tab sections in the libadwaita demo shortcuts dialog" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-sections.png" /> <p>Since shortcuts are shown as boxed lists, apps should avoid having too many in a single section. It was already not great with the old dialog, but is much worse in the new one.</p><p>Finally, <code>AdwShortcutsItem</code> is functionally identical to <code>GtkShortcutsShortcut</code>, except it doesn't support specifying gestures and icons.</p><h2 id="why-not-gestures">Why not gestures?</h2><p>This feature was always rather questionable, and sometimes doing more harm than good. For example, take these 2 apps - the old and the current image viewer, also known as Eye of GNOME and Loupe respectively:</p><p><img alt="Screenshot of EoG shortcuts window" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-eog.png" /></p><p><img alt="Screenshot of Loupe shortcuts window" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-loupe.png" /></p><p>Both of them specify a two-finger swipe left/right to go to the next/previous image. Well, does it work? The answer depends on what input device you're using.</p><p>In Loupe it will work on a touchpad, but not touchscreen: on a touchscreen you use one finger instead.</p><p>Meanwhile, in EoG it only works on touchscreen instead. On touchpad 2-finger swipe scrolls the current image if it's zoomed in.</p><p>So - while both of these apps have a swipe gesture, they are completely different - yet the dialog makes no distinction between them.</p><p>It's also not discoverable. HIG <a href="https://developer.gnome.org/hig/patterns/controls/menus.html#standard-primary-menu-items">recommends</a> naming the menu entry <strong>Keyboard Shortcuts</strong>, and it doesn't make a lot of sense that these gestures would be in there too - they have nothing to do with keyboard or shortcuts.</p><p>A much better place to document this would be help pages. And of course, ideally apps should have all of the typical gestures people are used to from other systems (pinch to zoom and rotate, double tap to zoom, swipes to navigate, long press to open context menus when it's not available via other means), and clear feedback while those gestures are performed - so that there's less of a need to remember which app has which gestures in the first place and they can be documented system-wide instead.</p><h2 id="why-not-icons">Why not icons?</h2><p>As for icons, the only app I'm aware of that did this was <code>gnome-games</code> - it used them to show gamepad navigation:</p><p><img alt="Shortcuts window from GNOME Games. Half of it is gamepad navigation rather than shortcuts" src="https://nyaa.place/blog/libadwaita-1-8/shortcuts-games.png" /></p><p>This was problematic in a similar way, but also there was no way to open this dialog using a gamepad in the first place. A much better solution (and pretty much the standard for gamepad navigation) would have been always visible hints at the bottom of the window or inline.</p><h2 id="auto-loading">Auto-loading</h2><p>Most apps using <code>GtkShortcutsWindow</code> weren't creating it programmatically - <code>GtkApplication</code> loads it automatically and creates an action for it. So, we do the same thing: if a resource with the name <code>shortcuts-dialog.ui</code> is present in the resource base path, <a href="https://nyaa.place/blog/libadwaita-1-8/gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.Application.html"><code>AdwApplication</code></a> will create the <code>app.shortcuts</code> action which will create and show the dialog in the active window when activated.</p><p>Some apps were already using an action with this name, in these cases no action will be created.</p><p>One thing that's not possible anymore is overriding the dialog for specific windows (<a href="https://docs.gtk.org/gtk4/method.ApplicationWindow.set_help_overlay.html"><code>gtk_application_window_set_help_overlay()</code></a>). This feature was extremely rarely used, and apps that really want different dialogs for different windows can just create the dialogs themselves instead of using auto-loading - this is just convenience API for the most common case.</p><h1 id="shortcut-label">Shortcut label</h1><p>One of the widgets that was deprecated is <a href="https://docs.gtk.org/gtk4/class.ShortcutLabel.html"><code>GtkShortcutLabel</code></a>. However, it had uses outside of  the shortcuts dialog as well. So, libadwaita has a replacement as well - <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.ShortcutLabel.html"><code>AdwShortcutLabel</code></a>. Unlike the dialog itself, this is a direct fork of the GTK widget, and works the same way - though the separation between individual keycaps looks a bit different now, hopefully to make it clearer:</p><div class="gallery">      <source media="(prefers-color-scheme: dark)" />    <img alt="Screenshot of GtkShortcutLabels with different shortcuts: Ctrl+C, Shift+A or Home, Alt+1 to 9, left and right Ctrl together, Ctrl+C followed by Ctrl+X, and " src="https://nyaa.place/blog/libadwaita-1-8/gtk-shortcut-label.png" />        <source media="(prefers-color-scheme: dark)" />    <img alt="Same but AdwShortcutLabel" src="https://nyaa.place/blog/libadwaita-1-8/adw-shortcut-label.png" />  </div><p>It also has a slightly different style, but it's been backported for <code>GtkShortcutLabel</code> as well for the most part.</p><p>And, unlike the shortcuts dialog, <code>AdwShortcutLabel</code> <strong>is</strong> a drop-in replacement.</p><h1 id="css-improvements">CSS improvements</h1><h2 id="media-queries">Media queries</h2><p>This cycle, GTK has added support for CSS media queries, allowing to define styles for light and dark, as well as regular and high contrast styles in the same file.</p><p>Media queries is fully supported on libadwaita side, and apps are encouraged to use them instead of <code>style-dark.css</code>, <code>style-hc.css</code> and <code>style-hc-dark.css</code>. Since this happened right at the end of the cycle (after the feature and API freeze, in fact, since GTK doesn't follow it), they are not deprecated just yet, but will be early next cycle.</p><p>Since we now have support for both variables and media queries, it's possible to do things like this now:</p><pre class="chroma"><code><span class="line"><span class="cl"><span class="p">:</span><span class="nd">root</span> <span class="p">{</span></span></span><span class="line"><span class="cl">  <span class="nv">--card-border</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">card</span><span class="o">-</span><span class="n">shade</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="p">@</span><span class="k">media</span> <span class="o">(</span><span class="nt">prefers-contrast</span><span class="o">:</span> <span class="nt">more</span><span class="o">)</span> <span class="p">{</span></span></span><span class="line"><span class="cl">  <span class="p">:</span><span class="nd">root</span> <span class="p">{</span></span></span><span class="line"><span class="cl">    <span class="nv">--card-border</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">border</span><span class="o">-</span><span class="kc">color</span><span class="p">);</span></span></span><span class="line"><span class="cl">  <span class="p">}</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="p">.</span><span class="nc">card-separator</span> <span class="p">{</span></span></span><span class="line"><span class="cl">  <span class="k">background</span><span class="p">:</span> <span class="nf">var</span><span class="p">(</span><span class="o">--</span><span class="n">card</span><span class="o">-</span><span class="n">border</span><span class="p">);</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span></code></pre><h2 id="typography">Typography</h2><p>Last cycle, I added <a href="https://nyaa.place/blog/libadwaita-1-8/../libadwaita-1-7/#font-additions">document and monospace font variables</a> and mentioned that the document font may change in future to be distinct from the UI font.</p><p>This has happened now, and it is actually distinct - Adwaita Sans 12pt instead of 11pt.</p><p>So - to mirror <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html#monospace"><code>.monospace</code></a>, there's now a <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html#document"><code>.document</code></a> style class as well. It uses the document font, and also increases the line height for better readability.</p>   <source media="(prefers-color-scheme: dark)" />  <img alt="Lorem ipsum with the document style class" src="https://nyaa.place/blog/libadwaita-1-8/document.png" /> <p>Additionally, the formerly mostly useless <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html#body"><code>.body</code></a> style class increases line height as well now, instead of just setting the default font size and weight. Apps should use it when displaying medium-long text, and libadwaita is using it in a bunch of standard widgets, such as in preferences group and status page descriptions, alert dialog body, or various pages in the about dialog.</p>   <source media="(prefers-color-scheme: dark)" />  <img alt="Alert dialog in libadwaita demo, with the body text having a bit larger line height than before" src="https://nyaa.place/blog/libadwaita-1-8/alert-dialog.png" /> <p>Fractal and Podcasts are already making use of both, and hopefully soon more apps will follow suit.</p><h1 id="other-changes">Other changes</h1><ul><li><p><a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PreferencesGroup.html"><code>AdwPreferencesGroup</code></a> can now be used with list models via <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.PreferencesGroup.bind_model.html"><code>adw_preferences_group_bind_model()</code></a>.</p></li><li><p>For convenience, it also allows adding rows that aren't <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PreferencesRow.html"><code>AdwPreferencesRow</code></a> to the internal list now, rather than treating them as other widgets. These rows will just not be searchable in <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PreferencesDialog.html"><code>AdwPreferencesDialog</code></a>.</p></li><li><p><a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.PreferencesPage.html"><code>AdwPreferencesPage</code></a> has <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.PreferencesPage.insert.html">a way</a> to insert groups anywhere now, rather than just append them at the end.</p></li><li><p>Both <code>AdwPreferencesGroup</code> and <code>AdwPreferencesPage</code> now have a way to inspect their groups/rows without peeking into their implementation: <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.PreferencesPage.get_group.html"><code>adw_preferences_page_get_group()</code></a> and <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.PreferencesGroup.get_row.html"><code>adw_preferences_group_get_row()</code></a>.</p></li><li><p><a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.WrapBox.html"><code>AdwWrapBox</code></a> now has a way to <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/method.WrapBox.remove_all.html">remove all children at once</a>.</p></li><li><p><a href="https://docs.gtk.org/gtk4/class.FlowBox.html"><code>GtkFlowBox</code></a> children have hover and active styles by default. Apps that use flowboxes in non-standard ways may need to disable this from CSS in some cases.</p></li><li><p><a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/class.HeaderBar.html"><code>AdwHeaderBar</code></a> now supports native window controls on macOS, same as <code>GtkHeaderBar</code> from the last cycle.</p></li><li><p>Window, dialog and sheet shadows have been reduced to increase performance.</p></li></ul><h1 id="future">Future</h1><p>While this cycle was pretty short and unexciting, there's a thing in works for the next cycle.</p><p>One of the most glaring omissions right now is sidebars. While we have split views, we don't have anything pre-built that could go into the sidebar pane - it's up to the apps to invent something using <a href="https://nyaa.place/blog/libadwaita-1-8/docs.gtk.org/gtk4/class.ListBox.html"><code>GtkListBox</code></a> or <a href="https://nyaa.place/blog/libadwaita-1-8/docs.gtk.org/gtk4/class.ListView.html"><code>GtkListView</code></a>, combined with the <a href="https://gnome.pages.gitlab.gnome.org/libadwaita/doc/main/style-classes.html#sidebars"><code>.navigation-sidebar</code></a> style class.</p><p>This is a lot messier than it may seem, and results in every app having sidebars that look and behave slightly different. We have helpers for boxed lists, so why not sidebars too?</p><p>There is also <a href="https://docs.gtk.org/gtk4/class.StackSidebar.html"><code>GtkStackSidebar</code></a>, but it's not flexible at all and doesn't play well with mobile phones.</p><p>Additionally, on mobile especially sidebars look and behave extremely out of place, and it would be nice to do something about - e.g. use boxed lists instead.</p><div class="gallery ;arge">      <source media="(prefers-color-scheme: dark)" />    <img alt="Screenshot of GtkShortcutLabels with different shortcuts: Ctrl+C, Shift+A or Home, Alt+1 to 9, left and right Ctrl together, Ctrl+C followed by Ctrl+X, and " src="https://nyaa.place/blog/libadwaita-1-8/sidebar.png" />        <source media="(prefers-color-scheme: dark)" />    <img alt="Same but AdwShortcutLabel" src="https://nyaa.place/blog/libadwaita-1-8/sidebar-mobile.png" />  </div><p>So, next cycle we'll (hopefully) have both a generic sidebar widget, and a stack sidebar replacement. They won't cover all of the use cases (I expect it to be useful for Builder's preferences dialog but not the main window), but a lot of apps don't do anything extraordinary and it should save them a lot of effort.</p><hr /><p>Thanks to the GNOME STF Team for providing the funding for this work. Also thanks to the GNOME Foundation for their support and thanks to all the contributors who made this release possible.</p></description><author>Alice Mikhaylenko</author><dc:creator>Alice Mikhaylenko</dc:creator><pubDate>Fri, 12 Sep 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://nyaa.place/blog/libadwaita-1-8</guid></item><item><title>Varun R Mallya: PythonBPF - Writing eBPF Programs in Pure Python</title><link>https://xeon.me/gnome/pythonbpf/</link><description><h2 id="introduction">Introduction</h2><p>Python-BPF offers a new way to write eBPF programs entirely in Python, compiling them into real object files. This project is open-source and available on <a href="https://github.com/pythonbpf/python-bpf">GitHub</a> and <a href="https://pypi.org/project/pythonbpf/">PyPI</a>. I wrote it alongside <a href="https://github.com/r41k0u">R41k0u</a>.</p><p>Update: This article has now taken off on <a href="https://news.ycombinator.com/item?id=45221023">Hacker News</a>.</p><h2 id="published-library-with-future-plans">Published Library with Future Plans</h2><p>Python-BPF is a published Python library with plans for further development towards production-ready use.<br />You can <code>pip install pythonbpf</code> but it&rsquo;s certainly not at all production ready and the code is hacky at best with more bugs than I could count. (This was a hackathon project afterall. We plan to fix it after we are done with the hackathon.)</p><h2 id="the-old-way-before-python-bpf">The Old Way: Before Python-BPF</h2><p>Before Python-BPF, writing eBPF programs in Python typically involved embedding C code within multiline strings, often using libraries like <code>bcc</code>. eBPF allows for small programs to run based on kernel events, similar to kernel modules.</p><p>Here&rsquo;s an example of how it used to be:</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bcc</span> <span class="kn">import</span> <span class="n">BPF</span></span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">bcc.utils</span> <span class="kn">import</span> <span class="n">printb</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="c1"># define BPF program</span></span></span><span class="line"><span class="cl"><span class="n">prog</span> <span class="o">=</span> <span class="s2">"""</span></span></span><span class="line"><span class="cl"><span class="s2">int hello(void *ctx) {</span></span></span><span class="line"><span class="cl"><span class="s2"> bpf_trace_printk("Hello, World!</span><span class="se">\\</span><span class="s2">n");</span></span></span><span class="line"><span class="cl"><span class="s2"> return 0;</span></span></span><span class="line"><span class="cl"><span class="s2">}</span></span></span><span class="line"><span class="cl"><span class="s2">"""</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="c1"># load BPF program</span></span></span><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="n">BPF</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="n">prog</span><span class="p">)</span></span></span><span class="line"><span class="cl"><span class="n">b</span><span class="o">.</span><span class="n">attach_kprobe</span><span class="p">(</span><span class="n">event</span><span class="o">=</span><span class="n">b</span><span class="o">.</span><span class="n">get_syscall_fnname</span><span class="p">(</span><span class="s2">"clone"</span><span class="p">),</span> <span class="n">fn_name</span><span class="o">=</span><span class="s2">"hello"</span><span class="p">)</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="c1"># header</span></span></span><span class="line"><span class="cl"><span class="nb">print</span><span class="p">(</span><span class="s2">"</span><span class="si">%-18s</span><span class="s2"> </span><span class="si">%-16s</span><span class="s2"> </span><span class="si">%-6s</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="s2">"TIME(s)"</span><span class="p">,</span> <span class="s2">"COMM"</span><span class="p">,</span> <span class="s2">"PID"</span><span class="p">,</span> <span class="s2">"MESSAGE"</span><span class="p">))</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="c1"># format output</span></span></span><span class="line"><span class="cl"><span class="k">while</span> <span class="mi">1</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="k">try</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="p">(</span><span class="n">task</span><span class="p">,</span> <span class="n">pid</span><span class="p">,</span> <span class="n">cpu</span><span class="p">,</span> <span class="n">flags</span><span class="p">,</span> <span class="n">ts</span><span class="p">,</span> <span class="n">msg</span><span class="p">)</span> <span class="o">=</span> <span class="n">b</span><span class="o">.</span><span class="n">trace_fields</span><span class="p">()</span></span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">ValueError</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="k">continue</span></span></span><span class="line"><span class="cl"> <span class="k">except</span> <span class="ne">KeyboardInterrupt</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="n">exit</span><span class="p">()</span></span></span><span class="line"><span class="cl"> <span class="n">printb</span><span class="p">(</span><span class="sa">b</span><span class="s2">"</span><span class="si">%-18.9f</span><span class="s2"> </span><span class="si">%-16s</span><span class="s2"> </span><span class="si">%-6d</span><span class="s2"> </span><span class="si">%s</span><span class="s2">"</span> <span class="o">%</span> <span class="p">(</span><span class="n">ts</span><span class="p">,</span> <span class="n">task</span><span class="p">,</span> <span class="n">pid</span><span class="p">,</span> <span class="n">msg</span><span class="p">))</span></span></span></code></pre></div><p>This approach, while functional, meant writing C code within Python, lacking support from modern Python development tools like linters.</p><h2 id="features-of-the-multiline-c-program-approach">Features of the Multiline C Program Approach</h2><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-python"><span class="line"><span class="cl"><span class="c1"># load BPF program</span></span></span><span class="line"><span class="cl"><span class="n">b</span> <span class="o">=</span> <span class="n">BPF</span><span class="p">(</span><span class="n">text</span><span class="o">=</span><span class="s2">"""</span></span></span><span class="line"><span class="cl"><span class="s2">#include &lt;uapi/linux/ptrace.h&gt;</span></span></span><span class="line"><span class="cl"><span class="s2"></span></span></span><span class="line"><span class="cl"><span class="s2">BPF_HASH(last);</span></span></span><span class="line"><span class="cl"><span class="s2"></span></span></span><span class="line"><span class="cl"><span class="s2">int do_trace(struct pt_regs *ctx) {</span></span></span><span class="line"><span class="cl"><span class="s2"> u64 ts, *tsp, delta, key = 0;</span></span></span><span class="line"><span class="cl"><span class="s2"></span></span></span><span class="line"><span class="cl"><span class="s2"> // attempt to read stored timestamp</span></span></span><span class="line"><span class="cl"><span class="s2"> tsp = last.lookup(&amp;key);</span></span></span><span class="line"><span class="cl"><span class="s2"> if (tsp != NULL) {</span></span></span><span class="line"><span class="cl"><span class="s2"> delta = bpf_ktime_get_ns() - *tsp;</span></span></span><span class="line"><span class="cl"><span class="s2"> if (delta &lt; 1000000000) {</span></span></span><span class="line"><span class="cl"><span class="s2"> // output if time is less than 1 second</span></span></span><span class="line"><span class="cl"><span class="s2"> bpf_trace_printk("</span><span class="si">%d</span><span class="se">\\</span><span class="s2">n", delta / 1000000);</span></span></span><span class="line"><span class="cl"><span class="s2"> }</span></span></span><span class="line"><span class="cl"><span class="s2"> last.delete(&amp;key);</span></span></span><span class="line"><span class="cl"><span class="s2"> }</span></span></span><span class="line"><span class="cl"><span class="s2"></span></span></span><span class="line"><span class="cl"><span class="s2"> // update stored timestamp</span></span></span><span class="line"><span class="cl"><span class="s2"> ts = bpf_ktime_get_ns();</span></span></span><span class="line"><span class="cl"><span class="s2"> last.update(&amp;key, &amp;ts);</span></span></span><span class="line"><span class="cl"><span class="s2"> return 0;</span></span></span><span class="line"><span class="cl"><span class="s2">}</span></span></span><span class="line"><span class="cl"><span class="s2">"""</span><span class="p">)</span></span></span></code></pre></div><p>The multiline C program approach allowed for features like BPF MAPS (hashmap type), map lookup, update, and delete, BPF helper functions (e.g., <code>bpf_ktime_get_ns</code>, <code>bpf_printk</code>), control flow, assignment, binary operations, sections, and tracepoints.</p><h2 id="similar-program-in-reduced-c">Similar Program in Reduced C</h2><p>For production environments, eBPF programs are typically written in pure C, compiled by <code>clang</code> into a bpf target object file, and loaded into the kernel with tools like <code>libbpf</code>. This approach features map sections, license global variables, and section macros specifying tracepoints.</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-c"><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;linux/bpf.h&gt;</span><span class="cp"></span></span></span><span class="line"><span class="cl"><span class="cp">#include</span> <span class="cpf">&lt;bpf/bpf_helpers.h&gt;</span><span class="cp"></span></span></span><span class="line"><span class="cl"><span class="cp">#define u64 unsigned long long</span></span></span><span class="line"><span class="cl"><span class="cp">#define u32 unsigned int</span></span></span><span class="line"><span class="cl"><span class="cp"></span></span></span><span class="line"><span class="cl"><span class="k">struct</span> <span class="p">{</span></span></span><span class="line"><span class="cl"> <span class="nf">__uint</span><span class="p">(</span><span class="n">type</span><span class="p">,</span> <span class="n">BPF_MAP_TYPE_HASH</span><span class="p">);</span></span></span><span class="line"><span class="cl"> <span class="nf">__uint</span><span class="p">(</span><span class="n">max_entries</span><span class="p">,</span> <span class="mi">1</span><span class="p">);</span></span></span><span class="line"><span class="cl"> <span class="nf">__type</span><span class="p">(</span><span class="n">key</span><span class="p">,</span> <span class="n">u32</span><span class="p">);</span></span></span><span class="line"><span class="cl"> <span class="nf">__type</span><span class="p">(</span><span class="n">value</span><span class="p">,</span> <span class="n">u64</span><span class="p">);</span></span></span><span class="line"><span class="cl"><span class="p">}</span> <span class="n">last</span> <span class="nf">SEC</span><span class="p">(</span><span class="s">".maps"</span><span class="p">);</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nf">SEC</span><span class="p">(</span><span class="s">"tracepoint/syscalls/sys_enter_execve"</span><span class="p">)</span></span></span><span class="line"><span class="cl"><span class="kt">int</span> <span class="nf">hello</span><span class="p">(</span><span class="k">struct</span> <span class="n">pt_regs</span> <span class="o">*</span><span class="n">ctx</span><span class="p">)</span> <span class="p">{</span></span></span><span class="line"><span class="cl"> <span class="nf">bpf_printk</span><span class="p">(</span><span class="s">"Hello, World!</span><span class="se">\\</span><span class="s">n"</span><span class="p">);</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="mi">0</span><span class="p">;</span></span></span><span class="line"><span class="cl"><span class="p">}</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="kt">char</span> <span class="n">LICENSE</span><span class="p">[]</span> <span class="nf">SEC</span><span class="p">(</span><span class="s">"license"</span><span class="p">)</span> <span class="o">=</span> <span class="s">"GPL"</span><span class="p">;</span></span></span></code></pre></div><h2 id="finally-python-bpf">Finally! Python-BPF</h2><p>Python-BPF brings the true eBPF experience to Python by allowing the exact same functionality to be replaced by valid Python code. This is a significant improvement over multiline C strings, offering support from existing Python tools.</p><div class="highlight"><pre class="chroma" tabindex="0"><code class="language-python"><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pythonbpf</span> <span class="kn">import</span> <span class="n">bpf</span><span class="p">,</span> <span class="nb">map</span><span class="p">,</span> <span class="n">section</span><span class="p">,</span> <span class="n">bpfglobal</span><span class="p">,</span> <span class="nb">compile</span></span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">ctypes</span> <span class="kn">import</span> <span class="n">c_void_p</span><span class="p">,</span> <span class="n">c_int64</span><span class="p">,</span> <span class="n">c_int32</span><span class="p">,</span> <span class="n">c_uint64</span></span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pythonbpf.helpers</span> <span class="kn">import</span> <span class="n">ktime</span></span></span><span class="line"><span class="cl"><span class="kn">from</span> <span class="nn">pythonbpf.maps</span> <span class="kn">import</span> <span class="n">HashMap</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nd">@bpf</span></span></span><span class="line"><span class="cl"><span class="nd">@map</span></span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">last</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="n">HashMap</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">HashMap</span><span class="p">(</span><span class="n">key_type</span><span class="o">=</span><span class="n">c_uint64</span><span class="p">,</span> <span class="n">value_type</span><span class="o">=</span><span class="n">c_uint64</span><span class="p">,</span> <span class="n">max_entries</span><span class="o">=</span><span class="mi">1</span><span class="p">)</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nd">@bpf</span></span></span><span class="line"><span class="cl"><span class="nd">@section</span><span class="p">(</span><span class="s2">"tracepoint/syscalls/sys_enter_execve"</span><span class="p">)</span></span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">hello</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">c_void_p</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">c_int32</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"entered"</span><span class="p">)</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">c_int32</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nd">@bpf</span></span></span><span class="line"><span class="cl"><span class="nd">@section</span><span class="p">(</span><span class="s2">"tracepoint/syscalls/sys_exit_execve"</span><span class="p">)</span></span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">hello_again</span><span class="p">(</span><span class="n">ctx</span><span class="p">:</span> <span class="n">c_void_p</span><span class="p">)</span> <span class="o">-&gt;</span> <span class="n">c_int64</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="nb">print</span><span class="p">(</span><span class="s2">"exited"</span><span class="p">)</span></span></span><span class="line"><span class="cl"> <span class="n">key</span> <span class="o">=</span> <span class="mi">0</span></span></span><span class="line"><span class="cl"> <span class="n">last</span><span class="p">()</span><span class="o">.</span><span class="n">update</span><span class="p">(</span><span class="n">key</span><span class="p">)</span></span></span><span class="line"><span class="cl"> <span class="n">ts</span> <span class="o">=</span> <span class="n">ktime</span><span class="p">()</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="n">c_int64</span><span class="p">(</span><span class="mi">0</span><span class="p">)</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nd">@bpf</span></span></span><span class="line"><span class="cl"><span class="nd">@bpfglobal</span></span></span><span class="line"><span class="cl"><span class="k">def</span> <span class="nf">LICENSE</span><span class="p">()</span> <span class="o">-&gt;</span> <span class="nb">str</span><span class="p">:</span></span></span><span class="line"><span class="cl"> <span class="k">return</span> <span class="s2">"GPL"</span></span></span><span class="line"><span class="cl"></span></span><span class="line"><span class="cl"><span class="nb">compile</span><span class="p">()</span></span></span></code></pre></div><p>Python-BPF uses <code>ctypes</code> to preserve compatibility, employs decorators to separate the BPF program from other Python code, allows intuitive creation of global variables, and defines sections and tracepoints similar to its C counterpart. It also provides an interface to compile and run in the same file.</p><h2 id="how-it-works-under-the-hood">How it Works Under the Hood</h2><ol><li><p><strong>Step 1: Generate AST</strong>The Python <code>ast</code> module is used to generate the Abstract Syntax Tree (AST).</p></li><li><p><strong>Step 2: Emit LLVM IR</strong><code>llvmlite</code> from Numba emits LLVM Intermediate Representation (IR) and debug information for specific parts like BPF MAPs. The <code>.py</code> file is converted into LLVM Intermediate Representation.</p></li><li><p><strong>Step 3: Compile LLVM IR</strong>The <code>.ll</code> file, containing all code written under the <code>@bpf</code> decorator, is compiled using <code>llc -march=bpf -O2</code>.</p><p><img alt="alt text" src="https://xeon.me/gnome/pythonbpf/image.png" /></p></li></ol><h2 id="salient-features">Salient Features</h2><p>Previous Python options for eBPF relied on <code>bcc</code> for compilation, which is not ideal for production use. The only two real options for production-quality eBPF programs were <code>aya</code> in Rust and Clang with kernel headers in C. Python-BPF introduces a third, new option, expanding the horizons for eBPF development.</p><p>It currently supports:</p><ul><li>Control flow</li><li>Hash maps (with plans to add support for other map types)</li><li>Binary operations</li><li>Helper functions for map manipulation</li><li>Kernel trace printing functions</li><li>Timestamp helpers</li><li>Global variables (implemented as maps internally with syntactical differences)</li></ul><h2 id="tldr">TL;DR</h2><ul><li>Python-BPF allows writing eBPF programs directly in Python.</li><li>This library compiles Python eBPF code into actual object files.</li><li>Previously, eBPF programs in Python were written as C code strings.</li><li>Python-BPF simplifies eBPF development with Python decorators.</li><li>It offers a new option for production quality BPF programs in Python.</li><li>The tool supports BPF maps, helper functions, and control flow, with plans to extend to completeness later.</li></ul><p>Thanks for reading my poorly written blog :)</p></description><author>Varun R Mallya</author><dc:creator>Varun R Mallya</dc:creator><pubDate>Fri, 12 Sep 2025 00:00:00 GMT</pubDate><guid isPermaLink="true">https://xeon.me/gnome/pythonbpf/</guid></item><item><title>Debarshi Ray: Toolbx — about version numbers</title><link>https://debarshiray.wordpress.com/2025/09/10/toolbx-about-version-numbers/</link><description><p>Those of you who follow the <a href="https://containertoolbx.org/">Toolbx</a> project might have noticed something odd about our <a href="https://github.com/containers/toolbox/releases/tag/0.2">latest release</a> that came out a month ago. The version number looked shorter than usual even though it only had relatively conservative and urgent bug-fixes, and no new enhancements.</p>   <p>If you were wondering about this, then, yes, you are right. Toolbx will continue to use these shorter version numbers from now on.</p>   <p>The following is a brief history of how the Toolbx version numbers evolved over time since the beginning of the project till this present moment.</p>   <figure class="wp-block-image size-large"><a href="https://debarshiray.wordpress.com/wp-content/uploads/2025/09/toolbx-versioning-scheme.png"><img alt="" class="wp-image-2723" height="341" src="https://debarshiray.wordpress.com/wp-content/uploads/2025/09/toolbx-versioning-scheme.png?w=1024" style="border: none;" width="1024" /></a></figure>   <p></p>   <p>Toolbx <a href="https://github.com/containers/toolbox/releases/tag/0.0.1">started out</a> with a <code>MAJOR.MINOR.MICRO</code> versioning scheme. eg., 0.0.1, 0.0.2, etc.. Back then, the project was known as fedora-toolbox, was implemented in POSIX shell, and this versioning scheme was meant to indicate the nascent nature of the project and the ideas behind it.</p>   <p>To put it mildly, I had absolutely no idea what I was doing. I was so unsure that for several weeks or few months before the <a href="https://github.com/containers/toolbox/commit/990e9eb5b70da8b47d2cf711db66ebe8989f05fb">first</a> Git commit in August 2018, it was literally a single file that implemented the <code>fedora-toolbox(1)</code> executable and a Dockerfile for the <code>fedora-toolbox</code> image on my laptop that I would email around to those who were interested.</p>   <p>A nano version was reserved for releases to address <a href="https://www.computer-dictionary-online.org/definitions-b/brown-paper-bag-bug">brown</a> <a href="http://www.catb.org/jargon/html/B/brown-paper-bag-bug.html">paper</a> <a href="https://lkml.org/lkml/1999/1/28/135">bag</a> bugs or other critical issues, and for release candidates. eg., several releases between 0.0.98 and 0.1.0 used it to act as an extended set of release candidates for the dot-zero 0.1.0 release. More on that later.</p>   <p>After two years, in <a href="https://github.com/containers/toolbox/releases/tag/0.0.90">version 0.0.90</a>, Toolbx switched from the POSIX shell implementation to a <a href="https://go.dev/">Go</a> implementation authored by <a href="https://martymichal.cz/">Ondřej Míchal</a>. The idea was to do a few more 0.0.9x releases to shake out as many bugs in the new code as possible, implement some of the bigger items on our list that had gotten ignored due to the Go rewrite, and follow it up with a dot-zero 0.1.0 release. That was in May 2020.</p>   <p>Things went according to plan until the beginning of 2021, when a combination of factors put a spanner in the works, and it became difficult to freeze development and roll out the dot-zero release. It was partly because we kept getting an endless stream of bugs and feature requests that had to be addressed; partly because real life and shifting priorities got in the way for the primary maintainers of the project; and partly because I was too tied to the sanctity of the first dot-zero release. This is how we ended up doing the extended set of release candidates with a nano version that I mentioned above.</p>   <p>Eventually, <a href="https://github.com/containers/toolbox/releases/tag/0.1.0">version 0.1.0</a> arrived in October 2024, and since then we have had three more releases — 0.1.1, 0.1.2 and 0.2. Today, the Toolbx project is seven years old, and some things have changed enough that it requires an update to the versioning scheme.</p>   <p>First, both Toolbx and the ideas that it implements are a lot more mature and widely adopted than they were at the beginning. So much so, that there are a few <a href="https://github.com/89luca89/distrobox/">independent</a> <a href="https://github.com/openSUSE/microos-toolbox/">reimplementations</a> of it. It&#8217;s time for the project to stop hiding behind a micro version.</p>   <p>Second, the practice of bundling and statically linking the Go dependencies sometimes makes it necessary to update the dependencies to address security bugs or other critical issues. It&#8217;s more convenient to do this as part of an upstream release than through downstream patches by distributors. So far, we have managed to avoid the need to do minimal releases targeting only specific issues for conservative downstream distributors, but the recent <a href="https://www.wiz.io/blog/nvidia-ai-vulnerability-cve-2025-23266-nvidiascape">NVIDIAScape</a> or <a href="https://nvidia.custhelp.com/app/answers/detail/a_id/5659/~/security-bulletin%3A-nvidia-container-toolkit---july-2025">CVE-2025-23266</a> and <a href="https://nvidia.custhelp.com/app/answers/detail/a_id/5659/~/security-bulletin%3A-nvidia-container-toolkit---july-2025">CVE-2025-23267</a> in the <a href="https://docs.nvidia.com/datacenter/cloud-native/container-toolkit/">NVIDIA Container Toolkit</a> gave me pause. We managed to escape this time too, but it&#8217;s clear that we need a plan to deal with these scenarios.</p>   <p>Hence, from now on, Toolbx releases will default to not having a micro version and use a <code>MAJOR.MINOR</code> versioning scheme. A micro version will be reserved for the same purposes that a nano version was reserved for until now — to address critical issues and for release candidates.</p>   <p>It&#8217;s easier to read and remember a shorter <code>MAJOR.MINOR</code> version than a longer one, and appropriately conveys the maturity of the project. When a micro version is needed, it will also be easier to read and remember than a longer one with a nano version. Being easy to read and remember is important for version numbers, because it separates them from Git commit hashes.</p>   <p>So, this is why the latest release is 0.2, not 0.1.3.</p></description><author>Debarshi Ray</author><dc:creator>Debarshi Ray</dc:creator><pubDate>Wed, 10 Sep 2025 21:49:26 GMT</pubDate><guid isPermaLink="true">https://debarshiray.wordpress.com/2025/09/10/toolbx-about-version-numbers/</guid></item><item><title>Development blog for GNOME Shell and Mutter: GNOME Kiosk Updates</title><link>https://blogs.gnome.org/shell-dev/2025/09/10/gnome-kiosk-updates/</link><description><p><strong>GNOME Kiosk</strong> is a separate Wayland compositor built on the same core components as GNOME Shell, such as Mutter.</p><p>While it does not provide a desktop UI, it is intended for kiosk and appliance use cases.</p><p>Originally designed to run a single application in fullscreen mode, recent development has expanded its scope toward more versatile window management and system integration.</p><hr /><h2 id="toc_1.1">Recent Releases Overview</h2><p><strong>47</strong></p><ul dir="auto"><li>Support for Shell introspection API (in <code>--unsafe-mode</code>).</li></ul><p><strong>48</strong></p><ul dir="auto"><li>Initial support for configurable windows via <code>window-config.ini</code>.</li><li>Added Shell Screenshot D-Bus API.</li></ul><p><strong>49</strong></p><ul dir="auto"><li>Extended window configuration: <code>set-on-monitor</code>, <code>set-window-type</code>, window tags.</li><li>Added support for remote sessions (Systemd).</li><li>Fixes for GrabAccelerators, media keys, and compositor shortcut inhibition.</li></ul><hr /><h2 id="toc_1.2">Window Configuration and Tagged Clients</h2><p>One of the recent main areas of development has been <a class="external" href="https://gitlab.gnome.org/GNOME/gnome-kiosk/-/blob/main/CONFIG.md?ref_type=heads#configuration-file">window configuration</a>.</p><ul dir="auto"><li>In GNOME 48, Kiosk gained initial support for configuring windows via a static configuration file (<code>window-config.ini</code>).</li><li>In GNOME 49, this functionality was extended with additional options:<ul dir="auto"><li><strong><code>set-on-monitor</code></strong>: place windows on a specific monitor.</li><li><strong><code>set-window-type</code></strong>: assign specific roles to windows (e.g. <code>desktop</code>, <code>dock</code>, <code>splash</code>).</li><li>Matching based on <strong>Window tags</strong>: allow selection of windows based on toplevel tags, a new feature in <a class="external" href="http://lists.freedesktop.org/archives/wayland-devel/2025-April/044134.html">Wayland protocols 1.43</a>.</li></ul></li></ul><p>Additionally, with the new (<a class="external" href="https://gitlab.gnome.org/GNOME/mutter/-/merge_requests/4539">in mutter from GNOME 49</a>) <strong><code>gnome-service-client</code></strong> utility, toplevel windows tags can be assigned to clients at launch, making it possible to configure their behavior in Kiosk without modification to the client.</p><h4 id="toc_1.2.1">Example: configuring a tagged client in Kiosk</h4><p>GNOME Kiosk searches for the window configuration file <code>window-config.ini</code> in the following locations:</p><ul><li>The base directory for user-specific application configuration usually <code>$HOME/.config/gnome-kiosk/window-config.ini</code></li><li>The system-wide list of directories for application data <code>$XDG_DATA_DIRS</code> This list usually includes:<ul><li><code>/var/lib/flatpak/exports/share/gnome-kiosk/window-config.ini</code></li><li><code>/usr/local/share/gnome-kiosk/window-config.ini</code></li><li><code>/usr/share/gnome-kiosk/window-config.ini</code></li></ul></li></ul><p>Therefore, for a user configuration, edit <code>$HOME/.config/gnome-kiosk/window-config.ini</code> to read:</p><pre><code>[all]set-fullscreen=falseset-above=false [desktop]match-tag=desktopset-window-type=desktopset-fullscreen=true</code></pre><p>With this configuration, GNOME Kiosk will treat any surface with the toplevel tag <code>desktop</code> as a „desktop“ type of window.</p><h4 id="toc_1.2.1">launching a tagged client</h4><pre><code>gnome-service-client -t desktop weston-simple-shm</code></pre><p>This command starts the <code>weston-simple-shm</code> client and associates the tag <code>desktop</code> with its surface.</p><p>The end result is the <code>weston-simple-shm</code> window running as a background window placed at the bottom of the windows stack.</p><p><img alt="" class="size-medium wp-image-3350 aligncenter" height="202" src="https://blogs.gnome.org/shell-dev/files/2025/09/Screenshot-From-2025-09-08-15-18-25-300x202.png" width="300" /><br />This combination makes it possible to build structured kiosk environments with different Wayland client used as docks or desktop windows for implementing root menus.</p><hr /><h2 id="toc_1.3">Accessibility and Input</h2><p>Several improvements have been made to input handling and accessibility:</p><ul dir="auto"><li>Fixes for <code>GrabAccelerators</code> support.</li><li>Support for media keys in Systemd sessions.</li><li>Ability to inhibit compositor shortcuts.</li><li>Compatibility with screen reader usage.</li></ul><hr /><h2 id="toc_1.4">Remote Sessions</h2><p>As of GNOME 49, Kiosk supports remote sessions when run under Systemd. This allows kiosk sessions to be used not only on local displays but also in remote session contexts.</p><hr /><h2 id="toc_1.5">D-Bus APIs</h2><p>Although GNOME Kiosk is a separate compositor, it implements selected D-Bus APIs also available in GNOME Shell for compatibility purposes. These include:</p><ul dir="auto"><li><strong>Screenshot API</strong> (added in 48).</li><li><strong>Shell introspection</strong> when started with <code>--unsafe-mode</code> (added in 47).</li></ul><p>This makes it possible to use existing GNOME testing and automation frameworks such as Ponytail and Dogtail with kiosk sessions.</p><p>These APIs allow automation scripts to inspect and interact with the user interface, enabling the creation of automated tests and demonstrations for kiosk application (using tools like <a class="external" href="https://gitlab.gnome.org/ofourdan/gnome-ponytail-daemon">GNOME ponytail</a> and <a class="external" href="https://gitlab.com/dogtail/dogtail">dogtail</a>).</p><p>GNOME Kiosk is the Wayland compositor used with the Wayland enabled version of Anaconda, the installer for Fedora (and Red Hat Enterprise Linux as well). The support for introspection and screenshots is used by <a class="external" href="https://github.com/rhinstaller/anabot">anabot</a>, the framework for automated testing of the installer.</p><hr /><h2 id="toc_1.7">Development Direction</h2><p>Future development of GNOME Kiosk is expected to continue along the following lines:</p><ul dir="auto"><li><strong>Configuration refinement</strong>: further improving flexibility of the window configuration system.</li><li><strong>Accessibility</strong>: ensuring kiosk sessions benefit from GNOME’s accessibility technologies.</li></ul><p>The goal remains to provide a focused, reliable compositor for kiosk and appliance deployments, without implementing the full desktop UI features of GNOME Shell.</p></description><author>Development blog for GNOME Shell and Mutter</author><dc:creator>Development blog for GNOME Shell and Mutter</dc:creator><pubDate>Wed, 10 Sep 2025 07:03:34 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/shell-dev/2025/09/10/gnome-kiosk-updates/</guid></item><item><title>Marcus Lundblad: Maps and GNOME 49</title><link>https://ml4711.blogspot.com/2025/09/maps-and-gnome-49.html</link><description><p></p><div class="separator" style="clear: both;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivXCw7GzdrbTBKT8VB1_IrcNyKC5tNFN7UWR1N2PREkETJWkPIO222QNQYIHMwmypgGQCfk9aJTSI2zpfwUCLBM_fYLOr82qnI1xhWSNuwFDGv3jKM2jeiet4zi7g36G7kTue3GgJBkTEhyphenhyphenMXZJnUuk1Jmb1cnPKQa8rjtWAMHqCwd_348NZNGAe70/s1600/about-49.0.png" style="display: block; padding: 1em 0px; text-align: center;"><img alt="About dialog for GNOME Maps 49.0" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivXCw7GzdrbTBKT8VB1_IrcNyKC5tNFN7UWR1N2PREkETJWkPIO222QNQYIHMwmypgGQCfk9aJTSI2zpfwUCLBM_fYLOr82qnI1xhWSNuwFDGv3jKM2jeiet4zi7g36G7kTue3GgJBkTEhyphenhyphenMXZJnUuk1Jmb1cnPKQa8rjtWAMHqCwd_348NZNGAe70/s16000/about-49.0.png" />&nbsp; &nbsp;</a><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEivXCw7GzdrbTBKT8VB1_IrcNyKC5tNFN7UWR1N2PREkETJWkPIO222QNQYIHMwmypgGQCfk9aJTSI2zpfwUCLBM_fYLOr82qnI1xhWSNuwFDGv3jKM2jeiet4zi7g36G7kTue3GgJBkTEhyphenhyphenMXZJnUuk1Jmb1cnPKQa8rjtWAMHqCwd_348NZNGAe70/s1600/about-49.0.png" style="display: block; padding: 1em 0px; text-align: center;">&nbsp;</a></div><p> As time is approaching the release of GNOME 49, I thought I should probably put together a small recap post covering some of the new things in Maps.&nbsp;</p><p>&nbsp;</p><h2 style="text-align: left;">&nbsp;Metro Station Symbols</h2><p style="text-align: left;">&nbsp;The map style now supports showing localized symbols for rail- and metro stations (relying on places being tagged with reference to the networks' entry in Wikidata.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2uJG3oUvAEjqdD3tVIfZUeizDLbG3hMyr7vASf8ZfKkzxe8EXWgGBCXPTDqQfI8AI7UWpFBLNbSQ8PWns5cZhfNEel8VjdsMRcliV5aLEI-rN3DpgUEW9R0kYsko2XgkKg6RRN1axx-z6C2CApqVpL50Kbka1wwRy1k1WQH0Lqbx7FwmmiiKk1eZz/s866/boston-t.png" style="margin-left: 1em; margin-right: 1em;"><img alt="&quot;T&quot; Subway symbols in Boston" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEh2uJG3oUvAEjqdD3tVIfZUeizDLbG3hMyr7vASf8ZfKkzxe8EXWgGBCXPTDqQfI8AI7UWpFBLNbSQ8PWns5cZhfNEel8VjdsMRcliV5aLEI-rN3DpgUEW9R0kYsko2XgkKg6RRN1axx-z6C2CApqVpL50Kbka1wwRy1k1WQH0Lqbx7FwmmiiKk1eZz/s16000/boston-t.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb785uoA09w60dWXXBWAy5lTNSLtzYxBswNBdQt-HczpbXJqdb2PxXr9jn9Ewt8t6JGbcGppSAZhByePGerUgG65Gnoa1pYIfAk2ffJyzXwyCdPviSSwelRtBZBh37gRfZOOE7TXQLoBFfA0Ii9gTReN13Aa8izIxx2nZv8-CSOwp0GNatSjUcELFz/s855/berlin-s-bahn.png" style="margin-left: 1em; margin-right: 1em;"><img alt="S-Bahn symbol in Berlin" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjb785uoA09w60dWXXBWAy5lTNSLtzYxBswNBdQt-HczpbXJqdb2PxXr9jn9Ewt8t6JGbcGppSAZhByePGerUgG65Gnoa1pYIfAk2ffJyzXwyCdPviSSwelRtBZBh37gRfZOOE7TXQLoBFfA0Ii9gTReN13Aa8izIxx2nZv8-CSOwp0GNatSjUcELFz/s16000/berlin-s-bahn.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicm3Sj_Vx4r67HzREVEhDO84lh9hrjeIGAz-u6yiLxEnx9UJrOdTMcyfZPwo5oRFrijkP2Q9ga1HMEiCnXx8hsDAXV7t1Gm6qBAoyJWCJESIde9-Lta5nvbvedCPwp7sSUI8QjSc_1-eAjSF7265ySSMsWd1m8vFKW-gkJzeSSxGvN5gyPflU4f3aa/s636/metro-stockholm.png" style="margin-left: 1em; margin-right: 1em;"><img alt="&quot;T&quot; metro symbols in Stockholm" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEicm3Sj_Vx4r67HzREVEhDO84lh9hrjeIGAz-u6yiLxEnx9UJrOdTMcyfZPwo5oRFrijkP2Q9ga1HMEiCnXx8hsDAXV7t1Gm6qBAoyJWCJESIde9-Lta5nvbvedCPwp7sSUI8QjSc_1-eAjSF7265ySSMsWd1m8vFKW-gkJzeSSxGvN5gyPflU4f3aa/s16000/metro-stockholm.png" /></a></div><br /><p></p><h2 style="text-align: left;">&nbsp;Highway Symbols in Place Details</h2><p style="text-align: left;">&nbsp;The existing code for showing custom highways shields in the map view (based on code from the OpenStreetMap Americana project) has been extended to expose the necessary bits to use it more generally as icon surfaces in a GtkImage widget. So now custom shields are shown in place details when clicking on a road label.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DdxFZX5LIqSDzq2r-QajHQwK8p1nMIynKh4G8HgbQ6qukxlvzF5yXOlrwzpyfYJMoG2UqVyd-C_LtZo_IuuHQKnwpH64nEsiHiyzQFYXO54csoctcmiGRGUvDynhNXt2e1xHkcveX6MAwf0zSynPkKu3PFOSW-fOXS5vayvU-GO77q2C71nN6zTN/s716/place-highway-shields-1.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing place details for Södertäljevägen, E4 - E20 concurrency" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEg1DdxFZX5LIqSDzq2r-QajHQwK8p1nMIynKh4G8HgbQ6qukxlvzF5yXOlrwzpyfYJMoG2UqVyd-C_LtZo_IuuHQKnwpH64nEsiHiyzQFYXO54csoctcmiGRGUvDynhNXt2e1xHkcveX6MAwf0zSynPkKu3PFOSW-fOXS5vayvU-GO77q2C71nN6zTN/s16000/place-highway-shields-1.png" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXMKHpj1DuxaMHw3g_ff_QpzfdxTIVcomaoyYmFC_e06XOidw64RJfMPXzidqmD3CZbZ08-Ve5srJ1F9GSM6P_dvQrWIaw_W6im13IN469O6OyDA9oCAqyT-dp7fnYAMkLHnmDLoG7v6oEFPHmJfM7py0TNtqzxvBxLswwvMvix-YEOaRMJvmuz_aw/s716/place-highway-shields-2.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing place details for Richmond-San Rafael Bridge in San Francisco" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgXMKHpj1DuxaMHw3g_ff_QpzfdxTIVcomaoyYmFC_e06XOidw64RJfMPXzidqmD3CZbZ08-Ve5srJ1F9GSM6P_dvQrWIaw_W6im13IN469O6OyDA9oCAqyT-dp7fnYAMkLHnmDLoG7v6oEFPHmJfM7py0TNtqzxvBxLswwvMvix-YEOaRMJvmuz_aw/s16000/place-highway-shields-2.png" /></a></div><br /><p></p><h2 style="text-align: left;">&nbsp;Adwaita Shortcuts Dialog</h2><p style="text-align: left;">The keyboard shortcuts help dialog was ported by Maximiliano to use AdwShortcutsDialog, improving adaptivity.</p><p style="text-align: left;">&nbsp;</p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga88aVgnyomepz0Kx0EODosKjasnoE4mnalG_0LM_7DYJ9sopjzlC6kEuI6lk11NLwli5NKu3Eol3yGfBgeCKNAeNx-VnGKJeJEgfbZEW3uJ_FfpsELuhYhO1eEd74ia5OCjvY7iV4Z_N5v7MoDGD6jF8t4o2IUIMjjseoSct9stzsuSjWAAt0whIz/s1065/adw-shortcuts.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Keyboard shortcuts help" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEga88aVgnyomepz0Kx0EODosKjasnoE4mnalG_0LM_7DYJ9sopjzlC6kEuI6lk11NLwli5NKu3Eol3yGfBgeCKNAeNx-VnGKJeJEgfbZEW3uJ_FfpsELuhYhO1eEd74ia5OCjvY7iV4Z_N5v7MoDGD6jF8t4o2IUIMjjseoSct9stzsuSjWAAt0whIz/s16000/adw-shortcuts.png" /></a></div><br /><p></p><h2 style="text-align: left;">&nbsp;Showing OSM Account Avatars in OSM Account Dialog</h2><p style="text-align: left;">If a user has set up OAuth for an OpenStreetMap account, and has set a personal profile picture in their OSM account this is now shown in place of the generic „face“ icon.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZGNIbHZ9_wgQutc8ySaUtmhsO4b0O9oZWIYLsdTJ12h5gCp7uC_NSuvX2qxdTItAvUQAzjGLKt419h7zh-tyNOoE1ikfigupXJlSzwvMp-umiKl5i_jiitQdWKYAtOm11mITFRfRXQrZY_30zsNBGONHYXEiRRNd-sBqH-FBCgNZzngXjXRjzOjXQ/s716/osm-user-avatar.png" style="margin-left: 1em; margin-right: 1em;"><img alt="OpenStreetMap account dialog" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEiZGNIbHZ9_wgQutc8ySaUtmhsO4b0O9oZWIYLsdTJ12h5gCp7uC_NSuvX2qxdTItAvUQAzjGLKt419h7zh-tyNOoE1ikfigupXJlSzwvMp-umiKl5i_jiitQdWKYAtOm11mITFRfRXQrZY_30zsNBGONHYXEiRRNd-sBqH-FBCgNZzngXjXRjzOjXQ/s16000/osm-user-avatar.png" /></a></div><br /><p></p><p style="text-align: left;">&nbsp;And speaking of editing points-of-interests, the edit dialog has been compacted a bit to better accomodate smaller screen sizes.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEsdecNNH8tYJ_D9faZmSs2nnr4s_bUz-D-Fw61i_-5AhdhoKjvlRxEI_hJ_220r-6dB-5932sk6cQHAA0wGHhQr-H-0PEKqzFb4Vm12zt5C-ucwgGkqscKb6hDcwPI_06_CVdqOyFBROLukkw_0nSvuvxUG0O0uebdJE7aL14F4BmgbFFDp9wznF5/s971/osm-edit-mobile-adjust2.png" style="margin-left: 1em; margin-right: 1em;"><img alt="POI editing in mobile mode" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgEsdecNNH8tYJ_D9faZmSs2nnr4s_bUz-D-Fw61i_-5AhdhoKjvlRxEI_hJ_220r-6dB-5932sk6cQHAA0wGHhQr-H-0PEKqzFb4Vm12zt5C-ucwgGkqscKb6hDcwPI_06_CVdqOyFBROLukkw_0nSvuvxUG0O0uebdJE7aL14F4BmgbFFDp9wznF5/s16000/osm-edit-mobile-adjust2.png" /></a></div><br />&nbsp;This screenshot also showcases the (fairly) new mobile form-factor emulation option in the GTK inspector.<p></p><p style="text-align: left;">&nbsp;</p><h2 style="text-align: left;">Softer Labels</h2><p style="text-align: left;">Some smaller adjustments has also been made to the map style, such as using slightly softer color for the place labels for towns and cities rather than pitch black (or bright white for dark mode).</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQY0SMIa03wb_Ejl4CWxdjtphOEv1s74v6mhQO_pwqNzO2kzNnI3qSYcSgqGo3WevrNJWYvmhQ2ECU6Ax6_teh4M8X8udNTRZMc2RUznUtps5CBWAFDfEOSv0a8KBxARnjuruvkqWYsSXzrouhqdJKdlyrIIQiSKh31LkNy2nEKCc_kJLNvFd_TilO/s1817/softer-colors-light.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEgQY0SMIa03wb_Ejl4CWxdjtphOEv1s74v6mhQO_pwqNzO2kzNnI3qSYcSgqGo3WevrNJWYvmhQ2ECU6Ax6_teh4M8X8udNTRZMc2RUznUtps5CBWAFDfEOSv0a8KBxARnjuruvkqWYsSXzrouhqdJKdlyrIIQiSKh31LkNy2nEKCc_kJLNvFd_TilO/w640-h410/softer-colors-light.png" width="640" /></a></div><br /><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_coDjjkh3sCzmOhfQKsq9FBnY0QHga820JiMFOSHZ0ORrJrZzxx3YI2T_GUZuN-IMvzDi99Z62pOAjoQWvSm_QL5Q5L9DfSGwQ0c_vt226MXBHyEMIGmo8nTXI2KCd439vl3ZfGIyQQ-NI087Mj3_jqSk1sNXp-XvbW4UCd1L5d_qMKqkBB8L0mq5/s1817/softer-colors-dark.png" style="margin-left: 1em; margin-right: 1em;"><img border="0" height="410" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEj_coDjjkh3sCzmOhfQKsq9FBnY0QHga820JiMFOSHZ0ORrJrZzxx3YI2T_GUZuN-IMvzDi99Z62pOAjoQWvSm_QL5Q5L9DfSGwQ0c_vt226MXBHyEMIGmo8nTXI2KCd439vl3ZfGIyQQ-NI087Mj3_jqSk1sNXp-XvbW4UCd1L5d_qMKqkBB8L0mq5/w640-h410/softer-colors-dark.png" width="640" /></a></div><br /><p></p><h2 style="text-align: left;">&nbsp;Marker Alignments</h2><p style="text-align: left;">Thanks to work done by Corentin Noël for libshumate 1.5, the center point for map markers can now be adjusted.</p><p style="text-align: left;">This means the place markers in Maps can now actually point to the actually coordinate (e.g. having the “tip of the needle” at the actual location).</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnkLDxb9ojEfUnMqYYqH4_W07FbeBjgyf-CduOmYTzIwO-1EGbRPXbK3ecA9_xQQmc_yQ7SWpxG48Vc-oKFoCAMPAjHaZPfQys3vOafdgy0djOIwwB68YxMjuf_hafxYY7d4FAmAcTutADeS6HB3RsUH_VcxUszG8MdpEzKMUHnq1M1sQFxmLkxFoM/s695/marker-align.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Showing place details for Branderslev" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEhnkLDxb9ojEfUnMqYYqH4_W07FbeBjgyf-CduOmYTzIwO-1EGbRPXbK3ecA9_xQQmc_yQ7SWpxG48Vc-oKFoCAMPAjHaZPfQys3vOafdgy0djOIwwB68YxMjuf_hafxYY7d4FAmAcTutADeS6HB3RsUH_VcxUszG8MdpEzKMUHnq1M1sQFxmLkxFoM/s16000/marker-align.png" /></a></div><br /><p></p><h2 style="text-align: left;">&nbsp;Updating the Highway Shields Defintions</h2><p style="text-align: left;">And finally of the last changes before the release was updating the definition for custom highway shields from OpenStreetMap Americana. So now, among others we support shields for national and regional highways in Argentina.</p><p style="text-align: left;"></p><div class="separator" style="clear: both; text-align: center;"><a href="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgQLhF-ZtSNMwOpzENfQpygPiXeYA_dfoLUPnaC65RnzfNUfpJLHlc-RV8SyvwMlUY9RdvJgKxxvll9uLJj6ei40o3oWZuH0PSDqLFl1GGZmieJu5oYDLqI0gjehrF2scNKN6UFLrnbi9k19Zi0wn70vDhR1BOnOu3teKNEPrLA1GxMoxtUV5WcPP9/s716/highway-shields-argentina.png" style="margin-left: 1em; margin-right: 1em;"><img alt="Highway shields in Argentina" border="0" src="https://blogger.googleusercontent.com/img/b/R29vZ2xl/AVvXsEjgQLhF-ZtSNMwOpzENfQpygPiXeYA_dfoLUPnaC65RnzfNUfpJLHlc-RV8SyvwMlUY9RdvJgKxxvll9uLJj6ei40o3oWZuH0PSDqLFl1GGZmieJu5oYDLqI0gjehrF2scNKN6UFLrnbi9k19Zi0wn70vDhR1BOnOu3teKNEPrLA1GxMoxtUV5WcPP9/s16000/highway-shields-argentina.png" /></a></div><p></p><p style="text-align: left;">And that's some of the highlights from the 49 release cycle!<br />&nbsp;</p></description><author>Marcus Lundblad</author><dc:creator>Marcus Lundblad</dc:creator><pubDate>Tue, 09 Sep 2025 22:43:00 GMT</pubDate><guid isPermaLink="true">https://ml4711.blogspot.com/2025/09/maps-and-gnome-49.html</guid></item><item><title>Christian Schaller: More adventures in the land of AI and Open Source</title><link>https://blogs.gnome.org/uraeus/2025/09/09/more-adventures-in-the-land-of-ai-and-open-source/</link><description><p>I been doing a lot of work with AI recently, both as part of a couple of projects I am part of at work, but I have also taken a personal interest in understanding the current state and what is possible. My favourite AI tool currently is <a class="external" href="https://claude.ai/">Claude.ai</a>. Anyway I have a <a class="external" href="https://www.prusa3d.com/product/prusa-core-one-kit/?utm_source=google&amp;utm_medium=cpc&amp;utm_campaign=EN-US_Search_Text_Brand&amp;utm_id=805226342&amp;gad_source=1&amp;gad_campaignid=805226342&amp;gclid=Cj0KCQjwoP_FBhDFARIsANPG24OJjzNFaxuOmyB5IelwfP5kUYZYKf0y9ELP8wjKiwJY0lglpD-G3vAaAhp7EALw_wcB">Prusa Core One 3D printer</a> now that I also love playing with and one thing I been wanting to do is to print some multicolor prints with it. So the Prusa Core One is a single extruder printer, which means it only has 1 filament loaded at any given time. Other printers on the market, like the PrusaXL has 5 extruders, so it can have 5 filaments or colors loaded at the same time. <div class="wp-caption alignright" id="attachment_11262" style="width: 310px;"><img alt="Prusa Single Extruder Multimaterial setting" class="size-medium wp-image-11262" height="60" src="https://blogs.gnome.org/uraeus/files/2025/09/Screenshot-From-2025-09-09-09-41-51-300x60.png" width="300" /><p class="wp-caption-text" id="caption-attachment-11262">Prusa Single Extruder Multimaterial setting</p></div><br />The thing is that the Prusa Slicer (the slicer is the software that takes a 3d model and prepares the instructions for the printer based on that 3d model) got this feature called Single Extruder Multi Material. And while it is a process that wastes a lot of filament and takes a lot of manual intervention during the print, it does basically work.</p><p>What I quickly discovered was that using this feature is non-trivial. First of all I had to manually add some G Code to the model to actually get it to ask me to switch filament for each color in my print, but the bigger issue is that the printer will ask you to change the color or filament, but you have no way of knowing which one to switch to, so for my model I had 15 filament changes and no simple way of knowing which order to switch in. So people where solving this among other things through looking through the print layer by layer and writing down the color changes, but I thought that this must be possible to automate with an application. So I opened Claude and started working on this thing I ended up calling Prusa Color Mate..</p><p>So the idea for the application was simple enough, have it analyze the project file, extract information about the order of color changes and display them for the user in a way that allows them to manually check of each color as its inserted. So I started off with doing a simple python script that would just print to the console. So it quickly turned out that the hard part of this project was to parse the input files and it was made worse by my ignorance. So what I learned the hard way is that if you store a project in Prusa Slicer it will use this format called 3mf. So my thought was, lets just analyze the <a class="external" href="https://3mf.io/">3mf</a> file and extract the information I need. It took my quite a bit of back and forth with Claude, feeding claude source code from Prusa&#8217;s implementation and pdf files with specifications, but eventually the application did spit out a list of 15 toolchanges and the colors associated with them. So I happily tried to use it to print my model. I quickly discovered that the color ordering was all wrong. And after even more back and forth with Claude and reading online I realized that the 3mf file is a format for storing 3d models, but that is not what is being fed your 3d printer, instead for the printer the file provided is a bgcode file. And while the 3mf file did contain the information that you had to change filament 15 times, the information on in which order is simply not stored in the 3mf file as that is something chosen as part of composing your print. That print composition file is using a file format called bgcode. So I now had to extract the information from the bgcode file which took me basically a full day to figure out with the help of Claude. I could probably have gotten over the finish line sooner by making some better choices underway, but the extreme optimism of the AI probably lead me to believe it was going to be easier than it was to for instance just do everything in Python.<br />At first I tried using this libbgcode library written in C++, but I had a lot of issues getting Claude to incorporate it properly into my project, with Meson and CMAKE interaction issues (in retrospect I should have just made a quick RPM of libbgcode and used that). After a lot of struggles with this Claude thought that parsing the bgcode file in python natively would be easier than trying to use the C++ library, so I went down that route. I started by feeding Claude a description of the format that I found online and asked it to write me a parser for it. It didn&#8217;t work very well and I ended up having a lot of back and forth, testing and debugging, finding more documentation, including a blog post about this meatpack format used inside the file, but it still didn&#8217;t really work very well. In the end what probably helped the most was asking it to use the relevant files from libbgcode and Prusa Slicer as documentation, because even if that too took a lot of back and forth, eventually I had a working application that was able to extract the tool change data and associated colors from the file. I ended up using one external dependency which was the heatshrink2 library that I PIP installed, but while that worked correctly, it took a look time for me and Claude to figure out exactly what parameters to feed it to work with the Prusa generated file.<br /><div class="wp-caption alignright" id="attachment_11263" style="width: 244px;"><img alt="Screenshot of Prusa Color Mate" class="size-medium wp-image-11263" height="300" src="https://blogs.gnome.org/uraeus/files/2025/09/prusacolormate-234x300.png" width="234" /><p class="wp-caption-text" id="caption-attachment-11263">Screenshot of Prusa Color Mate</p></div></p><p>So know I had the working application going and was able to verify it with my first print. I even polished it up a little, by also adding detection of the manual filament change code, so that people who try to use the application will be made aware they need to add that through Prusa Slicer. Maybe I could bake that into the tool, but atm I got only bgcode decoders, not encoders, in my project.<br /><div class="wp-caption alignright" id="attachment_11266" style="width: 310px;"><img alt="Missing G Code warning" class="size-medium wp-image-11266" height="241" src="https://blogs.gnome.org/uraeus/files/2025/09/Screenshot-From-2025-09-09-10-19-13-300x241.png" width="300" /><p class="wp-caption-text" id="caption-attachment-11266">Warning showed for missing G Code <img alt="Dialog that gives detailed instructions for how to add G Code" class="size-medium wp-image-11265" height="300" src="https://blogs.gnome.org/uraeus/files/2025/09/Screenshot-From-2025-09-09-10-19-17-133x300.png" width="133" /> Dialog that gives detailed instructions for how to add G Code</p></div></p><p>So to conclude, it probably took me 2.5 days to write this application using Claude, it is a fairly niche tool, so I don&#8217;t expect a lot of users, but I made it to solve a problem for myself. If I had to write this pre-AI myself it would have taken me weeks, like figuring out the different formats and how library APIs worked etc. would have taken me a long time. So I am not an especially proficient coder, so a better coder than me could probably put this together quicker than I would, but I think this is part of what I think will change with AI, that even with limited time and technical skills you can put together simple applications like this to solve your own problems.</p><p>If you are a Prusa Core One user and would like to play with multicolor prints you can find <a class="external" href="https://gitlab.com/cschalle/prusa_color_mate">Prusa Color Mate on Gitlab</a>. I have not tested it on any other system or printer than my own, so I don&#8217;t even know if it will work with other non-Core One Prusa printers. There are rpms for Fedora you can download in the packaging directory of the gitlab repo, which also includes a RPM for the heatshrink2 library. </p><p>As for future plans for this application I don&#8217;t really have any. It solves my issue the way it is today, but if there turns out to be an interested user community out there maybe I will try to clean it up and create a proper flatpak for it.</p></description><author>Christian Schaller</author><dc:creator>Christian Schaller</dc:creator><pubDate>Tue, 09 Sep 2025 14:39:49 GMT</pubDate><guid isPermaLink="true">https://blogs.gnome.org/uraeus/2025/09/09/more-adventures-in-the-land-of-ai-and-open-source/</guid></item></channel></rss>