📜 ⬆️ ⬇️

Broadway - rendering GTK3 interface in a browser (HTML5)

Sometimes it is necessary to provide access to applications that do not always have the ability to install locally, and it is not always necessary. Probably, the best way out here would be a web interface in JS / PHP and others like them. But perhaps there are other, simpler in some cases the way? Especially if the application should remain portable, and even better not to do almost anything else in the code to implement this functionality.
This opportunity is provided by Broadway - not a new one for a long time, but the backend for GTK3, which remains in the shadow, allowing to bring new opportunities to where everything seems to have been trodden long ago.




What is GTK Broadway?


')

About broadway told on Habré , already in 2011. However, little has changed since then in the field of coverage of this option.
UPD, thanks awoland :
Initially, this technology and the internal code name of the release of 6.3 X Window System 11 (X11R6.3):
“The X Window System 11 Release 6.3 (X11R6.3) development effort. It was a groundbreaking initiative for the World Wide Web. Any application used to access the web browser. "

The main idea is to write a single version of the code based on the usual and already familiar GTK3, which can simultaneously and practically without changes work as a classic graphical application, as well as render its interface using HTML5 and websockets in the browser. In versions 3.8+, it became possible to set a password for connection and the ability to run multiple applications on one server.

What is the version of GTK3?


Officially, Broadway was released with GTK3, but only since version 3.8 has this subsystem got rid of offensive errors. I use 3.10.7, because it changed the principle of use, fixed many errors and rendered the HTTP server as a separate application. Therefore, I will talk about 3.10, because all the same, everything will come to him.

Principle of operation




Together with GTK3, an HTTP server integrated with GTK3 (broadway d ) is installed. When launched, it creates a socket, for example /run/user/1000/broadway1.socket, and waits for the application to connect to GTK3 on this socket.
You can specify a different port (screen number), you can set a connection password (> = GTK 3.8).

Why do you need it


This mode of operation does not claim to replace the now standard interfaces based on PHP / JS / Java and others like them. But in this way, you can create a service, for example, in the form of a virtual machine, which will provide users with access to any computing services or utilities without wasting time on developing a special interface, while ensuring high performance on the server side. For example, I did the console to access the XenServer virtual machines on it and now I implement remote access to the cameras of my telescope.

Getting Broadway


At the moment, as far as I know, not a single distribution kit from those that I have tried provides GTK3 + broadway package in stable branches. Debian 7 has such a package in the experimental repository, but everything seems to go smoothly with it.
In Debian based systems, you can add a PPA compiled by a kind person (Nicolas Delvaux)
There is a backport made by him on the basis of 3.8.0

Both options should be used with caution and understanding, because there is a real opportunity to thoroughly break the system. I use 3.10.7, here already only from source codes.
Brief assembly instructions

Build as described in the LFS manual, not forgetting checkinstall instead of make install if you have a package manager
Unfortunately, an important nuance is not described there - besides assembling and installing the GTK3 library itself, you need to manually compile and copy broadwayd somewhere available through $ PATH, for example in / usr / sbin
cd gtk+-3.10.7/gdk/broadway make clean make cp broadwayd /usr/sbin 


Launch


If you run the application like this
 GDK_BACKEND=broadway BROADWAY_DISPLAY=:0 ./gtk_app 
,
then it will work in the background, like a web server, and we get access to the interface by logging into the browser at the appropriate address and port. In this example, it will be localhost: 8080 (The port is calculated as port = 8080 + (display - 1) ). The web server is already in delivery with GTK - broadwayd. In this case, there is no need to have a working X server on the host. Enough availability of necessary libraries. The application will be displayed in the browser in almost the same way as in the standard mode. Compare:





The main nuances of use


The first thing that catches your eye is the missing window name, as well as the title of the page says “broadway 2.0”. It is also not possible to manually resize a window by dragging
Using
 gtk_status_icon_set_visible(GTK_STATUS_ICON(tray_icon), TRUE); 

will cause a segfault. The next nuance is that everything that is executed in the browser is done relative to the host machine. For example, choosing a file on the local browser of the machine and doing something with it on the application side will not work. Or, calling libnotify will cause a pop-up window to appear on the host, not on the machine with the browser.
On the other hand, there are other advantages, such as simplified access to server resources, but you need to pay attention to security, for example through gtk_file_chooser_set_local_only, gtk_file_chooser_set_filter and configure jail for an individual user and run the web version under this user, otherwise the user will feel at ease least directory structure.

Another problem is that using a mouse in a browser in such an application you can get into the standard menu, but with your finger - not really (if we go from a mobile device). In addition, the size and position of the window is not the same everywhere - this will also need to be taken into account. And very unpleasant - GTK3 does not support single click . So I didn’t manage to choose another directory even by turning off the double tap (Android 4.2.2 / Firefox / Chrome). Log in to the same session simultaneously from different machines / browsers will not work, since the socket is one, the previous session will be automatically closed

Practice



Consider how you can consider the possibility of using Broadway in the application.
We will use Glade as an interface constructor. I use two versions of the interface in one application: one for normal use and one for browser, which tries to take into account the nuances of working in a browser and / or on a mobile device.
GTK allows loading the interface from the memory buffer, which we will use. In the Makefile, I add a transformation from the XML file in which the Glade interface is saved to the uint8_t array, which will load the application. This allows you to store everything in a single executable file.

 all: xxd -i desktop.glade ../src/desktop.h; xxd -i web.glade ../src/web.h; make -C ../src clean: make -C ../src clean 


