<?xml version="1.0"?>
<!DOCTYPE article PUBLIC "-//OASIS//DTD DocBook XML V4.1.2//EN" 
  "http://www.oasis-open.org/docbook/xml/4.1.2/docbookx.dtd" [
  <!ENTITY date "February 2002">
]>

<article id="GUADEC" lang="en">
<!-- $Id: template.xml,v 1.1 2002/01/13 23:59:12 jaime Exp $ -->
  <artheader>
    <title>gtkmm - GNOME with C++</title>
    <author>
      <firstname>Murray</firstname>
      <surname>Cumming</surname>
      <affiliation>
	      <address><email>murrayc@usa.net</email></address>
      </affiliation>
    </author>
    <date>21st May 2003</date>
    <abstract>
      <para>An introduction to GTK+'s C++ bindings, aimed either at newcomers or experienced GNOME developers, depending on the audience. This is just an update of the same talk given at last year's GUADEC. The advantages of gtkmm will be demonstrated. For instance, API-clarity, inheritance, encapsulation, type-safety and the use of the C++ standard library. Some gtkmm-specific techniques will be introduced. There will be brief comparisons with GTK+ and Qt, which will make gtkmm look good.</para>
<para>Some gnomemm libraries will be mentioned, particularly the C++ wrappers for libglade, GConf, libgnomecanvas, and gnome-vfs. Document/View with Bakery will be mentioned. The future of the gtkmm and gnomemm projects will be discussed. You will be encouraged to help.</para>
    </abstract>
  </artheader>
  <sect1 id="section-gtkmm-is-better">
    <title>gtkmm is better</title>

    <sect2>
      <title>Advantages of gtkmm</title>
<orderedlist>
<listitem><para>gtkmm allows you to write code using normal C++ techniques such as encapsulation, derivation, and polymorphism. As a C++ programmer you probably already realise that this leads to clearer and better organised code.</para></listitem>
<listitem><para>gtkmm is more type-safe, so the compiler can detect errors that would only be detected at run time when using C. This use of specific types also makes the API clearer because you can see what types should be used just by looking at a method's declaration.</para></listitem>
<listitem><para>Inheritance can be used to derive new widgets. The derivation of new widgets in GTK+ C code is so complicated and error prone that almost no C coders do it. As a C++ developer you know that derivation is an essential Object Orientated technique, for users of a an API as well as the developers of the API.</para></listitem>
<listitem><para>Member instances can be used, simplifying memory management. All GTK+ C widgets are dealt with as pointers. As a C++ coder you probably want to avoid pointers where possible.</para></listitem>
<listitem><para>Less code. The GTK+ C object model uses prefixed function names and cast macros. For instance:</para>
<programlisting>gtk_button_set_text(GTK_BUTTON(button), "sometext");</programlisting>
<para>gtkmm C++ code is shorter and clearer. For instance:</para>
<programlisting>button.set_text("sometext");</programlisting></listitem>
<listitem><para>C++ understands inheritance. In C, you need to know that a GtkTreeView is a GtkContainer, and cast it. C++ just knows that it is, and cast implicitly.</para></listitem> 
<listitem><para>C++ has method overloading, so 2 functions in C can be combined into one method with 2 overloads.</para></listitem>
<listitem><para>C++ has default method arguments. So if a method should almost always take certain values, you don't need to keep writing them in your code, or wondering what they should be.</para></listitem>
<listitem><para>There's no need to worry about GTK+'s reference-counting. Ever.</para></listitem>
<listitem><para>Templates can make some things much simpler. Try the TreeView. You'll understand the examples in C++, but maybe not in C.</para></listitem>
</orderedlist>
    </sect2>
    
    <sect2>
      <title>Helloworld in gtkmm</title>
      <para>
<programlisting>
#include &lt;gtkmm.h&gt;
#include &lt;iostream&gt;

class HelloWorld : public Gtk::Window
{
public:
  HelloWorld();
  virtual ~HelloWorld();
  
protected:
  //Signal handlers:
  virtual void on_button_clicked();

  //Member widgets:
  Gtk::Button m_button;
};


