Skip to content

Wrapping GObject for pygtk – a real world example

01/08/2009

How I wrapped scintilla

In this article I will tell you my journey wrapping pygtkscintilla, I think this could be useful to tell other people which mistakes I made and how I’ve solved them.

Know your enemy

To solve a problem you have to gather all possible information relate to this problem. Scintilla has a scary interface that have nothing to do with a well-formatted gtk-widget.

The interface is a very important thing. If you wanto to wrap scintilla you have to learn the basics of its usage.  Fortunately there was bait, an example  to test scintilla, it’s cast gold.

Here’s the code:

/* bait.c */
#include <gtk/gtk.h>

#include <Scintilla.h>
#include <SciLexer.h>
#define PLAT_GTK 1
#include <ScintillaWidget.h>

static int exit_app(GtkWidget*w, GdkEventAny*e, gpointer p) {
 gtk_main_quit();
 return w||e||p||1;    // Avoid warnings
}

int main(int argc, char **argv) {
 GtkWidget *app;
 GtkWidget *editor;
 ScintillaObject *sci;

 gtk_init(&argc, &argv);
 app = gtk_window_new(GTK_WINDOW_TOPLEVEL);
 editor = scintilla_new();
 sci = SCINTILLA(editor);

 gtk_container_add(GTK_CONTAINER(app), editor);
 gtk_signal_connect(GTK_OBJECT(app), "delete_event",
 GTK_SIGNAL_FUNC(exit_app), 0);

 scintilla_set_id(sci, 0);
 gtk_widget_set_usize(editor, 500, 300);

#define SSM(m, w, l) scintilla_send_message(sci, m, w, l)

 SSM(SCI_STYLECLEARALL, 0, 0);

And this is the Makefile associated:

##### Makefile #####
# Make file for bait on Linux or compatible OS
# Released to the public domain 2000 by Neil Hodgson neilh@scintilla.org
# This makefile tested with GCC 3.2 and GNOME 2.0

.SUFFIXES: .c .o .h .a

INCLUDEDIRS=-I../scintilla/include
CXXFLAGS= -DGTK -DSCI_LEXER -W -Wall -fPIC
LEXEROBJS=$(wildcard ../scintilla/gtk/Lex*.o)

all: bait

.c.o:
 gcc `pkg-config --cflags gtk+-2.0` $(INCLUDEDIRS) $(CXXFLAGS) -c $< -o $@
bait: bait.o $(LEXEROBJS) ../scintilla/bin/scintilla.a
 gcc `pkg-config --libs gtk+-2.0 gthread-2.0` -lstdc++ -DGTK $^ -o $@
clean:
 rm -rf bait *.o
&#91;/sourcecode&#93;

I noticed:
<ol>
	<li>How to initialize a scintilla editor</li>
	<li>How to interact with it. It uses just the SSM macro:  scintilla_send_message function.</li>
	<li>With the Makefile associated, how to compile and run it.</li>
</ol>
Once I've done this,  I needed a good interface to respond codegen (utility used to wrap gtk widgets, explained in the <a href="https://pygabriel.wordpress.com/2009/07/22/wrapping-gobjects-for-pygtk/" target="_blank">wrapping tutorial</a>).
<h3>It's time to start wrapping</h3>
There was 2 possibilities:
<ol>
	<li>Write myself the widget in C.</li>
	<li>Search the web for someone that have already done this.</li>
</ol>
I'm really lazy, I searched a lot on the web and I've found some alternatives:
<ul>
	<li>The geany editor: there was some files that wrapped the scintilla interface in a more convenient manner, however it wasn't well-formatted because they don't use intensively the C/GObject system.</li>
	<li>The anjuta editor:  They use a well formatted editor widget that wraps scintilla but there were interdependencies related to anjuta.</li>
	<li>The most natural GtkScintilla: someone have done this work long time ago, after some days I noticed that it was a very good starting point.</li>
</ul>
note: I discovered all this things browsing in the project files, reading headers and source files ( I felt like a true hacker).

I haven't modified the gtkscintilla.h header and I generated definition files. Next I wrote a simple override file and the initialization module (if you don't understand this first read the <a href="https://pygabriel.wordpress.com/2009/07/22/wrapping-gobjects-for-pygtk/" target="_blank">wrapping tutorial</a>).

With no problem I generated the wrapper, cool! (pygtk team have done a great work with codegen, I'm sad they didn't write any documentation)

Now comes the hard part...
<h3>Compiling</h3>
Welcome in the hell. Scintilla is distribuited as a static library, scintilla.a but the python module I needed was a shared library. I browsed in a sea of pain, errors, errors and errors, my module wouldn't compile.

The problem is that you can't link a static library to a shared library, the compiler tell you that you have to recompile your files with the -fPIC option. I ignored what the compiler told me, and I tried a lot of  dirty ways to make it work, without success...

