Nautilus and GTK+ 4

A couple weeks had passed, and the effort to make Nautilus buildable with GTK+ 4 had paid off – it builds (don’t mind the commit message, it’s about https://gitlab.gnome.org/GNOME/glib/commit/7e5db31d36532274c2b2428ef9bace796928785e) and runs!

Now, that alone doesn’t mean much, since Nautilus is nowhere near a usable state:

  • Some input event handlers rely on being able to chain up to the parent handler for certain things: the list view, in particular, on right clicks, to select the file before popping up a context menu for it. I don’t know of a way to achieve that yet, so the code is currently just commented out.
  • Support for XDS has been removed, as the implementation relied heavily on window properties, which have been removed. In particular, this should make DnD from file-roller to Nautilus useless (which doesn’t work in Wayland, either, AFAIR). Support for root window drops is gone as well, given that Nautilus does not handle the desktop.
  • Scrolling in canvas view broke completely and mouse rubberband selection is a tad wonky still, but only at the highest zoom level (at least it works great after moving it out to a drag gesture, despite breaking single-click selection, as the current selection is cleared at the beginning).
  • Header bar menus appear empty (not exactly a priority, although might be an easy win).
  • Canvas view item prelighting and selection coloring needs rethinking again and might end up looking differently. But, hey, at least the GtkSnapshot API is fun to use.

That’s all that comes to mind right now, but there’s still plenty to keep me busy.

Nautilus Tagged Entry Redux

It works!

Since my last post, the tagged entry became a subclass of GtkSearchEntry, as was the case with GdTaggedEntry (yay GTK+ 4) and the tags became GtkWidgets (instead of GtkBins). It didn’t take much effort to move from GtkBin to GtkWidget – only implementing size_allocate(), measure() and snapshot(), which are really trivial when working with actual widgets as children. That, and tweaking the appearance some more, as the move broke the styling a tad. Some perhaps questionable methods of dealing with that were employed, but nothing too nefarious.

With this out of the way now, I’ll be able to focus on porting the rest of Nautilus.

The code is available at https://gitlab.gnome.org/ernestask/tagged-entry, if you’re interested.

Tagged Entry in Nautilus

With the exams having been left in the past, I can get back to hacking on Nautilus again. This time, it’s coming up with a GTK+ 4-ready tagged entry for the search. Heavily inspired by Matthias’ prototype, here is a sneak peek at the work-in-progress implementation:

NautilusTaggedEntry and GtkSearchEntry for visual comparison (GTK+ 4)
GdTaggedEntry as a visual reference (GTK+ 3)

The styling still needs tweaking (I’m trying to reuse the entry-tag class from Adwaita as much as possible, but there are signs of breakage now that actual widgets are used) and the input – hooking up (oh, and the close button), but, so far, the code is infinitely simpler than that of GdTaggedEntry, which will hopefully remain to be true until the end. As of yet, the code isn’t anyplace public, but that should change by the end of the week, when all details are finalized. The code can be found at https://gitlab.gnome.org/ernestask/tagged-entry.

One downside to doing it the putting-things-into-boxen-and-adjusting-margins-and-padding way is that the new class can’t be used as a GtkSearchEntry transparently (for properties and signals), because then we run into ownership problems, but that’s nothing a simple getter can’t fix.

Anyhoo, to be continued soon-ish.

Input Event Handling in Nautilus

Designed by Smashicons from Flaticon

Gestures like these is now how almost all input is handled in Nautilus. The exception is the stuff that has no event controller counterpart in GTK+ 3.

This summer I’m working on porting Nautilus to GTK+ 4 as part of Google Summer of Code, and I’ve spent the entirety of the time on getting rid of deprecated 3.x API and obsolete ways of handling events. Despite slightly hack-ish ways of working around deprecations, it’s been smooth sailing so far – No Regressions! Almost ready to switch!

™ - one reported and fixed
† - “switch” here means staring at an endless stream of compiler errors

The hacks mostly pertain to replacing gtk_style_context_get_background_color():

Going back to event handling, the next immediate goal is to dismantle the old icon view we use, since it holds non-widget objects, which largely requires emulating GTK+ for event handling. The reason for that is simply that Nautilus predates GtkIconView and was never ported to using that (possibly for performance reasons). I’ve got code that uses gestures for button presses locally already, but will look for something better than adding a small GdkEvent clone that allows setting fields, which is required mostly for synthesizing “enter” and “leave” events for the children.

It’s a bit unfortunate that there only exists a subset of event controllers in GTK+ 3, but at the same time it’s a great opportunity to make the code GTK+ 4-compliant (still hoping to see the key event controllers soon). Where impossible to use one, I switched to handling ::event (bar some instances of ::key-press-event, where that prevented accelerator handlers from being run).

All in all, the pain has been minimal and I’m looking forward to getting back with a fresh perspective on things after the university exam period ends.

Edit: clarified the bit about the canvas view not holding widgets.

Redoing File Operation Management in Nautilus

This will serve as a sort of introduction to my project, as well as being a progress update.

Hi, I’m Ernestas and this summer I’m working on Nautilus as part of Google Summer of Code. The goal of the project is to have all I/O operations (i.e. file management, the cache, thumbnailing, searching) managed under a single entity with a capped worker thread count.

This talk by my mentor, Carlos, gives a reason why this is needed in a file manager – searching. Dropping down to the root folder and searching for something as innocent as, say, “a” will likely result in your demise, as Nautilus will happily perform an aggressive benchmark on your system instead of searching. Limiting the number of search jobs will help reduce the random reads performed by the disk as well as leaving the system in a usable state.

Another positive outcome is making the code more object-oriented – going from plain function calls and routing events in a very roundabout way to self-contained task classes with signals to provide progress information (e.g. file task progress, search hits, enumerating directory children for cache purposes) and all other nutrients required for a strong file manager. If the result is not having to split the vim window in four just to work in a nautilus-file-operations.c or nautilus-directory-async.c-equivalent file, I will be damn pleased.

The first two weeks haven’t been very eventful, as the exam schedule in my university clashes a bit with GSoC, but in a few days I will be able to return full-speed. Despite that, one of the goals has been reached – implementing a bare-bones task manager, creating a task API skeleton and porting over a file operation. The wip/ernestask/tasks branch contains the code if you’re interested.

The task manager currently allows limiting the running task count at compile time, but Carlos and I have discussed a more dynamic approach to take, once the groundwork is laid. As the task interface is generic, doing things like preventing conflicting operations as they are queued is a bit of a head-scratcher, but that will probably work out with error callbacks and the like. Another thing that is desirable is turning the manager into a scheduler of sorts, which can assign priorities to tasks, in turn letting short-lived, user-facing tasks take precedence (or something else entirely, this is yet to be decided).

Writing the tasks themselves is an experience in itself, requiring deep and wide class hierarchies (not to mention loads of private helper functions) to accomodate all idiosyncrasies of the code, but so far it’s been relatively straightforward. I’ll bet that a rain jacket will not help in the storm that is going to be shuffling around the code for the cache operations. :)

