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
-
Linux Servers Targeted by Akira Ransomware
A group of bad actors who have already extorted $42 million have their sights set on the Linux platform.
-
TUXEDO Computers Unveils Linux Laptop Featuring AMD Ryzen CPU
This latest release is the first laptop to include the new CPU from Ryzen and Linux preinstalled.
-
XZ Gets the All-Clear
The back door xz vulnerability has been officially reverted for Fedora 40 and versions 38 and 39 were never affected.
-
Canonical Collaborates with Qualcomm on New Venture
This new joint effort is geared toward bringing Ubuntu and Ubuntu Core to Qualcomm-powered devices.
-
Kodi 21.0 Open-Source Entertainment Hub Released
After a year of development, the award-winning Kodi cross-platform, media center software is now available with many new additions and improvements.
-
Linux Usage Increases in Two Key Areas
If market share is your thing, you'll be happy to know that Linux is on the rise in two areas that, if they keep climbing, could have serious meaning for Linux's future.
-
Vulnerability Discovered in xz Libraries
An urgent alert for Fedora 40 has been posted and users should pay attention.
-
Canonical Bumps LTS Support to 12 years
If you're worried that your Ubuntu LTS release won't be supported long enough to last, Canonical has a surprise for you in the form of 12 years of security coverage.
-
Fedora 40 Beta Released Soon
With the official release of Fedora 40 coming in April, it's almost time to download the beta and see what's new.
-
New Pentesting Distribution to Compete with Kali Linux
SnoopGod is now available for your testing needs