Now we have an array with an interface in the header file. The main loop is standard.

 int main(int argc, char *argv[]) { gtk_init(&argc, &argv); GtkWidget *main_window = glade_init( ); gtk_widget_show(main_window); gtk_main( ); } 


I will answer in advance about return - going with std = c99
Next, we need to understand when to use this or that type of interface.
Here that if Broadway is used, the GDK screen is called “browser” will help us.

 #ifdef __WIN32 G_MODULE_EXPORT #endif gboolean is_run_in_a_browser (void) { GdkScreen *current_screen = gdk_screen_get_default(); char *screen_name= gdk_screen_make_display_name(current_screen); gboolean is_browser = !strcmp(screen_name,"browser"); free(screen_name); return is_browser; } 


ifdef is needed here for adequate work under Win32, if necessary.
In this function, we check the name of the GDK window, and if this is a browser, then at the same time we remove the design (frame) of the window. Now we will load the interface depending on whether the application is running via broadway or not.

 #ifdef __WIN32 G_MODULE_EXPORT #endif GtkWidget *glade_init(void) { GtkBuilder *builder = gtk_builder_new( ); GError *error = NULL; gboolean web_run = is_run_in_a_browser(); gtk_builder_add_from_string(builder, web_run ? (char *)web_glade : (char *)desktop_glade, -1, &error); if (!error) { printf("Couldn't load builder buffer: %s", error->message); g_error_free(error); return NULL; } gtk_builder_connect_signals(builder, NULL ); GtkWidget *main_window = GTK_WIDGET (gtk_builder_get_object (builder, "mainwin")); g_object_unref(builder); return ( main_window ); } 


Run the application. We find out that the window location settings are not working. Immediately after launch, the resolution of the GDK screen 1024 * 768 is considered later. In addition, it is necessary to center the window with your hands, since the browser resolution rarely coincides with the default value in broadway.
After we open the application in the browser, we need to set the desired screen resolution (most often it will stretch to full screen) and at the same time combine the upper left corner with the origin. You can do this, for example.

 gtk_window_move(GTK_WINDOW(main_window),0,0); GdkScreen *current_screen = gdk_screen_get_default(); int32_t w = gdk_screen_get_width(current_screen); int32_t h = gdk_screen_get_height(current_screen); gtk_window_resize(GTK_WINDOW(main_window),w, h); 

Then the test application (VNC console) will look like this in Android / Firefox):



If before (up to 3.8), the user should have turned off the application on their own, otherwise if you close the browser or go from another location, all that was visible was a white background. Now broadway takes work with sockets and idle / disconnect on itself. Now we need to deal with other little things

A bit of customization broadwayd





Fortunately, GTK3 is a opensource, so you can climb deeper and change something.

Let's start with the window title.

The default text, “broadway 2.0,” is unlikely to suit anyone, change that. HTML5 server page consists of a template and a JS file. The title of the page is registered in the standard HTML header:
 <title>broadway 2.0</title> 

When building, the page is converted by the perl script into a simple C array, which is stored in gtk + -3.10.7 / gdk / broadway / clienthtml.h - static const char client_html [].
Then everything is simple, gtk + -3.10.7 / gdk / broadway / broadway-server.c:

 static void got_request (HttpRequest *request) ............... if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0) send_data (request, "text/html", client_html, G_N_ELEMENTS(client_html) - 1); 

Let's change a bit the work algorithm, we will use the heder as a format for sprintf. Therefore, gtk + -3.10.7 / gdk / broadway / clienthtml.h will have to be slightly corrected - add a shielding of percent signs, for example, like this:
 background-image: -moz-linear-gradient(#D1D2D2 0%%, #BABBBC 65%%, #D4D4D5 100%%);\n" 

instead
 background-image: -moz-linear-gradient(#D1D2D2 0%, #BABBBC 65%, #D4D4D5 100%);\n" 

And replace the title text
 <title>broadway 2.0</title> 

on specifier
 <title>%s</title> 

Let's change the algorithm of the server itself:

 char *http_title = getenv("GTK_HTTP_TITLE"); if (NULL == http_title) { http_title = "Default"; } size_t total_html_size = sizeof client_html + strlen(http_title) + 1; char *_client_html = malloc (total_html_size); snprintf(_client_html, total_html_size, client_html, http_title); if (strcmp (escaped, "/client.html") == 0 || strcmp (escaped, "/") == 0) send_data (request, "text/html", _client_html, strlen(_client_html) - 1); ........... g_free (_client_html); 

I could use asprintf, but then I would have to upgrade the Makefile, which I didn’t want to do.
Rebuild broadwayd, set a global variable and start the server
 export GTK_HTTP_TITLE="PAGE TITLE" 




You can change the default screen size, it may be relevant when used with mobile devices.

 static void gdk_broadway_screen_init (GdkBroadwayScreen *screen) { screen->width = 1024; screen->height = 768; } 


And change the name of the GDK screen, so you can, for example, create several specific versions of broadwayd and identify them in this way

 static gchar * gdk_broadway_screen_make_display_name (GdkScreen *screen) { return g_strdup ("browser"); } static gchar * gdk_broadway_screen_get_monitor_plug_name (GdkScreen *screen, gint monitor_num) { return g_strdup ("browser"); } 


Conclusion



Broadway is a really interesting feature of GTK3, which allows you to quickly create interesting lightweight services for a specific range of tasks. But, unfortunately, practically not used. With this article I wanted to draw the attention of a large number of people to broadway and maybe someone will be able to solve their problem using simple methods.

Source: https://habr.com/ru/post/212705/


All Articles