Eva and GemView update - Valentines 2022

There's been a slow but steady march of progress on these two projects over the past week, and I think it's now at the point where I could say that Eva is, while still a wip, somewhat useful.

What is useful, anyway?

Well first off, the program should be capable of performing it's main function without randomly crashing. In the case of a Gemini browser, I should be able to browse gemini protocol pages and follow links, and if I encounter a link of a different protocol the program should, preferably, either handle it or open it in an appropriate external program. At minimum, those links should not be able to upset the program state.

When I first publicly announced the projects, it was possible to browse gemini links to .gmi files, but the browser widget just assumed that everything was a gemini link and would return "load-failed" for any other protocol. The changes I pushed today are the beginning of a much more granular and correct approach to the various links that are to be found in geminispace. Eventually I intend for Gemview to be able to handle gemini://, mercury://, gopher:// and finger protocols, but for the time being only gemini and mercury are implemented. However, you will at least now get a message in the terminal that the protocol is not supported yet. As for http[s] links, they now open in your default browser via the webbrowser crate.

Could I have implemented that myself without pulling in another crate? Absolutely. However, when looking at everything that the crate provides in a small package it was obvious that it was the better solution. The functionality should work across different desktops and even operating systems, and has multiple fallbacks.

Url parsing is already implemented in the gmi crate, but there are currenty some issues with the implementation. Basically, relative links such as "news/" get parsed as if the host were "news" and the path were "/", which is obviously incorrect. I've filed an issue, and will be looking at the code myself time permitting. In the meantime, I've pulled in the Url crate from the Servo project to validate url's before attempting to load them.

One thing still missing is the ability for gemview to decide if it's receiving a .gmi document or something else over gemini. It's entirely possible to sent plain text over gemini, and also images. It's on my TODO list.

History

There are two main components to history in a web browser. Each instance, whether that be a window or a tab, should have a back/forward list enabling one to navigate backwards and forwards. This is done in GemView and Eva as of yesterday. The actual functionality was partially done several days earlier, but I had to sort out some ordering issues to make sure that the "page-loaded" signal was emitted only after the history transactions had occurred. I also wanted Eva to change the tab title based on the current host, and to set the window title based on the host in the current tab. You know, like a browser. That was pushed yesterday whil on my lunch break at work.

The other component to history, which is yet to be implemented, is an overall record of pages visited. In simpler browsers this is often a simple list, where in a full blown browser such as Firefox or Chromium one can expect some metadata to be stored along with each entry, such as the date and time of the last visit, along with a method to purge history based on time, and automatically discard entries older than a certain time. I intend for Eva to have the latter. Internally, this is goind to be done by maintaining a hash map where the url is the key and the most recent date and time of visit is the value, thus each visit to a given page will write over the last. The entire thing can be easily saved to disk in Toml format via serde. I've yet to work out all of the details, because I don't want to keep all of that data in memory at the same time, so there will likely be a fair amount of code around the finished mechanism.

Fonts

Gemview internally stores several Pango font descriptions, as pango is what gtk uses for font rendering. However, from the perspective of saving configuration a pango font description is very non-friendly. Don't get me wrong, Pango is a great font rendering library with very fine grained control. But lets take a look at all of the different blockers to getting a Pango FontDescription struct serialized and deserialized.

  • The FontDescription struct is an opaque struct
  • At least five different enums which are marked non-exhaustive
  • Weight specified as a string or as a glib value, with a getter marked as unsafe

By the time these blockers had been overcome, the amount of code (and work) would have been pretty high. So I used the same tactic as was employed in Gfret, just more fine grained. Eva has a Font mod which contains a struct reimplementing a significant subset of the Pango FontDescription struct, with both from_pango() and to_pango() methods. The Font struct is what gets stored on disk with Eva's config file, and is translated to a FontDescription in order to work with Gtk. From what I've seen of other Gtk+ based gemini browsers, Eva has by far the best font settings in that much more of what Pango supports is implemented. In practice, the parts that aren't implemented are not going to be noticed except in extremely rare cases.

Colors

Color support is at about the halfway point to where it is intended to be. Now, it made sense to implement font support directly into GemView, but not colors. You can easily set colors for fonts in markup, but backgrounds are another story. Yes, you can set a background property on a text element in Pango markup, but you can't set the overall color of the background of the page. So what you get is a block of color surrounding the text itself with bars of whatever the background color of the Gtk+ theme is showing through. Also, I wanted to be able to give an alternate background for preformatted and blockquote sections. Gtk+ really wants us to do things like this with Css, and in order to load some Css we need to be able to get the Gdk Screen, which we don't have available until the widget is realized, creating a chicken and egg problem if I tried to do it in GemView itself. So this is best done in the application, not the widget.

What works so far is this.

  • background color
  • text color
  • link color
  • link hover color
  • blockquote background color
  • blockquote text color
  • preformatted background color
  • preformatted text color

The checked boxes were basically the low hanging fruit. For preformatted and blockquote elements I'm going to be going back into the rendering function in GemView and doing some surgery. Those elements are going to have to go into a Gtk+ Box widget with it's own Css class in order to color the backgrounds differently. While I'm at it I intend to prettify things a bit so that those boxed elements have little niceties like rounded corners and possibly drop shadows, just like you might see in, say, this webpage.

Bookmarks

Bookmarks are one of the things that haven't yet been worked on, but let me briefly outline the plan.

