Archive for the ‘Programming’ Category

t

Last week I received an email if Bluefish could be improved for people with a visual impairment. I never occurred to me that there would be people with limited vision wanting to use Bluefish. The most requested features in the email were:

  1. Zoom in/out with ctrl+ / ctrl-
  2. Maximum screen estate
  3. Better cursor visibility

The first feature was easy. Bluefish  already has zoom with ctrl-mousewheel, so I added the accelerators (it turned out that the requester was not aware of this feature).

For the second feature I created an option that automatically hides all menu bars, status bars and toolbars on fullscreen (F11). It displays them again if you hit F11 again. This way basically every bit of the screen is used by the editor itself. The only issue I found is when LXDE is used. LXDE has bound F11 to the window-manager fullscreen, so the application fullscreen never gets called. I moved my code to the configure event handler, where I can detect both the internal fullscreen as well as a window manager fullscreen.

The third feature was the hardest bit. With some help from IRC I managed to make the cursor-aspect-ratio user defined.

In gtk2 it looks like this:

style "bluefish-cursor" {GtkWidget::cursor-aspect-ratio = %f }
class "GtkTextView" style "bluefish-cursor"

which is loaded with gtk_rc_parse_string()

In gtk3it is slightly nicer:

GtkTextView {-GtkWidget-cursor-aspect-ratio: %f;}

which is loaded with gtk_css_provider_load_from_data() and gtk_style_context_add_provider()

Next to a bigger cursor I made a setting to highlight the cursor position: it paints a differently coloured background on the character left and right of the cursor. I connected that to the mark-set insert-text and delete-range signals, the last two with g_signal_connect_after() to get the new location of the cursor and not the old location.

This code does have quite a performance impact: scrolling with the arrow keys is significantly slower with this option enabled. I used this code:

     gtk_text_buffer_get_bounds(btv->buffer, &it1, &it2);
     gtk_text_buffer_remove_tag(btv->buffer, btv->cursortag, &it1, &it2);
     it1 = *location;
     it2 = it1;
     gtk_text_iter_backward_char(&it1);
     gtk_text_iter_forward_char(&it2);
     gtk_text_buffer_apply_tag(btv->buffer, btv->cursortag, &it1, &it2);

What this code causes is an update the internal structure of the GtkTextBuffer (probably something like a balanced tree) that keeps track where each tag starts and stops – for every cursor move. After rethinking this I remembered this is much easier done in the expose event!

get the coordinates with gtk_text_view_get_iter_location(), convert them with gtk_text_view_buffer_to_window_coords() and paint with cairo_rectangle() and cairo_fill():

   gtk_text_buffer_get_iter_at_mark(buffer, &it, gtk_text_buffer_get_insert(buffer));
   gtk_text_view_get_iter_location(view,&it,&itrect);
   gtk_text_view_buffer_to_window_coords(view, GTK_TEXT_WINDOW_TEXT
            , itrect.x, itrect.y, &x2, &y2);
   cairo_rectangle(cr, (gfloat)x2-width, (gfloat)y2, (gfloat)(width*2 )
            , (gfloat)itrect.height);
   cairo_fill(cr);

The result is visible below. So now it is test time!

Improvements for visually impaired people

on April 29, 2012 by oli4444

Leave a Comment

t

Last days I have been debugging some weird reports. They all show the same characteristics:

  • the users are on Ubuntu 11.10
  • they use bluefish compiled against gtk 3.2 (so not the bluefish package that is provided by Ubuntu, but a newer one)
  • in the Bluefish run the sort function of a GtkTreeModelSort is called after the GtkTreeModelSort should have been finalized and free’ed.

First I used gobject-list.c from http://people.gnome.org/~mortenw/gobject-list.c to see all refs and unrefs on all GtkTreeModelSort objects in Bluefish (luckily there is only 1 used in Bluefish).This showed that there was indeed a GtkTreeModelSort with lots of references left after it should have been finalized. I tried the same thing on Fedora 16 (also gtk-3.2), but it can only be reproduced on Ubuntu 11.10.I tried to get backtraces with gobject-list (which uses libunwind for that) but those backtraces turned out to be useless.