After about 4 days of depression I was sorry with the wisdom of gcc compiler and I was gone in the scintilla/gtk directory to modify the makefile that compiles the scintilla stuff.

In the original makefile there was the compilation command without the -fPIC option and the command "ar" to make a static library.

The compilation commands:


.cxx.o:
 $(CC) $(CONFIGFLAGS) $(CXXFLAGS) -c $<
.c.o:
 $(CCOMP) $(CONFIGFLAGS) $(CXXFLAGS) -w -c $<

&#91;/sourcecode&#93;

Becomes:

&#91;sourcecode language='bash'&#93;
 .cxx.o:
 $(CC) $(CONFIGFLAGS) $(CXXFLAGS) -fPIC -c $<
 .c.o:
 $(CCOMP) $(CONFIGFLAGS) $(CXXFLAGS) -fPIC -w -c $<

&#91;/sourcecode&#93;

And I modified the creation of the library from static (compressed with ar) to shared (compiled with gcc -shared)

Before:

&#91;sourcecode language="bash"&#93;
COMPLIB= ../bin/scintilla.a
AR= ar
// other things //

$(COMPLIB): DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \
 CharClassify.o Decoration.o Document.o PerLine.o CallTip.o \
 ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatGTK.o \
 KeyMap.o LineMarker.o PositionCache.o ScintillaGTK.o CellBuffer.o ViewStyle.o \
 RESearch.o RunStyles.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \
 $(MARSHALLER) $(LEXOBJS)
 $(AR) rc $@ $^
&#91;/sourcecode&#93;

After:

&#91;sourcecode language='bash'&#93;
COMPLIB= ../bin/scintilla.so # MODIFIED
AR= ar
// other things //

$(COMPLIB): DocumentAccessor.o WindowAccessor.o KeyWords.o StyleContext.o \
 CharClassify.o Decoration.o Document.o PerLine.o CallTip.o \
 ScintillaBase.o ContractionState.o Editor.o ExternalLexer.o PropSet.o PlatGTK.o \
 KeyMap.o LineMarker.o PositionCache.o ScintillaGTK.o CellBuffer.o ViewStyle.o \
 RESearch.o RunStyles.o Style.o Indicator.o AutoComplete.o UniConversion.o XPM.o \
 $(MARSHALLER) $(LEXOBJS)
 gcc -shared -o $@ $^ # MODIFIED
&#91;/sourcecode&#93;

After recompiling scintilla I obtained my shared library scintilla.so !!! After this I clearly compiled and linked (reference the <a href="https://pygabriel.wordpress.com/2009/07/31/wrapping-pygtk-widgets-what-you-should-know/">basics tutorial</a>) my python module and run it without (too much) problems!

I post the pygtkscintilla makefile that compiled and linked the python module:


DEFS=`pkg-config --variable=defsdir pygtk-2.0`
CFLAGS=-I/usr/include/python2.6 `pkg-config --cflags gtk+-2.0 pygtk-2.0 gthread-2.0`  -I. -I..
CXXFLAGS=-DGTK2  
LDFLAGS=`pkg-config --libs gtk+-2.0 pygtk-2.0 pygobject-2.0 gthread-2.0`
LEXEROBJS=$(wildcard ~/workspace/pygtkscintilla/scintilla/gtk/Lex*.o)

all: gtkscintilla-wrap.c gtkscintilla-module.o gtkscintilla.o gtkscintilla.so

gtkscintilla-wrap.c: gtkscintilla.defs gtkscintilla.override
 python /usr/share/pygobject/2.0/codegen/codegen.py \
 --override gtkscintilla.override \
 --prefix gtkscintilla gtkscintilla.defs > $@

# Here's the magic!
gtkscintilla.so: gtkscintilla-wrap.o gtkscintilla.o  gtkscintilla-module.o
 gcc -shared  $(LDFLAGS) -L~/workspace/pygtkscintilla/scintilla/bin -lscintilla  $^ -o $@

gtkscintilla-wrap.o: gtkscintilla-wrap.c
 gcc $(CFLAGS) -fPIC -c $^ -o $@
gtkscintilla.o: gtkscintilla.c
 gcc $(CFLAGS) -fPIC -c $^ -o $@
gtkscintilla-module.o: gtkscintilla-module.c
 gcc  $(CFLAGS) -fPIC -c   $^ -o $@

clean:
 rm -f gtkscintilla.so gtkscintilla-wrap.c gtkscintilla.o gtkscintilla-module.o

Ok I’ve finished telling my story. I hope that my errors can help you!

Advertisements
No comments yet

Leave a Reply

Fill in your details below or click an icon to log in:

WordPress.com Logo

You are commenting using your WordPress.com account. Log Out / Change )

Twitter picture

You are commenting using your Twitter account. Log Out / Change )

Facebook photo

You are commenting using your Facebook account. Log Out / Change )

Google+ photo

You are commenting using your Google+ account. Log Out / Change )

Connecting to %s

%d bloggers like this: