GNOME.ORG

24 hours a day, 7 days a week, 365 days per year...

May 22, 2018

Three big things happening in librsvg

I am incredibly happy because of three big things that are going on in librsvg right now:

  1. Paolo Borelli finished porting all the CSS properties to Rust. What was once a gigantic RsvgState struct in C is totally gone, along with all the janky C code to parse individual properties. The process of porting RsvgState to Rust has been going on since about two months ago, and has involved many multi-commit merge requests and refactorings. This is a tremendous amount of really good work! The result is all in Rust now in a State struct, which is opaque from C's viewpoint. The only places in C that still require accessors to the State are in the filter effects code. Which brings me to...

  2. Ivan Molodetskikh, my Summer of Code student, submitted his first merge request and it's merged to master now. This ports the bookkeeping infrastructure for SVG filters to Rust, and also the feOffset filter is ported now. Right now the code doesn't do anything fancy to iterate over the pixels of Cairo image surfaces; that will come later. I am very happy that filters, which were a huge barrier, are now starting to get chipped away into nicer code.

  3. I have started to move librsvg's old representation of CSS properties into something that can really represent properties that are not specified, or explicitly set to inherit from an SVG element's parent, or set to a normal value. Librsvg never had a representation of property values that actually matched the SVG/CSS specs; it just knew whether a property was specified or not for an element. This worked fine for properties which the spec mandates that they should inherit automatically, but those that don't, were handled through special hacks. The new code makes this a lot cleaner. It should also make it easier to copy Servo's idioms for property inheritance.

May 21, 2018

De-Googling my phone, reloaded

Three weeks ago I blogged about how to get rid of non-free Google services and moving to free software on my Android phone. I’ve got a lot of feedback via email, lwn, and Google+, many thanks to all of you for helpful hints! As this is obviously important to many people, I want to tie up some lose ends and publish the results of these discussions.

Alternative apps and stores

  • Yalp is a free app that is able to search, install, and update installed apps from the Google Play Store. It doesn’t even need you to have a Google account, although you can use it to install already paid apps (however, you can’t buy apps within Yalp). I actually prefer that over uptodown now.

  • I moved from FreeOTP to AndOTP. The latter offers backing up your accounts with password or GPG encryption, which is certainly much more convenient than what I’ve previously been doing with noting down the accounts and TOTP secrets in an encrypted file on my laptop.

  • We often listen to internet radio at home. I replaced the non-free ad-ware TuneIn with Transistor, a simple and free app that even has convenient launcher links for a chosen station, so it’s exactly what we want. It does not have a builtin radio station list/search, but if you care about that, take a look at RadioDroid (but that doesn’t have the convenient quick starters).

Transport

In this area the situation is now much happier than my first post indicated. As promised I used trainline.eu for booking some tickets (both for Deutsche Bahn and also on Thalys), and indeed this does a fine job. Same price, European rebate cards like BahnCard 50 are supported, and being able to book with a lot of European train services with just one provider is really neat. However, I’m missing a lot of DB navigator’s great features: realtime information and alternatives, seat selection, car position indicator, regional tariffs, or things like “Länderticket”.

Fortunately it turns out that DB Navigator works just great with a trick: Disable the “Karte anzeigen” option in the menu, and it will immediately stop complaining about missing Play Services after each action. Also, logging in with your DB account never finishes, but after terminating and restarting the app you are logged in and everything works fine. That might be a “regular” bug or just a side effect without Play Services.

Wrt. rental bikes: citybik.es is an awesome project and freely available API that shows available bikes on a map all over Europe. The OpenBikeSharing uses that on Android. That plus the ordinary Nextbike app works well enough.

microG

A lot of people pointed out microG as a free implementation of Google Play Service APIs. Indeed I did try this even before my first blog post; but I didn’t mention it as I wanted to find out which apps actually need this API.

Also, this really appears to be something for the daunting: On my rooted Nexus 4 with LineageOS I didn’t get it to work, even after installing the handful of hacks that you need for signature spoofing; and I daresay that on a standard vendorized installation without root/replaced bootloader it’s outright impossible.

Fortunately there are LineageOS builds with microG included, which gets you much further. But even with that e. g. location still does not work out of the box, but one needs to hunt down and install various providers. I’ve heard from several people that they use this successfully, but as this wasn’t the point of my exercise I just gave up after that.

A really useful piece of functionality of Play Services is tracking and remote-controlling (lock, warn tone, erase) lost or stolen phones. With having backup, encryption and proper locking, a stolen phone is not the end of the world, but it’s still relatively important for me (even though I never had to actually use it yet). The only alternative that I found is Cerberus which looks quite comprehensive. It’s not free though (neither as in beer nor in speech), so unless you particularly distrust Google and are not a big company, it might just be better to keep using Play Services for this functionality.

Calendar and Contacts

I’m really happy with DAVDroid and radicale after using them for over a month. But most people don’t have a personal server to run these. etesync looks like an interesting alternative which provide the hosting for you for five coffees a year, and also offer (free) self-hosting for those who can and want to.

correct or inotify: pick one

Let's say you decide that you'd like to see what some other processes on your system are doing to a subtree of the file system. You don't want to have to change how those processes work -- you just want to see what files those processes create and delete.

One approach would be to just scan the file-system tree periodically, enumerating its contents. But when the file system tree is large and the change rate is low, that's not an optimal thing to do.

Fortunately, Linux provides an API to allow a process to receive notifications on file-system change events, called inotify. So you open up the inotify(7) manual page, and are greeted with this:

With careful programming, an application can use inotify to efficiently monitor and cache the state of a set of filesystem objects. However, robust applications should allow for the fact that bugs in the monitoring logic or races of the kind described below may leave the cache inconsistent with the filesystem state. It is probably wise to do some consistency checking, and rebuild the cache when inconsistencies are detected.

It's not exactly reassuring is it? I mean, "you had one job" and all.

Reading down a bit farther, I thought that with some "careful programming", I could get by. After a day of trying, I am now certain that it is impossible to build a correct recursive directory monitor with inotify, and I am not even sure that "good enough" solutions exist.

pitfall the first: buffer overflow

Fundamentally, inotify races the monitoring process with all other processes on the system. Events are delivered to the monitoring process via a fixed-size buffer that can overflow, and the monitoring process provides no back-pressure on the system's rate of filesystem modifications. With inotify, you have to be ready to lose events.

This I think is probably the easiest limitation to work around. The kernel can let you know when the buffer overflows, and you can tweak the buffer size. Still, it's a first indication that perfect is not possible.

pitfall the second: now you see it, now you don't

This one is the real kicker. Say you get an event that says that a file "frenemies.txt" has been created in the directory "/contacts/". You go to open the file -- but is it still there? By the time you get around to looking for it, it could have been deleted, or renamed, or maybe even created again or replaced! This is a TOCTTOU race, built-in to the inotify API. It is literally impossible to use inotify without this class of error.

The canonical solution to this kind of issue in the kernel is to use file descriptors instead. Instead of or possibly in addition to getting a name with the file change event, you get a descriptor to a (possibly-unlinked) open file, which you would then be responsible for closing. But that's not what inotify does. Oh well!

pitfall the third: race conditions between inotify instances

When you inotify a directory, you get change notifications for just that directory. If you want to get change notifications for subdirectories, you need to open more inotify instances and poll on them all. However now you have N2 problems: as poll and the like return an unordered set of readable file descriptors, each with their own ordering, you no longer have access to a linear order in which changes occurred.

It is impossible to build a recursive directory watcher that definitively says "ok, first /contacts/frenemies.txt was created, then /contacts was renamed to /peeps, ..." because you have no ordering between the different watches. You don't know that there was ever even a time that /contacts/frenemies.txt was an accessible file name; it could have been only ever openable as /peeps/frenemies.txt.

Of course, this is the most basic ordering problem. If you are building a monitoring tool that actually wants to open files -- good luck bubster! It literally cannot be correct. (It might work well enough, of course.)

reflections

As far as I am aware, inotify came out to address the needs of desktop search tools like the belated Beagle (11/10 good pupper just trying to get his pup on). Especially in the days of spinning metal, grovelling over the whole hard-drive was a real non-starter, especially if the search database should to be up-to-date.

But after looking into inotify, I start to see why someone at Google said that desktop search was in some ways harder than web search -- I mean we all struggle to find files on our own machines, even now, 15 years after the whole dnotify/inotify thing started. Part of it is that the given the choice between supporting reliable, fool-proof file system indexes on the one hand, and overclocking the IOPS benchmarks on the other, the kernel gave us inotify. I understand it, but inotify still sucks.

I dunno about you all but whenever I've had to document such an egregious uncorrectable failure mode as any of the ones in the inotify manual, I have rewritten the software instead. In that spirit, I hope that some day we shall send inotify to the pet cemetery, to rest in peace beside Beagle.

All Systems Go! 2018 CfP Open

The All Systems Go! 2018 Call for Participation is Now Open!

The Call for Participation (CFP) for All Systems Go! 2018 is now open. We’d like to invite you to submit your proposals for consideration to the CFP submission site.

ASG image

The CFP will close on July 30th. Notification of acceptance and non-acceptance will go out within 7 days of the closing of the CFP.

All topics relevant to foundational open-source Linux technologies are welcome. In particular, however, we are looking for proposals including, but not limited to, the following topics:

  • Low-level container executors and infrastructure
  • IoT and embedded OS infrastructure
  • BPF and eBPF filtering
  • OS, container, IoT image delivery and updating
  • Building Linux devices and applications
  • Low-level desktop technologies
  • Networking
  • System and service management
  • Tracing and performance measuring
  • IPC and RPC systems
  • Security and Sandboxing

While our focus is definitely more on the user-space side of things, talks about kernel projects are welcome, as long as they have a clear and direct relevance for user-space.

For more information please visit our conference website!

May 19, 2018

Internationalization of Fractal (3rd and last part)

“Tl;dr version”: I’ve finished implementing the i18n of Fractal and I’ve submitted a first French translation of it. With some help from Daniel (my mentor) to complete the integration with the build system, so thank him for that! Here are my merge requests: https://gitlab.gnome.org/World/fractal/merge_requests/105 and https://gitlab.gnome.org/World/fractal/merge_requests/107.

I am going to detail a little bit what was done in order to achieve this.

Integrate gettext-rs to the project

I first added gettext-rs as one of the dependencies of Fractal (in this commit), as I have explained it in the previous articles. Then, I put the initialization of gettext-rs by asking it to look for the locale files in ./fractal-gtk/po (in this commit).

Wrap all the translatable strings in the Rust source files

Then I took quite some time to examine every strings in the source files of the crate fractal-gtk to wrap all messages that would end up in the GUI with gettext (it turned out that I didn’t really need to use ngettext). Wrapping some strings in the format! macro was less obvious to deal with though. For instance:

secondary = format!("You've been invited to join to <b>{}</b> room by <b>{}</b>",
                    room_name, sender_name);

Couldn’t be straightforwardly rewritten like this:

secondary = format!(gettext("You've been invited to join to <b>{}</b> room by <b>{}</b>"),
                    room_name, sender_name);

Because the first argument of format! needs to be a string literal, so I had to use this work around instead:

let sentence_template = gettext("You've been invited to join to <b>{room_name}</b> room by <b>{sender_name}</b>");
secondary = sentence_template.replace("{room_name}", room_name.as_str())
                             .replace("{sender_name}", sender_name.as_str());

I explicitly did what format! would have done here without having the constraint of using a string literal. Because in some languages, the place of {room_name} and {sender_name} can be reversed. See this commit for more details.

Adding the support of gettext within the build system

Next, we needed a way to automatically generate PO and POT files and move MO files to the right place for gettext-rs to read. So I was going to have the meson build system helping me for that. I first added a POTFILES.in file which lists all the files with translatable strings in them and a LINGUAS file which list the languages for which we want to have PO files. And I’ve added a meson.build file and updated to one in the project root to be able to generate the mentioned file: you can run `ninja -C _build fractal-pot` to generate a POT file and `ninja -C _build fractal-update-po` to generate/update PO files. See these commit for more details on: the POTFILE.in, the LINGUAS file and the meson.build files.

Once the ability to generate the locale files implemented, Daniel helped my with this commit that removes the hard-coded path to bind the text domain for gettext. And he added a Spanish translation (see this commit). I also submitted a French translation, see this commit and this one.

After my MR merged, my first task for GSoC is completed!! 🙂

Talking at GPN 2018 in Karlsruhe, Germany

Similar to last year I managed to attend the Gulasch Programmier-Nacht (GPN) in Karlsruhe, Germany. Not only did I attend, I also managed to squeeze in a talk about PrivacyScore. We got the prime time slot on the opening day along with all the other relevant talks, including the Eurovision Song Contest, so we were not overly surprised that the audience had a hard time deciding where to go and eventually decided to attend talks which were not recorded. Our talk was recorded and is available here.

Given the tough selection of the audience by the other talks, we had the people who were really interested. And that showed during the official Q&A as well as in the hallway track. We exchanged contacts with other interested parties and got a few excellent comments on the project.

Another excellent part of this year’s GPN was the exhibition in the museum. As GPN takes places in a joint building belonging to the local media university as well as the superb art and media museum, the proximity to the artsy things allows for an interesting combination. This year, the open codes exhibition was not hosted in the ZKM, but GPN also took place in that exhibition. A fantastic setup. Especially with the GPN’s motto being “digital naïves”. One of the exhibition’s pieces is an assembly robot’s hand doing nothing else but writing a manifesto. Much like a disciplinary action for a school child. Except that the robot doesn’t care so much. Yet, it’s usefulness only expands to writing these manifestos. And the robot doesn’t learn anything from it. I like this piece, because it makes me think about the actions we take hoping that they have a desired effect on something or someone but we actually don’t know whether this is indeed the case.

