Overview
GTK+
programming in C++ is more
efficient and more powerful than
programming in C, and with the Xfce Foundation Classes (XFC) it's
easier
and a lot more fun. By combining the power of GTK+ and the
power
of C++, XFC provides the programmer with a well
integrated
set of C++ classes that wrap most of the functionality found in the
GTK+ libraries. The Xfce Foundation Classes is divided into two main
libraries: libXFCcore and
libXFCui, but other add-on libraries planned, such as libXFCde which
will provide a C++ interface for the Xfce core libraries.
The libXFCcore library wraps the GLib object system and selected
objects
from the GLIb utility library. Essentially, it provides a low level
object system that can be used to build other libraries; libXFCui
depends
on this library. libXFCcore uses the new libsigc++
2.0 callback library to implement a typesafe system of signals and
slots that makes using native GObject signals or creating your own very
easy. There is a standard string compatible UTF-8 string
class, a complete reference manual and several test programs.
The libXFCui library is a state-of-the-art graphical user interface
toolkit for developing GTK+ applications in C++. There are more than
420 classes that wrap most of the objects found in the ATK, GDK,
Gdk-Pixbuf, GTK and Pango libraries. Included is a C++ version of the
GTK+ widget demonstration
program, a full set of simple
example programs, several test applications, an extensive reference
manual
and a tutorial.
License
The
Xfce Foundation Classes is
released under the GNU Lesser General
Public License so it can be
used to develop open software, free software, or even
commercial non-free software without having to spend
anything for licenses or royalties.
Installation
The
first thing to do of course
is
download the XFC source code and install it. You can always get the
latest version from
http://xfc.xfce.org.
You can also view other sources of information online. XFC uses
GNU autoconf for configuration, so once untar'd run configure with the
--help argument to see a list of options. You should use the
GNU
compiler version
3.3.2 (or higher) to compile XFC.
The libXFCcore library has the following dependancies:
Most
Linux distributions include these packages. Just make
sure that
the development packages are also installed on your system. Once XFC is
installed you will find a complete reference manual and a tutorial
in the <docs> directory. If the API reference manual is
missing
for some reason,
don't
worry. It's
very likely
your Linux distribution comes with a program called Doxygen,
which should be in your <usr/bin> directory. XFC will use
Doxygen to
compile the API reference manual from special comments in the header
files, when you run make for the first time.
You can compile and install XFC with the following commands run in the
top-level
source directory:
$
./configure
--prefix=directory
$ make
$ make install
The
'--prefix' argument takes the
directory
where you want XFC installed. If the directory is omitted XFC
will install itself into the <usr/local>
directory. By default, configure builds libXFCcore and libXFCui with
debugging and compiler symbols so you can debug your applications
during development. If you want libXFCcore and libXFCui built without
debugging symbols, run configure with the following option:
./configure
--disable-debug
Alternativley, you can install the libXFCcore and libXFCui libraries
with
all debugging symbols stripped out by calling:
make
install-strip
The stripped libraries are much
smaller, and faster: libXFCcore is just 220 kbytes and libXFCui is 2.3
megabytes.
If you don't want to build the API reference, or if you don't have
Doxygen installed, run configure with the following option:
./configure
--disable-docs
Other configure options include: --disable-demos, --disable-examples
and --disable-tests, which disable the implied feature so it wont
get
compiled.
Documentation
The
Xfce Foundation Classes comes
with extensive documentation that you
can refer to when you need help. You will find all the documentation in
the XFC <docs> directory. The documentation is
divided
into a FAQ sheet, numerous HOWTOs with examples, an API reference
manual and a
tutorial.
The <docs/faq> subdirectory has a FAQ sheet that answers
several
commonly asked questions about XFC generally, and about GTK+
programming with
XFC. The
<docs/howto> subdirectory is a respository for a large
number of
HOWTOs that cover everything from general information and library
structure to individual widget programming. The
<docs/reference>
subdirectory contains a complete API reference manual. This manual is
compiled
by
Doxygen
from
special comments in the XFC header files. Every typedef, enum and
class is documented, including all public and protected member
functions and signals.
The
XFC Tutorial
There
is a good GTK+ programming tutorial in the
<docs/tutorial>
subdirectory.
This tutorial was designed with new GTK+ programmers in mind, so if
that's you,
and you take the time to work through each chapter you should gain a
clear understanding of the basics of GTK+ programming in C++ using XFC.
If you are already
familiar with GTK+ progamming in C you should still find the first
seven chapters helpful because they take you through you the
basics of XFC programming.
The tutorial starts off in chapter one by creating a basic application,
XfcApp, which is nothing more than an empty main window. In chapters
two and three, two simple applications are created: Hello World and
Hello Buttons, which serve to introduce you to important topics such as
packing widgets, libsigc++ signals and slots, and virtual signal
classes. The concept of 'packing
widgets' is especially important because it forms the basis of user
interface design in GTK+. The interesting stuff really begins in
chapter four. Starting with the XfcApp program from chapter one,
successive chapters take you through the process of enhancing XfcApp,
adding features such as an action-based menubar and toolbar, a
composite statusbar that looks and behaves just like a GNOME appbar,
and a client area that responds to mouse button events by displaying a
pop up context menu.
The tutorial finishes off by covering two important topics that are
essential for new
programmers. Chapter eight takes you
step-by-step through the process of turning XfcApp into a GNU compliant
autotools project. Then chapter nine shows you how to add international
support. If you already know how to build a GNU autotools project and
how to add international support, you can skip these two chapters.
Examples
and Test Programs
Several
sources of well documented example code are provided to help you get
started with XFC programming. There is the widget demonstration program
(xfc-demo) in the <demos/xfc-demo> subdirectory that uses
many of
the available widgets, including newer ones like EntryCompletion,
Expander and UIManager. In the <examples> directory there
are a
lot
of example programs. Each program focuses on the use
of a particular widget group and has an associated widget HOWTO in the
<docs/howto> subdirectory. In the <tests>
directory there
are
several test programs that take you step-by-step through the process of
using the
latest GTK+ widgets, like action-based menus and toolbars, combo
boxes and the new FileChooser widget. The <tutorial>
directory
contains the full source code for the examples used in the XFC tutorial.
Header
Files
The
XFC header files are well set
out and easy
to read. Each header file wraps one GTK+ object along with any helper
classes, enums and typedefs it needs. Any other header files
included are
wrapped in an include guard to prevent multiple inclusions when
compiling. The header
file of a derived class always includes the header file of its
immediate base
class. This means you only have to include the most derived header file
to include all the header files in an object's inheritance path. For
example, including <xfc/gtk/dialog.hh> also includes
<xfc/gtk/window.hh>, <xfc/gtk/bin.hh>,
<xfc/gtk/container.hh>
and <xfc/gtk/widget.hh> so you wouldn't need to include
these header files.
A typical header file has the following layout:
#ifndef
XFC_GTK_BUTTON_HH
#define XFC_GTK_BUTTON_HH
#ifndef XFC_GTK_BIN_HH
#include <xfc/gtk/bin.hh>
#endif
#ifndef __GTK_BUTTON_H__
#include <gtk/gtkbutton.h>
#endif
namespace
Xfc {
namespace
Gtk {
class
Button : public
Bin
{
Button(const
Button&);
Button& operator=(const
Button&);
protected:
//
Constructors
explicit
Button(GtkButton *button, bool
owns_reference
= false);
//
Signals
typedef
G::Signal0<void>
ClickedSignalType;
typedef
G::SignalProxy<TypeInstance, ClickedSignalType>
ClickedSignalProxy;
static
const
ClickedSignalType clicked_signal;
public:
//
Constructors
Button();
virtual
~Button();
//
Accessors
GtkButton*
gtk_button() const;
operator
GtkButton* () const;
bool
get_use_underline()const;
//
Methods
void
clicked();
void
set_use_underline(bool
use_underline);
//
Signal Proxies
const
ClickedSignalProxy
signal_clicked();
};
} //
namespace Gtk
} //
namespace Xfc
#endif
// XFC_GTK_BUTTON_H
This
cut down version of
<xfc/gtk/button.hh> should
help you better understand the XFC header files. As you can see the
class members have a specific organization. First all private
members are declared, then any protected members, and last the public
members. I find this layout helpful in understanding how an
unfamiliar object works.
The
copy constructor and
assignment operator are declared private to
prevent inadvertent copying. Most objects will have a
protected
constructor like Gtk::Button's. This constructor wraps a pointer to a
new GtkButton object and sets its 'owns_reference' flag to false,
telling XFC
that initially the button is in an unowned floating state with a
reference count of 1. Next any protected accessors and
methods
are declared and then any
properties
and
signals.
The button class
declares no properties. Gtk::Button has six protected signals but only
one is shown here: the clicked_signal. You would not connect a function
slot to a protected signal directly because it requires an object
instance. If you did, you would do it like this:
clicked_signal.connect(this,
sigc::mem_fun(this,
&MyButton::clicked_function));
Instead,
you would use the
signal's public proxy function,
signal_clicked():
Gtk::Button
*button = new
Gtk::Button("Click Me");
button->signal_clicked().connect(
sigc::mem_fun
(this,
&MyWindow::clicked_function));
As
you possibly guessed, signal_clicked() is
a convenience method that passes the
button's 'this' pointer implicitly to the protected clicked_signal.
In the public section of the button class any constructors and
the destructor are declared first, followed by any accessors, then any
methods, and last any proxy property and proxy signal functions. Most
classes
have two public accessor functions similar to these:
GtkButton*
gtk_button() const;
operator
GtkButton* () const;
The
first function, gtk_button(),
is an inline function that returns a pointer to the underlying
GtkButton object. The last function is Gtk::Button's
conversion operator. It does an implicit conversion from a
Gtk::Button object to a GtkButton pointer safely, by testing for
null. The proxy signal functions are declared last and are
inline functions that return a temporary proxy object that makes the
signal connection.
Virtual
Signal Classes
XFC
does not declare virtual
signal handlers in the widget classes.
Instead, they are declared in a separate class hierarchy to minimize
the overhead associated with implementing
large numbers of virtual functions. If you want to override one or more
virtual signal handlers for a widget class, your class must multiplely
inherit
from an appropriate signal handler class.
For example, if you wanted to override the "delete_event" signal
handler you would declare your window class like this:
#include
<xfc/gtk/window.hh>
#include
<xfc/gtk/widgetsignals.hh>
class
MyWindow
: public
Gtk::Window, protected
Gtk::WidgetSignals
{
protected:
virtual
bool
on_delete_event(const
Gdk::EventAny& event);
public:
MyWindow();
virtual
~MyWindow();
};
and
you would define the window
constructor like this:
MyWindow::MyWindow
: Gtk::WidgetSignals(this)
{
}
Each
widget that receives GTK+
signals has a corresponding signal
class. Your class can multiplely inherit from this signal class or one
of its
ancestor signal classes. In the above example, MyWindow could have
inherited from Gtk::WindowSignals but it only needs to override
on_delete_event(), so it inherits from Gtk::WidgetSignals. There is one
important point to note here. A signal class header file should be
included
after the include for the corresponding widget class header file. This
is because
signal class header files do not include widget class header files.
Compiling
an XFC Application
To
compile an XFC application you
need to use pkg-config which can be
obtained from
http://www.freedesktop.org.
pkg-config is a tool for managing library compile and link flags during
make file exceution. It reads the xfcui-X.X.pc file (X.X is the version
number)
which comes with XFC to
determine what compiler switches are needed to compile an XFC program.
The --cflags option will output a list of include
directories for the compiler to look in, and the --libs option will
output the list of libraries for the compiler to link with and the
directories to find them in. For example, a typical compile command
would look like this:
g++
-Wall
-g
-O2 helloworld.cc -o helloworld `pkg-config xfcui-X.X
--cflags --libs`
Replace
X.X with the major and
minor version numbers of the libXFCui library installed on your
system. Note
that the type of single quote
used in the compile command
above is significant. The
libraries that are linked by
this command are:
- The
libXFCcore library
(-lxfccore), the core object library.
- The
libXFCui library
(-lxfcui), the application development
platform based on GTK+.
- The
GTK library
(-lgtk), the widget library, based on top
of
GDK.
- The
GDK library
(-lgdk), the Xlib wrapper.
- The
gdk-pixbuf library
(-lgdk_pixbuf), the image
manipulation
library.
- The
Pango library
(-lpango) for internationalized text.
- The
gobject library
(-lgobject), containing the type system
on
which GTK is based.
- The
gmodule library
(-lgmodule), which is used to load run
time
extensions.
- The
GLib library
(-lglib), containing miscellaneous
functions;
GTK is built on top of GLib so you will always require this library.
- The
Xlib library
(-lX11) which is used by GDK.
- The
Xext library
(-lXext). This contains code for shared
memory
pixmaps and other X extensions.
- The
math library
(-lm). This is used by GTK for various
purposes.