Archive for the ‘Programming’ Category

Articles

Writing small GUI applications on Linux

In Gnome shell,gtk+,Programming on November 14, 2020 by oli4444 Tagged: , ,

Last years I had little time for programming. Most of that time was spent maintaining Bluefish and Jailkit. Last month I wanted to write some small utilities.

First utility I wrote was a gnome-shell extension to track how the time on the computer was spent. The extension polls the current active application and it’s window title every 10 seconds and appends that to a logfile. Although I have some experience with Javascript in websites, I found it very hard. Hardest was to find examples and documentation. A simple thing like how to append a single line to a logfile took me a lot of time.

Next utility I needed was a tool to parse the window activity logfile and show useful statistics. Because of the bad experience with Javascript I choose Python. I didn’t use Glade for years, but I decided to use it for the GUI. I was very surprised with the state of Python Gtk bindings and the combination of Python and Glade. It was excellent to see how quick one can write an application with the combination of python and glade. The documentation on Python and Gtk is good (https://python-gtk-3-tutorial.readthedocs.io/en/latest/) which helps. It surprises me that Glade is mentioned only in chapter 21 of that tutorial. I would have made it chapter 2, and I would have uses it everywhere else in the tutorial.

Because the combination worked very well for me, I also used it for my next utility: saving laptop batteries. Most of my family members keep their laptops always connected to the power at home (which currently is most of the time). I have a few Sonoff switches around with self-written firmware that I can switch on/off with a JSON call. The laptops now automatically switch off their power when their batteries are >95% charged, and switch on the power when their batteries reach < 10%. Then I improved the utility to read the status of the smart meter in house, so now the laptops prefer to charge when I have excess power from my solar panels.

I used pydbus to read the battery state from the system dbus. Paho MQTT was used to read the status of my Smart meter (I have a Raspberry Pi connected to it’s serial port that puts the values on an MQTT bus). Normal python libraries like requests for the JSON call and configparser for config file loading/saving. And again the combination of Glade with Gobject introspection for Gtk and Libnotify and I got everything working in < 250 lines of code. Very happy with the result 🙂

Articles

From “power on” to “gtk GUI usable” as fast as possible

In gtk+,Programming,raspberry pi on November 22, 2015 by oli4444

In my Raspberry Pi + Hifiberry-amp + Pitft project I’ve been looking how to speed up the boot process.

[edit] I updated various parts of this post with suggestions from the comments. [/edit]

The original boot process took around 60 seconds from “power on” until my gtk app was visible and responding. I used the original (Wheezy based) raspbian, with autologon on tty1, and in the .bash_profile I called startx. In /home/pi/.xinitrc I started my application without starting a display manager:
#!/bin/sh
PYTHONIOENCODING=utf_8
export PYTHONIOENCODING
exec /usr/bin/python /home/pi/sqgui2.py

(b.t.w. the PYTHONIOENCODING is there otherwise python will give an exception when calling print with a non-ascii unicode character)

By removing a few services from the init process I removed 10 seconds from the boot process. Still 50 seconds. But further options on Raspbian Wheezy are limited.

Next step was to move to Raspbian Jessie, which has systemd. This gave an unwanted side effect: the hifiberry was detected correctly, but did not produce any sound anymore. Removing a line added for the pitft device_tree=bcm2708-rpi-b-plus.dtb from /boot/config.txt fixed this problem. And the pitft is still working.

In systemd I can start X11 as soon as userspace is running. However this generated an error – the touchscreen device has to be available first. The touchscreen input is in udev configured as /dev/input/touchscreen. I created /etc/systemd/system/xinit-login.service with the following content:
[Unit]
Wants=dev-input-touchscreen.device
After=dev-input-touchscreen.device
DefaultDependencies=false
[Service]
Type=simple
ExecStart=/bin/su pi -l -c /usr/bin/xinit -- VT08
WorkingDirectory=/home/pi/
[Install]
WantedBy=local-fs.target

[edit] with suggestions from the comments in now looks like:

[Unit]
Wants=dev-input-touchscreen.device
After=dev-input-touchscreen.device
DefaultDependencies=false
[Service]
Type=simple
ExecStart=/usr/bin/xinit
WorkingDirectory=/home/pi/
User=pi
Group=Users
Environment=PYTHONIOENCODING=utf_8
[Install]
WantedBy=local-fs.target

and .xinitrc is now a hardlink to the gtk application sqgui.py [/edit]

This makes my xinit session start directly after the touchscreen device is available. This reduced the startup time to 28 seconds. Much better! (b.t.w. I haven’t look if all entries in xinit-login.service are correct, perhaps the contents can be improved).

Systemd has a good tool called systemd-analyze which analyzes the boot process. That way you can easily see which parts take too much time. That helped me to strip off another 2 seconds. An interesting question is how the udev config can be improved to create the touchscreen device earlier in the boot process. Another interesting question is how X11 can be configured to start faster, or how python + gtk3 can be configured to start faster. If you have any suggestions please leave them in the comments.

Next thing was to make the system readonly. I installed busybox-syslogd instead of rsyslogd, since it can do in-memory logging. [edit] I now switched to systemd-journald for in memory logging [/edit]

I analyzed which directories changed after a reboot, and moved those to a tmpfs in-memory filesystem. The /etc/fstab now looks like:
proc /proc proc defaults 0 0
/dev/mmcblk0p1 /boot vfat defaults,ro 0 2
/dev/mmcblk0p2 / ext4 defaults,noatime,ro 0 1
tmpfs /tmp tmpfs defaults,noatime 0 0
tmpfs /var/lock tmpfs defaults,noatime 0 0
tmpfs /var/lib/dhcpcd5 tmpfs defaults,noatime 0 0
tmpfs /var/log tmpfs defaults,noatime 0 0

Possibly this can be optimized with a single tmpfs mount and symlinks to reduce the mount time of 4 tmpfs filesystems.

[edit] did that, they are all symlinks to /tmp now [/edit]

The only remaining issue that I didn’t solve yet is handling of /etc/resolv.conf when moving the setup to a different network. Because /etc/ is readonly the resolv.conf is now fixed for my local wifi network.

[edit] disabling the UART, and moving from the debian networking scripts to systemd-networkd reduced the boot time to 21 seconds! [/edit]

Articles

A search interface in a 320×240 touchscreen

In gtk+,open source,Programming,raspberry pi on October 24, 2015 by oli4444

Last evenings I spent some time on my raspberry pi + hifiberry amp + piTFT + squeezebox project. Previously I created the interface to load a predefined playlist, and to control basics like volume and time. I also finished the integration of the display in the top of the Mission 731i speaker and placed the pi and amp inside the box (will post some pictures soon).

gui

This time I wanted to extend the user interface with a feature to search and browse in the mp3 collection. But that immediately raised the question: what kind of interface works best for a small screen size (320×240) and touch input (no keyboard, no mouse)? A possibility was a virtual keyboard with a entry or a combo, but my first mockup in glade resulted in 300×140 pixels just for the keyboard – leaving very little space for the search results. So I tried a treeview so the user can quickly scroll through the results. To reduce the number of results I added a combo with a prefix (a-z0-9) to the top.
search gui
The results work reasonably well, but there are some issues to resolve.

First of all the scrolling in the GtkTreeView is not using “kinetic scrolling” (you can’t scroll like you normally do on a touchscreen) although I enabled kinetic scrolling for the GtkScrolledWindow parent in glade. Scrolling using the scrollbar on the side works, but kinetic scrolling would work better.

Second, most touchscreen users kind of expect the context menu when you hold your finger for a while. I hoped this was automatically translated to a right-click, but that doesn’t work. So I have to find a way now to catch these events for the context menu’s (anybody a hint how to do this?).

The last issue I have is not related to the touchscreen. I have some scaling layout issues, sometimes a multiline label with a long text forces some buttons off the screen.
screenshot
So I also have to find out how ellipsize works with multiline labels.

Statuses

backwards rendering compatibility

In Bluefish,gtk+,open source,Programming on July 3, 2015 by oli4444

The last year I didn’t keep up with the latest GTK versions. With less time to code, installing new software was not my priority, so I did most of my programming on a machine running Ubuntu LTS.

Last week I had some spare time and I installed the latest Fedora. I installed the same Bluefish version (the latest, 2.2.7) but to my surprise some bits didn’t look as good anymore. Bluefish has a sidebar with several plugins, each in a GtkNotebook tab. This normally looks like this:

small_icons_tabs

But on the latest and greatest Fedora, it looks like this, instead of showing all the icons, only two are visible, unless you make the sidebar extremely wide:

sidebar-new-gtk

This makes me wonder if GTK has something like “backwards rendering compatibility testing”: see if applications that were not developed for the latest GTK release still look good and function properly. I have no idea if this could be done in an automatic way, but there are probably brighter people around that do have an idea how to do this.

b.t.w. I haven’t found a way yet to change my code in such a way that all icons become visible again. If anybody is willing to drop me a hint how to get all icons back in the original space I will be happy 🙂

Statuses

Cross-platform keyboard issues

In Bluefish,gtk+,Programming on October 5, 2014 by oli4444

We often receive bugreports from windows or OSX users with keyboard problems. For example on windows changing the keys ” to ¨ and ‘ to ´. Or on OSX the square brackets [] are not possible on a German keyboard layout (see https://bugzilla.gnome.org/show_bug.cgi?id=737547), or curly braces not on AZERTY layout (see https://bugzilla.gnome.org/show_bug.cgi?id=692721).

From what I understood this is caused by gtk handling the keyboard events itself, instead of waiting for the key-value that the operating system provides.

Is there a way how this can be fixed? Either in Bluefish or in GTK?

Statuses

Engaging developers

In Bluefish,Gnome,gtk+,open source,Programming on March 22, 2014 by oli4444

As Bluefish developer I’m not really tightly involved with gnome and gtk development. However, it is our platform, and although we ship OSX and Windows binaries, most of our users are on Linux, many of them using Gnome. We are as much affected by a gtk bug than any other gnome part. So if we find any, we try to contribute.

However, for some reason it feels that our “outside” contributions are not so welcome. I believe this is not intentional, but still this is not a good thing. So what makes me feel that these contributions are not so welcome? The lack of feedback and results.

An example: In 2012-09-05 I filed a bugreport https://bugzilla.gnome.org/show_bug.cgi?id=683388 with a patch to improve the GList documentation. I noticed that new developers often make trivial mistakes (for example appending in a loop). I got some feedback and reworked the patch, submitted on 2012-09-12. And then nothing happened anymore. For 1 year and 4 months there was a total silence. I was originally planning to work trough all of the glib documentation to make it easier for novice programmers to work with, but this result was not really motivating me to do any more work on glib. Until on 2014-01-20 the bug was closed with “fixed”. A tiny bit of documentation was added, but the majority of the patch was not committed. Perhaps it was considered low quality, but at least tell the contributer! And tell how to improve it!

A second example: Early this year a reproducible way to crash Bluefish was reported. We realized the bug was not in Bluefish but in Gtk, GtkTreeModelFilter to be more specific. Instead of just filing a bugreport with the problem, we tracked down the problem and found how to fix it, and filed that in bugzilla https://bugzilla.gnome.org/show_bug.cgi?id=722058 For us this is a critical bug. It makes Bluefish crash. It’s now three months later, and nothing has happened. I’m afraid that the next major gtk release will still have this bug, and Bluefish will remain a crappy application because it crashes because of this bug in gtk.

We should improve this! This is not the way to attract new developers! On the contrary, this does discourage new developers!

End note: I realize that I am not heavily involved with gtk or gnome. So there might be many valid reasons why the above two examples are completely wrong. Perhaps my complete feeling about the feedback and results is wrong. Perhaps my expectations are completely unrealistic. But if I have this feeling, there might be more occasional contributing developers that have this feeling. So we could at least then try to explain the true situation.

End note 2: I’m not a native English writer. So if my language was blunt or rude in any way to any person: this was really not intentional and I apologize. I don’t want to attack anyone. I don’t want to complain. I just want to send a signal that we can do better and should do better.

Statuses

a weird for loop

In Bluefish,Programming on November 5, 2013 by oli4444

Today I had the weirdest debugging session ever. A bug https://bugzilla.gnome.org/show_bug.cgi?id=704108 was reported that I could reproduce on Fedora 19, but not on Fedora 18, not on OSX, not on Ubuntu 12.04 (tried both 32bits and 64bits), and not on Ubuntu 13.10.

The bug report mentioned that the highlighting engine did not end single line comments on the first newline. First I tracked this down to a difference in the compiled DFA table. After further debugging I found that a variable in the language file compiler was not set correctly. This variable, only_symbols was defined in a loop:

gboolean only_symbols = TRUE;
gint j;
for (j = 0; j <=127 ; j++) {
  if (characters[j] == 1 && !character_is_symbol(st,context, j)) {
    only_symbols = FALSE;
    break;
  }
}

what I found: j not only loops from 0 to 127, but continues far beyond that number!?!? The function character_is_symbol() is a simple array lookup.

I even added an extra check inside the loop

if (j > 127) {
   g_assert_not_reached();
}

but although j reached values of 10000, this assertion was never reached????

The fix for the bug was to reverse the loop:
for (j = 127; j >=0 ; j--)

I am still completely baffled by this bug. How is this possible? Does this have to do with loop vectorization? Is this a bug in gcc? Is this a bug in my code? What is going on?

edit: thanks for your comments. It most likely was a combination of a 1-over array size (undefined) with the aggressive loop optimization that the latest gcc has (which then seems to remove the condition in the loop). Problem solved, code fix in svn!

Statuses

Icons in the file tree

In Bluefish,Gnome,gtk+,open source,Programming on November 2, 2013 by oli4444

The file tree in Bluefish shows icons for the files. To do so, it has an “icon name” column in the tree model, using the special feature of the cell_renderer_pixbuf to render icons by name.

renderer = gtk_cell_renderer_pixbuf_new();
gtk_tree_view_column_set_attributes(column, renderer, "icon-name", COL_ICON_NAME,NULL);

The column COL_ICON_NAME just contains the name (as string) of the icon.

Currently, the icon name is retrieved from a GIcon. The GIcon is retrieved by asking for the property “standard::icon” in g_file_enumerate_children_async().

This means that, for every file, the code creates a GIcon object, just to get a string with the icon name. From browsing trough the glib and gio code I understand that the GIcon is searched for using the mime type, with a binary search in an array that defines all the icons.

I was wondering if I can make the Bluefish code more efficient by caching the icon names for each mime type in a hash table. This has two advantages:

  1. a GIcon object is only created once for each mime type; after we know the corresponding icon name we can do a lookup in the hash table
  2. This needs only one copy of the icon name in memory. In the treestore we can have a pointer to the string in the hash table. Currently 500 text files have 500 copies of the string “text-plain” in memory.

But does this have disdvantages? Any ideas / comments ?

Statuses

Custom GtkTreeModel for a file browser

In Bluefish,gtk+,open source,Programming on October 17, 2013 by oli4444

Similar to other IDE’s and editors, Bluefish has a filebrowser in a side pane of the GUI. Previously Bluefish used a GtkTreeStore to store the icon and filename for each file/directory. To improve speed and reduce memory usage, I recently wrote a custom GtkTreeModel to replace the old store. This is the first post on the design of the custom TreeModel. The final code can be found here: https://sourceforge.net/p/bluefish/code/HEAD/tree/trunk/bluefish/src/file_treemodel.c

Bluefish Screenshot from 2013-10-17 14:14:23

I started with the excellent tutorial from Tim-Philipp Müller http://scentric.net/tutorial/

First thing I did was modifying the tutorial code from a listmodel to a treemodel. Therefore each record has a pointer “parent”, and each record should store it’s children.

One of the design decisions was how to store children: as a linked list, or an array of records, or an array of pointers to records. Some thoughts: The linked list is faster if you have to insert an entry somewhere in the middle, or remove one (with an array this requires realloc()). The array is faster if you need the nth element (with a linked list you need to traverse the list). The array also brings another advantage: use qsort for sorting (but the g_list_ functions have a good sort function for lists as well), and bsearch for searching if an entry exists (a linked list requires again to traverse all entries to see if an entry exists). An array of records needs more memory copying during sort, insert or delete. An array of pointers needs more memory (one extra pointer for each record).

In a file tree, most directories have the same files for most of the times. Sometimes a new file is added, or a file is deleted, but most of the time the list is stable. So I chose the array of pointers. But I’m still doubting if I should have chosen an array of records.

The minimal record looks like this:


struct _UriRecord {
gchar *name;
UriRecord *parent;
UriRecord **rows;
guint num_rows;
};

The file browser pane in Bluefish shows icons, and can show a name in bold or normal weight. The compare function for sorting returns directories before files, so I need to know if a record is a directory or a file. Bluefish also has filtering possibilities based on filename or mime type. So these properties are all added to each record.

Because I chose an array of pointers, it is costly to find the next item in the array from a record. Therefore I added the position in the array as property. The next one is simply pos+1. This has another advantage: after sorting, the TreeModel needs to inform all listerers that the order has changed. For that you need the old and the new order. Since the old order is stored in pos this is easily done in a loop over the array.

In the Bluefish code I oten need to convert from a GFile to a position in the TreeModel and vice versa. I therefore added a hash table to the treemodel with the GFile as key and the record as value. Since a GFile is refcounted, It takes only a pointer to add it to the record as well.

At last I need a way to refresh directories when I re-read them. I could simply delete them all, and add them again, but that would also delete the sub-directories. So I added a “possibly_deleted” property that is set to 1 before directory re-read, and set to “0” if an entry still exists. After closing the directory every record that still has “possibly_deleted” set to 1 can be removed.

To reduce memory usage, I changed several properties to 16bit or 8bit values. This requires an extra shift when accessing the properties, but with many records it reduces memory usage. These are the properties that are only needed when the records change (and directories are usually pretty stable).

The resulting record looks like this:


struct _UriRecord {
gchar *name;
gchar *icon_name;
gchar *fast_content_type;
GFile *uri;
UriRecord *parent;
UriRecord **rows;
guint16 num_rows;
guint16 pos;
guint16 weight;
guint8 isdir;
guint8 possibly_deleted;
};

On 64 bit systems this results in: 6*8bytes + 3*2bytes + 2*1byte = 56 bytes per record.

On 32 bit systems this results in : 6*4bytes + 3*2bytes + 2*1byte = 32 bytes per record.

More about this code in a few days. Any comments how this design could be improved? Please post a comment.

Statuses

The recent menu

In Bluefish,Gnome,gtk+,open source,Programming on July 4, 2013 by oli4444

The Bluefish mailinglist currently has a discussion on the working of the recent files menu. The current recent files menu in Bluefish shows the N most recent items that are not currently opened.

So if you have 15 items in the recent list, but 10 of them are currently open, Bluefish will only show 5.

Many other programs have a different approach: show all recent files, regardless if they are open or not. In the example above, depending on N, the list would either show 15 files, and only the last 5 would be actually useful (they open a file that is not open yet), or the list would show 5 files, all of them would be open already.

In a text editor like Bluefish you usually have many files open (I consider 10 files open very normal usage). So showing only files that are already open, or showing a very long list where only the last items are useful doesn’t look like a good user interface design to me.

But what to do now? Having a different behavior makes the learning curve for new users higher. What do you think is the best design for a recent files menu?