I also like the Critical Engineering Manifesto being exhibited. I like to think about how the people who actual implement cetain technologies can be held responsible for the effects of it on individuals or the society. Especially with more and more “IoT” deployments where the “S” represents their security. It’s easy to blame Facebook for “leaking” user profiles although it’s in their Terms of Services, but it’s harder to shift the blame for the smart milk sensor in your fridge invading my privacy by reporting how much I consume. We will have interesting times ahead of us.

An exhibit pointing out the beauty of algorithms and computation is a board that renders a Julia Set. That’s wouldn’t be so impressive in itself, but you can watch the machine actually compute the values. The exhibit has a user controllable speed regulator and an insight into the CPU as well as the higher level code. I think it’s just an ingenious idea to enable the user to go full speed and see the captivating movements of the beautiful Julia set while also allowing the go super slow to investigate how this beauty is composed of relatively simple operations. Also, the slow execution itself is relatively boring. We get to see that we have to go very fast in order to be entertained. So fast that we cannot really comprehend what is going on.

I whole heartedly recommend visiting this exhibition. And the GPN, of course, too. It’s a nice chaotic event with a particular flair. It’s getting more and more crowded though, so better while the feeling lasts and doesn’t get drowned by all the tourists.

Stickers in Riot

Yesterday I read a blog post about the new Riot.im Stickers. This is not a matrix.org feature, it's implemented as a widget, when you send an sticker you're sending a new event with the type "m.sticker", which is similar to the "m.image" event.

The matrix.org protocol is flexible so this is a good example of how to add new features to the clients that uses matrix without the need to change the protocol.

This is not a core feature because you can send images, but I think this is great and add a simple way to show reactions for the users, so as I was reading I thought that we can add this to Fractal, so I started to read how we can add support for this.

Reading the doc

The first thing to implement a feature is to read the specifications or the technical documentation so we can know what is needed... But there's no documentation yet about Stickers or widgets yet.

This is a problem because we can't implement a feature if we don't know what we should do. But free software give us a great opportunity when this happens, we've the Riot source code so we can look at the code and learn what they are doing.

Reading the code

Riot web is a javascript application that uses AJAX to communicate with different server APIs so the first thing that I did to start to understand the stickers thing was to open the firefox debugger and view how riot is communicating with the server.

From here I've learned that for stickers riot is asking to the scalar.vector.im server. But I don't understand the whole thing with the requests because riot does a lot of request to different APIs and I can't isolate the stickers thing easily.

To fill my understanding gap I go to the matrix-js-sdk and matrix-react-sdk and I did a quick grep to the source code looking for the API calls that I've view in firefox. With this I can understand the full stickers process.

Writing an example

To say that I know how this is working, it's not enough the code reading. To make sure that I've understood the whole process I need to write a simple program that does all the process and then I can say that I understand this.

So I started to write a simple python script using requests. This simple script does the request to the server and list all the stickers json so I can say that I'm able to communicate with the API.

Stickers in Fractal

After this small research I'm able to implement an initial sticker support for Fractal. I'll try to add a simple way to show and use stickers and a way to render stickers in the messages history.

If there's no secret problems we'll have a basic stickers support in Fractal soon.

May 18, 2018

Hello Planet GNOME!

Hey guys, although I’ve been around for a while hidden in the patches, some months ago (already!?!) I did my application to join the GNOME Foundation, and few days after – thanks to some anonymous votes – I got approved :), and thus I’m officially part of the family!

So, thanks again, and sorry for my late “hello” 🙂

Collabora and GStreamer spring in Sweden

Earlier this month, a few of us from Collabora, Olivier Crête, Nicolas Dufresne, George Kiagiadakis and I attended the GStreamer Spring Hackfest in Lund, Sweden. Hosted by Axis Communications (who uses GStreamer in their surveillance cameras for many years now), it was a great opportunity for the GStreamer community to touch base and work on open bugs and pet projects.



While I've been involved in the GStreamer project in the past, it was my first GStreamer hackfest. While a lot was achieved during the event, the most exciting outcomes were no doubt the closing of more than 350 bugs, and the agreement on a transition plan to move to GitLab.

Overall, the hackfest was very productive, with each member of our team managing to progress in their list of tasks while all taking part in bug triaging & cleaning in preparation of moving GStreamer's issue tracking to GitLab.

George spent time working on improving the new library API that is needed to introduce support for the non-interleaved audio layout, discussed a gst-rtsp-server issue with the Axis team, and merged all qt-gstreamer patches that were lying around in bugzilla and resolved all reported bugs, then declared it as unmaintained.

For his part, Nicolas participated in the planar audio format and split field interlaced video support work, started looking at adding per element latency tracing to GStreamer's existing latency tracer, and also discussed GStreamer CI, which will also move to GitLab to be able to run on pull requests also.

Olivier, during the first day, focused on the collective effort of reviewing all of the open bugs, managing to close a number of them while confirming and commenting on others. He also merged some outstanding patches he had (stay tuned for more details on those), and forward ported gst-validate for Android with the goal of running the CI on Android. He also merged a series of patches that enable bitcode embedding on the iOS target with the eventual goal of supporting tvOS as well.

As for myself, I mainly worked on (or rather started to work on) split-field interlacing support in GStreamer, adding relevant formats and modes in the GStreamer video library. In addition, as a Meson developer (Nirbheek Chauhan) was present, I took the opportunity to discuss with him the last bit of porting build system of Geoclue to Meson, a side project I've been working on. It helped me get it done faster but also helped Nirbheek find some issues in Meson and fix them!

All in all, my first GStreamer hackfest was an awesome experience (even though I was not feeling well). It was also very nice to hangout and socialize with old and new friends in the GStreamer community after a long time. Many thanks again to Axis for hosting us in their offices! See you at the GStreamer Conference this fall!

Boxes now supports RDP connections

Boxes has been the go-to option for easy virtual machine setups in GNOME for quite some time, but some people don’t know that our beloved application can also act as a remote viewer.

The “Enter URL” option in the new machine assistant is how you get a new remote machine added to your collection. It supports addresses of Spice and VNC servers and oVirt and Libvirt brokers. You can also paste the URL of an operating system image (iso, img, qcow, etc…) and Boxes will download and boot it for you.

However, there is life out of our GNU/Linux boxes and we need to stay connected. Windows is extremely popular and it ships a RDP server by default, making the adoption of open alternatives a bit unhandy there.

Imagine you have clients running Windows that need your remote support, or you couldn’t convince your family back home to switch to GNU/Linux, etc…

Now Boxes also supports RDP!

Boxes - screenshot

This feature is powered by FreeRDP. For convenience, I wrote a glib wrapper around the essential freerdp API so we can consume it via gobject-introspection in GNOME Boxes and others could reuse it for their own applications.

Heavily inspired in the gtk-vnc API,  I decided to name it gtk-frdp. So original! 😉

If you are interested in writing a RDP client of your own, or maybe port an existent one to gtk-frdp, you can achieve it with a few lines of code such as below (I choose Python for legibility, but it could be any gobject-introspected language of your choice).

from gi.repository import Gtk, GtkFrdp

window = Gtk.Window () display = GtkFrdp.Display () window.add (display)
display.open_host ("192.168.0.1", 3389) display.username = "username" display.password = "password"
window.show_all () Gtk.main ()

That simple!

This and a few other cool features will be available in our next stable release, GNOME 3.30. Stay tuned!

Startup Improvements in Xamarin.Forms on Android

With Xamarin.Forms 3.0 in addition to the many new feature work that we did, we have been doing some general optimizations across the board, from compile times to startup times and wanted to share some recent results on the net effect on one of our larger sample apps.

These are the results when doing a cold start for the SmartHotel360 application on Android when compiled for 32bits (armeabi-v7a) on a Google Pixel (1st gen).

Release Release/AOT Release/AOT+LLVM
Forms 2.5.0 6.59s 1.66s 1.61s
Forms 3.0.0 3.52s 1.41s 1.38s

This is independent of the work that we are doing to improve Android's startup speed, that both brings additional benefits today, and will bring additional benefits in the future.

One of the areas that we are investing on for Android is to remove any dynamic code execution at startup to integrate with the Java runtime, instead all of this is being statically computed, similar to what we are doing on Mac and iOS where we completely eliminated reflection and code generation from startup.

Fractal hackfest in Strasbourg

As Planet GNOME readers should be aware of by now 😉 we had a Fractal hackfest last week. I organised it with the help of Tobias and I want to thank all the parties that not only made it possible, but also made it an awesome event:

  • Epitech, the software engineering school where we had GUADEC in 2014, provided the venue
  • Purism sponsored the snacks and sent people to attend
  • the GNOME Foundation sponsored travel for some attendees and a dinner
  • AIUS took care of the catering on the first day, and also kindly lent us a kettle and coffee maker.

We were lucky to have Matthew from the core Matrix team with us for half of the event to answer our technical questions and help us steer our ship in the right direction.

I got involved with the discussions on various topics but as these have already been covered at length by the other attendees I will focus on some other stuff I managed to do. The first one is the one I’m the most happy about: I brought Quentin, a local student (sitting next to me on the picture), and he made his first GNOME contribution, which happened to be merge request !100 in Fractal 🎉. I also managed to write some code and make some progress on a few things. I landed the changes on generated avatars for users and rooms that don’t have one set, and started working on a couple of other contributions which should be finished in the near future. Keep an eye on the commit log to see them as they happen! 😊 I’m happy with what we have achieved so far and I’m looking forward 🤩 to more good things coming soon.

Apart from the technical side of things, I also tried to act as a city guide and hope my guests liked the places I took them. I for sure had lots of fun hanging out with all those people!

May 17, 2018

Working on GNOME To Do this Summer

A brief intro about myself
I am Rohit Kaushik (kaushik on IRC) from Delhi, India. I am currently pursuing B.E Computer Science at BITS Pilani, Goa. I am interested in Software Engineering, Machine Learning and Research. I usually spend my free time playing badminton, cricket or listening to music.
Last year, I worked on implementing Todoist for GNOME To Do and this time again I will be working on GNOME To Do, improving the two plugins that I wrote earlier and implementing newer features. I am grateful to GNOME and my mentor feaneron for giving me this opportunity.

About the Project

The project is aimed at improving todo.txt and Todoist error-free and support all the features of To Do. At the end of the project, we wish to have both the plugins in a usable and bug-free state. I am outlining the current list of task that I have planned to work on but any other suggestions are very much welcomed 🙂

Improvements to todo.txt plugin

  • Improve the parser and make it usable and bug-free
  • Add support for missing features, i.e list background colour, notes, subtask support
  • Handle edge cases in syntax parsing
  • Document the todo.txt syntax

Improvements to Todoist plugin

  • Move it outside GNOME Online Accounts – Currently Todoist uses GOA, for maintaining Todoist accounts and we wish to remove this dependency and have a login panel in To Do which manages user accounts.
  • Automatic synchronization of tasks and lists
  • Handling network loss and other failing cases.

I will keep this blog updated with the work in progress. If you have suggestion, please feel free to add them in comments or send me a mail.

Looking forward to a great Summer.

Cheers!

Performance hackfest

Last evening I came back from the GNOME performance hackfest happening in Cambridge. There was plenty of activity, clear skies, and pub evenings. Here’s some incomplete and unordered items, just the ones I could do/remember/witness/talk/overhear:

  • Xwayland 1.20 seems to be a big battery saver. Christian Kellner noticed that X11 Firefox playing Youtube could take his laptop to >20W consumption, traced to fairly intensive GPU activity. One of the first things we did was trying master, which dropped power draw to 8-9W. We presumed this was due to the implementation of the Present extension.
  • I was looking into dropping the gnome-shell usage of AtspiEventListener for the OSK, It is really taxing on CPU usage (even if the events we want are a minuscule subset, gnome-shell will forever get all that D-Bus traffic, and a11y is massively verbose), plus it slowly but steadily leaks memory.

    For the other remaining path I started looking into at least being able to deinitialize it. The leak deserves investigation, but I thought my time could be better invested on other things than learning yet another codebase.

  • Jonas Ådahl and Christian Hergert worked towards having Mutter dump detailed per-frame information, and Sysprof able to visualize it. This is quite exciting as all classic options just let us know where do we spend time overall, but doesn’t let us know whether we missed the frame mark, nor why precisely would that be. Update: I’ve been pointed out that Eric Anholt also worked on GPU perf events in mesa/vc4, so this info could also be visualized through sysprof
  • Peter Robinson and Marco Trevisan run into some unexpected trouble when booting GNOME in an ARM board with no input devices whatsoever. I helped a bit with debugging and ideas, Marco did some patches to neatly handle this situation.
  • Hans de Goede did some nice progress towards having the GDM session consume as little as possible while switched away from it.
  • Some patch review went on, Jonas/Marco/me spent some time looking at a screen very close and discussing the mipmapping optimizations from Daniel Van Vugt.
  • I worked towards fixing the reported artifact from my patches to aggressively cache paint volumes. These are basically one-off cases where individual ClutterActors break the invariants that would make caching possible.
  • Christian Kellner picked up my idea of performing pointer picking purely on the CPU side when the stage purely consists of 2D actors, instead of using the usual GL approach of “repaint in distinctive colors, read pixel to perform hit detection” which is certainly necessary for 3D, but quite a big roundtrip for 2D.
  • Alberto Ruiz and Richard Hughes talked about how to improve gnome-software memory usage in the background.
  • Alberto and me briefly dabbled with the idea of having specific search provider API that were more tied to Tracker, in order to ease the many context switches triggered by overview search.
  • On the train ride back, I unstashed and continued work on a WIP tracker-miners patch to have tracker-extract able to shutdown on inactivity. One less daemon to have usually running.

Overall, it was a nice and productive event. IMO having people with good knowledge both deep in the stack and wide in GNOME was determining, I hope we can repeat this feat again soon!

May 16, 2018

Banquets and Barbecues

tl;dr: We’re splitting up Fractal into two separate apps: One to replace IRC, the other to replace Telegram.

This is an in-depth post on the thinking behind the split of the Fractal app, which was decided at the hackfest in Strasbourg last week. For more information about the hackfest, have a look at my other blog post.

1-1 woes

