• Pl chevron_right

      Felipe Borges: One Project Selected for the December 2025 Outreachy Cohort with GNOME!

      news.movim.eu / PlanetGnome • 3 December 2025

    We are happy to announce that the GNOME Foundation is sponsoring an Outreachy project for the December 2025 Outreachy cohort.

    Outreachy provides internships to people subject to systemic bias and impacted by underrepresentation in the tech industry where they are living.

    Let’s welcome Malika Asman! Malika will be working with Lucas Baudin on improving document signing in Papers , our document viewer.

    The new contributor will soon get their blogs added to Planet GNOME making it easy for the GNOME community to get to know them and the projects that they will be working on. We would like to also thank our mentor, Lucas  for supporting Outreachy and helping new contributors enter our project.

    If you have any questions, feel free to reply to this Discourse topic or message us privately at soc-admins@gnome.org.

    • Pl chevron_right

      Cassidy James Blaede: Looking back on GNOME in 2025—and looking forward to 2026

      news.movim.eu / PlanetGnome • 2 December 2025 • 3 minutes

    foot-dark.png

    This past year has been an exceptional one for GNOME. The project released two excellent releases on schedule with GNOME 48 in March and GNOME 49 in September. Contributors have been relentless in delivering a set of new and improved default apps, constant performance improvements across the board benefitting everyone (but especially lower-specced hardware), a better experience on high end hardware like HiDPI and HDR displays, refined design and refreshed typography, all new digital wellbeing features and parental controls improvements, improved accessibility support across the entire platform, and much more.

    Just take a look back through This Week in GNOME where contributors provided updates on development every single week of 2025 so far. (And a huge thank you to Felix, who puts This Week in GNOME together !)

    All of these improvements were delivered for free to users of GNOME across distributions—and even beyond users of GNOME itself via GNOME apps running on any desktop thanks to Flatpak and distribution via Flathub.

    Earlier this year the GNOME Foundation also relaunched Friends of GNOME where you can set up a small recurring donation to help fund initiatives including:

    • infrastructure freely provided to Core, Circle, and World projects
    • services for GNOME Foundation members like blog hosting, chat, and video conferencing
    • development of Flathub
    • community travel sponsorship

    While I’m proud of what GNOME has accomplished in 2025 and that the GNOME Foundation is operating sustainably, I’m personally even more excited to look ahead to what I hope the Foundation will be able to achieve in the coming year.

    Let’s Reach 1,500 Friends of GNOME

    The newly-formed fundraising committee kicked off their efforts by announcing a simple goal to close out 2025: let’s reach 1,500 Friends of GNOME! If we can reach this goal by the end of this year, it will help GNOME deliver even more in 2026; for example, by enabling the Foundation to sponsor more community travel for hackfests and conferences, and potentially even sponsoring specific, targeted development work.

    But GNOME needs your help!

    How You Can Help

    First, if you’re not already a Friend of GNOME, please consider setting up a small recurring donation at donate.gnome.org . Every little bit helps, and donating less but consistently is super valuable to not only keep the lights on at the GNOME Foundation, but to enable explicit budgeting for and delivering on more interesting initiatives that directly support the community and the development of GNOME itself.

    Become a Friend of GNOME

    If you’re already a Friend of GNOME (or not able to commit to that at the moment—no hard feelings!), please consider sharing this message far and wide! I consistently hear that not only do so many users of GNOME not know that it’s a nonprofit, but they don’t know that the GNOME Foundation relies on individual donations—and that users can help out, too! Please share this post to your circles—especially outside of usual contributor spaces—to let them know the cool things GNOME does and that GNOME could use their help to be able to do even more in the coming year.

    Lastly, if you represent an organization that relies on GNOME or is invested in its continued success, please consider a corporate sponsorship . While this sponsorship comes with no strings attached, it’s a really powerful way to show that your organization supports Free and Open Source software—and puts their money where their mouth is.

    Sponsor GNOME

    Thank You!

    Thank you again to all of the dedicated contributors to GNOME making everyone’s computing experience that much better. As we close out 2025, I’m excited by the prospect of the GNOME Foundation being able to not just be sustainable, but—with your help—to take an even more active role in supporting our community and the development of GNOME.

    And of course, thank you to all 700+ current Friends of GNOME ; your gracious support has helped GNOME achieve everything in 2025 while ensuring the sustainability of the Foundation going forward. Let’s see if we can close out the year with 1,500 Friends helping GNOME do even more!

    • Pl chevron_right

      Federico Mena-Quintero: Mutation testing for librsvg

      news.movim.eu / PlanetGnome • 1 December 2025 • 10 minutes

    I was reading a blog post about the testing strategy for the Wild linker , when I came upon a link to cargo-mutants , a mutation testing tool for Rust. The tool promised to be easy to set up, so I gave it a try. I'm happy to find that it totally delivers!

    Briefly: mutation testing catches cases where bugs are deliberately inserted in the source code, but the test suite fails to catch them: after making the incorrect changes, all the tests still pass. This indicates a gap in the test suite.

    Previously I had only seen mentions of "mutation testing" in passing, as something exotic to be done when testing compilers. I don't recall seeing it as a general tool; maybe I have not been looking closely enough.

    Setup and running

    Setting up cargo-mutants is easy enough: you can cargo install cargo-mutants and run it with cargo mutants .

    For librsvg this ran for a few hours, but I discovered a couple of things related to the way the librsvg repository is structured. The repo is a cargo workspace with multiple crates: the librsvg implementation and public Rust API, the rsvg-convert binary, and some utilities like rsvg-bench .

    1. By default cargo-mutants only seemed to pick up the tests for rsvg-convert . I think it may have done this because it is the only binary in the workspace that has a test suite (e.g. rsvg-bench does not have a test suite).

    2. I had to run cargo mutants --package librsvg to tell it to consider the test suite for the librsvg crate, which is the main library. I think I could have used cargo mutants --workspace to make it run all the things; maybe I'll try that next time.

    Initial results

    My initial run on rsvg-covert produced useful results; cargo-mutants found 32 mutations in the rsvg-convert source code that ought to have caused failures, but the test suite didn't catch them.

    The running output of cargo-mutants on the librsvg

    The second run, on the librsvg crate, took about 10 hours. It is fascinating to watch it run. In the end it found 889 mutations with bugs that the test suite couldn't catch:

    5243 mutants tested in 9h 53m 15s: 889 missed, 3663 caught, 674 unviable, 17 timeouts
    

    What does that mean?

    • 5243 mutants tested : how many modifications were tried on the code.

    • 889 missed : The important ones: after a modification was made, the test suite failed to catch this modification.

    • 3663 caught : Good! The test suite caught these!

    • 674 unviable : These modifications didn't compile. Nothing to do.

    • 17 timeouts : Worth investigating; maybe a function can be marked to be skipped for mutation.

    Starting to analyze the results

    Due to the way cargo-mutants works, the "missed" results come in an arbitrary order, spread among all the source files:

    rsvg/src/path_parser.rs:857:9: replace <impl fmt::Display for ParseError>::fmt -> fmt::Result with Ok(Default::default())
    rsvg/src/drawing_ctx.rs:732:33: replace > with == in DrawingCtx::check_layer_nesting_depth
    rsvg/src/filters/lighting.rs:931:16: replace / with * in Normal::bottom_left
    rsvg/src/test_utils/compare_surfaces.rs:24:9: replace <impl fmt::Display for BufferDiff>::fmt -> fmt::Result with Ok(Default::default())
    rsvg/src/filters/turbulence.rs:133:22: replace - with / in setup_seed
    rsvg/src/document.rs:627:24: replace match guard is_mime_type(x, "image", "svg+xml") with false in ResourceType::from
    rsvg/src/length.rs:472:57: replace * with + in CssLength<N, V>::to_points
    

    So, I started by sorting the missed.txt file from the results. This is much better:

    rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with false
    rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with true
    rsvg/src/accept_language.rs:78:9: replace <impl fmt::Display for AcceptLanguageError>::fmt -> fmt::Result with Ok(Default::default())
    rsvg/src/angle.rs:40:22: replace < with <= in Angle::bisect
    rsvg/src/angle.rs:41:56: replace - with + in Angle::bisect
    rsvg/src/angle.rs:49:35: replace + with - in Angle::flip
    rsvg/src/angle.rs:57:23: replace < with <= in Angle::normalize
    

    With the sorted results, I can clearly see how cargo-mutants gradually does its modifications on (say) all the arithmetic and logic operators to try to find changes that would not be caught by the test suite.

    Look at the first two lines from above, the ones that refer to AcceptLanguage::any_matches :

    rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with false
    rsvg/src/accept_language.rs:136:9: replace AcceptLanguage::any_matches -> bool with true
    

    Now look at the corresponding lines in the source:

    ... impl AcceptLanguage {
    135     fn any_matches(&self, tag: &LanguageTag) -> bool {
    136         self.iter().any(|(self_tag, _weight)| tag.matches(self_tag))
    137     }
    ... }
    }
    

    The two lines from missed.txt mean that if the body of this any_matches() function were replaced with just true or false , instead of its actual work, there would be no failed tests:

    135     fn any_matches(&self, tag: &LanguageTag) -> bool {
    136         false // or true, either version wouldn't affect the tests
    137     }
    }
    

    This is bad! It indicates that the test suite does not check that this function, or the surrounding code, is working correctly. And yet, the test coverage report for those lines shows that they are indeed getting executed by the test suite. What is going on?

    I think this is what is happening:

    • The librsvg crate's tests do not have tests for AcceptLanguage::any_matches .
    • The rsvg_convert crate's integration tests do have a test for its --accept-language option, and that is what causes this code to get executed and shown as covered in the coverage report.
    • This run of cargo-mutants was just for the librsvg crate, not for the integrated librsvg plus rsvg_convert .

    Getting a bit pedantic with the purpose of tests, rsvg-convert assumes that the underlying librsvg library works correctly. The library advertises support in its API for matching based on AcceptLanguage, even though it doesn't test it internally.

    On the other hand, rsvg-convert has a test for its own --accept-language option, in the sense of "did we implement this command-line option correctly", not in the sense of "does librsvg implement the AcceptLanguage functionality correctly".

    After adding a little unit test for AcceptLanguage::any_matches in the librsvg crate, we can run cargo-mutants just for that the accept_language.rs file again:

    # cargo mutants --package librsvg --file accept_language.rs
    Found 37 mutants to test
    ok       Unmutated baseline in 24.9s build + 6.1s test
     INFO Auto-set test timeout to 31s
    MISSED   rsvg/src/accept_language.rs:78:9: replace <impl fmt::Display for AcceptLanguageError>::fmt -> fmt::Result with Ok(Default::default()) in 4.8s build + 6.5s test
    37 mutants tested in 2m 59s: 1 missed, 26 caught, 10 unviable
    

    Great! As expected, we just have 1 missed mutant on that file now. Let's look into it.

    The function in question is now <impl fmt::Display for AcceptLanguageError>::fmt , an error formatter for the AcceptLanguageError type:

    impl fmt::Display for AcceptLanguageError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            match self {
                Self::NoElements => write!(f, "no language tags in list"),
                Self::InvalidCharacters => write!(f, "invalid characters in language list"),
                Self::InvalidLanguageTag(e) => write!(f, "invalid language tag: {e}"),
                Self::InvalidWeight => write!(f, "invalid q= weight"),
            }
        }
    }
    

    What cargo-mutants means by " replace ... -> fmt::Result with Ok(Default::default()) is that if this function were modified to just be like this:

    impl fmt::Display for AcceptLanguageError {
        fn fmt(&self, f: &mut fmt::Formatter<'_>) -> fmt::Result {
            Ok(Default::default())
        }
    }
    

    then no tests would catch that. Now, this is just a formatter function; the fmt::Result it returns is just whether the underlying call to write!() succeeded. When cargo-mutants discovers that it can change this function to return Ok(Default::default()) it is because fmt::Result is defined as Result<(), fmt::Error> , which implements Default because the unit type () implements Default .

    In librsvg, those AcceptLanguageError errors are just surfaced as strings for rsvg-convert, so that if you give it a command-line argument with an invalid value like --accept-language=foo , it will print the appropriate error. However, rsvg-convert does not make any promises as to the content of error messages, so I think it is acceptable to not test this error formatter — just to make sure it handles all the cases, which is already guaranteed by its match statement. Rationale:

    • There already are tests to ensure that the error codes are computed correctly in the parser for AcceptLanguage ; those are the AcceptLanguageError 's enumeration variants.

    • There is a test in rsvg-convert's test suite to ensure that it detects invalid language tags and reports them.

    For cases like this, cargo-mutants allows marking code to be skipped . After marking this fmt implementation with #[mutants::skip] , there are no more missed mutants in accept_language.rs .

    Yay!

    Understanding the tool

    You should absolutely read " using results " in the cargo-mutants documentation, which is very well-written. It gives excellent suggestions for how to deal with missed mutants. Again, these indicate potential gaps in your test suite. The documentation discusses how to think about what to do, and I found it very helpful.

    Then you should read about genres of mutants . It tells you the kind of modifications that cargo-mutants does to your code. Apart from changing individual operators to try to compute incorrect results, it also does things like replacing whole function bodies to return a different value instead. What if a function returns Default::default() instead of your carefully computed value? What if a boolean function always returns true ? What if a function that returns a HashMap always returns an empty hash table, or one full with the product of all keys and values? That is, do your tests actually check your invariants, or your assumptions about the shape of the results of computations? It is really interesting stuff!

    Future work for librsvg

    The documentation for cargo-mutants suggests how to use it in CI, to ensure that no uncaught mutants are merged into the code . I will probably investigate this once I have fixed all the missed mutants; this will take me a few weeks at least.

    Librsvg already has the gitlab incantation to show test coverage for patches in merge requests, so it would be nice to know if the existing tests, or any new added tests, are missing any conditions in the MR. That can be caught with cargo-mutants.

    Hackery relevant to my tests, but not to this article

    If you are just reading about mutation testing, you can ignore this section. If you are interested in the practicalities of compilation, read on!

    The source code for the librsvg crate uses a bit of conditional compilation to select whether to export functions that are used by the integration tests as well as the crate's internal tests. For example, there is some code for diffing two images, and this is used when comparing the pixel output of rendering an SVG to a reference image. For historical reasons, this code ended up in the main library, so that it can run its own internal tests, but then the rest of the integration tests also use this code to diff images. The librsvg crate exports the "diff two images" functions only if it is being compiled for the integration tests, and it doesn't export them for a normal build of the public API.

    Somehow, cargo-mutants didn't understand this, and the integration tests did not build since the cargo feature to select that conditionally-compiled code... wasn't active, or something. I tried enabling it by hand with something like cargo mutants --package librsvg -- --features test-utils but that still didn't work.

    So, I hacked up a temporary version of the source tree just for mutation testing, which always exports the functions for diffing images, without conditional compilation. In the future it might be possible to split out that code to a separate crate that is only used where needed and never exported. I am not sure how it would be structured, since that code also depends on librsvg's internal representation of pixel images. Maybe we can move the whole thing out to a separate crate? Stop using Cairo image surfaces as the way to represent pixel images? Who knows!

    • Pl chevron_right

      GNOME Foundation News: Join Friends of GNOME

      news.movim.eu / PlanetGnome • 1 December 2025 • 1 minute

    This post was contributed by the Fundraising Committee from the GNOME Foundation.

    This week we are launching an end-of-year fundraising campaign with a simple goal: to reach 1,500 Friends of GNOME by the end of the year. We need your help: become a Friend of GNOME today at donate.gnome.org !

    Why give?

    We are a nearly 30-year-old Free Software project whose contributors believe in building something greater than ourselves. We give our work and time freely so that the world benefits. We believe in a world where everyone is empowered by technology they can trust, and we help make that possible by tirelessly building a diverse and sustainable free software personal computing ecosystem.

    This past year has been full of highlights from the community, culminating in the GNOME 48 and GNOME 49 releases. You can also read all about what contributors have been shipping week after week in This Week in GNOME , which is submitted and curated by community members.

    The GNOME Foundation supports the GNOME project by providing infrastructure, services for contributors, development of Flathub, community travel sponsorship, events, and more. Giving to the GNOME Foundation helps ensure we stay sustainable for the future, enables us to invest more directly into the community and development, and ultimately helps GNOME deliver even more goodness to each and every user for free.

    Become a Friend of GNOME

    Thank you to existing Friends of GNOME, sponsors, and supporters

    Of course, we would like to thank our 744 existing Friends of GNOME and corporate sponsors for their recurring support, as well our advisory board members for their support and guidance. And thank you to the many organizations that support us in other ways, including with infrastructure.

    Join us in celebrating!

    This week, we will also be sharing and celebrating the accomplishments of GNOME and our contributors over the past year on social media. Be sure to follow #FriendsOfGNOME across our social media accounts:

    Finally, if you’re already a Friend of GNOME or join us this month, please share your story with #FriendsOfGNOME as well so that we can thank you!

    • Pl chevron_right

      Sophie Herold: Weekly report #75

      news.movim.eu / PlanetGnome • 30 November 2025 • 3 minutes

    Hello world! Last week, I asked the people that financially support me, if I should post my updates publicly. A majority voted to release my future weekly reports to the public, some voted to make them public every other week. So I will try to post some of them publicly in the future.

    These updates are made possible by the amazing people that support me on Ko-fi , Patreon , Open Collective , and GitHub ! Thank you so much, folks!

    Since this is my first public weekly report, let’s maybe start with a short introduction: I started my GNOME related work in 2018 by working a bit on Gajim UI and starting the Pika Backup project. Since March 2024 I have slowly started to ask for donations for my work on GNOME. I am disabled due to ME/CFS and being autistic. Working within the GNOME project allows me to earn a bit of extra money on top of my social assistance while also doing something that I love, and I can do at my own pace. I am working on too many things within GNOME: Pika Backup, Loupe, glycin, websites, Release Team, Circle Committee, and a bunch of other things, like trying to advocate for queer and disabled people within the GNOME community.

    You will notice that my weekly reports will usually not contain giant achievements or huge promises. Maintenance work can be tedious, and generally, fundraisers have developed a frustrating habit of frequently over-promising and under-delivering. I don’t want to be part of that.

    So, let’s finally get to the actual updates for last week. We landed the translation support within www.gnome.org. At the moment, this is still practically invisible. We are waiting for the Translation Team to enable translators to do the work. Once we got some translations, we will also enable the language selection dialog. I also asked if we want translations for donate.gnome.org , but got no feedback so far.

    A release for gst-thumbnailers is now out, such that distributions can package it. There is more about the thumbnailers in the Release Team issue .  I updated the Circle benefits list, and updated circle.gnome.org to the version that does not list apps and components on its own. That’s something design people wanted to see for a while. Since the old Circle page stopped building, that was a good moment to finally do it :)

    I spend some time on Pika Backup hoping that we are very close to a 0.8 beta release. However, I noticed that the current state of the setup dialog isn’t what we want. After discussing the options with Fina, we are now sure that we have to rework what we have in some way. Not shying away from throwing code away, and reworking something again, is often very important for approaching at a good result. Maybe I will summarize this example, once we have arrived at a solution.

    Some of the less tangible work this week: Shortly discussed Emmanuele’s GNOME Governance proposal in Matrix. Something that might look like making changes within GNOME more complicated from the outside. But the actual goal is the opposite: Currently, it can be very hard to make changes within GNOME since there is no clear way how to go about it. This not only slows people down but, at least for me, can also me quite emotionally draining. So, a very important proposal. Maybe we got a tiny step closer to making it reality. Also contributed to an internal Release Team discussion and contacted an involved party.

    That’s all for this week! If you want to support my work financially, you can check my GitLab profile .

    Hope you all have a great week!

    • Pl chevron_right

      Allan Day: GNOME Foundation Update, 2025-11-28

      news.movim.eu / PlanetGnome • 28 November 2025 • 4 minutes

    Welcome to another GNOME Foundation update; an overview of everything that’s been happening at the Foundation. There was no update last week, due to me being away from my computer last Friday, so this post covers a two week period rather than the usual single week.

    Many thanks to everyone who responded to my request for feedback in my previous post! It was great to hear your views on these posts, and it was extremely motivating to get positive feedback on the blog series.

    Budget report

    In case you didn’t see it, last week Rob posted a detailed breakdown of the Foundation’s current operating budget . This is the second year in a row that we have provided a budget report for the community, and I’m thrilled that we’ve been able to keep up the momentum around financial transparency. I’d encourage you to give it a read if you haven’t already.

    Community travel

    One positive aspect of the current budget is that we have a healthy community travel budget, and I really want to encourage members to make use of the fund. The travel budget is there to be spent, and we absolutely want to see community members applying for travel. If you have been interested in organising a hackfest, or attending a GNOME conference, and finances have been a barrier, please do make use of the funding that is available. Information about how to apply can be found in the handbook .

    Also on travel: we are currently looking to recruit additional volunteers to help administer the travel budget, as part of the Travel Committee. So, if you are interested in helping with GNOME and would like to get involved, please do get in touch using the comments below, or by messaging the Travel Committee.

    Outreachy

    The Foundation has a proud history of funding outreach efforts, and has regularly supported interns through Outreachy . The December to March round is almost upon us, and the Internship Committee has coordinated the selection of an intern who we will be sponsoring. We were pleased to release the funding for this internship this week. More details about the internship itself will follow.

    Banking and finance systems

    As mentioned in recent updates, we have been working through a round of improvements to our banking setup, which will give us enhanced fraud protection, as well as automatic finance management features. This week we had a training session with our bank, the fraud protection features were turned on, and I signed the last of the paperwork. As a result, this round of work is now complete.

    I have also been going through the process of signing up for the new financial system that Dawn our new finance advisor will be setting up for us.

    Bookkeeping meetings

    Our regular monthly bookkeeping meeting happened last week, and we had another follow-up call more recently. We are still working through the 2024-25 financial year end accounts, which primarily involves resolving a list of small questions, to make sure that the accounts are 100% complete and accurate. Our bookkeeper has also been very patiently answering questions from Deepa, our treasurer, and myself as we continue to familiarise ourselves with the finance and accounting setup (thank you!)

    Board meeting

    The Board had a regular meeting this week. The topics under discussion included:

    • Setting goals for the upcoming fundraising campaign, in particular what the fundraising target should be, and what programs we want to fund with the proceeds.
    • Improving our minutes to meet the needs of different audiences (directors, auditors, the IRS, members, and so on). We also worked on a plan to clear the backlog of unapproved minutes.
    • Planning for a Board hackfest prior to next FOSDEM.

    We came away with a healthy list of action items, and I’m looking forward to making progress in each of these areas.

    GNOME.Asia

    Our upcoming conference is Tokyo continues to be a focus, and Kristi is busy putting the final arrangements together. The event is just 15 days away! A reminder: if you want to participate, please do head over to the site and register.

    Flathub

    There has been some good progress around Flathub over the past two weeks. Bart has done quite a bit of work to improve the performance of the Flathub website, which I’m sure users will appreciate. We also received some key pieces of legal work, which are required as part of the roadmap to establish Flathub as its own financial/legal entity. With those legal documents in place we have turned our attention to planning Flathub’s financial systems; discussions about this are ongoing.

    Digital Wellbeing

    There was another review call this week to check on progress as the current phase of the program reaches its final stages. The main focus right now is making sure that the new screen time limits feature is in good shape before we use up the remaining funding.

    Progress is looking good in general: the main changes for GNOME Shell and Settings have all been merged. There are two more pieces of work to land before we can say that we are in a feature complete state. After that we will circle back to UX review and papercut fixing. If you want more information about these features, I would recommend Ignacy’s recent post on the topic .

    Philip has also published a fantastic post on the web filtering functionality that has been implemented as part of this program.

    That’s it for this week! Thanks for reading, and see you next week.

    • Pl chevron_right

      Philip Withnall: Parental controls web filtering backend

      news.movim.eu / PlanetGnome • 27 November 2025 • 5 minutes

    In my previous post I gave an overview of the backend for the screen time limits feature of parental controls in GNOME. In this post, I’ll try and do the same for the web filtering feature.

    We haven’t said much about web filtering so far, because the user interface for it isn’t finished yet. The backend is, though, and it will get plumbed up eventually. Currently we don’t have a GNOME release targeted for it yet.

    When is web filterings? What is web filtering?

    (Apologies to Radio 4 Friday Night Comedy .)

    Firstly, what is the aim of web filtering? As with screen time limits, we’ve written a design document which (hopefully) covers everything. But the summary is that it should allow parents to filter out age-inappropriate content on the web when it’s accessed by child accounts, while not breaking the web (for example, by breaking TLS for websites) and not requiring us (as a project) to become curators of filter lists. It needs to work for all apps on the system (lots of apps other than web browsers can show web content), and needs to be able to filter things differently for different users (two different children of different ages might use the same computer, as well as the parents themselves).

    After looking at various different possible ways of implementing it, the best solution seemed to be to write an NSS module to respond to name resolution (i.e. DNS) requests and potentially block them according to a per-user filter list.

    A brief introduction to NSS

    NSS (Name Service Switch) is a standardised name lookup API in libc. It’s used for hostname resolution, but also for user accounts and various other things. Names are resolved by various modules which are dlopen() ed into your process by libc and queried in the order given in /etc/nsswitch.conf . So for hostname resolution, a typical configuration in nsswitch.conf would cause libc to query the module which looks at /etc/hosts first, then the module which checks your machine’s hostname, then the mDNS module, then systemd-resolved.

    So, we can insert our NSS module into /etc/nsswitch.conf , have it run somewhere before systemd-resolved (which in this example does the actual DNS resolution), and have it return a sinkhole address for blocked domains. Because /etc/nsswitch.conf is read by libc within your process, this means that the configuration needs to be modified for containers (flatpak) as well as on the host system.

    Because the filter module is loaded into the name lookup layer, this means that content filtering (as opposed to domain name filtering) is not possible with this approach. That’s fine — content filtering is hard, I’m not sure it gives better results overall than domain name filtering, and means we can’t rely on existing domain name filter lists which are well maintained and regularly updated. We’re not planning on adding content filtering.

    It also means that DNS-over-HTTPS/-TLS can be supported, as long as the app doesn’t implement it natively (i.e. by talking HTTPS over a socket itself). Some browsers do that, so the module needs to set a canary to tell them to disable it. DNS-over-HTTPS/-TLS can still be used if it’s implemented by one of the NSS modules, like systemd-resolved.

    Nothing here stops apps from deliberately bypassing the filtering if they want, perhaps by talking DNS over UDP directly, or by calling secret internal glibc functions to override nsswitch.conf . In the future, we’d have to implement per-app network sandboxing to prevent bypasses. But for the moment, trusting the apps to cooperate with parental controls is fine.

    Filter update daemon

    So we have a way of blocking things; but how does it know what to block? There are a lot of filter lists out there on the internet, targeted at existing web filtering software. Basically, a filter list is a list of domain names to block. Some filter lists allow wildcards and regexps, others just allow plain strings. For simplicity, we’ve gone with plain strings.

    We allow the parent to choose zero or more filter lists to build a web filtering policy for a child. Typically, these filter lists will correspond to categories of content, so the parent could choose a filter list for advertising, and another for violent content, for example. The web filtering policy is basically the set of these filter lists, plus some options like “do you want to enforce safe search”. This policy is, like all other parental controls policies, stored against the child user in accounts-service .

    Combine these filter lists, and you have the filter list to give to NSS in the child’s session, right? Not quite — because the internet unfortunately keeps changing, filter lists need to be updated regularly. So actually what we need is a system daemon which can regularly check the filter lists for updates, combine them, and make them available as a compiled file to the child’s NSS module — for each user on the system.

    This daemon is malcontent-webd . It has a D-Bus interface to allow the parent to trigger compiling the filter for a child when changing the parental controls policy for that child in the UI, and to get detailed feedback on any errors. Since the filter lists come from third parties on the internet, there are various ways they could have an error.

    It also has a timer unit trigger, malcontent-webd-update , which is what triggers it to periodically check the filter lists for all users for updates.

    High-level diagram of the web filtering system, showing the major daemons and processes, files, and IPC calls. If it’s not clear, the awful squiggled line in the bottom left is meant to be a cloud. Maybe this representation is apt.

    And that’s it! Hopefully it’ll be available in a GNOME release once we’ve implemented the user interface for it and done some more end-to-end testing, but the screen time limits work is taking priority over it.

    • Pl chevron_right

      Arun Raghavan: Rusty Pipes and Oxidized Wires

      news.movim.eu / PlanetGnome • 24 November 2025

    In case you missed it, the GStreamer Conference 2025 videos are up !

    This includes my talk on the new PipeWire native Rust bindings . You’ll want to skip the first 1:20 to get to the start.

    I talk a little bit about the motivation and structure of the project, and discuss my experience writing this low-level library in Rust.

    There are a lot of great talks, so it’s worth catching up if you weren’t there (or, if like me, you were there and had to pick between the two tracks with great difficulty).

    Comments and feedback are welcome! In the future, I’ll post a more long form update about the state of these bindings here as well.

    • Pl chevron_right

      Jakub Steiner: 12 months instead of 12 minutes

      news.movim.eu / PlanetGnome • 21 November 2025 • 2 minutes

    Hey Kids! Other than raving about GNOME.org being a static HTML , there’s one more aspect I’d like to get back to in this writing exercise called a blog post.

    Share card gets updated every release too

    I’ve recently come across an apalling genAI website for a project I hold deerly so I thought I’d give a glimpse on how we used to do things in the olden days. It is probably not going to be done this way anymore in the enshittified timeline we ended up in. The two options available these days are — a quickly generated slop website or no website at all, because privately owned social media is where it’s at.

    The wanna-be-catchy title of this post comes from the fact the website underwent numerous iterations (iterations is the core principle of good design) spanning over a year before we introduced the redesign.

    So how did we end up with a 3D model of a laptop for the hero image on the GNOME website, rather than something generated in a couple of seconds and a small town worth of drinking water or a simple SVG illustration?

    The hero image is static now, but used to be a scroll based animation at the early days. It could have become a simple vector style illustration, but I really enjoy the light interaction of the screen and the laptop, especially between the light and dark variants. Toggling dark mode has been my favorite fidget spinner.

    Creating light/dark variants is a bit tedious to do manually every release, but automating still a bit too hard to pull off (the taking screenshots of a nightly OS bit). There’s also the fun of picking a theme for the screenshot rather than doing the same thing over and over. Doing the screenshooting manually meant automating the rest, as a 6 month cycle is enough time to forget how things are done. The process is held together with duct tape, I mean a python script, that renders the website image assets from the few screenshots captured using GNOME OS running inside Boxes . Two great invisible things made by amazing individuals that could go away in an instant and that thought gives me a dose of anxiety.

    light.webp

    This does take a minute to render on a laptop (CPU only Cycles), but is a matter of a single invocation and a git commit. So far it has survived a couple of Blender releases, so fingers crossed for the future.

    Sophie has recently been looking into translations , so we might reconsider that 3D approach if translated screenshots become viable (and have them contained in an SVG similar to how os.gnome.org is done). So far the 3D hero has always been in sync with the release, unlike in our Wordpress days. Fingers crossed.