As with history, there is a bit of a discrepancy among browsers with their bookmarking features, with some browsers giving you little more than a list of url's while the old guard web browsers offer sgnificantly more, often in the form of a folder heirarchy. There are other strategies for organizing bookmarks as well, such as a tag based system such as in the web browser for Gnome, which I quite like. Then there's qutebrowser, which has just a flat list of links but integrates them verry well into it's completion system and also has a quickmarks feature, which gives you a two or three key code that you can enter to reach your most often used sites. While it seems that almost every Gemini browser just creates a .gmi page full of links and calls it a day. Well, Lagrange is a bit of an outlier as it offers some nice additional features like creating bookmarks from other pages, but that project seems to be in a whole other category anyway compared with most gemini clients.

What I intend for Eva is something quite like Epiphany (the Gnome browser) mixed with qutebrowser. I want the bookmarks to be organized by tag, and I want to have the feature of giving a short name to each bookmark, which will be integrated into completion for the search/url bar. I haven't decided yet it the actual bookmarks display is going to be a series of .gmi pages, a sidebar, or what, but I do know that it should be tag based and have good integration with completion so that typing the beginning of a name, url, or category should all bring up matches. I consider the folder based schemes rather outdated and problematic, as many links can fall into multiple categories.

For a short while when I first took up Rust I was working on a web browser using webkit, called rwb (I suck at naming things sometimes) that actually got fairly far along. It had both bookmarks and quickmarks, and it took another cue from qutebrowser with it's search system. Basically you could define a search engine and give it a two or three letter code, like aur for the Arch Linux aur, and then type aur feed reader into the address bar and it would search the aur for feed reader. This was nice to have. Anyway, I already wrote some of this once, so I know a bit about what it will look like. I'm just going to take the concept a bit further this time.

As for adding and editing bookmarks, that part is going to be all gui based with no need to edit files manually.

When will it be ready?

There's two ways to interpret that. One is a measure of time, while one is a measure of features. I choose to measure in features. So how does Eva stack up now, and how will it when it's "done"?

The gold standard right now in Gemini clients is no doubt the already mentioned Lagrange. I seriously doubt that Eva will ever reach the level of sophistication that this project has achieved, and that's not what I'm shooting for anyway. Lagrange has a bit of everything, and while I definitely wouldn't call it bloated by any measure, I might call it a bit busy. I also think the interface looks a bit flat, old fashioned and non-native when you look at things like buttons compared with Gtk.

Another feature packed browser for the smallweb is Kristall, and it's by a guy who is very active in the Zig community. Kristall is written in C++ using Qt and looks fantastic. It's also got probably more features than I really want to pack into Eva, but I wouldn't call it overboard. It fits nicely in a Plasma desktop.

There are a handful of Gtk based Gemini browsers that I'm aware of. The first, Castor, is quite simple and while it does the job pretty well it's not going to win a beauty contest and is lacking in a number of features such as tabs, and also misses a number of little things that users expect in a web browser. Little visual cues, like the cursor changing to a hand and the color of a link changing on hover, or changing the sensitivity of the back and forward buttons depending on whether there's anywhere to even go back or forward.

Another one would be Dragonstone, written in Vala. It's nice in a number of ways, but to me the page rendering is visually unappealing and none of the numerous buttons or menu items give you any real clue as to what they actually do. This one at least changes the appearance of links when you hover over them, but it doesn't change the cursor, and by putting the url bar into a headerbar without much spacing between elements there's almost nowhere to grab the title bar to position the window. My understanding is that the project is also in maintenance.

Geopard is in a similar state to the other two mentioned. It sins in the same way as Dragonstone with the headerbar. The page rendering is nicer than the other two. Once again, no tooltips or indication that you're hovering over a link. No keyboard shortcuts either. It uses all async io, which is theoretically very fast and cool but in practice probably overkill.

Basically all three that I've mentioned feel unfinished. Castor and Dragonstone both have Gopher support, and I know Castor at least has Finger support as well. I won't consider GemView or Eva as anywhere near complete until they support gemini, gopher and finger. Eva already, IMO at least, looks and feels more finished than those three. It's also using Gtk4, so it's more future-proof. I've already tried to tackle some of those little touches that the other three seem to just gloss right over, like the link hover changing both the link and cursor appearance and popping up a tooltip, keyboard shortcuts, and one that I didn't mention but consider essential, the tab name changes based on the domain of the loaded page as well as the window title following the current tab.

So I guess what I'm going for is a fairly simple browser much like Epiphany is that looks and feels native on a Gtk desktop, and actually feels finished. I like Lagrange, and Kristall is awesome as well, but I think for a lot of people they're just going to want something that does the job in a familiar way and then gets out of the way. Geminispace is, after all, about conveying ideas via text, and cutting out all of the BS that has ruined the WWW. So I think a nice, simple, clean ui that stays in the background until it's needed is going to appeal to a certain class of user.

My biggest blockers before an actual release are right now:

  • Gopher and Finger support
  • Displaying plain text and images instead of just assuming every gemini link is gemtext
  • Bookmarks as outlined above
  • History as outlined above

Once those things are working we'll do an alpha release. As for more features, I currently don't have other plans for Eva or GemView, but I'm open to suggestions. Hit me up on Mastodon or open an issue on one of the projects on Codeberg if you want a feature I haven't already described.