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
-
Fedora 39 Beta is Now Available for Testing
For fans and users of Fedora Linux, the first beta of release 39 is now available, which is a minor upgrade but does include GNOME 45.
-
Fedora Linux 40 to Drop X11 for KDE Plasma
When Fedora 40 arrives in 2024, there will be a few big changes coming, especially for the KDE Plasma option.
-
Real-Time Ubuntu Available in AWS Marketplace
Anyone looking for a Linux distribution for real-time processing could do a whole lot worse than Real-Time Ubuntu.
-
KSMBD Finally Reaches a Stable State
For those who've been looking forward to the first release of KSMBD, after two years it's no longer considered experimental.
-
Nitrux 3.0.0 Has Been Released
The latest version of Nitrux brings plenty of innovation and fresh apps to the table.
-
Linux From Scratch 12.0 Now Available
If you're looking to roll your own Linux distribution, the latest version of Linux From Scratch is now available with plenty of updates.
-
Linux Kernel 6.5 Has Been Released
The newest Linux kernel, version 6.5, now includes initial support for two very exciting features.
-
UbuntuDDE 23.04 Now Available
A new version of the UbuntuDDE remix has finally arrived with all the updates from the Deepin desktop and everything that comes with the Ubuntu 23.04 base.
-
Star Labs Reveals a New Surface-Like Linux Tablet
If you've ever wanted a tablet that rivals the MS Surface, you're in luck as Star Labs has created such a device.
-
SUSE Going Private (Again)
The company behind SUSE Linux Enterprise, Rancher, and NeuVector recently announced that Marcel LUX III SARL (Marcel), its majority shareholder, intends to delist it from the Frankfurt Stock Exchange by way of a merger.