Blog

Blog

Emacs Corner

Posted at 23:01 on 14 Nov 2008

I seem to be making a habit of posting random snippets of Emacs Lisp code. Well today is no exception so I've got a little function to share which helps search and replace symbols in glib-style C code. For example, if you want to rename MyCleverWidget, MY_CLEVER_WIDGET and my_clever_widget to MyDumbMess, MY_DUMB_MESS and my_dumb_mess respectively then this function can do it for you in one step. You just type in the symbol with words separated by underscores and it replaces with the right version. It asks about each match like query-replace does.

(defun renamespace-get-replacement (repl-data replace-count)
  (cond ((match-string 1)
         (car repl-data))
        ((match-string 2)
         (cadr repl-data))
        ((match-string 3)
         (caddr repl-data))))

(defun renamespace (full-symbol old-namespace new-namespace)
  "Interactively replace one glib-style symbol with another.
OLD-NAMESPACE should be a symbol with words separated by
underscores (like gtk_widget). A search will then be done for
three different variants of that symbol: gtk_widget, GTK_WIDGET
and GtkWidget. Each match will be replaced with NEW-NAMESPACE
which will be converted to the right format for that match.

If FULL-SYMBOL is non-nil (prefix arg if interactive) then the
search will be anchored to a complete symbol, otherwise it can
match part of a symbol.

The replacement is done interactively the same way
`query-replace' would."
  (interactive "P\nsOld namespace, (like gtk_widget): \nsNew namespace: ")
  (let* ((parts (split-string old-namespace "_"))
         (class (mapconcat 'capitalize parts ""))
         (const (mapconcat 'upcase parts "_"))
         (func (mapconcat 'downcase parts "_"))
         (re (concat "\\(" (regexp-quote class) "\\)"
                     "\\|\\(" (regexp-quote const) "\\)"
                     "\\|\\(" (regexp-quote func) "\\)"))
         (nparts (split-string new-namespace "_"))
         (nclass (mapconcat 'capitalize nparts ""))
         (nconst (mapconcat 'upcase nparts "_"))
         (nfunc (mapconcat 'downcase nparts "_"))
         (case-fold-search nil))
    (if full-symbol
        (setq re (concat "\\_<\\(?:" re "\\)\\_>")))
    (perform-replace re ; from-string
                     (list 'renamespace-get-replacement nclass nconst nfunc)
                     t ; query-flag
                     t ; regexp-flag
                     nil ; delimited flag
                     )))

I also made a little script to export Emacs' syntax highlighting to HTML which is how I got the purdy colours above. Maybe if I tidy that up I will blog that too.

Boston GNOME summit

Posted at 11:14 on 14 Oct 2008

I spent the last week in Boston for the GNOME UI hackfest and summit. It went pretty well and it was great to see so many enthusiastic hackers from all over the world working together.

The highlight for me was a talk by David Richards about the user experience in the City of Largo project. He is a sysadmin for a large city-wide installation of Linux and GNOME which uses NoMachine to access a remote shared server. He had many surprising insights into how GNOME is perceived by regular people. For example he reported that most people just don't understand files and folders and have no idea how to move content from one application to another. And somethingty percent of his users don't know how to right-click. The upside of his talk was that he is successfully using Compiz for a full composited desktop even over a remote session and it is very well received by his users. This bodes will for a Clutter-based desktop.

We also had a session in the summit about canvases. It was entitled 'Canvas Deathmatch' but it turned into almost unanimous agreement that we should use Clutter as the standard GNOME canvas. There was surprising support for just requiring a working OpenGL implementation for GNOME 3.0 to facilitate the fancy new panel and WM discussed during the hackfest.

There was another talk by some of the Novell employees about Linux on netbooks and they were specifically trying to rally people to support the Moblin project.

I was also able to use a lot of the time to make a Clutter version of Aisleriot (which is a collection of card games in GNOME games). It replaces the custom Cairo-based canvas with Clutter and has some animations for flipping over cards. I got a chance to talk to Jason Clinton who maintains GNOME games and he seemed pretty keen to get more of the games using Clutter. He had already started work on Clutterizing Gnometris and he had no objection to just dropping support for the non-GL versions of the games. Here is a screencast of my progress so far. It still has some glitches to work out and I'd like to make the animations more fancy.

image

blame-browse

Posted at 23:50 on 16 Aug 2008

The one thing that's worse about Git compared to Subversion is that git-blame is so much harder to use than svn blame. The output from git-blame is very wide so if you run it on the terminal then often most of the line of source code will be cropped off the right edge. SVN's revision numbers are replaced with a git commit hash so it's also not immediatly obvious what the parent of a commit is from the information in git-blame. When I use either blame command, I often find the commit reported against a given line is not the change that I'm interested in so I usually want to re-run the annotation with the parent commit.

I thought it might be fun to knock up a program to browse the output of git-blame. I initially thought 'oh that's easy, that'll take about half an hour' so I cobbled together a quick program in Ruby with the GTK bindings. It was pretty quick to write because Ruby (like Perl) has excellent support for processing text. However I eventually got fed up with the Ruby GTK bindings because they are randomly missing bindings for some functions that I wanted and it's difficult to debug. After discovering this bug I got fed up and rewrote it in C. I also ended up making it much more complicated because now it tries to run git asynchronously and process the output as it comes using the glib main-loop.

So far you can see the source code for the file you've annotated with the hash of the commit for the that line. A tooltip is displayed for the commit with a short summary. If you click on the commit you get more information in a dialog and you can jump to the parent commit from there.

image

The screenshot gives away that I stole a function from ebassi's Tweet and also that I fixed a tiny bug in it :)

There's quite a lot left to do:

  • I would like to add forward and back buttons to the main window so that you can move through the history of what you have visited.
  • Searching the source and jumping to a line number are probably pretty essential.
  • It should probably use GtkSourceView instead of my crazy custom widget.
  • The UI looks nasty

I also should probably have tried to implement within the giggle source code but I didn't look at this until I'd got too far. It looks like giggle already has a lot of code to handle running git asynchrously so I could've avoided a lot of work.

The code is available on Github at http://github.com/bpeel/blame-browse

Compiling Clutter on Windows with MinGW + MSYS

Posted at 20:23 on 13 Jul 2008

I keep getting asked how to compile Clutter on Win32 now that we have a native backend so here is some instructions to compile with MinGW and MSYS on a fresh Windows installation.

First you need to install the MinGW and MSYS packages from here.

Select the top package called 'Automated MinGW Intaller' and download the exe of the latest version. Run the executable and install to the default location. Make sure you DON'T install 'MinGW make' to make life easier.

Next download the 'MSYS Base System'. Use the .exe installer from 'Current release' (not the technology preview). Run the executable and install to the default location. Answer yes to whether you want to continue with the post install and tell it the location where you installed MinGW (which should be c:/MinGW).

Next install the 'MSYS supplementary tools'. Again select .exe from the current release and install it to the default location.

To make downloading the dependencies for Clutter easier, we want to be able to run the mingw-cross-compile.sh script which will do some of the leg work automatically. However to do this we first need some extra utilities.

Make a directory called c:/msys/1.0/clutter-work and another directory called downloads under that. Go back to the SourceForge page for MinGW and select the 'User Contributed: mingwPORT' section. Download the wget tarball to the newly created downloads folder.

Start MSYS and type the following to install wget.

cd /clutter-work/downloads
tar -jvxf wget-1.9.1-mingwPORT.tar.bz2
cd wget-1.9.1/mingwPORT
mkdir /usr/src
PATH="$PATH":"$PWD" ./mingwPORT.sh 

Press enter at each question to just use the default

Next we need to install unzip.exe which we can get from the GNUWin32 ports. Visit here and download the 'complete package, except sources'. Install it to the default location.

Now we can type the following to download and install the clutter dependencies using the helper script:

cd /clutter-work
wget -O downloads/mingw-cross-compile.sh \
'http://svn.o-hand.com/view/*checkout*/clutter/trunk/clutter/build/mingw/mingw-cross-compile.sh'
PATH="$PATH:/c/Program Files/GnuWin32/bin" sh ./downloads/mingw-cross-compile.sh

Press enter to all of the questions to get the default except the 'Do you want to download and install Clutter...' questions because these will try to use SVN which we don't have installed.

Next we need to install pkg-config to get Clutter's configure script to work. Type the following:

cd /clutter-work/downloads
wget 'http://pkgconfig.freedesktop.org/releases/pkg-config-0.23.tar.gz'
tar -zvxf pkg-config-0.23.tar.gz
cd pkg-config-0.23
prefix=/clutter-work/clutter-cross
libdir="${prefix}/lib"
includedir="${prefix}/include"
CFLAGS="-g -O2 -Wall -I${includedir}/glib-2.0 -I${libdir}/glib-2.0/include" \
LDFLAGS="-L${libdir} -lglib-2.0 -lintl -liconv" \
./configure
make all install

Now we should finally be ready to compile Clutter:

cd /clutter-work/downloads
wget http://www.clutter-project.org/sources/clutter/0.8/clutter-0.8.0.tar.bz2
cd ..
tar -jvxf downloads/clutter-0.8.0.tar.bz2
cd clutter-0.8.0
PKG_CONFIG_PATH=/clutter-work/clutter-cross/lib/pkgconfig \
 PATH="$PATH:/clutter-work/clutter-cross/bin" \
 CFLAGS="-mms-bitfields -I/clutter-work/clutter-cross/include -g -O2 -Wall" \
 ./configure --prefix=/clutter-work/clutter-cross --with-flavour=win32
make all install

Now to prove that it worked we can run test-actors. Windows needs the Clutter DLL to be in the system path for this to work so type the following:

export PATH="$PATH:/clutter-work/clutter-cross/bin"
cd /clutter-work/clutter-0.8.0/tests
.libs/test-actors

If you want to compile a simple app without using autotools, it's easiest to use the libtool generated in the Clutter source so that it can work some voodoo with the included libraries. This assumes you've still got your path set up from the previous test:

libtool --mode=link gcc -Wall -g -o simple-app simple-app.c \
-I/clutter-work/clutter-cross/include \
`PKG_CONFIG_PATH=/clutter-work/clutter-cross/lib/pkgconfig pkg-config clutter-0.8 --cflags --libs`

Enjoy!

Abusing Clutter

Posted at 22:57 on 06 Jun 2008

I thought it might be fun to see how easy it is to use Clutter with full 3D actors instead of just flat rectangles. I started off by thinking I could make something like a table tennis game with a proper model for a table and the bats. I made a model for the table with a bit of wrestling with Blender so I needed a way to display the model in Clutter.

I decided to write a library to display MD2 models as a Clutter actor. MD2 is the model format from Quake 2 for players and weapons. It seemed like a good format because it's quite simple and it already represents the model as a set of triangle fans and triangle strips so it fits nicely with OpenGL.

The result of that is available in a git repo here:

git clone git://github.com/bpeel/clutter-md2.git

You can create an actor from an MD2 file by passing it the filename. When painting the model it scales the coordinates to fit in the width and height of the actor while preserving the aspect ratio (so you can position it easily with other pixel-based actors). You can rotate and move the actor with the regular actor API. There is also a new behaviour to animate the model using the frames in the file. The frames are interpolated as key frames to make the animation a bit smoother.

image

I didn't have much luck with the MD2 exporter of Blender because it kept complaining that I'd scaled the model and it made a mess when it tried to convert it to triangles. So for now I've given up on the table tennis game and started making a simpler game to demonstrate the library using the ready-made MD2 models from here.

The game creates a scrolling road (made entirely out of ClutterRectangles) and animates driving past some tractors in a car (which are MD2 models). You can move the car with the arrow keys, but other than that it needs a lot of work.

image

The git repo for the game is at:

git clone git://github.com/bpeel/tractordodge.git