phone

    • chevron_right

      Cassidy James Blaede: Publish Your Godot Engine Game to Flathub

      news.movim.eu / PlanetGnome · Wednesday, 11 December, 2024 - 00:00 · 19 minutes

    card.png

    If you follow me on the fediverse ( @cassidy@blaede.family ), you may have seen me recently gushing about ROTA , a video game I recently discovered. Besides the absolutely charming design and ridiculously satisfying gameplay, the game itself is open source , meaning the developer has published the game’s underlying code out to the world for anyone to see, learn from, and adapt.

    Screenshot of ROTA, a colorful 2D platformer

    As someone passionate about the Linux desktop ecosystem broadly and Flathub as an app store specifically, I was excited by the possibility of helping to get ROTA onto Flathub so more people could play it—plus, such a high-quality game being on Flathub helps the reputation and image of Flathub itself. So I kicked off a personal project (with the support of my employer¹) to get it onto Flathub —and I learned a lot —especially what steps were confusing or unclear.

    As a result, here’s how I recommend publishing your Godot Engine game to Flathub. Oh, and don’t be too scared; despite the monumental size of this blog post, I promise it’s actually pretty easy! 😇

    Overview

    Let’s take a look at what we’re going to achieve at a high level. This post assumes you have source code for a game built with a relatively recent version of Godot Engine (e.g. Godot Engine 3 or 4), access to a Linux computer or VM for testing, and a GitHub account. If you’re missing one of those, get that sorted before continuing! You can also check the list of definitions at the bottom of this page for reference if you need to better understand something, and be sure to check out the Flathub documentation for a lot more details on Flatpak publishing in general.

    Illustration with the Godot Engine logo, then an arrow pointing to the Flathub logo

    To build a Flatpak of a Godot Engine game, we only need three things:

    1. Exported PCK file
    2. Desktop Entry, icon, and MetaInfo files
    3. Flatpak manifest to put it all together

    The trick is knowing how and where to provide each of these for the best experience publishing your game (and especially updates) to Flathub. There are a bunch of ways you can do it, but I strongly recommend:

    1. Upload your PCK file to a public, versioned URL, e.g. as a source code release artifact.

    2. Include the Desktop Entry, icon, and MetaInfo files in the repo with your game’s source code if it’s open source, or provide them via a dedicated repo, versioned URL, or source code release artifact.

      You can alternatively upload these directly to the Flatpak Manifest repository created by Flathub, but it’s better to keep them with your game’s other files if possible.

    3. Your manifest will live in a dedicated GitHub repo owned by the Flathub org. It’s nice (but not required) to also include a version of your manifest with your game’s source code for easier development and testing.

    Let’s get into each of those steps in more detail.

    1. Handling Your PCK File

    When you export a Godot Engine game for PC, you’re actually creating a platform-agnostic PCK file that contains all of your game’s code and assets, plus any plugins and libraries. The export also provides a copy of the platform-specific binary for your game which—despite its name—is actually just the Godot Engine runtime. The runtime simply looks for a PCK file of the same name sitting on disk next to it, and runs it. If you’re familiar with emulating retro games, you can think of the binary file as the Godot “emulator”, and the PCK file as your game’s “ROM.”

    To publish to Flathub, we’ll first need your game’s exported PCK file accessible somewhere on the web via a public, versioned URL. We’ll include that URL in the Flatpak manifest later so Flatpak Builder knows where to get the PCK file to bundle it with the Godot Engine binary into a Flatpak. Technically any publicly-accessible URL works here, but if your game is open source, I highly recommend you attach the PCK file as a release artifact wherever your source code is hosted (e.g. GitHub). This is the most similar to how open source software is typically released and distributed, and will be the most familiar to Flathub reviewers as well as potential contributors to your game.

    No matter where you publish your PCK file, the URL needs to be public, versioned, and stable : Flatpak Builder should always get the exact same file when hitting that URL for that release, and if you make a new release of your game, that version’s PCK file needs to be accessible at a new URL. I highly recommend semantic versioning for this, but it at least needs to be incrementally versioned so it’s always obvious to Flathub reviewers which version is newest, and so it matches to the version in the MetaInfo (more on that later). Match your game’s regular versioning scheme if possible.

    Bonus Points: Export in CI

    Since Godot Engine is open source and has command-line tools that run on Linux, you can use a source code platform’s continuous integration (CI) feature to automatically export and upload your PCK file. This differs a bit depending on your source code hosting platform and Godot Engine version, but triggered by a release, you run a job to:

    1. Grab the correct version of the Godot Engine tools binary from their GitHub release
    2. Export the PCK file from the command line ( Godot Docs )
    3. Upload that PCK file to the release itself

    This is advantageous because it ensures the PCK file attached to the release is exported from the exact code from in the release, increasing transparency and reducing the possibility of human error. Here is one example of such a CI workflow.

    About That Binary…

    Since the exported binary file is specific to the platform and Godot Engine version but not to your game, you do not need to provide it when publishing to Flathub; instead, Flathub builds Godot Engine runtime binaries from the Godot Engine source code for each supported version and processor architecture automatically. This means you just provide the PCK file and specify the Godot Engine version; Flathub will build and publish your Flatpak for 64-bit Intel/AMD PCs, 64-bit ARM computers, and any supported architectures in the future.

    2. Desktop Entry, Icon, and MetaInfo Files

    Desktop Entry and MetaInfo are FreeDesktop.org specifications that ensure Linux-based OSes interoperate; for our purposes, you just need to know that a Desktop Entry is what makes your game integrate on Linux (e.g. show in the dock, app menus, etc.), while MetaInfo provides everything needed to represent an app or game in an app store, like Flathub.

    Writing them is simple enough, especially given an example to start with. FreeDesktop.org has a MetaInfo Creator web app that can even generate a starting point for you for both, but note that for Flathub:

    • The icon name given must match the app ID, which the site lists as a “Unique Software Identifier”; don’t worry about icon filenames yet, as this can be handled later in the manifest

    • The “Executable Name” will be godot-runner for Godot Engine games

    If included in your source code repository, I recommend storing these files in a flatpak/ directory as launcher.desktop , metainfo.xml , and, if it doesn’t exist in a suitable format somewhere else in the repo, icon.png . The exported names will need to match the app ID, but that can be handled later in the manifest.

    If your game is not open source or these files are not to be stored in the source code repository, I recommend storing and serving these files from the same versioned web location as your game’s PCK file.

    Here are some specifics and simple examples to give you a better idea:

    Desktop Entry

    You’ll only ever need to set Name, Comment, Categories, and Icon. See the [Additional Categories spec]((https://specifications.freedesktop.org/menu-spec/latest/additional-category-registry.html) what you can include in addition to the Game category. Note the trailing semicolon!

    [Desktop Entry]
    Name=ROTA
    Comment=Gravity bends beneath your feet
    Categories=Game;KidsGame;
    Icon=net.hhoney.rota
    Exec=godot-runner
    Type=Application
    Terminal=false
    
    flatpak/launcher.desktop

    Icon

    This is pretty straightforward; you need an icon for your game! This icon is used to represent your game both for app stores like Flathub.org and the native app store clients on players computers, plus as the launcher icon e.g. on the player’s desktop or dock.

    If your game is open source, it’s easy enough to point to the same icon you use for other platform exports. If you must provide a unique icon for Flathub (e.g. for size or style reasons), you can include that version in the same place as your Desktop Entry and MetaInfo files. The icon must be a square as an SVG or 256×256 pixel (or larger) PNG.

    MetaInfo

    I won’t cover absolutely everything here (see the Flathub docs covering MetaInfo Guidelines for that), you should understand a few things about MetaInfo for your game.

    The top-most id must be in valid RDNN format for a domain or code hosting account associated with the game. For example, if your website is example.com , the ID should begin with com.example. . You should also use this prefix for the developer id to ensure all of your apps/games are associated with one another. I strongly recommend using your own domain name rather than an io.itch. or io.github. prefix here, but ultimately it is up to you. Note that as of writing, Itch.io-based IDs cannot be verified on Flathub .

    Screenshots should be at stable URLs; e.g. if pointing to a source code hosting service, make sure you’re using a tag (like 1.0.0 ) or commit (like 6c7dafea0993700258f77a2412eef7fca5fa559c ) in the URL rather than a branch name (like main ). This way the right screenshots will be included for the right versions, and won’t get incorrectly cached with an old version.

    You can provide various URLs to link people from your game’s app store listing to your website, an issue tracker, a donation link, etc. In the case of the donation link, the Flathub website displays this prominently as a button next to the download button.

    Branding colors and screenshots are some of your post powerful branding elements! Choose colors that compliment (but aren’t too close to) your game’s icon. For screenshots, include a caption related to the image to be shown below it, but do not include marketing copy or other graphics in the screenshots themselves as they may be rejected.

    Releases must be present, and are required to have a version number; this must be an incrementing version number as Flatpak Builder will use the latest version here to tag the build. I strongly recommend the simple Semantic Versioning format, but you may prefer to use a date-based 2024.12.10 format. These release notes show on your game’s listing in app stores and when players get updates, so be descriptive—and fun!

    Content ratings are developer-submitted, but may be reviewed by Flathub for accuracy—so please, be honest with them. Flathub uses the Open Age Ratings Service for the relevant metadata; it’s a free, open source, and straightforward survey that spits out the proper markup at the end.

    This example is pretty verbose, taking advantage of most features available:

    <?xml version="1.0" encoding="UTF-8"?>
    <component type="desktop-application">
      <id>net.hhoney.rota</id>
      
      <name>ROTA</name>
      <summary>Gravity bends beneath your feet</summary>
    
      <developer id="net.hhoney">
        <name translatable="no">HHoney Software</name>
      </developer>
    
      <description>
        <p>Move blocks and twist gravity to solve puzzles. Collect all 50 gems and explore 8 vibrant worlds.</p>
      </description>
    
      <content_rating type="oars-1.1">
        <content_attribute id="violence-cartoon">mild</content_attribute>
      </content_rating>
      
      <url type="homepage">https://hhoney.net</url>
      <url type="bugtracker">https://github.com/HarmonyHoney/ROTA/issues</url>
      <url type="donation">https://ko-fi.com/hhoney</url>
    
      <branding>
        <color type="primary" scheme_preference="light">#ff99ff</color>
        <color type="primary" scheme_preference="dark">#850087</color>
      </branding>
    
      <screenshots>
        <screenshot type="default">
          <image>https://raw.githubusercontent.com/HarmonyHoney/ROTA/6c7dafea0993700258f77a2412eef7fca5fa559c/media/image/assets/screens/1.png</image>
          <caption>Rotate gravity as you walk over the edge!</caption>
        </screenshot>
        <screenshot>
          <image>https://raw.githubusercontent.com/HarmonyHoney/ROTA/6c7dafea0993700258f77a2412eef7fca5fa559c/media/image/assets/screens/2.png</image>
          <caption>Push, pull and rotate gravity-blocks to traverse the stage and solve puzzles</caption>
        </screenshot>
        <screenshot>
          <image>https://raw.githubusercontent.com/HarmonyHoney/ROTA/6c7dafea0993700258f77a2412eef7fca5fa559c/media/image/assets/screens/3.png</image>
          <caption>Collect all 50 gems to unlock doors and explore 8 vibrant worlds!</caption>
        </screenshot>
      </screenshots>
    
      <releases>
        <release version="1.0" date="2022-05-07T22:18:44Z">
          <description>
            <p>Launch Day!!</p>
          </description>
        </release>
      </releases>
    
      <launchable type="desktop-id">net.hhoney.rota.desktop</launchable>
      <metadata_license>CC0-1.0</metadata_license>
      <project_license>Unlicense</project_license>
    </component>
    
    flatpak/metainfo.xml

    Bonus Points: Flathub Quality Guidelines

    Beyond Flathub’s base requirements for publishing games are their Quality Guidelines . These are slightly more opinionated human-judged guidelines that, if met, make your game eligible to be featured in the banners on the Flathub.org home page, as a daily-featured app, and in other places like in some native app store clients. You should strive to meet these guidelines if at all possible!

    One common snag is the icon: generally Flathub reviewers are more lenient with games, but if you need help meeting the guidelines for your Flathub listing, be sure to reach out on the Flathub Matrix chat or Discourse forum .

    3. Flatpak manifest

    Finally, the piece that puts it all together : your manifest! This can be a JSON or YAML file, but is named the same as your game’s app ID.

    The important bits that you’ll need to set here are the id (again matching the app ID), base-version for the Godot Engine version, the sources for where to get your PCK, Desktop Entry, MetaInfo, and icon files (in the below example, a source code repository and a GitHub release artifact), and the specific build-commands that describe where in the Flatpak those files get installed.

    For the supported Godot Engine versions, check the available branches of the Godot Engine BaseApp .

    For git sources, be sure to point to a specific commit hash; I also prefer to point to the release tag as well (e.g. with tag: v1.2.3 ) for clarity, but it’s not strictly necessary. For file sources, be sure to include a hash of the file itself, e.g. sha256: a89741f… ). For a file called export.pck , you can generate this on Linux with sha256sum export.pck ; on Windows with CertUtil -hashfile export.pck sha256 .

    id: net.hhoney.rota
    runtime: org.freedesktop.Platform
    runtime-version: '24.08'
    base: org.godotengine.godot.BaseApp
    base-version: '3.6'
    sdk: org.freedesktop.Sdk
    command: godot-runner
    
    finish-args:
      - --share=ipc
      - --socket=x11
      - --socket=pulseaudio
      - --device=all
    
    modules:
      - name: rota
        buildsystem: simple
    
        sources:
          - type: git
            url: https://github.com/HarmonyHoney/ROTA.git
            commit: be542fa2444774fe952ecb22d5056a048399bc25
    
          - type: file
            url: https://github.com/HarmonyHoney/ROTA/releases/download/something/ROTA.pck
            sha256: a89741f56eb6282d703f81f907617f6cb86caf66a78fce94d48fb5ddfd65305c
    
        build-commands:
          - install -Dm644 ROTA.pck ${FLATPAK_DEST}/bin/godot-runner.pck
          - install -Dm644 flatpak/launcher.desktop ${FLATPAK_DEST}/share/applications/${FLATPAK_ID}.desktop
          - install -Dm644 flatpak/metainfo.xml ${FLATPAK_DEST}/share/metainfo/${FLATPAK_ID}.metainfo.xml
          - install -Dm644 media/image/icon/icon256.png ${FLATPAK_DEST}/share/icons/hicolor/256x256/apps/${FLATPAK_ID}.png
    
    
    net.hhoney.rota.yml

    Once you have your manifest file, you’re ready to test it and submit your game to Flathub . To test it, follow the instructions at that link on a Linux computer (or VM); you should be able to point Flatpak Builder to your manifest file for it to grab everything and build a Flatpak of your game.

    The Flathub Submission PR process is a bit confusing; you’re just opening a pull request against a specific new-pr branch on GitHub that adds your manifest file; Flathub will then human-review it and run automated tests on it to make sure it all looks good. They’ll provide feedback on the PR if needed, and then if it’s accepted, a bot will create a new repo on the Flathub org just for your game’s manifest. You’ll automatically have the correct permissions on this repo to be able to propose PRs to update the manifest, and merge them once they pass automated testing.

    Please be sure to test your manifest before submitting so you don’t end up wasting reviewers’ time. 🙏

    You Did It!

    You published your game to Flathub! Or at least you made it this far in the blog post; either way, that’s a win.

    I know this was quite the slog to read through; my hope is that it can serve as a reference for game developers out there. I’m also interested in adapting it into documentation for Flatpak, Flathub, and/or Godot Engine—but I wasn’t sure where it would fit and in what format. If you’d like to adapt any of this post into proper documentation, please feel free to do so!

    If you spot something wrong or just want to reach out, hit me up using any of the links in the footer.

    Bonus Points: Publishing Updates

    When I wrapped this blog post up, I realized I missed mentioning how to handle publishing updates to your game on Flathub. While I won’t go into great detail here, the gist is:

    1. Update your MetaInfo file with the new release version number, timestamp, and release notes; publish this either in your source code repo or alongside the PCK file; if you have new screenshots, be sure to update those URLs in the MetaInfo file, too!

    2. Export a new PCK file of your release, uploading it to a public, stable URL containing the new version number (e.g. a GitHub release)

    3. Submit a pull request against your Flatpak manifest’s GitHub repo, pointing the manifest at new versioned locations of your files; be sure to update the file hashes as well!

    After passing automated tests, a bot will comment on the PR with command to test your Flatpak. Do this as the resulting Flatpak is what will be published to players after the PR is merged. If it all looks good, merge it, and you’re set! If not, repeat the above steps until everything is as expected. :)


    ¹At Endless , we run game-making programs to help underrepresented learners develop and practice soft skills like communication, problem decomposition, and collaboration—as well as technical skills—through an immersive journey of video game development.

    Godot Engine is an important tool for these programs, and we are constantly looking for examples of open source games built with Godot Engine to use as examples or even real-world projects for learners. This is how I came across ROTA, but getting ROTA onto Flathub in and of itself was a great learning opportunity for me to better understand open source game development, Godot Engine, building Flatpaks, and publishing to Flathub.


    Definitions

    There are a lot of terms and technologies involved on both the Godot Engine and Flathub side, so let’s start with some definitions. Don’t worry if you don’t fully understand each piece of these, but you can use this as a cheat sheet to refer back to.

    Godot Engine

    Open source game engine that includes the editor (the actual app you use to create a game), tools (command-line tools for exporting a game), and runtime (platform-specific binary distributed with your game which actually runs it)

    Export

    Prepare your game for distribution; Godot Engine’s export workflow packages up your game’s code, assets, libraries, etc. and turns it into a playable game.

    PCK File

    The platform-agnostic result of a Godot Engine export to use along with the platform-specific runtime. Contains all of your game’s code, assets, etc. packed up with a .pck extension.

    Flatpak

    App/game packaging format for Linux that works across nearly every different Linux distribution. An important design of Flatpak is that it is sandboxed , which keeps each app or game from interfering with one another and helps protect players’ privacy.

    Flathub

    The de facto Linux app store with thousands of apps and games, millions of active users , and a helpful community of open source people like me! It uses Flatpak and other open standards to build, distribute, and update apps and games.

    Flatpak Manifest

    A structured file (in JSON or YAML format) that tells Flatpak how to package your game, including where to get the game itself from. Flathub hosts the manifest files for apps and games on their GitHub organization, regardless of where your game is developed or hosted.

    Flatpak Builder

    Command-line tool that takes a Flatpak manifest and uses it to create an actual Flatpak. Used for local testing, CI workflows, and Flathub itself.

    Flatpak BaseApp

    Shared base for building a Flatpak; i.e. all Godot 3.6 games can use the same BaseApp to simplify the game’s manifest, and Flatpak Builder will take care of the common Godot 3.6-specific bits.

    Desktop Entry

    A simple INI-like file that determines how your game shows up on Linux, i.e. its name, icon, and categories.

    MetaInfo

    Open standard for describing apps and games to be displayed in app stores; used by Flathub and Linux app store clients to build your game’s listing page.

    App ID

    A unique ID for your game in reverse domain name notation (RDNN), based on a valid web domain or source code hosting account you control. Required by Flatpak and validated by Flathub to ensure an app or game is what it claims to be.

    Flathub Verification

    Optional (but highly recommended!) process to verify that your game on Flathub is published by you. Uses your game’s app ID to verify ownership of your domain or source code hosting account.

    • wifi_tethering open_in_new

      This post is public

      cassidyjames.com /blog/publish-godot-engine-game-flathub-flatpak/

    • Pictures 1 image

    • visibility
    • chevron_right

      Christian Hergert: Vacation? What’s that?

      news.movim.eu / PlanetGnome · Sunday, 8 December, 2024 - 21:17 · 2 minutes

    I tend to bulk most of my vacation at the end of the year because it creates enough space and time for fun projects. Last year, however, our dog Toby went paraplegic and so were care-taking every three hours for about two months straight. Erratic sleep, erratic self-care, but in the end he could walk again so definitely worth it.

    That meant I didn’t really get to do my fun end-of-year hacks beyond just polishing Ptyxis which I had just prototyped for RHEL/CentOS/Bluefin (and more recently Fedora).

    This year I’m trying something I’ve wondered about for a while. What would it look like if you shoved a full-featured IDE into the terminal?

    The core idea that makes this possible is using a sub-shell with a persistent parent process. So just like you might “ jhbuild shell ” you can “ foundry enter ” to enter the “IDE”.

    In the JHBuild case it would exec over itself after setting things up. In the foundry case it maintains an ancestor process and spawns a sub-shell beneath that.

    When running foundry commands from a sub-shell it will proxy that work to the ancestor instance. This all happens with a private D-Bus peer-to-peer process. So you can have multiple of these in place across different terminal tabs eventually.

    This is all built with a “libfoundry” that I could consume from Builder in the future to provide the same feature from a full-blown GTK-based IDE too. Not to mention the IDE becomes instantly script-able from your shell. It also becomes extremely easy to unit test.

    Since I originally created Builder, I wrote a library to make doing futures, concurrency, and fibers much easier in C. That is libdex . I tend to make things more concurrent while also reducing bug counts when using it. Especially for the complex logic parts which can be written in synchronous looking C even though it is asynchronous in nature.

    So the first tenant of the new code is that it will be heavily based on DexFuture .

    The second tenant is going to be a reversal of something I tried hard to avoid in Builder. That is a “dot” directory in projects. I never liked how IDEs would litter projects with state files in projects. But since all the others continue to do so I don’t see much value in tying our hands behind our back out my own OCD purity. Instead, we’ll drop a .foundry directory with appropriate VCS ignore files. This gives us convenient space for a tmpdir, project-wide settings, and user settings.

    The project is just getting started, but you can follow along at chergert/foundry and I’ll try to write more tidbits as I go.

    Next time, we’ll cover how the command line tools are built as an N-ary tree to make tab-completion from bash easy.

    • wifi_tethering open_in_new

      This post is public

      blogs.gnome.org /chergert/2024/12/08/vacation-whats-that/

    • chevron_right

      This Week in GNOME: #177 Scrolling Performance

      news.movim.eu / PlanetGnome · Friday, 6 December, 2024 - 00:00 · 2 minutes

    Update on what happened across the GNOME project in the week from November 29 to December 06.

    GNOME Core Apps and Libraries

    Files

    Providing a simple and integrated way of managing your files and browsing your file system.

    Peter Eisenmann reports

    Khalid Abu Shawarib greatly improved Files' scrolling performance in folders with many thumbnails. The changes resulted in an approximate 10x increase of FPS on tested machines. For details see https://gitlab.gnome.org/GNOME/nautilus/-/merge_requests/1659

    GTK

    Cross-platform widget toolkit for creating graphical user interfaces.

    Jeremy Bicha says

    GTK’s Emoji Chooser has been updated for Unicode 16 . This is included in the new GTK 4.17.1 development release and will also be in 4.16.8.

    Third Party Projects

    Pipeline

    Follow your favorite video creators.

    schmiddi reports

    Pipeline version 2.1.0 was released. This release brings some major UI improvements to the channel page and video page, which were mostly implemented by lo. There are also many fixes included in this release, for example very long channel names and video title not allowing the window to shrink to narrow displays, or fixing a bug where the watch-later list was scrolled to the bottom at startup. Compared to the last TWIG announcement, there were also three minor releases fixing many more bugs, like bad video player performance on some devices or errors migrating from the old versions of the application.

    Miscellaneous

    Sophie 🏳️‍🌈 🏳️‍⚧️ (she/her) reports

    Image Viewer (Loupe) landed in GNOME 45 with its own image loading library, glycin . The reason was that the previously used library GdkPixbuf did not fulfill the security and feature requirements we have for an image loader today.

    In parallel to the ongoing work on glycin and Loupe , there have been thoughts on introducing glycin to the rest of GNOME. There are more details available in a new Move away from GdkPixbuf GNOME initiative. Contributions and feedback are very welcome.

    You can also support my work on glycin and Loupe financially.

    GNOME Foundation

    ramcq announces

    The GNOME Foundation is pleased to announce its Request for Proposals for contractors to complete the Digital Wellbeing / Parental Controls and Flathub Payments projects funded by Endless. Please see the GNOME Desktop-Wide Web/Network Filtering and Flathub Program Management posts on the project Discourse forums for the full RFQ details, where you can also ask any questions you have for the project teams. Both roles are open for applications until Wednesday December 18th and we look forward to discussing the projects with prospective applicants and reviewing your proposals.

    That’s all for this week!

    See you next week, and be sure to stop by #thisweek:gnome.org with updates on your own projects!

    • chevron_right

      Jussi Pakkanen: Compiler daemon thought experiment

      news.movim.eu / PlanetGnome · Wednesday, 4 December, 2024 - 23:46 · 2 minutes

    According to information I have picked up somewhere (but can't properly confirm via web searches ATM)  there was a compiler in the 90s (the IBM VisualAge compiler maybe?) which had a special caching daemon mode. The basic idea was that you would send your code to that process and then it could return cached compile results without needing to reparse and reprocess same bits of code over and over. A sort of an in-compiler CCache, if you will. These compilers no longer seem to exist, probably because you can't just send snippets of code to be compiled, you have to send the entire set of code up to the point you want to compile. If it is different, for example because some headers are included in a different order, the results can not be reused. You have to send everything over and at that point it becomes distcc.

    I was thinking about this some time ago (do not ask why, I don't know) and while this approach does not work in the general case, maybe it could be made to work for a common special case. However I am not a compiler developer so I have no idea if the following idea could work or not. But maybe someone skilled in the art might want to try this or maybe some university professor could make their students test the approach for course credit.

    The basic idea is quite simple. Rather than trying to cache compiler internal state to disk somehow, persist it in a process without even attempting to be general.

    The steps to take

    Create a C++ project with a dozen source files or so. Each of those sources include some random set of std headers and have a single method that does something simple like returns the sum of its arguments. What they do is irrelevant, they just have to be slow to compile.

    Create a PCH file that has all the std headers used in the source files. Compile that to a file.

    Start compiling the actual sources one by one. Do not use parallelism to emphasize the time difference.

    When the first compilation starts, read the PCH file contents into memory in the usual way. Then fork the process. One of the processes carries on compiling as usual. The second process opens a port and waits for connections, this process is the zygote server process.

    When subsequent compilations are done, they connect to the port opened by the zygote process, send the compilation flags over the socket and wait for the server process to finish.

    The zygote process reads the command line arguments over the socket and then forks itself. One process starts waiting on the socket again whereas the other compiles code according to the command line arguments it was given.

    The performance boost comes from the fact that the zygote process already has stdlib headers in memory in compiler native data structures. In the optimal case loading the PCH file takes effectively zero time. What makes this work (in this test at least) is that the PCH file is the same for all compilations and it is the first thing the compiler starts processing. Thus it is always the same for all compilations. Conceptually at least, the actual compiler might do something else. There may be a dozen other reasons it might not work.

    If someone tries this out, do let us know whether it actually worked.

    • wifi_tethering open_in_new

      This post is public

      nibblestew.blogspot.com /2024/12/compiler-daemon-thought-experiment.html

    • chevron_right

      Christian Hergert: Ptyxis Progress Support

      news.movim.eu / PlanetGnome · Tuesday, 3 December, 2024 - 20:30

    The upcoming systemd v247 release will have support for a feature originating from ConEmu (a terminal emulator for Windows) which was eventually adopted by Windows Terminal.

    Specifically, it is an OSC (Operating System Command) escape sequence which defines progress state.

    Various systemd tools will natively support this. Terminal emulators which do not support it simply ignore the OSC sequence but those that do support it may provide additional UI to the application.

    Lennart discussed this briefly in their ongoing systemd 247 features series on Mastodon and so I took up a quick attempt to implement the sequence parsing for VTE-based terminals.

    That has since been iterated upon and landed in VTE. Additionally, Ptyxis now has corresponding code to support it as well.

    Once GNOME CI is back up and running smoothly this will be available in the Ptyxis nightly build.

    A screenshot of Ptyxis running in a window with two tabs. One of the tabs has a progress indicator icon showing about 75 percent completion of a task.

    • wifi_tethering open_in_new

      This post is public

      blogs.gnome.org /chergert/2024/12/03/ptyxis-progress-support/

    • chevron_right

      Hubert Figuière: Integrating the RawTherapee engine

      news.movim.eu / PlanetGnome · Saturday, 18 March, 2023 - 00:00 · 6 minutes

    RawTherapee is one of the two major open source RAW photo processing applications, the other is Darktable.

    Can I leverage RawTherapee RAW processing code for use in Niepce? Yes I can.

    So let's review of I did it.

    Preamble

    License-wise GPL-3.0 is a match.

    In term of tech stack, there are a few complexities.

    1. RawTherapee is written in C++, while Niepce is being converted to Rust. Fortunately it's not really an issue, it require just a bit of work, even at the expense of writing a bit of C++.
    2. It is not designed to be used as a library: it's an application. Fortunately there is a separation between the engine (rtengine) and the UI (rtgui) which will make our life easier. There are a couple of places where this separation blurs, but nothing that can't be fixed.
    3. The UI toolkit is gtkmm 3.0 . This is a little point of friction here as Niepce uses GTK4 with some leftovers C++ code using gtkmm 4.0 . We are porting the engine, so it shouldn't matter except that the versions of neither glibmm nor cairomm match (ie they are incompatible) and the engine relies on them heavily.
    4. Build system: it uses CMake. Given that RawTherapee is not meant to be built as a library, changes will be required. I will take a different approach though.

    Organization

    The code will not be imported in the repository and instead will be used as a git submodule. I already have cxx that way for the code generator. Given that some code needs to be changed, it will reference my own fork of RawTherapee, based on 5.9, with as much as I can upstreamed.

    The Rust wrappers will live in their own crate: Niepce application code is setup as a workspace with 4 crates: npc-fwk , npc-engine , npc-craw and niepce . This would be the fifth: rtengine .

    The rtengine crate will provide the API for the Rust code. No C++ will be exposed.

    npc-craw (Niepce Camera Raw 1 ), as it is meant to implement the whole image processing pipeline, will use this crate. We'll create a trait for the pipeline and implement it for both the ncr pipeline and rtengine .

    Integrating

    Build system

    Niepce wrap everything into a meson build. So to build rtengine we will build a static library and install the supporting file. We have to bring in a lot of explicit dependencies, which bring a certain amount bloat, but we can see later if there is a way to reduce this. It's tedious to assemble everything.

    The first build didn't include everything needed. I had to fix this as I was writing the wrappers.

    Dependencies

    glibmm and cairomm: the version used for gtkmm-3.0 and gtkmm-4.0 differs. glibmm changed a few things like some enum are now C++ enum class (better namespacing), and Glib::RefPtr<> is now a std::shared_ptr<> . The biggest hurdle is the dependency on the concurrency features of glibmm ( Glib::Mutex ) that got completely removed in glibmm-2.68 (gtkmm-3.0 uses glibmm-2.4). I did a rough port to use the C++ library, and upstream has a languishing work in progress pull request . Other changes include adding explicit includes . I also need to remove gtkmm dependencies leaking into the engine.

    Rust wrapper

    I recommend heavily to make sure you can build your code with the address sanitizer. In the case of Niepce, I have had it for a long time, and made sure it still worked when I inverted the build order to link the main binary with Rust instead of C++.

    Using cxx I created a minimum interface to the C++ code. The problem was to understand how it works. Fortunately the command line interface for RawTherapee does exactly that. This is the logic we'll follow in the Rust code.

    Lets create the bridge module. We need to bridge the following types:

    • InitialImage which represents the image to process.
    • ProcParams which represents the parameters for processing the the image.
    • PartialProfile which is used to populate the ProcParams from a processing profile.
    • ProcessingJob which represents the job of processing the image.
    • ImageIO which is one of the classes the processed image data inherit from, the one that implement getting the scanlines.

    Ownership is a bit complicated you should pay attention how these types get cleaned up. For example a ProcessingJob ownership get transfered to the processImage() function, unless there is an error, in which case there is a destroy() function (it's a static method) to call. While PartialProfile needs deleteInstance() to be called before being destroyed, or it will leak.

    Example:

    let mut proc_params = ffi::proc_params_new();
    let mut raw_params = unsafe {
        ffi::profile_store_load_dynamic_profile(image.pin_mut().get_meta_data())
    };
    ffi::partial_profile_apply_to(&raw_params, proc_params.pin_mut(), false);
    

    We have created proc_params as a UniquePtr<ProcParams> . We obtain a raw_params as a UniquePtr<PartialProfile> . UniquePtr<> is like a Box<> but for use when coming from a C++ std::unique_ptr<> .

    raw_params.pin_mut().delete_instance();
    

    raw_params will be freed when getting out of scope, but if you don't call delete_instance() (the function is renamed in the bridge to follow Rust conventions), memory will leak. The pin_mut() is necessary to obtain a Pin<> of the pointer for a mutable pointer required as the instance.

    let job = ffi::processing_job_create(
        image.pin_mut(),
        proc_params.as_ref().unwrap(),
        false,
    );
    let mut error = 0_i32;
    // Warning: unless there is an error, process_image will consume it.
    let job = job.into_raw();
    let imagefloat = unsafe { ffi::process_image(job, &mut error, false) };
    if imagefloat.is_null() {
        // Only in case of error.
        unsafe { ffi::processing_job_destroy(job) };
        return Err(Error::from(error));
    }
    

    This last bit, we create the job as a UniquePtr<ProcessingJob> but then we have to obtain the raw pointer to sink either with process_image() , or in case of error, sink with processing_job_destroy() . into_raw() do consume the UniquePtr<> .

    image is also is a UniquePtr<InitialImage> and InitialImage has a decreaseRef() to unref the object that must be called to destroy the object. It would be called like this:

    unsafe { ffi::decrease_ref(image.into_raw()) };
    

    Most issues got detected with libasan, either as memory errors or as memory leaks. There is a lot of pointer manipulations, but let's limit this to the bridge and not expose it ; at least unlike in C++, cxx::UniquePtr<> consume the smart pointer when turning it into a raw pointer, there is no risk to use it again, at least in the Rust code.

    Also, some glue code needed to be written as some function take Glib::ustring instead of std::string , constructors needs to be wrapped to return UniquePtr<> . Multiple inheritence make some direct method call not possible, and static methods are still work in progress with cxx.

    One good way to test this was to write a simple command line program. As the code shown above, it's tricky to use correctly, so I wrote a safe API to use the engine, one that is more in line with Niepce "architecture".

    At that point rendering an image is the following code:

    use rtengine::RtEngine;
    
    let engine = RtEngine::new();
    if engine.set_file(filename, true /* is_raw */).is_err() {
        std::process::exit(3);
    }
    
    match engine.process() {
        Err(error) => {
            println!("Error, couldn't render image: {error}");
            std::process::exit(2);
        }
        Ok(image) => {
            image.save_png("image.png").expect("Couldn't save image");
        }
    }
    

    Results

    I have integrated it in the app. For now switching rendering engine needs a code change, there is a bit more work to integrate rendering parameters to the app logic.

    Here is how a picture from my Canon G7X MkII looked with the basic pipeline from ncr :

    ncr rendering

    Here is how it looks with the RawTherapee engine:

    RawTherapee engine rendering

    As you can notice, lens correction is applied.

    1

    there is an unrelated ncr crate on crates.io, so I decided to not use that crate name, and didn't want to use npc-ncr , even though the crate is private to the application and not intended to be published separately.

    • wifi_tethering open_in_new

      This post is public

      www.figuiere.net /hub/wlog/integrating-rtengine/

    • chevron_right

      Adrien Plazas: Mushroom Gardiane Recipe

      news.movim.eu / PlanetGnome · Friday, 17 March, 2023 - 23:00 · 3 minutes

    Gardiane is a traditional recipe from Camargue, this vegan variant replaces streaked bull meat by mushrooms. I tried it with seitan too but it ends up a bit too soggy and mushy to my liking, especially after some time in the fridge. This vegan variant also has the advantage of requiring virtually no set up — in the original recipe you have to marinate the meat for 24–48 hours — and of taking less time to cook, as you only need 1–2 hours instead of 2–4 hours.

    Regarding olives, the most traditional would be black Picholines, though I prefer to use black Lucques. Please please please do not use greek style olives as they contain way too much salt, they would spoil the gardiane. I strongly recommend using olives with stones as it helps keeping them in good shape while everything cooks, and removing the stones with your mouth is part of the experience, like cherry stones in clafoutis.

    For 6–8 servings.

    Ingredients

    • 2 kg of large white or brown common mushrooms
    • 200 g of firm tofu
    • 200 g of smoked firm tofu
    • 500 g of black olives, preferably stoned Picholines or Lucques
    • 2 large yellow onions
    • 75 cl of red wine, preferably Côte du Rhône or Languedoc
    • 6 garlic cloves
    • ⅓ tsp of ground cloves
    • 2 tsp of thyme
    • 2 tsp of rosemary
    • 2 large bay leaves
    • a bit of ground black pepper
    • 1 tsp of salt
    • 3 tbsp of starch or flower
    • 500 g long grain white rice, preferably Camargue
    • some olive oil
    • some water
    ingredients.jpg

    This day I couldn’t find Picholines or Lucques, and I forgot to invite the tofu to the familly photo

    Instructions

    • Remove the stems from the mushrooms. Remove dirty bits from the stems.
    • Peel the mushroom caps, this will help the wine soak in.
    • Cut the caps into 3–4 cm wide pieces, in pratice that means you don’t cut the small ones, you cut the medium-sized ones in two, and you cut the larger ones in three or four.
    • Wash the caps and stems in a salad spinner.
    peeled-mushrooms.jpg

    The mushrooms, peeled, cut and washed

    • Cut the tofu in 2 cm long and 5 mm thick batonnets.
    cut-smoked-tofu.jpg

    The cut smoked tofu

    • Peel the onions. Cut the onions in 8–10 vertically.
    • Peel the garlic cloves. Mince the garlic cloves.
    • If the olives come in water, remove the water.
    • Put a large pot on medium heat.
    • In the pot, put a bit of olive oil and lightly brown the onions with the garlic, the thyme and the rosemary. Reserve.
    browned-onions.jpg

    The browned onions

    • In the pot, put a bit of olive oil and lightly brown the tofu. Reserve.
    browned-tofu.jpg

    The browned tofu

    • In the pot, put a bit of olive oil and lightly brown the mushrooms. Do it in several batches so they don’t cook too much in their own water, the goal is to get somw brown bits.
    browned-mushrooms.jpg

    A batch of browned mushrooms, these cooked in their own water a bit too much, but it’s fine as they still have some brown bits

    • Remove the pot from the fire, and pour everything in it but the starch or flour, the black pepper and the rice. This means you add the wine, the mushrooms, the onions, the tofu, the olives, the bay leaves, the ground cloves, and the salt.
    • Add water in the pot until everything is covered.
    ready-to-cook.jpg

    The pot is filled with all the ingredients, the gardiane is ready to be cooked

    • Cover the pot, put it on medium-low heat and let it cook for 2 hours.
    • While the gardiane cooks, prepare and cook the rice.
    • Remove the pot from the stove.
    • Put some sauce from the gardiane in a glass with the starch or flour. Mix them with a spoon and put the liquid back in the pot.
    • Add the black pepper in the pot and stir, the starch or flour will very lightly thicken the sauce.
    a-plate.jpg

    A served plate

    • Serve the gardiane either aside the rice or on top of it, as you prefer. Serve with another bottle of a similar wine.
    selfie-with-tobias-bernard.jpg

    This recipe is approved by Tobias Bernard

    • wifi_tethering open_in_new

      This post is public

      adrienplazas.com /blog/2023/03/18/mushroom-vegan-gardiane-recipe.html

    • chevron_right

      Alexander Mikhaylenko: Libadwaita 1.3

      news.movim.eu / PlanetGnome · Friday, 17 March, 2023 - 14:39 · 5 minutes

    Another cycle, another release. Let’s take a look at what’s new.

    Banners

    Screenshot of AdwBanner

    AdwBanner is a brand new widget that replaces GtkInfoBar .

    Jamie started implementing it before 1.2 was released, but we were already in the API freeze so it was delayed to this cycle instead.

    While it looks more or less the same as GtkInfoBar , it’s not a direct replacement. AdwBanner has a title and optionally one button. That’s it. It does not have a close button, it cannot have multiple buttons or arbitrary children. In exchange, it’s easier to use, behaves consistently and has an adaptive layout:

    Wide screenshot of AdwBanner. The button is on the right, the title is centered.

    Medium-width screenshot of AdwBanner. The button is on the right, the title is left-aligned as it wouldn't fit centered.

    Narrow screenshot of AdwBanner. The title is center-aligned, the button is centered below it.

    Like GtkInfoBar , AdwBanner has a built-in revealer and can be shown and hidden with an animation.

    There are situations where it cannot be used, but in most of those cases GtkInfobar was already the wrong choice and they should be redesigned. For example, Epiphany was using them for the “save password” prompt, and is using a popover for that now.

    Tab Overview

    A work-in-progress grid-based tab overview A work-in-progress carousel-based tab overview

    AdwTabOverview is a new tab overview widget for AdwTabView that finally makes it possible to use tabs on mobile devices without implementing a mobile switcher manually.

    Back when I wrote HdyTabView , I mentioned a tab overview widget in the works, and even had demo screenshots . Of course, basically everything from that demo got rewritten since then, and the carousel for narrow mode got scrapped completely, but now we’re getting into The Ship of Theseus territory.

    This required a pretty big rework of AdwTabView to allow tabs to have thumbnails when they are not visible, and in particular it does not use a GtkStack internally anymore.

    By default the selected tab has a live thumbnail and other thumbnails are static, but apps can opt into using live thumbnails for specific pages. They can also control the thumbnail alignment in case the thumbnail gets clipped. Thumbnails themselves are currently not public, but it might be interesting to use them for e.g. tooltips at some point.

    Overview is not currently used very widely – it’s available in Console, and there is a merge request adding it to Epiphany, but I didn’t have the energy to finish the latter this cycle.

    Tab Button

    Screenshot of AdwTabButton. It's showing two tab buttons. One displays 3 open tabs, the other one 15 and has an attention indicator

    AdwTabButton is much less interesting, it’s just a button that shows the number of open tabs in a given AdwTabView . It’s intended to be used as the button that opens the tab overview on mobile devices.

    Unlike tab overview, this widget is more or less a direct port of what Epiphany has been using since 3.34. It does have one new feature though – it can display an indicator if a tab needs attention.

    Accessibility

    You might have noticed that widgets like AdwViewStack , AdwTabView or AdwEntryRow were not accessible in libadwaita 1.2.x. The reason for that is that GTK didn’t provide public API to make that possible. While GtkAccessible existed, it wasn’t possible to implement it outside GTK itself.

    This cycle, Lukáš Tyrychtr has implemented the missing pieces, as well as fixed a few other issues. And so libadwaita widgets are now properly accessible.

    Animation Additions

    One of AdwAnimation features is that it automatically follows the system setting for disabling animations. While this is the expected behavior in most cases, there are a few where it gets in the way instead.

    One of these cases is in apps where the animations are the app’s primary content, such as Elastic , and so I added a property that allows a specific animation to ignore the setting.

    The animation in the demo is now using it as well, for the same reason as Elastic, and in the future it will allow us to have working spinners while animations are disabled system-wide as well.

    A screenshot of an animation graph from Elastic

    Elastic also draws an animation graph before running the actual animation, and while for timed animations it’s relatively easy since easing functions are available through the public API , it wasn’t possible for spring animations. It is now, via calculate_value() and calculate_velocity() .

    All of this uncovered a few bugs with spring animations – for example, the velocity was completely wrong for overdamped springs, and Manuel Genovés fixed them.

    Unrelated to the above, a common complaint about AdwPropertyAnimationTarget was that it prints a critical if the object containing the property it’s animating is finalized before the target. While it was easy to avoid in C, it was nearly impossible from bindings. And so we don’t print that critical anymore.

    Other Changes

    • Christopher Davis added a way to make AdwActionRow subtitle selectable .
    • Matt Jakeman added title-lines and subtitle-lines properties to AdwExpanderRow , matching AdwActionRow .
    • AdwEntryRow now has a grab_focus_without_selecting() method, matching GtkEntry .
    • The API to set an icon on AdwActionRow and AdwExpanderRow are now deprecated, since they were mostly unused. Apps that need icons can add a GtkImage as a prefix widget instead.
    • AdwMessageDialog now has the async choose() method, matching the new GTK dialogs like GtkAlertDialog . The response signal is still there and is not deprecated, but in some cases the new method may be more convenient, particularly from bindings:

      [GtkCallback]
      private async void clicked_cb () {
          var dialog = new Adw.MessageDialog (
              this,
              "Replace File?",
              "A file named “example.png” already exists. Do you want to replace it?"
          );
      
          dialog.add_response ("cancel", "_Cancel");
          dialog.add_response ("replace", "_Replace");
      
          dialog.set_response_appearance (
              "replace",
              DESTRUCTIVE
          );
      
          var response = yield dialog.choose (null);
      
          if (response == "replace") {
              // handle replacing
          }
      }
      
    • Corey Berla added missing drag-n-drop related API to AdwTabBar to make it work properly in Nautilus.
    • Since GTK now allows to change texture filtering, AdwAvatar properly scales custom images, so they don’t appear pixelated when downscaled or blurry when upscaled. This only works if the custom image is a GdkTexture – if your app is using a different GdkPaintable , you will need to do the equivalent change yourself.
    • Jason Francis implemented dark style and high contrast support when running on Windows.
    • Selected items in lists and grids are now using accent color instead of grey, same as Nautilus in 43. Sidebars and menus still look the same as before.

    New Dependencies

    The accessibility additions, scaled texture render nodes in AdwAvatar , as well as mask render nodes (that I didn’t mention because it’s an internal change) and deprecation fixes mean that libadwaita 1.3 requires GTK 4.10 instead of 4.6.


    As always, thanks to all the contributors, and thanks to my employer, Purism, for letting me work on libadwaita and GTK to make this release happen.

    • wifi_tethering open_in_new

      This post is public

      blogs.gnome.org /alexm/2023/03/17/libadwaita-1-3/

    • chevron_right

      Sam Thursfield: Status update 17/03/2023

      news.movim.eu / PlanetGnome · Friday, 17 March, 2023 - 12:02

    Hello from my parents place, sitting on the border of Wales & England, listening to this excellent Victor Rice album , thinking of this time last year when I actually got to watch him play at Freedom Sounds Festival, which was one of my first adventures of the post-lockdown 2020s.

    I have many distractions at the moment, many being work/life admin but here are some of the more interesting ones:

    • Playing in a new band in Santiago – Killo Karallo – recording some initial music which is to come out next week
    • Preparing new Vladimir Chicken music, also cooked and ready for release in April
    • Figuring out how we can grow the GNOME OpenQA tests while keeping them fun to work with. Here’s an experimental commandline tool which might help with that.
    • Learning about marketing, analytics, and search engine optimization.
    • Trying out the new LLaMA language model and generally trying to keep up with the ongoing revolution in content generation technology.

    Also I got to see snow real for the first time in a few years! Thanks Buxton!