GTK hacking in Pike
I’ve found out that it’s great fun programming desktop applications and of course it gets more fun the more you learn. Now I’m doing a Twitter client in Pike – my favorite programming language – mostly because I wanted to try out GTK programming in Pike. I use the good Twitter client Pino – written in Vala – and I have borrowed the concept and layout from it. I call it Tweepi.
The only major difference between Tweepi and Pino – besides they are written in different programming languages – is that Pino uses WebKit to draw the status messages where I am using good old GTK widgets – and I guess there are no bindings to WebKit in Pike for that matter
One thing I noticed is that the Gtk.Label widget sucks at displaying longer texts that line wraps. Since the label widget handles some HTML formatting I thought that it would be suitable for displaying the status messages, but the text looked like shit, line wrapping where ever it felt like. And the Gtk.TextView widget doesn’t handle formatting per default so I Googled some and found that you can format text in Gtk.TextViews by inserting Gtk.TextTags at desired positions. And since Pike has the most awesome HTML parser It was just a matter of sending the text through the parser and create some Gtk.TextTags and inserting them at the same position in the text buffer. (Well, actually it wasn’t that easy but with some help from a Python class I found on the web it was doable).
So now I have a start at something that is a Gtk.HtmlTextView – actually it inherits Gtk.TextView but has an additional method insert_html_text(string text) – and albeit quite simple at the moment it’s worth continuing on. The code for the HtmlTextView is available at my Github repository.
In general I find the GTK implementation in Pike to be pretty OK, but there exist some verbose, and tedious, stuff like getting the text from a Gtk.TextView:
- Gtk.TextBuffer b = my_textview->get_buffer();
- string text = b->get_text(b->get_start_iter(), b->get_end_iter(), 0);
which in Vala and C# would be done like:
- // Vala
- string text = my_textview.get_buffer().text;
- // C#
- string text = myTextView.Buffer.Text;
Anyway! Tweepi isn’t done yet but I think I have solved the most tedious stuff and it’s starting to become useful. It’ll probably be done in a couple of weeks and I will of course release the sources then.
Roxen Application Launcher 0.4.4
So, here’s a new release of the Roxen Application Launcher for Linux (RAL). The previous versions used my home made (sloppy so) HTTP client which didn’t handle redirects or secure connections – thank you tec for the feed back – since I had some major problems getting libsoup working with binary files like images and such. Binary files was heavily scrambled when read from or written to disk so I made my own simple HTTP client that kept the data as a byte array to prevent some underlying libraries (GLib) from fiddling with it.
But I solved the libsoup issue so now the RAL handles redirects and secure connections. This is how I solved it:
The libsoup issue
When uploading a file back to the Roxen server I use IOChannel (g_io_channel in plain C) instead of Gio. So the upload works like this:
- var sess = new Soup.SessionSync();
- var mess = new Soup.Message("PUT", get_uri());
- mess.request_headers.append("Cookie", get_cookie());
- mess.request_headers.append("Translate", "f");
- IOChannel ch = new IOChannel.file(local_file, "r");
- ch.set_encoding(null); // Enables reading of binary data
- string data;
- size_t len;
- ch.read_to_end(out data, out len);
- mess.request_body.append(Soup.MemoryUse.COPY, data, len);
- sess.send_message(mess);
And that seems to work like a charm!
When downloading data it’s a bit more tricky! Of course I tried using IOChannel in this case also but that made no difference. Downloaded images ended up 4 bytes long! But then I thought: You can make your own C bindings in Vala (remember the Vala compiler generates C code) through what is called Vapi files. So what I did was writing a C function that takes a SoupMessageBody object/struct passed from Vala and writes the data part to a file given as argument.
- gboolean save_soup_data(SoupMessageBody *data, const char *file)
- {
- FILE *fh;
- if ((fh = fopen(file, "w")) == NULL) {
- fprintf(stderr, "Unable to open file \"%s\" for writing!\n", file);
- return FALSE;
- }
- int wrote = fwrite(data->data, 1, data->length, fh);
- if (wrote != (int)data->length) {
- fprintf(stderr, "wrote (%d) != data->length (%d). Data may have been "
- "truncated", wrote, (int)data->length);
- }
- fclose(fh);
- return TRUE;
- }
And this was then made available to Vala by the following Vapi file:
- [CCode (cprefix = "", lower_case_cprefix = "", cheader_filename = "")]
- namespace Soppa // Soppa is Swedish for Soup ;)
- {
- [CCode (cname = "save_soup_data")]
- public bool save_soup_data(Soup.MessageBody data, string file);
- }
And this is how the actual Vala code downloading the files looks like:
- var sess = new Soup.SessionSync();
- var mess = new Soup.Message("GET", get_uri());
- mess.request_headers.append("Cookie", get_cookie());
- mess.request_headers.append("Translate", "f");
- sess.send_message(mess);
- if (mess.status_code == Soup.KnownStatusCode.OK) {
- // Here I call the C function made available through the Vapi file
- if (Soppa.save_soup_data(mess.response_body, local_file)) {
- message("The file was downloaded and written to disk OK");
- }
- else {
- message("Failed writing data to disk!");
- }
- }
So that’s that on that!
The notification
I also – just for fun – implemented a notification mechanism through libnotify. Since I believe that can be rather annoying it’s not activated by default but can easily be activated by a checkbox in the user interface.
The packages
The Roxen Application Launcher for Linux can be downloaded at the download page at Github where also the work in progress sources is available or downloaded below!
Roxen Application Launcher 0.4.4 23:06, Wed 13 January 2010 :: 373.5 kB
Stay black!
Extracting text from PDFs

