Debarshi's den

Archive for the ‘GNOME’ Category

About -Wextra and -Wcast-function-type

leave a comment »

About eight months ago, around the time when GCC 8.x started showing up on my computers, I started moving my code away from using -Wextra. This aligns nicely with the move to the Meson build system, which is nice; but went against the flow of Autotools’ AX_COMPILER_FLAGS, which isn’t ideal but is an acceptable trade-off.

But why?

GCC 8.x added a warning called -Wcast-function-type to the -Wextra umbrella. It warns when a function pointer is cast to an incompatible function. At a glance, this seems desirable, but it isn’t. It runs contrary to one of the widely used C idioms in GNOME. For example, it’s triggered by this text book use of g_list_copy_deep to copy a list of reference counted objects:

another_list = g_list_copy_deep (list, (GCopyFunc) g_object_ref, NULL);

Note that this is different from -Wincompatible-pointer-types, which would’ve triggered if the cast to GCopyFunc was missing:

another_list = g_list_copy_deep (list, g_object_ref, NULL);

It’s easy to imagine similar examples with uses of gtk_container_forall or gtk_container_foreach with gtk_widget_destroy, and so on.

The C standard (eg., see article 6.5.2.2 of the C11 standard) steps around the issue of passing more arguments to a function than it actually has parameters for by calling it undefined behaviour. However, the calling conventions of all the platforms supported by GLib are defined in a way to make this work.

So how do we disable -Wcast-function-type?

One option is to use a compiler directive with #pragma as suggested by AX_COMPILER_FLAGS. However, attempts to ignore it through a #pragma on older versions of GCC that didn’t have this specific warning will trigger -Wpragmas, and, ironically, using G_GNUC_CHECK_VERSION to conditionally disable it on newer compilers will trigger -Wexpansion-to-defined, again, because of -Wextra and the fact that the implementation of the macro has a #ifdef around __GNUC__. Regardless, for a warning that gets triggered by such a widely used programming construct, it would lead to a ton of boilerplate all over the codebase, instead of being a solitary exception tucked away in one corner of the project.

Therefore, my preference has been to append -Wno-cast-function-type and -Wno-error=cast-function-type to the list of compiler flags of modules using -Wextra. This avoids almost all of the above problems. One small wrinkle is that if a translation unit or file does trigger some other unrelated diagnostic, then an older compiler will also emit -Wunknown-warning for the presence of the unknown -Wno-cast-function-type flag. I find this acceptable because, in the first place, a file shouldn’t trigger any other diagnostic, especially on an older compiler, and if there does happen to be something, say a deprecation warning, then it’s likely something that needs to be fixed anyway.

Given that this can repeat with future versions of GCC, it seems wiser to avoid -Wextra and instead explicitly list out the desired compiler warnings. This isn’t hard to do because the GCC documentation clearly marks which warnings are turned on by -Wextra, -Wpedantic, etc..

Advertisements

Written by Debarshi Ray

1 April, 2019 at 13:05

Posted in C, GNOME, GNU

GNOME Photos: an overview of zooming

with 2 comments

I was recently asked about how zooming works in GNOME Photos, and given that I spent an inordinate amount of time getting the details right, I thought I should write it down. Feel free to read and comment, or you can also happily ignore it.

Smooth zooming

One thing that I really wanted from the beginning was smooth zooming. When the user clicks one of the zoom buttons or presses a keyboard shortcut, the displayed image should smoothly flow in and out instead of jumping to the final zoom level — similar to the way the image smoothly shrinks in to make way for the palette when editing, and expands outwords once done. See this animated mock-up from Jimmac to get an idea.

For the zooming to be smooth, we need to generate a number of intermediate zoom levels to fill out the frames in the animation. We have to dish out something in the ballpark of sixty different levels every second to be perceived as smooth because that’s the rate at which most displays refresh their screens. This would have been easier with the 5 to 20 megapixel images generated by smart-phones and consumer-grade digital SLRs; but just because we want things to be sleek, it doesn’t mean we want to limit ourselves to the ordinary! There is high-end equipment out there producing images in excess of a hundred megapixels and we want to robustly handle those too.

Downscaling by large factors is tricky. When we are aiming to generate sixty frames per second, there’s less than 16.67 milliseconds for each intermediate zoom level. All we need is a slightly big zoom factor that stresses the CPU and main memory just enough to exceed our budget and break the animation. It’s a lot more likely to happen than a pathological case that crashes the process or brings the system to a halt.

Mipmaps to the rescue!

A 112.5 megapixel or 12500×9000 image being smoothly zoomed in and out on an Intel Kaby Lake i7 with a HiDPI display. At the given window size, the best fit zoom level is approximately 10%. On a LoDPI display it would’ve been 5%. Note that simultaneously encoding the screencast consumes enough extra resources to make it stutter a bit. That’s not the case otherwise.

Photos uses GEGL to deal with images, and image pixels are held in GeglBuffers. Each GeglBuffer implicitly supports 8 mipmap levels. In other words, a GeglBuffer not only has the image pixels at the original resolution, or level zero, at which they were fed into the buffer, but it also caches progressively lower resolution representations of it. For example, at 50% or level one, at 25% or level two, and so on.

This means that we never downscale by more than a factor of two during an animation. If we want to zoom an image down to 30%, we take the first mipmap level, which is already cached at 50%, and from there on it’s just another 60% to reach the originally intended zoom target of 30%. Knowing that we won’t ever have to downscale by more than a factor of two in a sensitive code path is a relief.

But that’s still not enough.

It doesn’t take long to realize that the user barely catches a fleeting glimpse of the intermediate zoom levels. So, we cut corners by using the fast but low quality nearest neighbour sampler for those; and only use a higher quality box or bilinear sampler, depending on the specific zoom level, for the final image that the user will actually see.

With this set-up in place, on the Intel Kaby Lake i7 machine used in the above video, it consistently takes less than 10 milliseconds for the intermediate frames, and less than 26 milliseconds for the final high quality frame. On an Intel Sandybridge i7 with a LoDPI display it takes less than 5 and 15 milliseconds respectively, because there are less pixels to pump. On average it’s a lot more faster than these worst case figures. You can measure for yourselves using the GNOME_PHOTOS_DEBUG environment variable.

A lot of the above was enabled by Øyvind Kolås’ work on GEGL. Donate to his fund-raiser if you want to see more of this.

There’s some work to do for the HiDPI case, but it’s already fast enough to be perceived as smooth by a human. Look at the PhotosImageView widget if you are further interested.

An elastic zoom gesture

While GTK already comes with a gesture for recognizing pinch-to-zoom, it doesn’t exactly match the way we handle keyboard, mouse and touch pad events for zooming. Specifically, I wanted the image to snap back to its best fit size if the user tried to downscale beyond it using a touch screen. You can’t do that with any other input device, so it makes sense that it shouldn’t be possible with a touch screen either. The rationale being that Photos is optimized for photographic content, which are best viewed at their best fit or natural sizes.

For this elastic behaviour to work, the semantics of how GtkGestureZoom calculates the zoom delta had to be reworked. Every time the direction of the fingers changed, the reference separation between the touch points relative to which the delta is computed must be reset to the current distance between them. Otherwise, if the fingers change direction after having moved past the snapping point, the image will abruptly jump instead of sticking to the fingers.

The image refuses to become smaller than the best fit zoom level and snaps back. Note that simultaneously encoding the screencast consumes enough extra resources to make it stutter a bit. That’s not the case otherwise.

With some help from Carlos Garnacho, we have a custom gesture that hooks into GtkGestureZoom’s begin and update signals to implement the above. The custom gesture is slightly awkward because GtkGestureZoom is a final class and can’t be derived, but it’s not too bad for a prototype. It’s called PhotosGestureZoom, in case you want to look it up.

The screencasts feature a 112.5 megapixel or 12500×9000 photo of hot air balloons at ClovisFest taken by Soulmates Photography / Daniel Street available under the Creative Commons Attribution-Share Alike 3.0 Unported license.

The touch points were recorded in an X session with a tool written by Carlos Garnacho.

Written by Debarshi Ray

8 February, 2019 at 18:36

Posted in C, Fedora, GEGL, GNOME, GTK+, Photos

GNOME Terminal: a little something for Fedora 29

with 5 comments

Can you spot what that is?

GNOME Terminal: Fedora 29 teaser

Written by Debarshi Ray

24 May, 2018 at 12:14

Posted in Fedora, GNOME, GTK+, Terminal, VTE

GNOME Terminal: separate menu items for opening tabs and windows

with one comment

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.

Written by Debarshi Ray

11 May, 2018 at 14:42

Posted in Fedora, GNOME, GTK+, Terminal, VTE

Libre Graphics Meeting 2018

with 2 comments

I spent the last seven days attending Libre Graphics Meeting in sunny and beautiful Seville. This was my second LGM, the first being six years ago in Vienna, so it was refreshing to be back. I stayed in one of the GIMP apartments near the Alameda de Hércules garden square. Being right in the middle of the city meant that everything of interest was either within walking distance or a short bus ride away.

IMG_20180425_140117284