HelloWorld::HelloWorld()
:  m_button("Hello World")   // A button with the label "Hello World".
{
  // Sets the border width of the window.
  set_border_width(10);
          
  // When the button receives the "clicked" signal, it will call the
  // on_button_clicked() method, defined below.
  m_button.signal_clicked().connect( SigC::slot(this, &amp;HelloWorld::on_button_clicked) );

  // This packs the button into the Window (a container).
  add(m_button);

  // The final step is to display this newly created widget:
  m_button.show();
}

HelloWorld::~HelloWorld
{
}

void HelloWorld::on_button_clicked()
{
  std::cout &lt;&lt; "Hello World" &lt;&lt; std::endl;
}
 
int main (int argc, char *argv[])
{
  Gtk::Main kit(argc, argv);

  HelloWorld helloworld;
  kit.run(helloworld); //Shows the window and returns when it is closed.

  return 0;
}
</programlisting>
</para>

    </sect2>

    <sect2>
      <title>Brief comparison with Qt</title>
 <para>Qt was written when C++ was not standardised or well supported by compilers. Its design today is still based on choices available at that time, so it does not play well with more up-to-date code. Development of Qt is still closed - There is still no public development mailing list, and TrollTech have the normal corporate conservatism. As an open-source project, its design would have been improved through public debate, and it would have been possible to discard the baggage, by creating both stable and development versions.</para>
    <para>Qt duplicates a lot of stuff that is now in the standard library, such as containers and type information. Most significantly, they modified the C++ language to provide signals, so that it's difficult to use Qt classes with non-Qt classes. gtkmm was able to use standard C++ to provide signals without changing the C++ language. And we use Standard C++ Library containers such as std::string, std::list, std::vector and their iterators. We even provide optional STL-style interfaces to other things such as container children, allowing you to use familiar iterators and push_back(), etc with these.</para>
    <para>With gtkmm normal C++ memory management can be used. Qt demands that all widgets are dealt with as pointers, and that you use new without using delete.</para>

<para>Here's a summary of those differences.
<table>
  <title>Comparison table</title>
  <tgroup cols="3">
  <thead>
    <row><entry></entry><entry>gtkmm</entry><entry>Qt</entry></row>
  </thead>
  <tbody>
  <row><entry>signals</entry><entry>pure C++</entry><entry>moc extends C++ language</entry></row>
  <row><entry>containers</entry><entry>pure C++</entry><entry>Qt-specific containers</entry></row>
  <row><entry>memory management</entry><entry>normal C++ choices</entry><entry>pointers only, and you can new, but you shouldn't delete</entry></row>
  <row><entry>GNOME classes</entry><entry>Yes</entry><entry>No</entry></row>
  <row><entry>Widget arrangement</entry><entry>Choice of containers</entry><entry>Containers and Layout classes are separate. Children must be added to both.</entry></row>
<row><entry>typesafe signal handlers</entry><entry>compile-time</entry><entry>runtime</entry></row>
<row><entry>License</entry><entry>LGPL</entry><entry>GPL</entry></row>
<row><entry>Development</entry><entry>Public</entry><entry>Secret</entry></row>
  </tbody>
  </tgroup>
</table>
We think that gtkmm makes your code clearer and more consistent. We think it gives you less to learn and less to worry about.</para>
<para>Note that I could be slightly wrong about the difficulties of using delete with Qt. Someone sent me a test case last year but I lost it before having a chance to try it. At the least, I don't think there is any way to stop Qt from deleting things that you newed, and I still suspect that it causes problems to delete something that you newed yourself. I wish I hadn't lost that test case and wish I had manged to build my own quick test case with the bizarre Qt build system. Sorry, don't flame me.</para> 
    </sect2>

  </sect1>

  <sect1 id="section-gtkmm">
    <title>gtkmm-specific techniques</title>
     
    <sect2>
      <title>Glib::ustring</title>
      <para>glib::ustring has much the same interface as std::string, but contains UTF8 strings. Note that a normal ANSI string is also a UTF8 string, so, if you want to, you can use this class without every thinking about UTF8.</para>
      <para>Also, this class has conversions to and from std::string, so you can use a std::string instead of a glib::ustring - However, operations on individual characters would not work with multi-byte translations, just as normal pointer arithmetic on a C char* wouldn't work.</para>
      <para>In a perfect world the C++ Standard Library would contain a a UTF8 string, but it doesn't.</para> 
    </sect2>

    <sect2>
      <title>Glib::RefPtr&lt;&gt;</title>
      <para>GObject is a bit stricter than GtkObject about how we can manage its memory. We can only unref() a GObject, we can never destroy it. Therefore our C++ wrapper (which
is used by the C GObject) must remain alive as long as the C instance. But of course it should be deleted when glib tells us that the C instance has died.</para>
      <para>Of course you don't want to worry about all that, so we've created the RefPtr&lt;&gt; smartpointer which does all that for you. Objects such as Gdk::Bitmap can now only be instantiated with a create() function. For instance,