One of the biggest problems with Fractal at the moment is that 1-1 messaging is pretty terrible. Since the rooms in the sidebar are sorted by most recent activity, high-traffic public rooms (such as GNOME IRC channels) tend to drown out rooms with less traffic, such as 1-1s and small groups. This is problematic because the signal-to-noise ratio in 1-1 chats and small groups tends to be much higher than in high-traffic public rooms. This leaves the user constantly searching for the rooms they care about, while the rooms they don’t care about are always at the top.

1-1 chats are quickly drowned out by high-traffic public rooms in the sidebar

One way to solve this problem is having a favorites group for “important” rooms. This is a feature Fractal has had for a while, and it does solve some of the problems with a room list sorted purely by recent activity. However, it only works well for rooms that are important over long periods of time, and needs to be managed manually. 1-1 chats are often brief, and there can be many of them in parallel. Putting them in favorites doesn’t make sense in many cases, as it would balloon the size of the favorites group, and require lots of manual work when starting or ending a conversation.

The “obvious” solution would be doing what Riot does: Having a separate group of 1-1 rooms in the sidebar, and thereby keeping the 1-1 conversations in one consistent place. However, this creates more problems than it solves. In practice, it results in multiple groups of arbitrary length competing for real estate in the sidebar. If you have a lot of 1-1s, this means that you’ll be able to see very few rooms (even when most of the 1-1s are old and not relevant at the moment). In Riot, this group is capped at 10 visible rooms by default, but that’s still not great if you only need 2 of them at the moment. The category can be collapsed, but then you can’t see which 1-1s have new messages, and it also means lots of busywork collapsing/expanding the group. Clearly this isn’t an ideal solution, which is why we were very hesitant to go down this path.

Riot’s separate 1-1 category doesn’t really solve the problem, because old 1-1s take up a ton of vertical real estate when it’s expanded

A way out?

As we were discussing this issue over the past few months, I started looking more closely at the way people use different messaging tools. One thing I found puzzling is that despite the fact that Matrix theoretically supports the use cases covered by popular apps like Whatsapp and Telegram, few people are actually using it to replace those apps. Instead, they use it to replace IRC and Slack.

Why? My theory is that most chat rooms fall in one of three categories:
Private Chats, which include 1-1s and small groups; Team Chats, which are larger, but still private and invite-only; and Public Rooms, which are basically like IRC.