Unlike other conferences that I have been to, LGM 2018 started at six o’clock in the evening. That was good because one didn’t have to worry about waking up in time not to miss the opening keynote; and you haven’t attended LGM if you haven’t been to the State of Libre Graphics. Other than that I went to Øyvind’s presentation on colour; saw Nara describe her last ten years with Estúdio Gunga; and listened to Dave Crossland and Nathan Willis talk about fonts. There was a lot of live coding based music and algorave going on this year. My favourite was Neil C. Smith’s performance using Praxis LIVE.

IMG_20180425_155837676.jpg

All said and done, the highlight of this LGM had to be the GIMP 2.10.0 release at the beginning of the conference. GEGL 0.4.0 was also rolled out to celebrate the occasion. Much happiness and rejoicing ensued.

I spent my time at LGM alternating between delicious tapas, strolling down the narrow and colourful alleys of Seville, sight-seeing, and hacking on GEGL. I started sketching out a proper codec API for GeglBuffer modelled on GdkPixbuf, and continued to performance tune babl, but those are topics for later blog posts.

IMG_20180430_140438859~2

Written by Debarshi Ray

30 April, 2018 at 22:33

GNOME Terminal 3.28.x lands in Fedora

with one comment

The following screenshots don’t have the correct colours. Their colour channels got inverted because of this bug.

Brave testers of pre-release Fedora builds might have noticed the absence of updates to GNOME Terminal and VTE during the Fedora 28 development cycle. That’s no longer the case. Kalev submitted gnome-terminal-3.28.1 as part of the larger GNOME 3.28.1 mega-update, and it will make its way into the repositories in time for the Fedora 28 release early next month.

The recent lull in the default Fedora Workstation terminal was not due to the lack of development effort, though. The recent GNOME 3.28 release had a relatively large number of changes in both GNOME Terminal and VTE, and it took some time to update the Fedora-specific patches to work with the new upstream version.

Here are some highlights from the past six months.

Unified preferences dialog

The global and profile preferences were merged into a single preferences dialog. I am very fond of this unified dialog because I have a hard time remembering whether a setting is global or not.

gnome-terminal-3.28-preferences

Text settings

The profile-specific settings UI has seen some changes. The bulk of these are in the “Text” tab, which used to be known as “General” in the past.

It’s now possible to adjust the vertical and horizontal spacing between the characters rendered by the terminal for the benefit of those with visual impairments. The blinking of the cursor can be more easily tweaked because the setting is now exposed in the UI. Some people are distracted by a prominently flashing cursor block in the terminal, but still want their thin cursors to flash elsewhere for the sake of discoverability. This should help with that.

gnome-terminal-3.28-preferences-text

Last but not the least, it’s nice to see the profile ID occupy a less prominent position in the UI.

Colours and bold text

There are some subtle improvements to the foreground colour selection for bold text. As a result, the “allow bold text” setting has been deprecated and replaced with “show bold text in bright colors” in the “Colors” tab. Various inconsistencies in the Tango palette were also resolved.

Port to GAction and GMenu

The most significant non-UI change was the port to GAction and GMenuModel. GNOME Terminal no longer uses the deprecated GtkAction and GtkUIManager classes.

Blinking text

VTE now supports blinking text. Try this:

  $ tput blink; echo "blinking text"; tput sgr0


If you don’t like it, then there’s a setting to turn it off.

Overline and undercurl

Similar to underline and strikethrough, VTE now supports overline and undercurl. These can be interesting for spell checkers and software development tools.

Written by Debarshi Ray

16 April, 2018 at 16:18

Posted in Fedora, GNOME, GTK+, Terminal, VTE

The ways of the GNOME people

with 2 comments

This is a serious post. Or is it? 😉

Hidden away in the farthest corner of the planet, its slopes covered in mist and darkness and its peaks lost in the clouds, stands the formidable Mount GNOME. Perched atop the mountain is a castle as menacing as the mountain itself – its towering walls made of stones as cold as death, and the wind howling through the courtyard like a dozen witches screaming for blood.

Living inside the imposing blackness are a group of feral savages, of whom very little is known to the world outside. The deathly walls of the castle bear testimony to their skull-crushing barbarism, and their vile customs have laid waste to the surrounding slopes and valleys. Mortally fearful of invoking their mad wrath, no human traveller has dared to come near the vicinity of their territory. Shrouded in anonymity, they draw their name from the impregnable mountain that they inhabit – they are the GNOME people.

Legend has it that they are unlike any human settlement known to history. Some say that they are barely human. They are like a foul amorphous mass that glides around Mount GNOME, filling the air with their fiendish thoughts, and burning every leaf and blade of grass with their fierce hatred. Living in an inferno of collectivism, the slightest notion of individuality is met with the harshest of punishments. GNOMEies are cursed with eternal bondage to the evil spirits of the dark mountain.

Happy Easter!

Written by Debarshi Ray

30 March, 2018 at 11:48

Posted in GNOME, Internet