Talk to you again in a couple of weeks,
Ernestas

Autoconf and Meson walk into a bar…

…and by the time Meson has finished its second drink, Autoconf realizes it’s missing its wallet.

Not a very well-crafted joke, but it serves to make a point.

Building with Autotools is slow.

Although Nautilus has recently gotten better (cutting forty-ish seconds off the configuration phase on my machine, all thanks to Mohammed Sadiq), it takes over a minute to even reach the point where we can begin building, anyway, which is obscene.

I started toying with the idea of switching to Meson in Nautilus completely in late September of 2016 (very convenient, since libgd would soon get a WIP Meson branch). Things were going smoothly, albeit slowly – barely anyone knew what I was doing and there was no pressure to finish it soon. I deemed the work ready in late January/early February (not as convenient, since Meson support would land in libgd master not long after, requiring a tweak on our side) and we were very excited to merge the work – the builds were really fast.

Switching to Meson completely was not going to happen at that point, since it was very late in the cycle and we didn’t want to surprise the packagers near the end. Before deciding that, we had to consider other developers/contributors – not all distributions currently ship the version of Meson we require (>= 0.37.0) – that would mean having to install the latest version through other means (most likely, pip), which might not be an option for some people for personal reasons (I also really like having only distribution packages installed).

With the switch out of the way, we really pushed for its inclusion – rigorous testing (ha) and peer-review happened until midnight, when Carlos ACKed the patch. I pushed it and went to sleep thinking happy thoughts. Things were pretty calm before the storm – issues started cropping up in Continuous. Some of them were things to be fixed in Meson[1][2] (the first thing to completely break the build was printing \u2026 in a message), some were things I had not considered and fixed (unconditional documentation generation!) and some were small mysteries (including the actual source of generated enum descriptions and seeing things build out of order due to very high parallelization).

One of the more subtle breakages, unrelated to Continuous, was projects that build Nautilus extensions. Due to an incompatibility in the generated pkg-config file, those projects would fail to find the version of nautilus-extension they require. The most notable of those being file-roller.

The dust seems to have settled by now and I hope to receive more feedback from developers and contributors as soon as we start defaulting to Meson, but despite all the hiccups along the way, I think we did a pretty good job and hope to see more modules receiving the same treatment. :)

If you’re interested, the rough timeline can be found here (I don’t envy Carlos when he has to review these things).