<programlisting>
Glib::RefPtr&lt;Gdk::Bitmap&gt; bitmap = Gdk::Bitmap::create(window, data, width, height);
</programlisting>
</para>
      <para>You have no way of getting a bare Gdk::Bitmap. bitmap is then a smart pointer, so you can do this, much like a normal
pointer:
<programlisting>
if(bitmap)
{
  int depth = bitmap->get_depth().
}
</programlisting>
</para>
<para>
When bitmap goes out of scope an unref() will happen in the background and you
don't need to worry about it anymore.
</para>
       <para>This should mean that you *never* need to ref()/unref() a GDK
object again. GTK+ is a little inconsistent about its refcounting, though there
are a loose set of rules. All gtkmm methods do any extra referencing for you, so
you don't need to worry about that.</para>
    </sect2>

    <sect2>
      <title>Signals</title>
      <para>signals are prefixed by signal_, and accessible via accessors. For instance,</para>
<para>
<programlisting> button.signal_clicked().connect( SigC::slot(*this, &amp;Something::somemethod) );</programlisting>
</para>
    </sect2>

  </sect1>

  <sect1>
    <title>libglademm</title>
    <para>You can use C++ code to instantiate and arrange widgets, but this
soon becomes tedious. The <literal>Glade</literal> application allows you to layout widgets
on screen and then save an XML description of the arrangement. Your application can then use the <literal>libglademm</literal> API to load that XML file at runtime and obtain a pointer to specifically named widget instances.
</para>
    <para>This lets you just write code to respond to user interaction and to do actual processing - the interesting stuff that makes your application special.</para>
    <para>
<programlisting>
Glib::RefPtr&lt;Gnome::Glade::Xml&gt; refXml = Gnome::Glade::Xml::create("basic.glade");

Gtk::Dialog* pDialog = 0;
refXml-&gt;get_widget("DialogBasic", pDialog);
</programlisting>
    </para>
  </sect1>

  <sect1>
    <title>Other gnomemm libraries</title>
    <para>gtkmm's gtkmmproc system makes it quite easy to create gtkmm-like wrappers for any GObject- or GtkWidget-based API.</para>
    <para>gconfmm and libgnomecanvasmm have been API stable for a long time, and are in common use.</para>
    <para>gnome-vfsmm has been started and seems very useful. It is making good progress and I see no reason why the API shouldn't be stabilised after a few months.</para>
    <para>libgnomeuimm is not yet API stable because its dependency, libbonbouimm is not API stable, partly because orbitcpp is not stable, because orbitcpp is difficult. Luckily, there is nothing very useful in libgnomeuimm. If anyone actually needs it, we will happily release a stable libgnomeuimm version, without the libbonobouimm stuff, and work on a development branch.
</para>
<para>Gergo Erdi and now Bowie Owens are making surprisingly good progress with orbitcpp - but we don't know how much more work there is to do. You should help, and if you don't care enough to help then you probably don't need it. You need it to write Bonobo controls, but not many people need to do that.</para>
  </sect1>

  <sect1 id="section-further-information">
    <title>Further Information</title>
    <para>More information is available at www.gtkmm.org, including an FAQ, a tutorial, and reference documentation. We are happy to answer your questions on gtkmm-list@gnome.org.</para> 
  </sect1>


</article>