Luckily I received some help on IRC #gtk+ from Company and alex. The first idea was to use systemtap, but since there is no useful kernel for systemtap available for Ubuntu I had to use something more low tech suggested by Company:  I set a breakpoint on gtk_tree_model_sort_new to retrieve the pointer of the GtkTreeModelSort. Once I got that pointer I could set a breakpoint on g_object_ref and g_object_unref with a condition on this pointer. Then I created an automatic backtrace on each breakpoint:

break g_object_ref if object == 0x123123123
commands
bt
c
end

I configured gdb to log everrything to a file, and did a bluefish run. This resulted in a 2.1 Mb logfile with backtraces. This log also showed there were more refs than unrefs.

In this logfile there were a lot of similar backtraces, with an identical function doing a ref and an unref. I wrote a short python script to parse the backtraces and skip all ‘valid pairs’

After this step I had only 15 backtraces left. And from these backtraces the leaking references were easily identified.

Because I was unsure if this is a Ubuntu specific bug or a generic gtk bug the resulting bugreport can be found both at https://bugzilla.gnome.org/show_bug.cgi?id=669376 and at https://bugs.launchpad.net/bugs/926889

Now I am wondering if this approach would work for any reference count leaking problem. I guess the most difficult issue is to find the value of the pointer that is leaking if you have many objects of the same type.. Any suggestions how to do this?

Debugging a reference count bug

Tagged: on February 5, 2012 by oli4444

8 Comments

t

Bluefish has a side-pane in it’s main interface, which is implemented using a GtkHPaned widget. Users may drag the handle to increase or decrease the side pane. Now lets see what happens if the user makes the sidebar smaller than the widgets in there. I created a mini example application that works with both Gtk+-2 and Gtk+-3. There is a GtkEntry in the left sidebar, and a GtkTextView on the right. This is a screenshot with Gtk+-2:

Initial view of the example application

Now see what happens if you drag the handle to the left in Gtk+-2:

Gtk+-2 making the widget smallerThe widget now becomes smaller, and it is cropped on the right side, which looks natural.

Now see what happens if you drag the handle to the left in Gtk+-3.2:

What it looks like inb Gtk+-3.2The widget is cropped from the left side, which has the content, which looks awful. Also there is a huge empty space after the “Hello World” because the GtkEntry minimum width is very large.

My suggestions for improvement:

  • decrease the minimum width of the GtkEntry to 30 pixels or so
  • when cropping widgets, crop from the right if the widget is on the left side of the handle, crop from the left if the widget is on the right side of the handle. That suggests that the user drags the handle as a layer on top over the widget which feels much more natural.

b.t.w. GtkEntry is not the only widget that has a too-large minimum width. In Bluefish we also use libgucharmap, and the gucharmap widget forces an even wider sidebar in Gtk+-3.2.

The (too large) minimum width of a GtkEntry in Gtk+-3.2

on December 14, 2011 by oli4444

2 Comments

t

Bluefish has several dialogs that use a GtkLabel with wrap enabled inside a GtkTable. Since the width-for-height changes in Gtk+-3.2 these GtkLabel’s take an enormous amount of vertical space. If this launchpad bug is correct it will use enough vertical space to put every word on a new line.

The suggestion in that bugreport is to switch to GtkGrid. This is a good suggestion, but is has a drawback. In Gtk+-2 there is no way to set widget specifc expand properties in a GtkGrid (in a GtkTable this is done with gtk_table_attach()). In Gtk+-3 new properties have been added to GtkWidget to control whether a widget may expand or not. We (Bluefish developers) try to remain compatible with Gtk+-2 at the moment. So what to do? GtkGrid may solve our problem in Gtk+-3 but causes problems in Gtk+-2, and GtkTable solves our problem in Gtk+-2 but causes problems in Gtk+-3 ?

Luckily I found a workaround:

#if GTK_CHECK_VERSION(3,2,0)
    gtk_label_set_width_chars(GTK_LABEL(label),50);
#endif

This fixes the problem with a GtkLabel with wrap in a GtkTable in Gtk+-3.2. So for the moment we stick with GtkTable with this workaround.

GtkTable and GtkLabel with wrap on Gtk+-3, and trying to stay compatible with Gtk+-2…

on November 30, 2011 by oli4444

1 Comment

