Discarding photo fails with Go and Fyne
Faster Thanks to Prepping
Newly loaded photos are displayed by showImage()
from line 37 onwards; it tries to load them from the cache first and, if this fails, scrapes them from the disk using loadImage()
and decodes them. This takes time, but at some point this has to be done. Because of this delay of a good second, preloadImage()
uses a Goroutine starting in line 31 with go func
to handle loading in the background while the main program continues to run and respond to user input. When the user requests the next image, it is usually already in the cache, and showImage()
fetches it and sends it to the screen at lightning speed.
Invisible Cache
Thanks to the hashicorp/golang-lru package from GitHub, the LRU cache maintained in the Cache
global variable need not worry about wasted RAM. Line 23 in Listing 2 defines a cache with a maximum of 128 entries for preprocessed images, into which Add()
(line 45, Listing 3) inserts new items under the photo's file path URL, while Get()
(line 39) retrieves them from the cache. Although the LRU cache provides the Contains()
function that determines whether an item is in the cache, users should always try to retrieve an item if they actually need it in order to avoid race conditions. Otherwise, although Contains()
might report that the entry is there, a concurrent program could also cause it to disappear before the following Get()
.
If the cache is full, Add()
simply throws the oldest entry out of the cache before inserting the new one, according to LRU rules. For the app, which later may still be looking for the old entry because the user went back to that old photo, this is not the end of the world. It can simply retrieve the image from the disk and put it back in the cache. This takes a bit longer, but in this inconvenient case you just have to wait.
By the way, one more subtle feature of Go's strict type system: Containers such as the LRU cache let you store generic data types. Therefore, when fetching, you must make sure that the entry is given the correct type again using runtime type assertions. For example, line 42 converts a found cache entry into a pointer to a canvas.Image
type because the retrieved photo is of that type, even though the LRU cache had stored it as a generic interface{}
type in the meantime.
Such manipulations wreak havoc with Go's strict type system, however. What Go normally fields at compile time therefore turns into an annoying runtime error if these conversions have not been carefully tested.
By the way, Fyne normally avoids absolute coordinate values in layout instructions and scales widgets like buttons automatically. Because of the widgets' captions and the font used, this can be done without explicit layout instructions. However, this is not possible with photos because Fyne has no way of knowing how big the containing canvas object needs to actually appear on the screen. If you don't give Fyne a minimum size for the widget in the form of SetMinSize()
, you may have to use a magnifying glass to search the screen for the widget you are looking for. Without defaults, Fyne paints 0x0-sized images, often resulting in perplexingly hard-to-find app windows. If you specify the minimum size, like in line 66 of Listing 3, you can see what's going on.
Finally, Listing 4 implements the virtual trash can that uses toTrash()
to dump photo files to a newly created old/
directory as needed. This is done by the Rename()
function from the standard os package, which works without complaint as long as the original and the target file reside on the same storage medium.
Listing 4
trash.go
package main import ( "os" "path/filepath" "fyne.io/fyne/v2" ) const TrashDir = "old" func toTrash(file fyne.URI) { err := os.MkdirAll(TrashDir, 0755) panicOnErr(err) err = os.Rename(file.Name(), filepath.Join(TrashDir, file.Name())) panicOnErr(err) } func panicOnErr(err error) { if err != nil { panic(err) } }
Adapting the Look & Feel
To make Go download the Fyne packages used in the listings from the server at fyne.io
onto your local system and compile the whole enchilada, you need the sequence in Listing 5.
Listing 5
trash.go
$ go mod init inuke $ go mod tidy
A subsequent
go build inuke.go image.go trash.go
should then generate a binary inuke
without any errors. Upon launch, it will display the first photo in the current directory inside its GUI window. In the usual Go style, the compiler can also cross-compile for other platforms. In the case of Fyne, this even goes so far as to have the GUI code draw in the look and feel of the other platform. How this works is described in detail in the Fyne book by the Fyne guru himself [4]. The code from the three listings also compiles without problems on a Mac and results in a slightly adapted Apple look, as shown in Figure 4.
The graphical interfaces' implementation also depends heavily on the operating system you use. On Linux, Fyne taps into the libx11-dev, libgl1-mesa-dev, lbxcursor-dev, and xorg-dev libraries using a C wrapper from Go. You need to install these on Ubuntu, for example, by typing
sudo apt-get install
to ensure that a subsequent go build
for a Fyne app actually finds the required underpinnings.
« Previous 1 2 3 Next »
Buy this article as PDF
(incl. VAT)
Buy Linux Magazine
Subscribe to our Linux Newsletters
Find Linux and Open Source Jobs
Subscribe to our ADMIN Newsletters
Support Our Work
Linux Magazine content is made possible with support from readers like you. Please consider contributing when you’ve found an article to be beneficial.
News
-
Gnome 48 Debuts New Audio Player
To date, the audio player found within the Gnome desktop has been meh at best, but with the upcoming release that all changes.
-
Plasma 6.3 Ready for Public Beta Testing
Plasma 6.3 will ship with KDE Gear 24.12.1 and KDE Frameworks 6.10, along with some new and exciting features.
-
Budgie 10.10 Scheduled for Q1 2025 with a Surprising Desktop Update
If Budgie is your desktop environment of choice, 2025 is going to be a great year for you.
-
Firefox 134 Offers Improvements for Linux Version
Fans of Linux and Firefox rejoice, as there's a new version available that includes some handy updates.
-
Serpent OS Arrives with a New Alpha Release
After months of silence, Ikey Doherty has released a new alpha for his Serpent OS.
-
HashiCorp Cofounder Unveils Ghostty, a Linux Terminal App
Ghostty is a new Linux terminal app that's fast, feature-rich, and offers a platform-native GUI while remaining cross-platform.
-
Fedora Asahi Remix 41 Available for Apple Silicon
If you have an Apple Silicon Mac and you're hoping to install Fedora, you're in luck because the latest release supports the M1 and M2 chips.
-
Systemd Fixes Bug While Facing New Challenger in GNU Shepherd
The systemd developers have fixed a really nasty bug amid the release of the new GNU Shepherd init system.
-
AlmaLinux 10.0 Beta Released
The AlmaLinux OS Foundation has announced the availability of AlmaLinux 10.0 Beta ("Purple Lion") for all supported devices with significant changes.
-
Gnome 47.2 Now Available
Gnome 47.2 is now available for general use but don't expect much in the way of newness, as this is all about improvements and bug fixes.