Xfce Foundation Classes
 « Index | Basic XFC Application Hello Buttons »

Chapter 2: Hello World


Hello World is a simple program that contains one widget: a button. It's the classic 'hello world' example XFC style. The window displayed cannot be closed by the window manager. Instead, it can only be closed by clicking the button.

The header file for the Hello World program is <helloworld.hh>:

#include <xfc/main.hh>
#include <xfc/gtk/window.hh>
#include <xfc/gtk/widgetsignals.hh>

using namespace Xfc;

class HelloWorld : public Gtk::Window, protected Gtk::WidgetSignals
{
protected:
    virtual bool on_delete_event(const Gdk::EventAny& event);
    void on_hello();

public:
    HelloWorld();
    ~HelloWorld();
};

and the source file is <helloworld.cc>:

#include "helloworld.hh"
#include <xfc/gtk/button.hh>
#include <iostream>

HelloWorld::HelloWorld()
: Gtk::WidgetSignals(this)
{
    // Sets the title of the window
    set_title("Hello World");
    
    // Set the default size    of the window
    set_default_size(200, -1);
    
    // Sets the border width of the window.
    set_border_width(10);

    // Creates a new button with the label "Hello World".
    Gtk::Button *button = new Gtk::Button("Click me...");

    // When the button receives the "clicked" signal, it calls the on_hello() slot.
    button->signal_clicked().connect(sigc::mem_fun(this, &HelloWorld::on_hello));

    // This will cause the window to be destroyed by calling HelloWindow's inherited dispose method.
    button->signal_clicked().connect(sigc::mem_fun(this, &HelloWorld::dispose));

    // This packs the button into the window (a Gtk::Container).
    add(*button);

    // The final step is to display this newly created widget.
    button->show();
}

HelloWorld::~HelloWorld()
{
}

bool
HelloWorld::on_delete_event(const Gdk::EventAny& event)
{
    // When the window is given the "delete_event" signal (this is given by the window manager,
    // usually by the "close" option, or on the titlebar), the on_delete_event() slot is called.
    // If you return false a "destroy" signal is emitted. Returning true means you don't want
    // the window to be destroyed. This is useful for popping up 'are you sure you want to quit?'
    // type dialogs.
    std::cout << "delete event occurred" << '\n';
    return true;
}

void
HelloWorld::on_hello()
{
    std::cout << "Hello World" << std::endl;
}

int main (int argc, char *argv[])
{
    using namespace Main;

    init(&argc, &argv);

    HelloWorld window;
    window.signal_destroy().connect(sigc::ptr_fun(&Xfc::Main::quit));
    window.show();

    run();
    return 0;
}


Compiling Hello World

If you compiled and installed XFC yourself, you will find the source code for Hello World in the <tutorial/chapter02> source directory along with a Makefile. If XFC came pre-installed, or you installed it from an RPM package, you will find the source code in the </usr/share/doc/xfcui-X.X/tutorial/chapter02> subdirectory. In this case you will have to create the Makefile yourself (replace X.X with the version number of the libXFCui library you have installed).

To create a Makefile for Hello World, add the following lines to a new text file and save it using the name "Makefile":

CC = g++

CFLAGS = -Wall -O2

helloworld: helloworld.cc helloworld.hh
    $(CC) helloworld.cc -o helloworld `pkg-config xfcui-X.X --cflags --libs`

clean:
    rm -f *.o helloworld


If you cut and paste these lines make sure the whitespace before $(CC) and rm is a tab character. When you compile and run this program you will see the following window appear:



Stepping through the source code

The Hello World header file includes three other header files:

#include <xfc/main.hh>
#include <xfc/gtk/window.hh>
#include <xfc/gtk/widgetsignals.hh>


Every program needs to include the first header file. It provides access to library initialization functions and the main event loop. The second header file declares the Gtk::Window object and the last header file declares Gtk::WidgetSignals, the virtual signal  handler class for Gtk::Widget.

Next, a using statement is used to open the Xfc:: namespace so that type names don't need to be prefixed with Xfc::

using namespace Xfc;

The HelloWorld class is derived from Gtk::Window and Gtk::WidgetSignals. The Gtk::Window inheritance path looks like this:

G::TypeInstance <- G::Object <- Gtk::Object <- Gtk::Widget <- Gtk::Container <- Gtk::Bin <- Gtk::Window

HelloWorld redeclares the Gtk::WidgetSignals virtual on_delete_event() handler so it can override its default behaviour. Next, it declares an on_hello() method that responds to button clicks. The only other methods declared are the constructor and destructor.

The HelloWorld source file includes the following files:

#include "helloworld.hh"
#include <xfc/gtk/button.hh>
#include <iostream>

The file <xfc/gtk/button.hh> declares the Gtk::Button class. <iostream> is the C++ header file that provides access to the standard C++ stream objects, such as 'cin' and 'cout'.

Looking at the HelloWorld constructor, the first line sets the window title to "Hello World":

set_title("Hello World");

Then the second line sets the initial size of the window:

set_default_size(200, -1);

A 'width' or 'height' value of -1 tells GTK+ to use the natural size for that dimension. In this case, the height.