Unwanted line breaks in text copied from PDF
Anybody working with information sooner or later have to copy and paste text from PDF-files. And anybody who has done that knows what a pain in the a** that is! You get actual line breaks from the visual line breaks in the PDF. The other day I began a job where I have to copy and paste text from a whole bunch of PDF files and it didn’t take long before I almost exploded with anger
So I thought: Why not make a simple application that extracts the text from the PDF and – to the most possible degree – normalizes the unwanted line breaks.
And then there was Textifyer
So I fired up Visual C# Express and started hacking. I soon found the PDFbox component – using IKVM.NET – and it didn’t take long before I had some code that actually extracted the text from a PDF file. (a PDF extraction in C# howto)
I figured out how to detect unwanted line breaks: Each line with an unwanted line break ends with a space character. Lines with a wanted line break doesn’t (in 99% of the cases). So it is just a matter of of looping over the lines and if it ends with a space skip adding a line break and just append it to the previous text buffer.

Unwanted line breaks removed
So now I just have to clean up the interface and bug test the program – which will happen automatically since I’m copy and paste from a whole bunch of PDFs at the moment. When I feel it’s working alright I will release the program. It’s really nothing hardcore about it anyway

Of course there’s drag-n-drop support!
Bitlyfier – A Bit.ly client for GNOME
For those of us tweeting – or sharing web addresses in general – these long addresses with extensive query strings you wan’t to share isn’t too user friendly. So we have Bit.ly, among others, that lets you shorten a URL – or give it an alias if you like – and also gives you statistics on how many clicks it has and if it’s shared on Twitter and what not.
Since I’m on the quest of learning the programming language Vala I though why not making a Bit.ly desktop client for GNOME. So I did!
The desktop client
There’s really nothing extraordinary about it, in fact it’s quite simple. Put a long URL in the input field and hit “OK”. You’ll get the shortened URL back in the same input field.
NOTE! The screenshots is showing the Swedish translation but the interface is orginally in English.
Shortening a long URL

The shortened URL

To use the application you will of course need a Bit.ly account. The first time Bitlyfier is launched it will ask for your Bit.ly account settings. Just fill in your username and API key (it’s found on your account page at http://bit.ly/account).
Bitlyfier account settings

The command line interface
For the hacker you, Bitlyfier can also be used as a command line tool. These are the options:
- Usage:
- bitlyfier [OPTION...] - Bitlyfier, URL shortener/expander
- Help Options:
- -h, --help Show help options
- Application Options:
- -e, --expand Expands the given URL
- -s, --shorten Shortens the given URL
- -n, --no-gui Sets the application in command line mode
- -g, --gconf Invokes setting username and apikey
NOTE! You should quote the value of the ‘-s’ flag. If the URL to be shortened
contains a querystring with ampersands the URL will be truncated if it’s not
quoted.
So to shorten a long URL do like:
user@machine:~$ bitlyfier -n -s "http://domain.com/long/url/to/shorten"
The Vala Bitly API classes
The Bitly API class I’ve written can of course be used standalone (it’s located in src/bitly.vala in the sources package downloadable below). Here’s an example of usage:
- // main.vala
- // Compile: valac --pkg gee-1.0 --pkg json-glib-1.0 --pkg libsoup-2.4 -o main
- int main(string[] argv)
- {
- Bitly.Api api = new Bitly.Api("username", "R_the_api_key");
- Bitly.Response response = api.shorten("http://domain.com/the/long/url");
- stdout.printf("Short URL: %s\n", response.get_string("shortUrl"));
- response = api.stats("A2ma2z");
- stdout.printf("Clicks: %d\n", response.get_integer("clicks"));
- return 0;
- }
More about the Bit.ly API and what the API methods do can be read about at http://bit.ly/6HIqjS.
The sources
The development sources of this application is available at Bitlyfier at Github. The current stable release can be found at the Download page.