t

There is a weird widget scaling issue happening with Bluefish compiled on Ubuntu 11.10 with gtk-3.2.0 that I don’t see on the same Ubuntu 11.10 with Bluefish compiled with gtk-2.24.6 nor on Fedora 15 compiled with Bluefish compiled with either gtk-3.0.12 or gtk-2.24.4.

Bluefish has a GtkHPaned widget to show a sidebar (by default on the left). Inside that sidebar is a GtkNotebook, and inside that notebook is a GtkComboBox. The text string in the GtkComboBox sometimes becomes quite long. Normally this string is just shortened by gtk as can be seen below (the string is file:///home/olivier etc. etc.):

On Ubuntu 11.10 with gtk-3.2, however, this string defines the GtkComboBox minimum width, and if you try to move the GtkHPaned handle to the left it makes all of the contents inside the GtkHPaned move to the left, outside the window border (watch the left side of the GtkNoteBook, see that one of the tabs is moved outside the window? See that the contents of the GtkTreeView are moved outside the window?):

In this example there is a long string in the active entry of the GtkComboBox, but if there is a short string active and a long string only in the popup menu, the issue still appears. So the minimum width is defined by the longest string in the GtkListModel.

In the documentation I cannot find if a GtkComboBox should shrink smaller than the text that is possibly in the popup menu. But I do know that this has never been a problem before on any gtk version up to gtk-3.0 (but Fedora 16 is not yet released, so my only Gtk-3.2 box has Ubuntu 11.10), so I’m wondering if the bug is in Bluefish, Ubuntu or Gtk?

Update 1: I can reproduce this on Fedora 16 beta, so this is not an Ubuntu issue, it is either Gtk-3.2 or Bluefish

Update 2: thanks to the comment from Benjamin Otte I fixed part of the issue by setting the ellipsize property to the GtkComboBox text renderer. However it is still not really back to normal nice behavior. The GtkComboBox furthermore has weird/buggy behavior if ellipsize is disabled. If there used to be a long string in the model, but that string is gone, it still wants a very big width. I think at least this bit is buggy.

Bluefish, Ubuntu or Gtk bug?

on October 25, 2011 by oli4444

5 Comments

t

I’m wondering which version number we should give to the next Bluefish release. Are the changes just minor, so should we use 2.0.4, or are the changes big enough to justify a 2.2.0 version number?

On the surface the changes are not very dramatic. Several new features, such as “select block” (<shift><ctrl><b>) which will select the syntax block that the cursor is in (use multiple times to get one of the the parent blocks), the block stack is displayed on the statusbar (for example “{ { /*” if you are in a comment that is in a loop in a function), and a completely rewritten search and replace engine. It can now search (and replace) recursively trough files, do both backward and forward searches, and gives more options for the regular expression searches. The quickbar feature has been removed because it turned out to be difficult to port to gtkuimanager. Perhaps it will be added again if there is a lot of demand for that.

However, under the hood there are massive changes. All of the menu and toolbar code and their calbacks have been rewritten to use GtkUIManager. The code now compiles with gtk+-3. The syntax highlighting engine has been changed a lot. The internal syntax caching structures have been rewitten, and all the code that handles that. Almost 30 commit on bftextview2_scanner.c for example, a 30k diff on a 60k file.

So from a developer point of view, 2.2.0 is justified. But from a user point of view, this should be just 2.0.4.

Next Bluefish version, 2.0.4 or 2.2.0 ?

on October 1, 2011 by oli4444

7 Comments

t

It seems to be trendy to blog about startup times. So lets talk about the recent changes bluefish startup time. So what caused the changes? The current subversion trunk compiles on gtk-3, while the latest stable release (2.0.3) did not, most notably because it uses GtkItemFactory to generate menu’s. I did several optimizations for the new code already: I moved all the bluefish-specific stock icons  from external png files to inline-pixmaps to reduce the file seek times, and I changed from seperate toolbar and menu definition files to a single file again to reduce the disk seek times.

So is the new gtk-3 compatible version faster? Both versions built against the same gtk-2 release shows that the old version was faster. On my development machine (core 2 duo 3.1 GHz) the time is too short to see a real difference (total startup took 0.6 s) So I tested this on an older computer (IBM T43 laptop with 1.8GHz Pentium M and a SSD) to make it easier to measure the startup time. I measured several times to make the results more accurate:


GtkItemFactory uses a struct that is directly compiled into the binary. GtkUIManager uses a XML format that first needs to be parsed. In Bluefish we load this file from disk which adds some seek time (but the laptop has a SSD so that should not be much). Could this change be the cause of the 0.3 s difference?

Luckily not everything is slower, the syntax scanning speed has increased a lot over the last releases. This is measured on the same laptop:

Given that the scanner engine did spend close to 50% of it’s time settings GtkTextTag’s (see the Bluefish editor widget design) the boost is pretty impressive.

Bluefish startup time

on September 16, 2011 by oli4444

1 Comment

t

For long running applications it is important that there are no memory leaks. For an application that runs for a short time the memory will be freed after the application quits, but for an application that runs for days or weeks or more, any memory that is allocated by the application should be free’ed by the application, otherwise I will not be available for other programs for a long time.

A very useful tool for memory leak debugging is valgrind. It makes your program run a lot slower (10X?) but it will resturn all interesting memory allocations that have not been explicitly free’ed. GTK does one thing that valgrind doesn’t like: the slice allocator does it owns memory management. Memory seems to be leaking, but it is ready to be used by the slice allocator. Luckily you can turn that off with the environment variable G_SLICE=always-malloc.

$ G_SLICE=always-malloc valgrind --tool=memcheck src/bluefish

valgrind will now report if you have memory leaks. To see where the leaking memory is allocated use

$ G_SLICE=always-malloc valgrind --tool=memcheck --leak-check=full --num-callers=32 src/bluefish

Valgrind will show several false positives, that is memory that gtk is allocating that is not supposed to be free’ed.

Sometimes the origin of the memory leak is not good enough, because it is a reference counted gobject, and you can’t find where the reference is increased that-should-have-been-decreased or another bug like that. A useful tool to debug that is the gobject-lifetime debugger library http://cgit.collabora.co.uk/git/user/danni/gobject-list.git/tree/ or the similar refdbg http://gitorious.org/refdbg/refdbg which is packaged for Debian.

The gobject-list library is used like this:

LD_PRELOAD=~/libgobject-list.so src/bluefish

I get a lot of output here, and there seem to many false positives (I hope, because valgrind doesn’t report them!?!). I have to play with this a little more to learn how to use it effectively.

memory leak debugging

on May 7, 2011 by oli4444

2 Comments

Post

On GList anti-patterns and good documentation

In Gnome,open source,Programming on April 15, 2011 by oli4444

Several people posted GList anti-patterns, calling the code completely broken. Although I agree such code is broken, it must be said that the glib documentation for a very long time didn’t even specify if g_list_append() would return the first or the last item of the list. I know for sure that some of the early Bluefish code called append() in a loop. Currently there is a note in the glib documentation that calling g_list_append() has to traverse the list every time. That note is a major improvement, but for a beginning programmer it would be better to show an example that g_list_prepend() in a loop followed by a g_list_reverse() is actually faster than g_list_append() in a loop.

There are quite a few linked list implementations that look like the glib GQueue implementation (so they keep a pointer to the head and the tail) in which append() is equally fast to prepend(), so programmers coming from another language or library might not even think about the difference between the two. Perhaps we should  recommend beginning programmers to use a GQueue instead of a GList ?

t

The Bluefish syntax scanning engine uses a DFA state table. To move from one state to the other we use a 16 bit unsigned integer. That means we can switch between 65536 states. But we now have a 100% complete HTML5 + SVG (+ all attributes of all tags in both languages) language definition, which needs about 70000 states.

A state table only needs to be able to switch to other states in the same context. Right now we keep all contexts in the same state table. A possible design change would be to create separate state tables for each context. That would raise the limit to 65536 states per context. Right now I cannot image which language file will hit this limit (but then, 640K memory is enough for a computer, right?)

Update: the new design is working, we have a  65536 state limit per context now, and right now no single language is getting even close to that limit.

Bluefish scanning engine: DFA state table limit reached

on March 11, 2011 by oli4444

Leave a Comment

Follow

Get every new post delivered to your Inbox.