The next line sets the border width of the window to 10. The border is a blank area around the inside edge of the window where no widgets will go.

set_border_width(10);

HelloWorld inherits set_border_width() from Gtk::Container. Next, we create a button with the label "Click me..." and connect it to the on_hello() method using a libsigc++ slot:

Gtk::Button *button = new Gtk::Button("Click me...");
button->signal_clicked().connect(sigc::mem_fun(this, &HelloWorld::on_hello));


Obviously, the "clicked" signal is emitted when the button is clicked with the mouse pointer. signal_clicked() is the proxy signal function for Gtk::Button::clicked_signal. You can connect more than one slot to a signal. Here we connect a second slot that calls the window's inherited dispose() method so that when the button is clicked our window is destroyed.

button->signal_clicked().connect(sigc::mem_fun(this, &HelloWorld::dispose));

Just a brief word about dispose(). When you want to destroy a widget you call dispose(). There is no destroy method in XFC. The name dispose is used because it better reflects what happens when a widget is destroyed. In GTK+ 2.0, when you ask for a widget to be destroyed it may not be destroyed immediately. Instead, it gets marked for destruction and is disposed of later when its reference count drops to zero.

Next we make a packing call which that tells XFC that the button is to be placed in the window where it will be displayed. Note that HelloWorld is also a Gtk::Container and a container can only contain one widget. There are other widgets, such as boxes and tables, which are designed to layout multiple widgets in various ways.

add(*button);

The final step in the constructor is to display the newly created button by making it visible:

button->show();

The on_delete_event() handler is a bit special. It's the predefined virtual signal handler for the 'delete_event' signal. A delete_event is occurs when the window manager sends this event to the application. We have a choice here as to what to do about these events. We can ignore them, make some sort of response, or simply quit the application. The value you return from this handler lets GTK+ know what action to take. By returning true we let GTK+ know that we don't want to have the 'destroy_signal' emitted, keeping our application running. By returning false, we ask that the destroy_signal be emitted.

bool
HelloWorld::on_delete_event(const Gdk::EventAny& event)
{
    std::cout << "delete event occurred" << '\n';
    return true;
}


on_delete_event() uses a C++ console output statement to display the message "delete event occurred". It does this by using the output operator <<. The << causes whatever expression is on its right side to be output to the device on the left. 'cout' is the predefined identifier that stands for console output and refers to the computer screen. To use cout in your program you include the C++ header file <iostream>.

Next is the slot method that will be called when the button is clicked. It uses a C++ console output statement to display the message "Hello World" on the screen:

void
HelloWorld::on_hello()
{
    std::cout << "Hello World" << std::endl;
}


I assume you know about the main() function. As with other applications, all XFC applications must have one of these:

int main(int argc, char *argv[]);

After the initial using statement the first line of code calls init() to initializes the toolkit:

init(&argc, &argv);

This function initializes the library for use, sets up default signal handlers, and checks the arguments passed to your application on the command line, looking for one of the following:
  • --gtk-module
  • --g-fatal-warnings
  • --gtk-debug
  • --gtk-no-debug
  • --gdk-debug
  • --gdk-no-debug
  • --display
  • --sync
  • --name
  • --class
Any argument it recognizes is removed from the list, and 'argc' and 'argv' are modified to make it look like the argument never existed, allowing your application to parse the remaining arguments.

Next, an instance of HelloWindow is created on the stack.

HelloWorld window;

The Xfc::Main::quit() function causes the program to end. This function tells GTK+ that it is to exit from the main event loop when control is returned to it. There is no need to write a method that calls this function. Instead, we simply generate a slot for it and connect that slot to our main window's destroy signal. The next line accomplishes this:

window.signal_destroy().connect(sigc::ptr_fun(&Xfc::Main::quit));

The window widget is shown last so the whole window will pop up at once rather than seeing the window pop up, and then the button form inside of it. Although with such a simple example, you'd never notice.

window.show();

And of course, we call run() to start the main processing loop which then waits for events to come from the X server.

run();

And the final return. Control returns here after Xfc::Main::quit() is called.

return 0;

When you click the mouse on a XFC button, the widget emits a 'clicked' signal. In order for us to use this information, XFC sets up the Gtk::Button 'clicked_signal' signal to catch that signal and dispatch it to any connected slots. In our example, when the button we created is clicked, the on_hello() method is called first and then the window's inherited Gtk::Object::dispose() method which destroys the window. This causes the window to emit the "destroy" signal, which is caught by its Gtk::Object 'destroy_signal', which calls Xfc::Main::quit(), which simply exits.

Another course of events is to use the window manager to kill the window, which will cause the 'delete_event' to be emitted. This is caught by the Gtk::Window 'delete_event_signal' which calls our on_delete_event() method. If we return true here, the window will be left as is and nothing will happen. Returning false will cause GTK+ to emit the 'destroy' signal which of course calls Xfc::Main::quit().

The next chapter takes you through building another XFC application: Hello Buttons, an enhanced version of Hello World which uses a packing box to add two button widgets to a main window.


Copyright © 2004-2005 The XFC Development Team Top
XFC 4.4
Index