Thursday, September 15, 2011

Portable library for C++ GUI programming

It has been for a few occasions that I find my self wanting to port my GUI programs (most of which were written with gtkmm) to other platforms for the enjoyment of my friends. However, while most GUI toolkits claim to be portable to all platforms (Linux, Windows, and Mac), they generally require installation of multiple shared libraries by the users.

This is a major show stopper for most of my friends and is sufficient to kill any interest in them on the first mention. Therefore, the only viable mean is for me to make and send them statically-linked, monolithic executables that they can happily click on to start the shows. (They generally don't mind waiting a few minutes to download a bloated binary, as long as it remains a single step.)

My recent survey of the GUI library landscape brought my attention to GLUT. While it still requires installation on Windows, I can easily find static versions of FreeGLUT library for MingW that can be used to cross-compile, on Linux, statically-linked executables that can run independently on Windows. Furthermore, the GLUT framework, which, according to this, "is installed with every install of Mac OS X".

However, GLUT library only provides facilities for managing windows and handling user inputs. It is by no means a GUI toolkit and you will have to draw all user-interactive elements by yourself (in OpenGL). I do find a GUI library, GLUI, that is built on and should be as portable as GLUT. However, after porting a couple programs to GLUI, I failed to find it enjoyable for me to break up the C++-elegant logic of gtkmm and redo my work in a less polished API.

What follows is the birth of gltk, it is an implementation of the gtkmm API on GLUT. I actually started with adding the libsigc++'s signal-slot API to GLUI since the original callback mechanism only supported single static callback function and I needed more flexibility to port my programs. But, the hack soon proliferated into the entire source tree, and I decided it would be much more enjoyable for me to start something entirely from scratch.

After a somewhat persisting part-time effort that lasted more than a month, I have just made the first release of the library. It's usable for a simple application that only needs some buttons, checkboxes, sliders, single line text labels or entries to control calculations. For myself, this represent over 80% of the applications that I would have considered porting. I am feeling pretty happy about it and I hope some others will also find it useful.

Project Homepage: http://gltk.ccdw.org/

Tuesday, April 26, 2011

Permutation

The following spaghetti prints all permutations of a string ("abcd"). I wrote it as an example to show the benefit of structured programming in my class.
#include <iostream>
using namespace std;
int main()
{
        char c[] = "abcd\n";
        int size = sizeof(c) - 2;
        int n[size + 1];
        n[size] = 1;
        int idx = size;
        char t;
new_round:
        for (int i = 0; i < idx; i ++) n[i] = i + 1;
        cout << c;
start_shift:
        idx = 0;
        t = c[0];
shift_next:
        if (n[idx]) goto shift_done;
        idx ++;
        c[0] = c[idx];
        c[idx] = t;
        t = c[0];
        goto shift_next;
shift_done:
        n[idx] --;
        if (idx == size) return 0;
        if (n[idx] == 0) goto start_shift;
        goto new_round;
}
The structured version is as follows:
#include <iostream>
using namespace std;
int main()
{
        char c[] = "abcd\n";
        int size = sizeof(c) - 2;
        int n[size + 1];
        n[size] = 1;
        int idx = size;
        char t;
        do {
                if (n[idx]) {
                        for (int i = 0; i < idx; i ++) n[i] = i + 1;
                        cout << c;
                }
                idx = 0;
                t = c[0];
                while (n[idx] == 0) {
                        idx ++;
                        c[0] = c[idx];
                        c[idx] = t;
                        t = c[0];
                }
                n[idx] --;
        } while (idx < size);
        return 0;
}
The idea is to rotate a string by n times, where n is the length of the string. While, before each rotation, rotate the n-1 substring at the front n-1 times. And while, before each rotation, rotate the n-2 substring at the front n-2 times. And so on... We can see that this is more elegantly done recursively:
#include <iostream>
using namespace std;
char c[] = "abcd\n";
int size = sizeof(c) - 2;
void rotate(int l)
{
        char ch = c[l - 1];
        for (int i = l - 1; i; i --) c[i] = c[i - 1];
        c[0] = ch;
}
void perm(int l)
{
        if (l == 1) cout << c;
        else for (int i = 0; i < l; i ++) {
                perm(l - 1);
                rotate(l);
        }
}
int main()
{
        perm(size);
        return 0;
}
The above thinking counts on the string to have all distinct chars. When this isn't the case, a different approach is to consider the lexical order of the permutations. From a given permutation, we simply need to figure out the next in the lexical order until the order is "maximized". It turns out that this is in the C++ STL. My reimplementation is as follows:
#include <iostream>
using namespace std;
void swap(char & a, char & b)
{
        char c = a;
        a = b;
        b = c;
}
// increase the order of string
bool incr(char * str, size_t len)
{
        size_t i = 1;
        while (i < len && str[i - 1] >= str[i]) i ++;
        if (i == len) return false; // no kink
        // found a kink
        size_t j = i - 1;
        while (j > 0 && str[j - 1] < str[i]) j --; // size kink
        swap(str[i], str[j]); // shave kink
        // reverse rest
        for (i --, j = 0; j < i; i --, j ++) swap(str[i], str[j]);
        return true;
}
int main()
{
        char c[] = "aabbc\n";
        int size = sizeof(c) - 2;
        do cout << c; while (incr(c, size));
}

Thursday, March 17, 2011

Building driver for AverMedia A827 on Linux kernel 2.6.38

Vendor: AVerMedia
Product: AVerTV Hybrid Volar HX
Model: A827

This is a Analog+DVB-T USB TV receiver with official support for Linux up until 2009-11-26. The latest driver can be downloaded from the product page above.

The "Normal" automatic process of installing the driver fails for 2.6.38 kernel. Using the "Expert" process to extract the driver source code to a selected location allows one to compile the driver manually and track down the problems. First, the function calls for mutex initialization are gone and should be replaced with those of semaphore initialization. Second, the Teletext support is also gone and should be eliminated from the driver source code. These fixes are summarized in this patch.

However, compiling the driver with "make" results in the WARNINGs that the symbols "param_array_get" and "param_array_set" are undefined. This is due a prebuilt object file, "aver/osdep_dvb.o_shipped", that was built with an older version of kernel. Building this file requires some internal header files from kernel source tree that are not normally available in, e.g., linux-headers or kernel-headers packages. Provided that the kernel source tree for building the running kernel is installed/available in the system, the shipped object file can be removed. After this, the "make" command can complete without incidence. Installing the drivers ("averusbh826d.ko"  "h826d.ko") to the module directory, e.g., "/lib/modules/2.6.38/kernel/drivers/media/dvb/dvb-usb" and updating the module dependency with "depmod -a", the adapter seems to work normally afterwards.

Saturday, February 26, 2011

Straightforward

We make a choice. We stick to it. We can modify it. We can change it. But, we should never forget about it.

Monday, January 17, 2011

Addiction is the lost of ability to move on

Life is a tour of the world. You come without any preconception and build up a mind of yourself. You travel through time and space, through different stages of growth and experience. And when the time comes for you to leave, you leave with nothing but your mind. Just like for any tour, moving on is just as important as moving in. If you can not, the tour will still end wherever you are.