Initial Touch and Web Browsing experiments on Librem 5 prototyping boards

Nicole Faerber

Mobile Development Lead at Purism

When it comes to prototyping the Librem 5, we are working hard and making progress on several sides. As you have seen in yesterday’s testing update blog post, we are working on development hardware in order to start getting software development groundwork done. Today, I’m sharing the results of a quick experiment with web and touch on a prototype board.

So far we have managed to get a pure mainline Linux kernel 4.13.5 to work on the development hardware which is based on a i.MX6DL (dual core 1GHz), although we’re still evaluating i.MX8 in parallel. For this test setup I had a 10″ 1280×800 LVDS display attached, with a temporary capacitive touchscreen. The before mentioned blog post has some pictures of the boards. Why mainline? Because we want to be as upstream and mainline as possible. And we want to be blob free too, so if a current mainline Linux kernel is working then this is very good—and it is!

As the base OS for this test we used Debian unstable for ARM hardfloat (armhf). We need the unstable branch since we need to have Mesa >17.1 for proper 3D support. Why Debian? Because PureOS is based on Debian and again we want to be as close to upstream and mainline as possible, so we try this first. Any deviation from upstream would mean additional support effort, which we want to avoid as much as possible—not just because of the effort involved, but also because we want to create a device that neatly fits into an overall vision of a free and open source IT world.

The 3D acceleration support is provided by the Etnaviv kernel driver (mainline since 4.6) and the userspace Etnaviv support by Mesa. Using this combination we can run Wayland in accelerated mode giving nice UI performance also for 2D applications. For testing UI stuff we are currently fully basing on Wayland with the Weston compositing manager. You can see some more screenshots in yesterday’s post.

A lot of desktop infrastructure still depends on X11 and some X server to run, even if it is only running in the background.

  • Due to its very long history, the X11 protocol and some features of the X server have been in use everywhere in desktop environments and applications, and it will take some time for these to be replaced with newer Wayland based or other code. But this effectively means that we can not yet run, for example, a full GNOME on the development boards.
  • On regular PCs this is usually circumvented by running Xwayland in the background, which provides X server functions and uses Wayland as its drawing surface. For some reason—I am still unsure about the root cause—Xwayland does not work on our setup yet. First of all, Xwayland does not support GLES but only pure OpenGL… but the Etnaviv Mesa driver only supports GLES so Xwayland falls back to software rendering—and then it crashes. So for now, I am stuck with Wayland + Weston.

This is not totally bad since it gives us a good idea of what is already working properly with Wayland and what isn’t.

I also wanted to see how more complex applications (like a web browser) behave in this environment… But all the browsers I tried either used ancient versions of WebKitGTK (and thus GTK2 without Wayland support) or they depended on X11 for some reason. I tried Epiphany, netsurf, Firefox and Chromium (Chromium just silently crashed). So what does a good Haeckse do in this case? Write her own 🙂

Using WebKit2GTK, this is pretty easy and straightforward (my code is below, and as you can see it’s pretty short! But be warned, this was just a quick’n’dirty test thing!), which allowed me to successfully launch a webpage as you can see in the screenshot above. On the left is a terminal window where I started the application and on the right is the application output window displaying the Purism website—ta-da! As I mentioned earlier, we also have a touchscreen attached to the screen of the board and, although you can’t tell just by looking at the screenshot, I can scroll the web view with a finger, and two finger pinch zooming does work. Excellent!

Here’s the code for my ultra-mini webkit browser (which I compiled on the development board itself):

#include <gtk/gtk.h>
#include <glib/gprintf.h>
#include <webkit2/webkit2.h>
#include 


typedef struct {
	GtkWidget *win;
	GtkWidget *entry;
	GtkWidget *webview;
} appdata; 


void uri_entered (GtkEntry *entry, gpointer user_data)
{
appdata *data = (appdata *)user_data;
const gchar *entry_text;

	entry_text = gtk_entry_get_text(GTK_ENTRY(data->entry));
	if (entry_text != NULL && strlen(entry_text) != 0)
		webkit_web_view_load_uri(WEBKIT_WEB_VIEW(data->webview), entry_text);
}


static void web_view_load_changed (WebKitWebView  *web_view,
                                   WebKitLoadEvent load_event,
                                   gpointer        user_data)
{
appdata *data = (appdata *)user_data;

    switch (load_event) {
    case WEBKIT_LOAD_STARTED:
        g_printf("load started '%s'\n", webkit_web_view_get_uri (web_view));
	gtk_entry_set_text(GTK_ENTRY(data->entry), webkit_web_view_get_uri (web_view));
        break;
    case WEBKIT_LOAD_REDIRECTED:
        g_printf("load redirected '%s'\n", webkit_web_view_get_uri (web_view));
	gtk_entry_set_text(GTK_ENTRY(data->entry), webkit_web_view_get_uri (web_view));
        break;
    case WEBKIT_LOAD_COMMITTED:
        g_printf("load committed '%s'\n", webkit_web_view_get_uri (web_view));
        break;
    case WEBKIT_LOAD_FINISHED:
        g_printf("load finished '%s'\n", webkit_web_view_get_uri (web_view));
        break;
    }
}


int main(int argc, char** argv)
{
GtkWidget *vb;
GtkEntryBuffer *eb;
appdata mdata;

	gtk_init(&argc, &argv);
	mdata.win = gtk_window_new(GTK_WINDOW_TOPLEVEL);
	gtk_window_set_default_size (GTK_WINDOW(mdata.win), 640, 480);
	g_signal_connect (mdata.win, "delete_event", G_CALLBACK (gtk_main_quit), NULL);

	vb = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);
	gtk_container_add(GTK_CONTAINER(mdata.win), GTK_WIDGET(vb));

	eb = gtk_entry_buffer_new(NULL, -1);
	mdata.entry = gtk_entry_new_with_buffer(eb);
	gtk_entry_set_text(GTK_ENTRY(mdata.entry), "https://www.puri.sm");
	g_signal_connect(G_OBJECT(mdata.entry), "activate", G_CALLBACK(uri_entered), &mdata);

	gtk_box_pack_start(GTK_BOX(vb), mdata.entry, FALSE, FALSE, 0);

	mdata.webview = webkit_web_view_new();
	g_signal_connect(mdata.webview, "load-changed", G_CALLBACK(web_view_load_changed), &mdata);
	gtk_box_pack_start(GTK_BOX(vb), mdata.webview, TRUE, TRUE, 0);

	gtk_widget_show_all(mdata.win);

	webkit_web_view_load_uri(WEBKIT_WEB_VIEW(mdata.webview), "https://www.puri.sm");

	gtk_main();
}

And here is a matching Makefile:

CC = gcc
CFLAGS = -g -O2 -Wall

# for GTK3
CFLAGS += `pkg-config --cflags gtk+-wayland-3.0`
LDFLAGS += `pkg-config --libs gtk+-wayland-3.0`

# for WebKit GTK3
CFLAGS += `pkg-config --cflags webkit2gtk-4.0`
LDFLAGS += `pkg-config --libs webkit2gtk-4.0`

OBJS = miniwebkit.o
PRG = miniwebkit

all: $(PRG)

$(PRG): $(OBJS)
	$(CC) -o $(PRG) $(OBJS) $(LDFLAGS)

clean:
	rm -f $(OBJS) $(PRG)

Pretty easy, isn’t it?