Team Chats and Public Rooms share many characteristics: Both have relatively high amounts of traffic, and there’s a lot of noise. The main difference is that Team Chats are private and the members rarely change (e.g. a company’s internal Slack), while Public Rooms can be joined by anyone at any time, and there is no expectation of privacy (e.g. #gnome-hackers on IRC).

However, Private Chats have relatively little in common with the other two categories: They are low-traffic, and have little or no noise. This may sound like a small difference, but I think it’s the reason why 1-1s suck in Fractal/Riot/IRC, and why people aren’t using Matrix to replace Telegram.

The Banquet and the Barbecue

I’ve come to the conclusion that one app can’t cover all the use cases that the Matrix protocol supports, and still provide competitive UX. If you design an app to deal with lots of high-traffic rooms (e.g. Riot as it is today), it will suck for 1-1s, so people will use something else for those. Similarly, Telegram is primarily designed for 1-1s and small groups, which is why it’s a terrible experience if you have many high-traffic groups.

If we want Matrix to succeed as more than an IRC/Slack replacement we need multiple apps, each focusing on a distinct use case. For messaging, I think the most important distinction to make is between what I call the Banquet and the Barbecue.

Slack is one of the most widely used apps covering the Banquet use case

The Banquet is a big, loud place. There are tons of people, and you don’t know many of them. Lots of things are happening all the time, and it’s hard to keep track of everything. This is what Matrix is currently mostly used for. Slack, IRC, and Discord are also all in this category.

iMessage is a good example of an app focused on the Barbecue use case

The Barbecue is at the other end of the spectrum: It’s a calm, private environment where friends, family, co-workers, and other acquaintances hang out. Conversations are mostly between 2 or 3 people, slow, and often very personal. Telegram, Whatsapp, iMessage, Facebook Messenger, and a myriad of other chat apps are optimized for this use case.

Fracturing Fractal

Now, what does this mean for Fractal? After a long discussion on Thursday, we decided to split up Fractal into two separate apps with different interfaces, each containing a subset of the user’s Matrix rooms.

Exactly how rooms will be split between the two apps is not 100% clear yet. 1-1s are clearly Barbecue, public rooms are clearly Banquet, but private groups could go either way. For these cases we may need a way to explicitly move rooms between apps. The distinction should probably be part of the Matrix spec, so the intent for a room to be a Barbecue or Banquet room could be set when creating a room, and persist across devices.

The two apps will share practically all the internals, and even large parts of the interface. However, the split will allow us to do some things differently in each app to optimize the interfaces for the different use cases. Some of the changes we’re considering are a bubble-style message view in the Barbecue app, and more room categories (such as low-priority) in the Banquet app’s sidebar.

For more details on the split have a look at the blog posts by Daniel, Eisha, Julian, and Adrien.

Messages and Discussions

How exactly the apps will be branded (and what will happen to the Fractal name we all love) is still being decided, but there is some consensus to move to GNOME-style generic names. The Barbecue app will almost certainly be called “Messages”. For the Banquet app there’s less agreement, but my current favorite is “Discussions”.

Early-stage mockups showing what the two different apps could look like

The Fractal brand will not go away though: We’re thinking of keeping it around as the name of the community project that develops both GNOME Matrix apps, and/or using it for the backend powering both apps.

There are lots of details to be figured out in this transition, both from a design and an implementation perspective, but I’m very excited about this new direction. If you’d like to join the effort, come talk to us on Matrix.

Note: I have no illusions that this change will magically get everyone to leave Whatsapp/Telegram/iMessage and move to Matrix. In the short term, the goal is simply to make Matrix 1-1s a good experience. That said, if we ever want Matrix to make inroads with the general public, I think a move in this direction is an important precondition.

lightweight concurrency in lua

Hello, all! Today I'd like to share some work I have done recently as part of the Snabb user-space networking toolkit. Snabb is mainly about high-performance packet processing, but it also needs to communicate with management-oriented parts of network infrastructure. These communication needs are performed by a dedicated manager process, but that process has many things to do, and can't afford to make blocking operations.

Snabb is written in Lua, which doesn't have built-in facilities for concurrency. What we'd like is to have fibers. Fortunately, Lua's coroutines are powerful enough to implement fibers. Let's do that!

fibers in lua

First we need a scheduling facility. Here's the smallest possible scheduler: simply a queue of tasks and a function to run those tasks.

local task_queue = {}

function schedule_task(thunk)
   table.insert(task_queue, thunk)
end

function run_tasks()
   local queue = task_queue
   task_queue = {}
   for _,thunk in ipairs(queue) do thunk() end
end

For our purposes, a task is just a function that will be called with no arguments.

Now let's build fibers. This is easier than you might think!

local current_fiber = false

function spawn_fiber(fn)
   local fiber = coroutine.create(fn)
   schedule_task(function () resume_fiber(fiber) end)
end

function resume_fiber(fiber, ...)
   current_fiber = fiber
   local ok, err = coroutine.resume(fiber, ...)
   current_fiber = nil
   if not ok then
      print('Error while running fiber: '..tostring(err))
   end
end

function suspend_current_fiber(block, ...)
   -- The block function should arrange to reschedule
   -- the fiber when it becomes runnable.
   block(current_fiber, ...)
   return coroutine.yield()
end

Here, a fiber is simply a coroutine underneath. Suspending a fiber suspends the coroutine. Resuming a fiber runs the coroutine. If you're unfamiliar with coroutines, or coroutines in Lua, maybe have a look at the lua-users wiki page on the topic.

The difference between a fibers facility and just coroutines is that with fibers, you have a scheduler as well. Very much like Scheme's call-with-prompt, coroutines are one of those powerful language building blocks that should rarely be used directly; concurrent programming needs more structure than what Lua offers.

If you're following along, it's probably worth it here to think how you would implement yield based on these functions. A yield implementation should yield control to the scheduler, and resume the fiber on the next scheduler turn. The answer is here.

communication

Once you have fibers and a scheduler, you have concurrency, which means that if you're not careful, you have a mess. Here I think the Go language got the essence of the idea exactly right: Do not communicate by sharing memory; instead, share memory by communicating.

Even though Lua doesn't support multiple machine threads running concurrently, concurrency between fibers can still be fraught with bugs. Tony Hoare's Communicating Sequential Processes showed that we can avoid a class of these bugs by treating communication as a first-class concept.

Happily, the Concurrent ML project showed that it's possible to build these first-class communication facilities as a library, provided the language you are working in has threads of some kind, and fibers are enough. Last year I built a Concurrent ML library for Guile Scheme, and when in Snabb we had a similar need, I ported that code over to Lua. As it's a new take on the problem in a different language, I think I've been able to simplify things even more.

So let's take a crack at implementing Concurrent ML in Lua. In CML, the fundamental primitive for communication is the operation. An operation represents the potential for communication. For example, if you have a channel, it would have methods to return "get operations" and "put operations" on that channel. Actually receiving or sending a message on a channel occurs by performing those operations. One operation can be performed many times, or not at all.

Compared to a system like Go, for example, there are two main advantages of CML. The first is that CML allows non-deterministic choice between a number of potential operations in a generic way. For example, you can construct a operation that, when performed, will either get on one channel or wait for a condition variable to be signalled, whichever comes first. In Go, you can only select between operations on channels.

The other interesting part of CML is that operations are built from a uniform protocol, and so users can implement new kinds of operations. Compare again to Go where all you have are channels, and nothing else.

The CML operation protocol consists three related functions: try which attempts to directly complete an operation in a non-blocking way; block, which is called after a fiber has suspended, and which arranges to resume the fiber when the operation completes; and wrap, which is called on the result of a successfully performed operation.

In Lua, we can call this an implementation of an operation, and create it like this:

function new_op_impl(try, block, wrap)
   return { try=try, block=block, wrap=wrap }
end

Now let's go ahead and write the guts of CML: the operation implementation. We'll represent an operation as a Lua object with two methods. The perform method will attempt to perform the operation, and return the resulting value. If the operation can complete immediately, the call to perform will return directly. Otherwise, perform will suspend the current fiber and arrange to continue only when the operation completes.

The wrap method "decorates" an operation, returning a new operation that, if and when it completes, will "wrap" the result of the completed operation with a function, by applying the function to the result. It's useful to distinguish the sub-operations of a non-deterministic choice from each other.

Here our new_op function will take an array of operation implementations and return an operation that, when performed, will synchronize on the first available operation. As you can see, it already has the equivalent of Go's select built in.

function new_op(impls)
   local op = { impls=impls }
   
   function op.perform()
      for _,impl in ipairs(impls) do
         local success, val = impl.try()
         if success then return impl.wrap(val) end
      end
      local function block(fiber)
         local suspension = new_suspension(fiber)
         for _,impl in ipairs(impls) do
            impl.block(suspension, impl.wrap)
         end
      end
      local wrap, val = suspend_current_fiber(block)
      return wrap(val)
   end

   function op.wrap(f)
      local wrapped = {}
      for _, impl in ipairs(impls) do
         local function wrap(val)
            return f(impl.wrap(val))
         end
         local impl = new_op_impl(impl.try, impl.block, wrap)
         table.insert(wrapped, impl)
      end
      return new_op(wrapped)
   end

   return op
end

There's only one thing missing there, which is new_suspension. When you go to suspend a fiber because none of the operations that it's trying to do can complete directly (i.e. all of the try functions of its impls returned false), at that point the corresponding block functions will publish the fact that the fiber is waiting. However the fiber only waits until the first operation is ready; subsequent operations becoming ready should be ignored. The suspension is the object that manages this state.

function new_suspension(fiber)
   local waiting = true
   local suspension = {}
   function suspension.waiting() return waiting end
   function suspension.complete(wrap, val)
      assert(waiting)
      waiting = false
      local function resume()
         resume_fiber(fiber, wrap, val)
      end
      schedule_task(resume)
   end
   return suspension
end

As you can see, the suspension's complete method is also the bit that actually arranges to resume a suspended fiber.

Finally, just to round out the implementation, here's a function implementing non-deterministic choice from among a number of sub-operations:

function choice(...)
   local impls = {}
   for _, op in ipairs({...}) do
      for _, impl in ipairs(op.impls) do
         table.insert(impls, impl)
      end
   end
   return new_op(impls)
end

on cml

OK, I'm sure this seems a bit abstract at this point. Let's implement something concrete in terms of these primitives: channels.

Channels expose two similar but different kinds of operations: put operations, which try to send a value, and get operations, which try to receive a value. If there's a sender already waiting to send when we go to perform a get_op, the operation continues directly, and we resume the sender; otherwise the receiver publishes its suspension to a queue. The put_op case is similar.

Finally we add some synchronous put and get convenience methods, in terms of their corresponding CML operations.

function new_channel()
   local ch = {}
   -- Queues of suspended fibers waiting to get or put values
   -- via this channel.
   local getq, putq = {}, {}

   local function default_wrap(val) return val end
   local function is_empty(q) return #q == 0 end
   local function peek_front(q) return q[1] end
   local function pop_front(q) return table.remove(q, 1) end
   local function push_back(q, x) q[#q+1] = x end

   -- Since a suspension could complete in multiple ways
   -- because of non-deterministic choice, it could be that
   -- suspensions on a channel's putq or getq are already
   -- completed.  This helper removes already-completed
   -- suspensions.
   local function remove_stale_entries(q)
      local i = 1
      while i <= #q do
         if q[i].suspension.waiting() then
            i = i + 1
         else
            table.remove(q, i)
         end
      end
   end

   -- Make an operation that if and when it completes will
   -- rendezvous with a receiver fiber to send VAL over the
   -- channel.  Result of performing operation is nil.
   function ch.put_op(val)
      local function try()
         remove_stale_entries(getq)
         if is_empty(getq) then
            return false, nil
         else
            local remote = pop_front(getq)
            remote.suspension.complete(remote.wrap, val)
            return true, nil
         end
      end
      local function block(suspension, wrap)
         remove_stale_entries(putq)
         push_back(putq, {suspension=suspension, wrap=wrap, val=val})
      end
      return new_op({new_op_impl(try, block, default_wrap)})
   end

   -- Make an operation that if and when it completes will
   -- rendezvous with a sender fiber to receive one value from
   -- the channel.  Result is the value received.
   function ch.get_op()
      local function try()
         remove_stale_entries(putq)
         if is_empty(putq) then
            return false, nil
         else
            local remote = pop_front(putq)
            remote.suspension.complete(remote.wrap)
            return true, remote.val
         end
      end
      local function block(suspension, wrap)
         remove_stale_entries(getq)
         push_back(getq, {suspension=suspension, wrap=wrap})
      end
      return new_op({new_op_impl(try, block, default_wrap)})
   end

   function ch.put(val) return ch.put_op(val).perform() end
   function ch.get()    return ch.get_op().perform()    end

   return ch
end

a wee example

You might be wondering what it's like to program with channels in Lua, so here's a little example that shows a prime sieve based on channels. It's not a great example of concurrency in that it's not an inherently concurrent problem, but it's cute to show computations in terms of infinite streams.

function prime_sieve(count)
   local function sieve(p, rx)
      local tx = new_channel()
      spawn_fiber(function ()
         while true do
            local n = rx.get()
            if n % p ~= 0 then tx.put(n) end
         end
      end)
      return tx
   end

   local function integers_from(n)
      local tx = new_channel()
      spawn_fiber(function ()
         while true do
            tx.put(n)
            n = n + 1
         end
      end)
      return tx
   end

   local function primes()
      local tx = new_channel()
      spawn_fiber(function ()
         local rx = integers_from(2)
         while true do
            local p = rx.get()
            tx.put(p)
            rx = sieve(p, rx)
         end
      end)
      return tx
   end

   local done = false
   spawn_fiber(function()
      local rx = primes()
      for i=1,count do print(rx.get()) end
      done = true
   end)

   while not done do run_tasks() end
end

Here you also see an example of running the scheduler in the last line.

where next?

Let's put this into perspective: in a couple hundred lines of code, we've gone from minimal Lua to a language with lightweight multitasking, extensible CML-based operations, and CSP-style channels; truly a delight.

There are a number of possible ways to extend this code. One of them is to implement true multithreading, if the language you are working in supports that. In that case there are some small protocol modifications to take into account; see the notes on the Guile CML implementation and especially the Manticore Parallel CML project.

The implementation above is pleasantly small, but it could be faster with the choice of more specialized data structures. I think interested readers probably see a number of opportunities there.

In a library, you might want to avoid the global task_queue and implement nested or multiple independent schedulers, and of course in a parallel situation you'll want core-local schedulers as well.

The implementation above has no notion of time. What we did in the Snabb implementation of fibers was to implement a timer wheel, inspired by Juho Snellman's Ratas, and then add that timer wheel as a task source to Snabb's scheduler. In Snabb, every time the equivalent of run_tasks() is called, a scheduler asks its sources to schedule additional tasks. The timer wheel implementation schedules expired timers. It's straightforward to build CML timeout operations in terms of timers.

Additionally, your system probably has other external sources of communication, such as sockets. The trick to integrating sockets into fibers is to suspend the current fiber whenever an operation on a file descriptor would block, and arrange to resume it when the operation can proceed. Here's the implementation in Snabb.

The only difficult bit with getting nice nonblocking socket support is that you need to be able to suspend the calling thread when you see the EWOULDBLOCK condition, and for coroutines that is often only possible if you implemented the buffered I/O yourself. In Snabb that's what we did: we implemented a compatible replacement for Lua's built-in streams, in Lua. That lets us handle EWOULDBLOCK conditions in a flexible manner. Integrating epoll as a task source also lets us sleep when there are no runnable tasks.

Likewise in the Snabb context, we are also working on a TCP implementation. In that case you want to structure TCP endpoints as fibers, and arrange to suspend and resume them as appropriate, while also allowing timeouts. I think the scheduler and CML patterns are going to allow us to do that without much trouble. (Of course, the TCP implementation will give us lots of trouble!)

Additionally your system might want to communicate with fibers from other threads. It's entirely possible to implement CML on top of pthreads, and it's entirely possible as well to support communication between pthreads and fibers. If this is interesting to you, see Guile's implementation.

When I talked about fibers in an earlier article, I built them in terms of delimited continuations. Delimited continuations are fun and more expressive than coroutines, but it turns out that for fibers, all you need is the expressive power of coroutines -- multi-shot continuations aren't useful. Also I think the presentation might be more straightforward. So if all your language has is coroutines, that's still good enough.

There are many more kinds of standard CML operations; implementing those is also another next step. In particular, I have found semaphores and condition variables to be quite useful. Also, standard CML supports "guards", invoked when an operation is performed, and "nacks", invoked when an operation is definitively not performed because a choice selected some other operation. These can be layered on top; see the Parallel CML paper for notes on "primitive CML".

Also, the choice operator above is left-biased: it will prefer earlier impls over later ones. You might want to not always start with the first impl in the list.

The scheduler shown above is the simplest thing I could come up with. You may want to experiment with other scheduling algorithms, e.g. capability-based scheduling, or kill-safe abstractions. Do it!

Or, it could be you already have a scheduler, like some kind of main loop that's already there. Cool, you can use it directly -- all that fibers needs is some way to schedule functions to run.

godspeed

In summary, I think Concurrent ML should be better-known. Its simplicity and expressivity make it a valuable part of any concurrent system. Already in Snabb it helped us solve some longstanding gnarly issues by making the right solutions expressible.

As Adam Solove says, Concurrent ML is great, but it has a branding problem. Its ideas haven't penetrated the industrial concurrent programming world to the extent that they should. This article is another attempt to try to get the word out. Thanks to Adam for the observation that CML is really a protocol; I'm sure the concepts could be made even more clear, but at least this is a step forward.

All the code in this article is up on a gitlab snippet along with instructions for running the example program from the command line. Give it a go, and happy hacking with CML!

GNOME Performance Hackfest

We’re about to finish the three days long first GNOME Performance Hackfest here in Cambridge.

We started covering a few topics, there are three major areas we’ve covered and in each one of those there has been a bunch of initiatives.

photo_2018-05-15_16-05-20

photo_2018-05-16_16-45-16

 

 

GNOME Shell performance

Jonas Adahl, Marco Trevisan, Eric Anholt, Emmanuele Bassi, Carlos Garnacho and Daniel Stone have been flocking together around Shell performance. There has been some high level discussions about the pipeline, Clutter, Cogl, cairo/gtk3 and gtk4.

The main effort has been around creating probes across the stack to help Christian Hergert with sysprof (in drm, mutter, gjs…) so that we can actually measure performance bottlenecks at different levels and pinpoint culprits.

We’ve been also looking at the story behind search providers and see if we can rearchitect things a bit to have less roundtrips and avoid persistent session daemons to achieve the same results. Discussions are still ongoing on that front.

GNOME Session resource consumption

Hans de Goede put together a summary of the resource consumed in a typical GNOME session in Fedora and tweaks to avoid those, you can check the list in the agenda.

There are some issues specific to Fedora there, but the biggest improvement that we can achieve is shutting down’s GDM’s own gnome-shell instance, for which Hans already has a working patch. This should reduce resource consumption by 280megs of RAM.

The second biggest target is GNOME Software, which we keep running primarily for the shell provider. Richard Hughes was here yesterday and is already working on a solution for this.

We are also looking into the different GNOME Settings Daemon processes and trying to figure out which ones we can shut down until needed.

Surely there’s stuff I’ve missed, and hopefully we’ll see blogposts and patches surfacing soon after we wrap up the event. Hopefully we can follow up during GUADEC and start showing the results.

On Tuesday we enjoyed some drinks out kindly hosted by Collabora.

collabora-logo-small
I’d like to thank the Eben Upton and the Raspberry Pi Foundation for sponsoring the venue and sending Eric Anholt over.

raspberry-pi-logo-8240ABBDFE-seeklogo.com

Internationalization of Fractal (part 2)

A textual program using gettext

For my investigations, I first tried to write a textual program that works with gettext. I spent quite some time to figure out how all of this works but I finally was able to make it work. And that means that we should be able to implement i18n for Fractal using gettext!

I created a new Rust binary project with cargo and I added gettext-rs as a dependency in the Cargo.toml file by adding this line:

gettext-rs = { git = "https://github.com/Koka/gettext-rs", features = ["gettext-system"] }

I edited the main.rs source file to have a basic test to see if gettext-rs works correctly, here is its content:

extern crate gettextrs;
use gettextrs::*;

fn main() {
     setlocale(LocaleCategory::LcAll, "");
     bindtextdomain("test", "./po");
     textdomain("test");

    println!("Original: Open");
    println!("Translated: {}", gettext("Open"));

    println!("Original: Text Editor");
    println!("Translated singular: {}", ngettext("Text Editor", "Text Editors", 1));
    println!("Translated plural: {}", ngettext("Text Editor", "Text Editors", 2));
}

In the root directory of the project, I created a directory named “po”, then a subdirectory named “fr” (as I want to do a little French translation) inside “po” and then again, a directory “LC_MESSAGES” inside “fr”. So that I had the same folder hierarchy inside my “po” directory as in “/usr/share/locale”, because gettext will look for the translations in MO files that are in directories like “[TARGET]/[LANGUAGE]/LC_MESSAGES/[PACKAGE].mo”. [TARGET] and [PACKAGE] are defined by the call “bindtextdomain([PACKAGE], [TARGET]);” in the program. So here, the package name is “test” and the targeted directory is “./po”.

Next, I used the utility xgettext to extract all the translatable strings from the source file with this command:

xgettext -o po/template.pot src/*

And I edited template.pot to replace “CHARSET” with “UTF-8”. To get the file in which I would do the French translation, I used:

msginit --locale=fr --input=po/template.pot --output=po/fr/test.po

Finally, I added the translations of the strings on the lines with “msgid” in the lines with “msgstr” and my PO file had this content:

# French translations for PACKAGE package.
# Copyright (C) 2018 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Eisha <eisha@ernesto>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-15 12:33+0200\n"
"PO-Revision-Date: 2018-05-15 12:34+0200\n"
"Last-Translator: Eisha <eisha@ernesto>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: ../src/main.rs:10
msgid "Open"
msgstr "Ouvrir"

#: ../src/main.rs:13 ../src/main.rs:14
msgid "Text Editor"
msgid_plural "Text Editors"
msgstr[0] "Un éditeur de texte"
msgstr[1] "Des éditeurs de texte"

I compiled the MO file like this:

mgsfmt po/fr/test.po  -o po/fr/LC_MESSAGES/test.mo

The the program was finally ready to test, so when launching:

LANG=en_US cargo run

I get this output:

Original: Open
Translated: Open
Original: Text Editor
Translated singular: Text Editor
Translated plural: Text Editors

And when I launch it like this:

LANG=fr_FR cargo run

I get the expected output:

Original: Open
Translated: Ouvrir
Original: Text Editor
Translated singular: Un éditeur de texte
Translated plural: Des éditeurs de texte

You can find the program I have written in this repository.

A GTK program using gettext

When I got this textual program working, I had to test it with a GTK program in order to know if gettext-rs could still translate the strings in the source file and most importantly, if/how it could also translate strings from Glade files.

So I wrote a GTK program (with the crate gtk-rs) for which I created an empty window with the following title “A window title from Glade” with Glade, I saved this minimal UI in the file ui/main_window.glade. And I wrote the following code in main.rs:

extern crate gtk;
extern crate gettextrs;

use gtk::prelude::*;

use gettextrs::*;

fn main() {
    setlocale(LocaleCategory::LcAll, "");
    bindtextdomain("test", "./po");
    textdomain("test");

    gtk::init().unwrap();

    let window: gtk::Window = gtk::Builder::new_from_file("./ui/main_window.glade")
        .get_object("main_window").expect("Failed to load the main window");

    // UI initialization
    let label = gtk::Label::new(gettext("A label from the source code").as_str());
    window.add(&label);
    window.show_all();

    window.connect_delete_event(|_, _| {
        gtk::main_quit();
        Inhibit(false)
    });

    gtk::main();
}

Then, I followed the same procedure as before to generate the POT, PO and MO files, except that I also indicated to xgettext to parse the Glade file like this:

xgettext -o po/template.pot src/* ui/*

So that the content of po/fr/test.po was (at the end of the procedure):

# French translations for PACKAGE package.
# Copyright (C) 2018 THE PACKAGE'S COPYRIGHT HOLDER
# This file is distributed under the same license as the PACKAGE package.
# Eisha <eisha@ernesto>, 2018.
#
msgid ""
msgstr ""
"Project-Id-Version: PACKAGE VERSION\n"
"Report-Msgid-Bugs-To: \n"
"POT-Creation-Date: 2018-05-15 19:16+0200\n"
"PO-Revision-Date: 2018-05-15 19:17+0200\n"
"Last-Translator: Eisha <eisha@ernesto>\n"
"Language-Team: French\n"
"Language: fr\n"
"MIME-Version: 1.0\n"
"Content-Type: text/plain; charset=UTF-8\n"
"Content-Transfer-Encoding: 8bit\n"
"Plural-Forms: nplurals=2; plural=(n > 1);\n"

#: ../src/main.rs:19
msgid "A label from the source code"
msgstr "Une étiquette du code source"

#: ../ui/main_window.glade:7
msgid "A window title from Glade"
msgstr "Un titre de fenêtre de Glade"

When running this program with:

LANG=en_US cargo run

The window opened is like this:

Capture du 2018-05-16 11-09-51

And when running it with:

LANG=fr_FR cargo run

The window opened is like this:

Capture du 2018-05-16 11-11-54

So it seems that GtkBuilder is calling gettext when parsing the UI file.

You can find this other program I have written in this repository.

So now I can start to implement i18n support within Fractal! Although I will also have to figure out how to properly integrate this with meson.

Introducing the 1.8 freedesktop runtime in the gnome nightly builds

All the current Flatpak runtimes in wide use are based on the 1.6 Freedesktop runtime. This is a two-layered beast where the lower layer is built using Yocto and the upper layer is built using flatpak-builder.

Yocto let us get a basic system bootstrapped, but it is not really a great match for the needs of a Flatpak runtime. We’ve long wanted a base that targeted sandboxed builds which is closer to upstream and without the embedded cross-compiled legacy of Yocto. This is part of the reason why Tristan started working on BuildStream, and why the 1.8 Freedesktop runtime was created from scratch, using it.

After a herculean effort from the people at Codethink (who sponsor this effort) we now have a working Yocto-free version of the Platform and Sdk. You can download the unstable version from here and start playing with it. It is not yet frozen or API/ABI stable, but its getting there.

The next step in this effort is to test it as widely as possible to catch any issues before the release is frozen. In order to do this I rebased the Gnome nightly runtime builds on top of the new Freedesktop version this week. This is a good match for a test release, because it has no real ABI requirements (being rebuilt with the apps daily), yet gets a fair amount of testing.

WARNING: During the initial phase it is likely that there will be problems. Please test your apps extra carefully and report all the issues you find.

In the future, the goal is to also convert the Gnome runtimes to BuildStream. Work on this has started, but for now we want to focus on getting the base runtime stable.

Fractal Hackfest in Strasbourg

Last week we had an intense 4-day hackfest in Strasbourg to map out the future of Fractal, a native GNOME Matrix messaging app. The event was held at Epitech in Strasbourg’s old town, and organized by Alexandre Franke. Among the attendees were core Fractal contributors Daniel, Alexandre, Eisha, and Julian, as well as Dorota, Adrien, and Francois from Purism. Special thanks go to Matthew from the Matrix core team for joining us on the first two days.

Our main priorities for the hackfest were to plan the roadmap for the next months, decide on the tasks for our GSoC students (Eisha and Julian), and work on the design of some important missing features, like the room settings.

I personally attended the hackfest in both my role as designer on the Fractal project and as a Purism employee currently working on the apps for the Librem 5. One of the reasons why several members of the Librem 5 team attended the hackfest was that we will need a Matrix messaging app on the phone and wanted to explore a potential collaboration.

The hackfest was extremely productive, so much so that I’ll need multiple blog posts to report on all the things we worked on. Here’s a quick outline of some of the most important things that happened:

  • We’re splitting the app into two separate apps (more on this in a future blog post)
  • A big refactor of the backend is happening soon to enable the split
  • We discussed having a system-level Matrix daemon, which different apps could use as a backend (e.g. the two different messaging apps and a calls app)
  • Matthew explained that room types will be simplified into 1-1, private groups and public groups in the future (which nicely complements our split). We discussed whether 1-1s should be immutable (they should :P)
  • Matthew explained how end-to-end encryption and calls work in Matrix, and how we could get them in Fractal
  • We came up with an initial design for multi-account (which basically consists of an account chooser at startup, and a separate window for each account)
  • We discussed a design for read receipts. Not quite done yet, but we’re on the right path, I think.
  • We talked about what it will take to make Fractal work on mobile. Not too big of a problem design-wise, but we’ll need Rust bindings for libhandy and emeus
  • Eisha will be investigating i18n, because we really want to make the app translatable (currently this is hard to do because we use Rust)
  • Julian will be working on a big message history UI refactor/redesign, as well as other UI stuff, such as user account settings
  •  There is a huge number of message types we don’t support yet and we discussed the design for most of them (including in-app viewers and a history of sent files)
  • With Matthew’s help, Daniel fixed the slow initial sync
  • Julian worked on a nicer UI for the GTK emoji chooser and Rust bindings for gspell
  • Alexandre landed the new, prettier default avatars
  • Quentin started packaging Fractal for macOS
  • We fought our way though the garbage fire that is the Join and History settings in Riot, and emerged with a design that isn’t terrible (thanks Dorota and Julian!)
Matthew explaining device verification for E2E chats

Thanks everyone for attending, Epitech and Alexandre for the venue, and Purism for sponsoring the hackfest! It was amazingly productive to have everyone in one place, and I look forward to seeing you all at GUADEC in July :)

 

GIMP 2.10.0 is out!

Hey all!

So we are a bit late to announce it, since this happened on April 27, during Libre Graphics Meeting 2018 (by the way, can you spot ZeMarmot team, Aryeom and Jehan, in the goodbye photo of the meeting?), but yeah after 6 years of hard work, GIMP 2.10.0 is finally out!

This is a huge release. You can read the release notes which are scrolling like forever and that is still not actually the full deal. We had so many awesome changes and cool new features in this release that we had to cut down the release notes contents when writing it.

We are obviously not going to detail the participation of ZeMarmot in this release, since Jehan (hence ZeMarmot project) is the second biggest contributor of GIMP 2.10.0 with 1126 commits. So our overall report would basically be about as big as the release notes themselves. Let’s spare you this!

I hope you will enjoy this new version (you can download it here) as much as we enjoyed creating it. These have been a very exciting 6 years of contributions. And that is not finished! We are barely back from Libre Graphics Meeting and a bit exhausted (this is the reason why we failed a bit to send this news in a timely manner), and we already started working on GIMP 3, with the port to GTK+3 (in the same time as we fix flow of bugs, as always just after a major release).
Future for GIMP is bright! 😀

A big thanks to all our donators for helping us make such great software! With every bit of your donations, you contributed to Free Software. We love you!

ZeMarmot team

Reminder: our Free Software contribution can be funded
on: Liberapay, Patreon or Tipeee (and other) through
ZeMarmot project.

May 15, 2018

Announcing Board of Directors Elections 2018

From 2016 to 2017, I was a director on the GNOME Foundation Board of Directors. This is a great opportunity for anyone working on the GNOME project. And because Board elections are coming up, I wanted to share the news.

The most important deadlines in the GNOME Board Elections are the following:
May 12
List of candidates opens.

May 24
Last day to announce candidacies, submit summary statements.

May 25
Final list of candidates.

May 26
Instructions mailed to eligible voters, voting begins.

June 9
Voting closes.
Preliminary results will be announced on June 12, with June 19 as the last day to challenge results (election becomes official).

Serving on the Board is a great way to participate in open source software. I found my time on the Board to be personally very rewarding.

Time commitments are generally a regular phone call (an hour) and attendance at GUADEC. Directors also pick up projects and to-dos from time to time.

I would submit my name again for the Board, but GUADEC falls at a time when I need to be here at the County. That's our budget presentation time, so I can either attend GUADEC or I can present my department budget to the county Board.

Fractal Hackfest 2018

The last couple of days I was in Strasbourg for the Fractal Hackfest. We made some fundamental decisions for the future of Fractal, our Matrix client.  We also decided on some basic architectural changes we want to make.

You probably already read about the split of Fractal into two separate apps, to cover two different use cases: Barbecue and Banquet. Barbecue will mostly cover “one to one” chats and Banquet high-traffic group chats and IRC-like rooms. We are certain that the split is the right direction for Fractal, but we didn’t define the exact split between the apps.

Before we can start working on the two different apps we need to refactor the code. Currently Fractal is structured in two parts: fractal-api and fractal-gtk. The first one is a library which handles all the communication with Matrix. The other part contains all logic and UI. The first big task will be to nicely separate the logic from the UI, so that the code can be shared between the apps and have just few different UI elements, to better fit each use case. We talked about a lot of things and Daniel and Tobias have written some really good posts to sum up the event, therefore I won’t go into every detail in this post.

This picture is from a lunch break. We got our food from different restaurants and ate all together. This was my first hackfest, and I had a lot of fun, I definitely loved the city and made new friends.

Emoji Picker

During the train ride to Strasbourg I did some hacking. I worked on a patch for the gtk emoji chooser, which on many systems looks quite broken:

After my changes the popover will look like this:

I already opened a merge request to GTK. We are still discussing a few things but I hope it will be merged soon.

Spell check

I also worked on the integration of spell check into Fractal. I will use gspell, an integration for spellcheck for GTK applications, also used by Gedit. The first step was to create gspell Rust bindings, but I will write a different post on that and how to create Rust bindings with GIR. For now, here’s a basic demonstration of the working gspell-rs bindings:

Not just coding

I didn’t only code and work on Fractal, but I also a got to do a little bit of sightseeing. The last day (Monday) was completely different than the previous days, since everybody had to leave and we hadn’t planned any thing for it. I visited the cathedral, from inside and I also climbed the top to see the panorama of Strasbourg. For lunch we, the remaining people, ate at a local restaurant. On the menu was limitless Flamenkuchen, with close to 1 liter of beer for each of us. 

Google Summer of Code

Many people already know I got accepted as a student to GSoC. It was really nice to meet my mentor, Daniel and also Eisha, the other student working on Fractal. Now I can connect the Matrix ID to a real person, which makes interaction with them much easier online. I guess this Hackfest was a really nice conclusion for the community bonding period and a good start for GSoC.

The time in Strasbourg was limited therefore we didn’t have much time to define all of the tasks for the summer.  But I will be starting to work on the User Account Settings for this week. Also the spell checking is one of my proposed GSoC tasks, so I’m already ahead of my planned schedule. I definitely won’t have trouble finding more tasks though :)

Thank You!

Thanks to the GNOME Foundation and Purism for making it possible for me to attend this hackfest. GNOME sponsored my trip to and from Strasbourg, and Purism paid for my accomodation (I shared a room with Tobias). The location was awesome, and the city was perfect for a hackfest, I am so glad I have been there. I would also like to thank everyone who organized and helped make the event happen. I think it was a big success and this is one of the reasons I love the GNOME community so much.

Fracturing Fractal

Last week my employer Purism allowed me to attend the Fractal hackfest in Strasbourg. There we chatted about the future of Fractal and of the messaging applications Purism needs for the Librem 5.

Fractal will have two split:

  • a "vertical" split, separating the frontend of Fractal from its backend so we can have a shared Matrix backend;
  • a "horizontal" split, separating Fractal into two applications communicating with the Matrix backend:
    • one focusing on public rooms where you chat with strangers and most messages are noise for you (this application will be very similar to current Fractal),
    • the other focusing on private conversations with few persons where you want to read everything and which will also support SMS.

Also, hackfests are hard. 🍺😶

May 14, 2018

Improving the development experience for GNOME Settings

After Bastien and Rui announced that they were stepping down from maintainership of GNOME Settings, I went ahead and volunteered to take care of it. This was not a random act, though;  for quite some time, I’ve been adding and changing code all around. I was pretty involved in moving to the new layout, and with the help of other contributors, implemented the redesigns of various panels. Clearly, I have a technical debt to the app.

Adding to that, assuming maintainership over it also aligns well with the goals of my employer, Endless, and gives a nice upstream/downstream overlap. With that, I can spend a bigger chunk of my work time on upstream tasks. Moreover, it allows us to have a stronger relationship with the GNOME community — after all, it allows me to bridge the insights and knowledge we gain from our users to a wider community.

Turns out, GNOME Settings is a pretty popular app amongst our users. It is one of the top apps that our users run. Developing and improving it became an important part of our fixed set of tasks. Specially now that we’re on the verge of a big release and one exciting new feature (amongst many!) was added into Settings. I’ll write more about it soon, hold your horses! 🙂

Without further ado, let’s start by checking some facts about Settings.

Knowing Settings

  • It has 371 unique dependencies (give or take, depending on the distro);
  • As of today, there are more than 17,500 commits and 500 tags;
  • It has roughly 440,000 lines of code, effectively making it part of the huge apps of GNOME, together with Evolution, GNOME Builder and Mutter.
  • It has 24 panels, the latest one being Thunderbolt;
  • First commit dates back to February 10th 1998, 21:22:12

As you can see, this is really no regular GNOME app. It has an old code base, half a million lines of code, dozens of thousands of commits and went through a lot of contributors. During all this time, it has being serving as the central hub of hardware and modules setting management. This gives us the dimension of this app.

But life is not a bed of roses.

Problems

Of course, during this time, GNOME Settings aged, was rewritten at least three times, and more recently was ported to another build system, Meson. Maintaining an app of this size, with such a colossal amount of knowledge involved, is not easy.

As I learn and find my way around the code base, a few problems were found:

  • You need to have the development packages of everything to build it. This is obvious, but I don’t really enjoy messing up with my host system.
  • It is not trivial to debug Settings. There was only a rudimentary logging system around.
  • There are at least 4 different code styles being used, and none documented.
  • Tests were scattered all around the code base.

With that, the reader hopefully  has enough context to follow the rest of this article: the recent changes that make the development experience of GNOME Settings smoother and more streamlined.

Flatpak, Flakpat, Flaptak, Flatkap, Flapkat!

Flatpak is an application distribution module, and has high adoption from the GNOME community. Turns out, Flatpak also became an excellent development tool, much beyond my initial expectations. It allows me, as a developer, to have a finer control over the build and execution environment, and keeps my system clean and organized. It allows me to install multiple versions of a given app, and they’ll share every common file they have. It’s awesome.

Flatpak is also tightly integrated into GNOME Builder, and developing apps on Builder with Flatpak is a super smooth experience these days. Thanks to Christian Hergert, we have a prime quality IDE!

This led to the creation of a Flatpak manifest for GNOME Settings. Of course, GNOME Settings is not meant to run as a Flatpak by end users. The Flatpak integration is strictly for development purposes.

You'll be warned when running Settings with Flatpak.You’ll be warned when running Settings with Flatpak.

Spotlights to the blueish “I am a development version” header bar:

Blue headerbarsFancy header bar!

These details might seem small, but they transform the development experience from a burden to a breeze. One can literally clone GNOME Settings from GNOME Builder and just press the Run button – everything will happen automatically. Besides that, Flatpak integration means I can develop GNOME Settings in a locked host system, such as Endless OS or Fedora Atomic, without having to unlock it and install development packages.

This work was partially done in my work time. Thanks Endless for letting me improve my own workflow 😛

Faster CI

GNOME Settings gained rudimentary CI support just before the 3.28 release. It allows us to have fancy green icons on commits, like these:

CI in actionWe’re in a good state, everything is building!

CI is important to make sure everything is always building and working fine. Merge requests are always built before being merged, and having a more automated contribution workflow benefits everyone.

But it was inefficient and bloated.

Thanks to the independent contributor Claudio André, the CI was completely revamped. The build process was shrinked, the build environment was standardized so we can reliably reproduce build failures, and the fat was trimmed. In fact, CI times were cut down from 17 minutes to 3 minutes in average.

Thanks Claudio for your contributions!

Tests, More and Better

Another important aspect of improving the development experience is adding more tests, that validate a larger portion of the code base.

Thanks to Red Hat’s Benjamin Berg, the tests in GNOME Settings were reorganized and improved. As a courtesy, more network tests were also added. These tests are integrated into the CI, and every contribution is tested in a job:

CI in GitlabThe tests run on every commit, and every merge request.

For obvious reasons, tests are absolutely important to avoid regressions. Unfortunately, though, the tests available in GNOME Settings don’t cover even a tiny fraction of the code base. Writting tests is a great way to start contributing to GNOME Settings!

Thanks Benjamin for reorganizing the tests!

Documentation

In addition to all this mentioned work, I personally have been working on improving the developer documentation available in GNOME Settings. As first steps in that direction, the current code style was documented and contribution guidelines were added.

The goal here is that people unfamiliar with the code base can find answers about code style by their own, reducing the communication overload and making the whole contribution process more efficient. It is also important to clearly document what is the expected behavior of contributors.

Improving the documentation is another wonderful and easy way to contribute.

But That’s not all

Even though these advancements mark a real improvement over the current state, there is a long way ahead. Ideally, we want to automate everything that can be automated, and test everything that should be tested. Settings needs and deserves to have some fresh air and code!

A unmerged feature that Claudio worked on is generating development Flatpak bundles. This is useful to lower the testing barrier, since one wouldn’t need to build Settings AND all the dependencies whatsoever. Just download, double-click the file, install and run. Dead easy.

If you have ideas on how the DX can be improved, feel free to share them! I’d love to hear your comments, suggestions, and ideas.

Acknowledgements

I’d like to thank my employer, Endless, for letting me use part of my work time to develop what I developed. I’d also like to thank Red Hat’s Benjamin Berg for reworking the test suite; independent contributor Claudio André, for making the CI smooth and fast; and specially Bastien Nocera, for helping and advising and reviewing code even after stepping down from the maintainer position.

Advertisements

Google Summer of Code 2018 at GNOME

Brief Introduction

Hi! I am Aditya Manglik from Wien, a.k.a. carpediem on IRC. Currently I am pursuing a Bachelor’s thesis in Deep Learning from TU Wien. I am interested in software, operating systems and AI. Travel, hiking and football occupy rest of the time.

I started with Linux ~7 years ago when my Windows desktop failed to boot because of a curious experiment accident with system32 files. Looking back at that moment, I am glad for the few hours of initial pain which was worth several years of sanity. Since then I have been working with Linux as the primary platform. I like Open Source Software because it’s much more fun to break and fix something, which really helps understand what’s happening in the machine. I used to like C/ C++ quite a bit, but you can probably throw any language and I am happy to learn it.

Google Summer Of Code

I got selected for Google Summer of Code 2018 program as part of GNOME. A big thanks to my mentors, Felipe Borges and Christian Kellner for giving me this chance.

gnome-logos-1

My project aims to implement the power panel in gnome-usage, which would inform users about how various hardware components and software applications are consuming power. The major objectives include:

  1. Develop the infrastructure to determine and evaluate power consumption
  2. Develop D-Bus API for accessing the data from shared library
  3. Implement front-end panel for displaying data in Usage

I hope this project represents a solid contribution to the community. Looking forward to a great summer with GNOME!

Reducing the number of image copies in GNOME

Our graphics stack that deals with images has evolved a lot over the years.

In ye olden days

In the context of GIMP/GNOME, the only thing that knew how to draw RGB images to X11 windows (doing palette mapping for 256-color graphics cards and dithering if necessary) was the GIMP. Later, when GTK+ was written, it exported a GtkPreview widget, which could take an RGB image buffer supplied by the application and render it to an X window — this was what GIMP plug-ins could use in their user interface to show, well, previews of what they were about to do with the user's images. Later we got some obscure magic in a GdkColorContext object, which helped allocate X11 colors for the X drawing primitives. In turn, GdkColorContext came from the port that Miguel and I did of XmHTML's color context object (and for those that remember, XmHTML became the first version of GtkHtml; later it was rewritten as a port of KDE's HTML widget). Thankfully all that stuff is gone now; we can now assume that video cards are 24-bit RGB or better everywhere, and there is no need to worry about limited color palettes and color allocation.

Later, we started using the Imlib library, from the Enlightenment project, as an easy API to load images — the APIs from libungif, libjpeg, libpng, etc. were not something one really wanted to use directly — and also to keep images in memory with a uniform representation. Unfortunately, Imlib's memory management was peculiar, as it was tied to Enlightenment's model for caching and rendering loaded/scaled images.

A bunch of people worked to write GdkPixbuf: it kept Imlib's concepts of a unified representation for image data, and an easy API to load various image formats. It added support for an alpha channel (we only had 1-bit masks before), and it put memory management in the hands of the calling application, in the form of reference counting. GdkPixbuf obtained some high-quality scaling functions, mainly for use by Eye Of Gnome (our image viewer) and by applications that just needed scaling instead of arbitrary transformations.

Later, we got libart, the first library in GNOME to do antialiased vector rendering and affine transformations. Libart was more or less compatible with GdkPixbuf: they both had the same internal representation for pixel data, but one had to pass the pixels/width/height/rowstride around by hand.

Mea culpa

Back then I didn't understand premultiplied alpha, which is now ubiquitous. The GIMP made the decision to use non-premultiplied alpha when it introduced layers with transparency, probably to "avoid losing data" from transparent pixels. GdkPixbuf follows the same scheme.

(Now that the GIMP uses GEGL for its internal representation of images... I have no idea what it does with respect to alpha.)

Cairo and afterwards

Some time after the libart days, we got Cairo and pixman. Cairo had a different representation of images than GdkPixbuf's, and it supported more pixel formats and color models.

GTK2 got patched to use Cairo in the toplevel API. We still had a dichotomy between Cairo's image surfaces, which are ARGB premultiplied data in memory, and GdkPixbufs, which are RGBA non-premultiplied. There are utilities in GTK+ to do these translations, but they are inconvenient: every time a program loads an image with GdkPixbuf's easy API, a translation has to happen from non-premul RGBA to premul ARGB.

Having two formats means that we inevitably do translations back and forth of practically the same data. For example, when one embeds a JPEG inside an SVG, librsvg will read that JPEG using GdkPixbuf, translate it to Cairo's representation, composite it with Cairo onto the final result, and finally translate the whole thing back to a GdkPixbuf... if someone uses librsvg's legacy APIs to output pixbufs instead of rendering directly to a Cairo surface.

Who uses that legacy API? GTK+, of course! GTK+ loads scalable SVG icons with GdkPixbuf's loader API, which dynamically links librsvg at runtime: in effect, GTK+ doesn't use librsvg directly. And the SVG pixbuf loader uses the "gimme a pixbuf" API in librsvg.

GPUs

Then, we got GPUs everywhere. Each GPU has its own preferred pixel format. Image data has to be copied to the GPU at some point. Cairo's ARGB needs to be translated to the GPU's preferred format and alignment.

Summary so far

  • Libraries that load images from standard formats have different output formats. Generally they can be coaxed into spitting ARGB or RGBA, but we don't expect them to support any random representation that a GPU may want.

  • GdkPixbuf uses non-premultiplied RGBA data, always in that order.

  • Cairo uses premultiplied ARGB in platform-endian 32-bit chunks: if each pixel is 0xaarrggbb, then the bytes are shuffled around depending on whether the platform is little-endian or big-endian.

  • Cairo internally uses a subset of the formats supported by pixman.

  • GPUs use whatever they damn well please.

  • Hilarity ensues.

What would we like to do?

We would like to reduce the number of translations between image formats along the loading-processing-display pipeline. Here is a plan:

  • Make sure Cairo/pixman support the image formats that GPUs generally prefer. Have them do the necessary conversions if the rest of the program passes an unsupported format. Ensure that a Cairo image surface can be created with the GPU's preferred format.

  • Make GdkPixbuf just be a wrapper around a Cairo image surface. GdkPixbuf is already an opaque structure, and it already knows how to copy pixel data in case the calling code requests it, or wants to turn a pixbuf from immutable to mutable.

  • Provide GdkPixbuf APIs that deal with Cairo image surfaces. For example, deprecate gdk_pixbuf_new() and gdk_pixbuf_new_from_data(), in favor of a new gdk_pixbuf_new_from_cairo_image_surface(). Instead of gdk_pixbuf_get_pixels() and related functions, have gdk_pixbuf_get_cairo_image_surface(). Mark the "give me the pixel data" functions as highly discouraged, and only for use really by applications that want to use GdkPixbuf as an image loader and little else.

  • Remove calls in GTK+ that cause image conversions; make them use Cairo image surfaces directly, from GdkTexture up.

  • Audit applications to remove calls that cause image conversions. Generally, look for where they use GdkPixbuf's deprecated APIs and update them.

Is this really a performance problem?

This is in the "excess work" category of performance issues. All those conversions are not really slow (they don't make up for the biggest part of profiles), but they are nevertheless things that we could avoid doing. We may get some speedups, but it's probably more interesting to look at things like power consumption.

Right now I'm seeing this as a cool, minor optimization, but more as a way to gradually modernize our image API.

We seem to change imaging models every N years (X11 -> libart -> Cairo -> render trees in GPUs -> ???). It is very hard to change applications to use different APIs. In the meantime, we can provide a more linear path for image data, instead of doing unnecessary conversions everywhere.

Code

I have a use-cairo-surface-internally branch in gdk-pixbuf, which I'll be working on this week. Meanwhile, you may be interested in the ongoing Performance Hackfest in Cambridge!

May 13, 2018

2018-05-13 Sunday.

  • Breakfast, to the conference, Jules' talk on Facebook's use of Infer - to find various classes of problem, interesting. Bid 'bye & kindly dropped to the airport by a friendly organizer.
  • Poked at socket code on the plane.

May 12, 2018

2018-05-12 Saturday.

  • Overslept, taxi to the conference; tried to learn Spanish by listening to security talks - with mixed success. Lunch - presented some slides on our security fun:
    Update on security challenges of the LibreOffice code-base

    Almeria is a lovely place - GUADEC should be amazing here.
  • Walking tour of Almeria in the evening, passed a marching band, and a statue being propelled by lots of apparently dis-embodied legs; interesting. Party in the evening.

Fractal Hackfest, Strasbourg (day 2)

The second day of Fractal hackfest was really productive, we talk about a lot of topics and takes some important decisions.

E2E Encryption

The encryption is a needed feature but encryption is hard to do in rooms. Matrix uses public-key cryptography, for rooms they are using Megolm, that's a protocol to exchange encrypted messages with more than one and share that message keys in a one-to-one secure communication.

I don't know a lot about this E2E because for me it's more important to have the client working with a basic functionality before the encryption. So you should read the official doc because maybe this that I'm writing here is completely wrong.

To do all this E2E key sharing, client side encryption and communication, Riot has three different implementations of the same lib, so they have this code in the JavaScript SDK, the same ported to iOS version in ObjectiveC and the same ported to Android in Java. Below this lib there's the libolm that does the real encryption.

For the future it should be a good solution to have only one lib that does the encryption thing, so we need to push in that direction and maybe matrix.org and Purism can pay for that work to be done.

From Fractal, we've two options or wait until we've the official E2E C/C++-lib or something, or try to port the iOS lib to Rust or C to use in our codebase. I think that the best solution is the first one, in any case, we'll need to wait some time to view E2E in Fractal.

Calls

Calls are easy compared to the Encryption thing, the protocol is well documented and it's really simple. The hard part here is that the call is implemented using the webRTC and that is a web protocol... But it seems that there's something done in this case with GStreamer working with webRTC.

Multiple accounts

We was talking yesterday about the multiple accounts problem, if we want to support and in that case what solution we should take.

We've two possible solutions, one is to support multiple accounts at the same time and a way to change between accounts, and the other one is to open a window for each account.

At the end we think that the best solution could be to open a separated window for each account so if you've multiple accounts, at first you should choose what account you want to open and then from the menu you can open a new window and go to the account selection menu again.

We need to work in the design of this feature and it's not confirmed but I think that this was the best solution, because it's simple and powerful.

Communities

Communities are something really new in the Matrix.org protocol and it's not well documented yet and there's some functionality that is not implemented so we decide to wait until this functionality is more mature to view how we can integrate this in Fractal.

Communities today are a group of rooms and a group of people and a full html description to show in the community page. There's other features like show a label for each member of the community or group, so I think these features are cool. We'll need to support some parts of the communities protocol soon.

Google Summer of Code

As I said this year we've two students working on Fractal thanks to Google, as part of the GNOME organization, and both students comes to the Hackfest so thank you Julian and Eisha for coming and for the work done before the GSoC and for sure for the work you'll be doing during the summer.

We're talking about how we'll be organizing, I'm the mentor of both but we'll have the help from Tobias Bernard and from Alexandre Franke so we'll have a summer hacking group to improve Fractal a lot.

We'll have a weekly meeting to talk about what we're doing and what to do in the next week.

For this first week we'll start with two needed features. Julian will be working in the user preference dialog and Eisha will start to work in the internationalization (i18n) because it's not easy to use gettext in rust and we want to translate the app to make it more accessible for everyone in the world.

Hacking a bit

In the meantime, between functionality discussion I was working in a way to use Fractal without SecretService, so if you're using Fractal outside GNOME or KDE you can configure it to store password and token in a plain text. We shouldn't store passwords in a clear text file, but I think that this will simplify the day for many people that wants to use Fractal but don't want to write the user and password every time.

This is not finished yet, but we'll have this very soon, and with this it's possible to implement other password & token storage services and make it configurable, so maybe in the future someone implements the storage for MacOS or something.

Holidays

This was my last day in the hackfest, I've the travel back to Spain the Sunday but I'll do some tourism here so I need to leave the people, they will continue working the Saturday and the Sunday.

This have been the first Fractal hackfest and it was a great experience, to meet other people working on it and to talk about the future of the application. It's really cool that with less than a year project we've now a big community, so thank you all form coming and see you on GUADEC.

There's a lot of work to do, but we're lucky because we're two students working in Fractal this summer and the people from Matrix.org and Purism are working with us, so thank you all.

I want to thank again the GNOME foundation and GNOME people for make this possible and to my company Wadobo, for let me spend some time working on this great project.

May 11, 2018

GNOME Terminal: separate menu items for opening tabs and windows

Astute users might have noticed that the GNOME Terminal binary distributed by Fedora has separate menu items for opening new tabs and windows, while the vanilla version available from GNOME doesn’t.

gnome-terminal-menuitems-tabs-windows

With separate menu items

This has been the case since Fedora 25 and was achieved by a downstream patch that reverted two upstream commits.

gnome-terminal-menuitems-unified-tabs-windows

Without separate menu items

I am happy to say that since version 3.28 GNOME Terminal has regained the ability to have separate menu items as a compile time option. The gnome-terminal-server binary needs to be built with the DISUNIFY_NEW_TERMINAL_SECTION pre-processor macro defined. Here’s one way to do so.

Adaptive GNOME Web

I started working on making GNOME Web work well on the Librem 5; to be sure it fits a phone's screen I want the windows to fit in a 360 points width, which is definitely small. To do so I started with the advices from Tobias Bernard to make Web have two modes that I named normal and narrow. The normal mode is Web as you know it, while the narrow mode moves all buttons from the header bar but the hamburger menu to a new action bar at the bottom, letting the windows reach yet unreachable widths.

Web autmatically adapting to small sizes.

And now, with device rotation on a tablet.

The code is overall ready, I still need to break it into reviewable bits before submitting it upstream.

Once this get merged:

  • we want to not show tabs in narrow mode and instead to display a popover listing the available pages,
  • we want to make the search bar shrink rather than to limit the minimum window size,
  • we consider migrating away from the application menu model.

A quick layout test of the pages popover.

P.S.: I forgot to give you a link to the unfinished code for you to play with. 😀

May 10, 2018

X server pointer acceleration analysis - part 4

This post is part of a four part series: Part 1, Part 2, Part 3, Part 4.

In the first three parts, I covered the X server and synaptics pointer acceleration curves and how libinput compares to the X server pointer acceleration curve. In this post, I will compare libinput to the synaptics acceleration curve.

Comparison of synaptics and libinput

libinput has multiple different pointer acceleration curves, depending on the device. In this post, I will only consider the one used for touchpads. So let's compare the synaptics curve with the libinput curve at the default configurations:

But this one doesn't tell the whole story, because the touchpad accel for libinput actually changes once we get faster. So here are the same two curves, but this time with the range up to 1000mm/s. These two graphs show that libinput is both very different and similar. Both curves have an acceleration factor less than 1 for the majority of speeds, they both decelerate the touchpad more than accelerating it. synaptics has two factors it sticks to and a short curve, libinput has a short deceleration curve and its plateau is the same or lower than synaptics for the most part. Once the threshold is hit at around 250 mm/s, libinput's acceleration keeps increasing until it hits a maximum much later.

So, anything under ~20mm/s, libinput should be the same as synaptics (ignoring the <7mm/s deceleration). For anything less than 250mm/s, libinput should be slower. I say "should be" because that is not actually the case, synaptics is slower so I suspect the server scaling slows down synaptics even further. Hacking around in the libinput code, I found that moving libinput's baseline to 0.2 matches the synaptics cursor's speed. However, AFAIK that scaling depends on the screen size, so your mileage may vary.

Comparing configuration settings

Let's overlay the libinput speed toggles. In Part 2 we've seen the synaptics toggles and they're open-ended, so it's a bit hard to pick a specific set to go with to compare. I'll be using the same combined configuration options from the diagram there.

And we need the diagram from 0-1000mm/s as well. There isn't much I can talk about here in direct comparison, the curves are quite different and the synaptics curves vary greatly with the configuration options (even though the shape remains the same).

Analysis

It's fairly obvious that the acceleration profiles are very different once depart from the default settings. Most notable, only libinput's slowest speed setting matches the 0.2 speed that is the synaptics default setting. In other words, if your touchpad is too fast compared to synaptics, it may not be possible to slow it down sufficiently. Likewise, even at the fastest speed, the baseline is well below the synaptics baseline for e.g. 0.6 [1], so if your touchpad is too slow, you may not be able to speed it up sufficiently (at least for low speeds). That problem won't exist for the maximum acceleration factor, the main question here is simply whether they are too high. Answer: I don't know.

So the base speed of the touchpad in libinput needs a higher range, that's IMO a definitive bug that I need to work on. The rest... I don't know. Let's see how we go.

[1] A configuration I found suggested in some forum when googling for MinSpeed, so let's assume there's at least one person out there using it.

X server pointer acceleration analysis - part 3

This post is part of a four part series: Part 1, Part 2, Part 3, Part 4.

In Part 1 and Part 2 I showed the X server acceleration code as used by the evdev and synaptics drivers. In this part, I'll show how it compares against libinput.

Comparison to libinput

libinput has multiple different pointer acceleration curves, depending on the device. In this post, I will only consider the default one used for mice. A discussion of the touchpad acceleration curve comes later. So, back to the graph of the simple profile. Let's overlay this with the libinput pointer acceleration curve:

Turns out the pointer acceleration curve, mostly modeled after the xserver behaviour roughly matches the xserver behaviour. Note that libinput normalizes to 1000dpi (provided MOUSE_DPI is set correctly) and thus the curves only match this way for 1000dpi devices.

libinput's deceleration is slightly different but I doubt it is really noticeable. The plateau of no acceleration is virtually identical, i.e. at slow speeds libinput moves like the xserver's pointer does. Likewise for speeds above ~33mm/s, libinput and the server accelerate by the same amount. The actual curve is slightly different. It is a linear curve (I doubt that's noticeable) and it doesn't have that jump in it. The xserver acceleration maxes out at roughly 20mm/s. The only difference in acceleration is for the range of 10mm/s to 33mm/s.

30mm/s is still a relatively slow movement (just move your mouse by 30mm within a second, it doesn't feel fast). This means that for all but slow movements, the current server and libinput acceleration provides but a flat acceleration at whatever the maximum acceleration is set to.

Comparison of configuration options

The biggest difference libinput has to the X server is that it exposes a single knob of normalised continuous configuration (-1.0 == slowest, 1.0 == fastest). It relies on settings like MOUSE_DPI to provide enough information to map a device into that normalised range.

Let's look at the libinput speed settings and their effect on the acceleration profile (libinput 1.10.x).

libinput's speed setting is a combination of changing thresholds and accel at the same time. The faster you go, the sooner acceleration applies and the higher the maximum acceleration is. For very slow speeds, libinput provides deceleration. Noticeable here though is that the baseline speed is the same until we get to speed settings of less than -0.5 (where we have an effectively flat profile anyway). So up to the (speed-dependent) threshold, the mouse speed is always the same.

Let's look at the comparison of libinput's speed setting to the accel setting in the simple profile:

Clearly obvious: libinput's range is a lot smaller than what the accel setting allows (that one is effectively unbounded). This obviously applies to the deceleration as well: I'm not posting the threshold comparison, as Part 1 shows it does not effect the maximum acceleration factor anyway.

Analysis

So, where does this leave us? I honestly don't know. The curves are different but the only paper I could find on comparing acceleration curves is Casiez and Roussel' 2011 UIST paper. It provides a comparison of the X server acceleration with the Windows and OS X acceleration curves [1]. It shows quite a difference between the three systems but the authors note that no specific acceleration curve is definitely superior. However, the most interesting bit here is that both the Windows and the OS X curve seem to be constant acceleration (with very minor changes) rather than changing the curve shape.

Either way, there is one possible solution for libinput to implement: to change the base plateau with the speed. Otherwise libinput's acceleration curve is well defined for the configurable range. And a maximum acceleration factor of 3.5 is plenty for a properly configured mouse (generally anything above 3 is tricky to control). AFAICT, the main issues with pointer acceleration come from mice that either don't have MOUSE_DPI set or trackpoints which are, unfortunately, a completely different problem.

I'll probably also give the windows/OS X approaches a try (i.e. same curve, different constant deceleration) and see how that goes. If it works well, that may be a a solution because it's easier to scale into a large range. Otherwise, *shrug*, someone will have to come with a better solution.

[1] I've never been able to reproduce the same gain (== factor) but at least the shape and x axis seems to match.

May 09, 2018

System76 and the LVFS

tl;dr: Don’t buy System76 hardware and expect to get firmware updates from the LVFS

System76 is a hardware vendor that builds laptops with the Pop_OS! Linux distribution pre-loaded. System76 machines do get firmware updates, but do not use the fwupd and LVFS shared infrastructure. I’m writing this blog post so I can point people at some static text rather than writing out long replies to each person that emails me wanting to know why they don’t just use the LVFS.

In April of last year, System76 contacted me, wanting to work out how to get on the LVFS. We wrote 30+ cordial emails back and forth with technical details. Discussions got stuck when we found out they currently use a nonfree firmware flash tool called afuefi rather than use the UEFI specification called UpdateCapsule. All vendors have support for capsule updates as a requirement for the Windows 10 compliance sticker, so it should be pretty easy to use this instead. Every major vendor of consumer laptops is already using capsules, e.g. Dell, HP, Lenovo and many others.

There was some resistance to not using the proprietary AUEFI executable to do the flashing. I still don’t know if System76 has permission to redistribute afuefi. We certainly can’t include the non-free and non-redistributable afuefi as a binary in the .cab file uploaded to the LVFS, as even if System76 does have special permission to distribute it, as the LVFS would be a 3rd party and is mirrored to various places. IANAL and all that.

An employee of System76 wrote a userspace tool in rust to flash the embedded controller (EC) using a reverse engineered protocol (fwupd is written in C) and the intention was add a plugin to fwupd to do this. Peter Jones suggested that most vendors just include the EC update as part of the capsule as the EC and system firmware typically form a tightly-coupled pair. Peter also thought that afuefi is really just a wrapper for UpdateCapsule, and S76 was going to find out how to make the AMI BIOS just accept a capsule. Apparently they even built a capsule that works using UpdateCapsule.

I was really confused when things went so off-course with a surprise announcement in July that System76 had decided that they would not use the LVFS and fwupd afterall even after all the discussion and how it all looked like it was moving forwards. Looking at the code it seems the firmware update notifier and update process is now completely custom to System76 machines. This means it will only work when running Pop_OS! and not with Fedora, Debian, Ubuntu, SUSE, RHEL or any other distribution.

Apparently System76 decided that having their own client tools and firmware repository was a better fit for them. At this point the founder of System76 got cc’d and told me this wasn’t about politics, and it wasn’t competition. I then got told that I’d made the LVFS and fwupd more complicated than it needed to be, and that I should have adopted the infrastructure that System76 had built instead. This was all without them actually logging into the LVFS and seeing what features were available or what constraints were being handled…

The way forward from my point of view would be for System76 to spend a few hours making UpdateCapsule work correctly, another few days to build an EFI binary with the EC update, and a few more hours to write the metadata for the LVFS. I don’t require an apology, and would happily create them a OEM account on the LVFS. It looks instead that the PR and the exclusivity are more valuable that working with other vendors. I guess it might make sense for them to require Pop_OS! on their hardware but it’s not going to help when people buy System76 hardware and want to run Red Hat Enterprise Linux in a business. It also means System76 also gets to maintain all this security-sensitive server and client code themselves for eternity.

It was a hugely disappointing end to the discussion as I had high hopes System76 would do the right thing and work with other vendors on shared infrastructure. I don’t actually mind if System76 doesn’t use fwupd and the LVFS, I just don’t want people to buy new hardware and be disappointed. I’ve heard nothing more from System76 about uploading firmware to the LVFS or using fwupd since about November, and I’d given multiple people many chances to clarify the way forward.

If you’re looking for a nice laptop that will run Linux really well, I’d suggest you buy a Dell XPS instead — it’ll work with any distribution you choose.

Redesigning the lock screen

Last November we had a small hackfest in London, focused on GNOME Shell design. We explored various themes during the hackfest and came up with a bunch of initial designs, which we’ve subsequently been developing. The main area of recent work has been the login and unlock experience. The rest of this post gives an overview of the design that we’ve come up with.

Background

Unlocking and logging into a device is something that people do a lot. Since people do it a lot, it’s important that the experience is smooth and doesn’t get in the way. However, it’s also important for it to look and feel really good. Login/unlock is the gateway to the rest of the experience. It is the public face of the product. It therefore needs to make a good impression and reinforce a positive relationship with the user.

This is one of the reasons why we’ve spent a fair bit of time on the design for login and unlock, as well as why we’ve involved a larger design team than usual. The hackfest that we had last year allowed us to bring extra designers in – people like Robin Tafel (Endless) and Cassidy James (System76/elementary OS) – as well as to work more closely with new regular participants, like Tobias Bernard.

When we originally discussed login/unlock at the hackfest, we came up with a long list goals and objectives for the new design. Chief amongst these was the idea of making the lock screen frictionless, so that people can get to their session easily. We also wanted to add a little joy and delight to an experience that can sometimes feel a bit flat, and we wanted to improve the navigational aspects of the design, with a clear spatial model.

Finally, we wanted to improve how the login/unlock UI performs in different scenarios. the current design works reasonably well for a small number of users, but doesn’t perform great on single user machines, or on those with many users. We wanted to make sure that it scales.

The lock screen

Without further ado, mockups! Here’s what we currently have for the lock screen:

Key press or mouse click then reveals the password entry:

This motion mockup shows what the transitions would look like, going from the session, to a locked screen, and back to the session again:

As you can see, the existing “shield” concept has been retained – when you lock the device, a layer appears to slide down over the content. This slides up when the system is unlocked. We’ve tried to hold on to some of the character of the existing design, particularly with the centered time and date, so it is identifiably the same product as before.

So what’s changed? Here are some of the main things:

  1. The grey background is gone – the password field appears with the same background as the rest of the lock screen. This reduces the amount of friction the user experiences when logging in, and makes the process a lot smoother.
  2. Notifications are more minimal, have been moved to the side of the screen, and continue to be shown while the user authenticates (they’re currently hidden once the password field is visible) – giving users more time to register what’s been happening while the device has been locked.
  3. We’re going straight to user login from boot. This is an obvious win for single-user systems, since it’s less work to start using the machine. However, it’s also usually the right thing to do for multi-user systems too, since there is often one person who uses the machine more than others.
  4. We’re using a blurred version of the regular desktop background for the lock screen wallpaper, rather than a separate user-defined lock screen wallpaper. This is suggestive of a semi-transparent film or sheet that’s been placed over the session, but it also ties in with the user selection screen (described below).

There are a number of other smaller changes too, which I won’t go into here, although I’m obviously happy to answer questions, and there’s also more information on the design page.

User selection

The other major part of the design is the user selection screen. This can be accessed from the lock screen as well as the session, and is used when switching user. The existing implementation uses a fairly simple list of users. We’ve given this a fairly thorough overhaul as part of the new design:

There’s also a motion mockup, which shows the transition from boot to login to user selection:

As you can see, the new design uses a grid of tiles, each of which features a blurred version of the user’s wallpaper. These are a key part of the spatial model for login. This allows users to orient themselves and contextualises navigation.

The user grid is designed to scale, so that it works well with large numbers of users. There’s also a simple username entry screen that can be used on deployments where a grid of user accounts might not be appropriate.

Next steps

We’re hoping that work on implementing the designs will start soon, and it would be great if anyone wants to help make them a reality. That said, the designs aren’t set in stone, and we expect them to continue to evolve as we get feedback and as implementation takes place. Hopefully we’ll get chance to do some user testing on them too, before they land in a stable version.

Questions and comments are welcome.

ostree & Flatpak at CERN

A week and a half ago I spent a few days in Geneva and gave a presentation about ostree and Flatpak at the CERN Computing Seminar. I started by briefly introducing Endless to give some context of the problems we’re trying to solve and how we’re using ostree and Flatpak for that, then proceeded to talk more in detail about these technologies. In the end, there were several questions, and I was happy to learn afterwards that among the audience there were some of the people working at the CVMFS project: a software distribution service to help deploy data-processing infrastructure and tools. I don’t know the full details about the project’s implementation, but from the problems they’re trying to solve it seems like ostree (or more specifically libostree) could perhaps be used to replace part of the core, which would leverage all the niceties of using a complex Open Source project (more eyeballs looking into bugs, more testing, etc.). I also think more use-cases could be found in the organization, so I hope my talk was a small seed to help introduce these projects at CERN in the medium/long term. The presentation has been recorded if you’re interested.

Getting authorization to access CERN this time was also different, as for the first time I got an entrance pass as a member of the CERN Alumni. So I would like to thank Antonella Del Rosso for the Alumni initiative and also for allowing me to kindly borrow her EU-CH power adapter when I forgot mine at my friends’ home. In the end Antonella also interviewed me about my experience at CERN and after I left, and produced this summary if you want to check it out.
I would also like to thank Miguel Ángel Marquina of the CERN Computing Seminar for organizing the presentation and all the details around it.

Photo showing the author and his daughter sitting close to the lake in Geneva.

Sitting by the lake with my daughter

Having spent more than 2 years in the region, it is the friends we have there that we miss the most. So it was great to meet them and old colleagues again.
My family traveled there with me and we stayed with friends from Spain, so it was funny to see our daughter (who used to play with those friends’ kids all the time when we lived there) excusing her shyness for not speaking Spanish. But after a day or two they were all successfully playing together; it’s amazing how children can get along no matter what differences or barriers they find, while adults often resort to stupid feelings and dangerous actions.
The mountains landscape is another thing we miss in Berlin and the Spring’s clear weather allowed us to fully gaze at the Jura or the Mont Blanc which should last us for another few more months. After that, I guess I’ll try to find some graffiti of mountains around Berlin 🙂

May 07, 2018

Google Summer of Code 2018: Introduction

Hi! My name is Ruxandra, but friends call me Ruxe [/ruːksɛ/], and throughout this post I would like to better introduce myself and give you a hint of what my summer journey with GSoC is going to look like.

I have quite a few interests, from photography and digital drawing, crafts and music, cooking and experimenting with not-so-good tasting cocktails (but they’ve been getting better, I promise 😊), to traveling and attempting to take better care of the environment. I try to allocate more or less time for each of them depending on a number of factors, but there’s one thing that has always been a part of my weekly activities: games.

When it comes to games, well video games have pretty much always been a constant in my life, in various forms; from the Disney Active CDs my dad used to bring me and my sister as kids, to the console ones I still enjoy playing with friends and family. Recent years did not, however, find me in front of my computer playing games, but rather discovering the open source world and developing applications.

Although I have worked on multiple game development projects, both by myself and in a team while studying for my Computer Science Degree at the University Politehnica of Bucharest, the one experience which I believe turned me from occasional player into dedicated game developer consisted of working on my first mobile game for my diploma project. It turned out to be appreciated by both my kind friends and colleagues at the university who volunteered to play it as testers, and the jury alike. It was then when I decided to continue studying and enrol for a masters program in Computer Graphics, Multimedia and Virtual Reality, which I am currently pursuing, to further hone my skills.

This summer I will be working on modernising Five or More, one of the few gnome games which haven’t been rewritten in Vala as part of the Games Modernisation Initiative. It’s a simple and fun game whose objective is to align, as often as possible, five or more (no pun intended 😊) objects of the same shape and color, causing them to disappear. Besides the Vala rewrite, there are some other items that have to be tackled, like updating artwork, adding sounds and gamepad support, or some that I have already completed while preparing my application, such as migrating to Meson and dropping autotools, porting to gettext and integrating libgnome-games-support.

I am very grateful for the opportunity to participate in GSoC 2018 to work on this project, and more so I am grateful for my mentor Robert Roth (IRC: evfool), who has been kind enough to guide me throughout the pre-GSoC and the application process and has made the entire process easy and straightforward.

In my next blog post I will try to offer a more technical view of my project, by explaining the process I will undertake in order to port the game to Vala in a timely and productive manner, and make sure that anyone who is interested in my project can easily track my progress in order to be able to offer valuable feedback in early stages of the development.

Thank you for sticking with me until the end of this blog post. Head over to my page and subscribe to my RSS feed if you wish to keep an eye on my progress or to the About section if you would like to get in touch with me.

Until next time,
Ruxe

Indonesian recipes

In late February and early March I attended the GNOME Recipes hackfest in Yogyakarta, Indonesia. It was my second time visiting Indonesia, and food was a bit of a theme. The hackfest was about GNOME Recipes, so food, but also I love Indonesian food and I was eager to taste some more so I can improve how I cook it at home.

I haven’t contributed to GNOME Recipes. (Shamefully, not even a recipe yet!) So why was I going to a GNOME Recipes hackfest? It’s because on Endless OS we have a Cooking app, which in many ways is not as good as GNOME Recipes. It’s certainly less lovingly curated, and less community-oriented, than GNOME Recipes, and it allows recipe submissions by users while the Endless app is read-only.

However, there are a few things Endless’s Cooking app does better than GNOME Recipes: it is visually more appealing, it’s available in several languages (Arabic, Bengali, English, Portuguese, Spanish, and also a Spanish version customized for Guatemala), and it uses a better database backend (which also makes it fully offline.) It does these things using Endless’s “modular framework,” which if you want to know more about, I gave a talk two years ago at GUADEC. This modular framework is the product that I primarily work on at Endless, so a few of my team joined in the GNOME Recipes hackfest to see whether the two apps could share some technology.

It turns out that Matthias was eager to have somebody come along and make a database backend for GNOME Recipes, so the answer was yes, we could very well share some technology.

As an experiment, we made a recipes “lookalike” app using the modular framework technologies of which you can see some nice screenshots in Martin’s blog post.

We worked out some goals that we wanted to achieve by GUADEC in order to present our work, which you can see in the hackfest notes.

Outreach

There were also some goings on besides the hackfest. On the day before the hackfest started we did an outreach event for the students of AMIKOM University Yogyakarta, where the hackfest was held. We gave some talks on our work, and GNOME contributor and Endless Ambassador Siska closed the morning out with a very successful talk on how to get involved in GNOME.

Instagram Photo

After that I gave a live demo of how to make a GNOME app, the result of which you can find on GitHub here!

GNOME hackers and students seated around a table, watching a programming demo on a projector

This is me doing the live-coding demo of a GNOME app. Some of the students said I looked like Tony Stark.

 

Translation

One of the most interesting discussions we had was about how to internationalize GNOME Recipes. In different countries people cook very differently, so translating a recipe from one language into another is not enough. You also have to adapt the recipe to the ingredients that you can get in the country, and sometimes it’s not possible to get the same taste. For example, if I wanted to adapt my beloved pesto recipe from Marcella Hazan’s Classic Italian Cookbook, to Indonesia, first of all I’d probably have to substitute Thai basil which would change the taste entirely. Or to adapt Indonesian recipes to Canada, you have to go to some lengths to find ingredients like terasi (shrimp paste) and kemiri (candlenuts), and we just can’t get some of the same vegetables.

It can also be that when one language is used in two countries, the same recipe still won’t work for both. For example, in the UK, baking measurements are given by weight, and in Canada and the US they are given by volume. The metric system (ºC, kg, ml) is used in the UK and the imperial system (ºF, pounds, quarts, ounces, bushels, specks, caltrops, and jeroboams) in the US. To make matters worse, Canada uses the metric system for weight and volume measurements (kg, ml) but oven temperatures are given in Fahrenheit as in the US. All three countries cook with teaspoons and tablespoons, but teaspoons and tablespoons are metric in Canada and the UK (5 ml and 15 ml) but imperial in the US (4.93 ml and 14.79 ml).

We also discussed that many translation tools assume that the source language is always English since that’s the lingua franca of programmers, but it’s definitely not the lingua franca of cooking!

I would go so far as to say that all the existing translation infrastructure that we have for internationalizing GNOME is not going to be good enough to translate the recipes in GNOME Recipes.

Progress since then

In the time since the hackfest, I was able to make a little bit of progress on our goals. I worked on splitting out the code that handles data modelling into DModel, a separate library, so that GNOME Recipes could use it.

Food

I did get a chance to learn the flavors of Indonesian food more. When I lived in the Netherlands I already became familiar with some Indonesian food, but the Indonesian food in Indonesia is really much more delicious. In Vancouver we have only one Indonesian restaurant, which is kind of far away. And I found only one Indonesian store where I can buy ingredients like shrimp paste and candlenuts, which is even farther away.

Siska brought in packets of rendang spice paste for everyone to take home, for which I was especially grateful. Here’s a picture of my rendang that I made when I got back to Vancouver:

Beef rendang, still cooking down, next to a pot of rice cooking

Rendang and rice

I also tried to make the spice paste myself (because soon I will be out of the spice paste packets) but I haven’t got it figured out yet.

Some of the other dishes that I’ve made at home:

Yellow coconut curry in a bowl with kale and rice

Gulai curry (substituting kale for the cassava greens)
(The recipe is from Daily Cooking Quest which is a cooking blog from an Indonesian blogger who emigrated to the United States, and I’ve had good luck with those recipes because she uses ingredients that are possible for me to get in Vancouver, and she also gives the Indonesian names of the ingredients)

Fried noodles on a plate, with a fried egg and chili paste

Mi goreng

I am going to try making gudeg this week, which is a jackfruit curry, a specialty of Yogyakarta.

Acknowledgements

Sponsored by GNOME FoundationI’d like to thank AMIKOM University Yogyakarta for hosting the hackfest and giving us the opportunity to get some students interested in open source development, and the GNOME Foundation for sponsoring my travel and accommodations during the hackfest. Thanks also to Cosimo, Ekta, Elvin, Emmanuele, Haris, Jonathan, Kukuh, Martin, Matthias, Rama, Siska, and Umang, and also Kiki from Mozilla who joined on the last day, and Angky from Endless who helped arrange the hosting and logistics, for making the event a success!

May 06, 2018

Updating Endless OS to GNOME Shell 3.26 (Video)

It’s been a pretty hectic time during the past months for me here at Endless, busy with updating our desktop to the latest stable version of GNOME Shell (3.26, at the time the process started), among other things. And in all this excitement, it seems like I forgot to blog so I think this time I’ll keep it short for once, and simply link to a video I made a couple of months ago, right when I was about to finish the first phase of the process (which ended up taking a bit longer than expected).

Note that the production of this video is far from high quality (unsurprisingly), but the feedback I got so far is that it has been apparently very useful to explain to less technically inclined people what doing a rebase of this characteristics means, and with that in mind I woke up this morning realizing that it might be good to give it its own entry in my personal blog, so here it is.


(Pro-tip: Enable video subtitles to see contextual info)

Granted, this hasn’t been a task as daunting as The Great Rebase I was working on one year ago, but still pretty challenging for a different set of reasons that I might leave for a future, and more detailed, post.

Hope you enjoy watching the video as much as I did making it.

Feeds