Re: Derived interfaces : An Example Solution
- From: Jeff Franks <jcf tpg com au>
- To: murrayc usa net
- Cc: gtk-devel-list <gtk-devel-list gnome org>
- Subject: Re: Derived interfaces : An Example Solution
- Date: Sun, 04 Nov 2001 18:19:24 +1100
Murray Cumming wrote:
So, if interfaces can't really be inherited, what does this do:
gpointer g_type_interface_peek_parent (gpointer g_iface)
?
Translating the GTK interfaces into C++ was tricky. You can only derive
an interface from G_TYPE_INTERFACE, not an exisitng interface.
Interfaces are GTK's equivalent to C++'s idea of the pure virtual
function and abstract interface class(see Bjarne Stroustrup, 3rd
edition, 25.6 Interface Classes, P 778).
Murray, I thought the easiest way was to share with you the example
source I have been working with. All the instructions are in the
attached file (14kb). The following is the introduction from this file.
/* This example shows what I think is the basic C++ code needed to get
the GTK+
* interface classes encapsulated correctly. This test includes the
necessary
* skeleton framework of classes. As the example I've encapsulated
GtkEditable,
* GtkEditableClass and GtkEntry and hooked them up to the GtkEditable
insert_text
* signal.
*
* You can compile this test file example with:
*
* g++ -Wall -g test.cc -o test `pkg-config gtk+-2.0 --cflags --libs`
-lstdc++
*
* Run test from the console. First you will see the line:
*
* Inside Gtk::EditableClass::init...
*
* showing you that in fact the init function inside Gtk::EditableClass
was called.
*
* Then, after typing a letter into the entry widget you will see the
following 3 lines
*
* Inside Gtk::EditableClass::insert_text_proxy...
* Inside Gtk::Editable::on_insert_text...
* Inside Gtk::Editable::on_insert_text's call to parent function...
*
* showing you that the correct sequence of functions were called and
that Gtk::Editable,
* GtkEditableClass and Gtk::Entry are all hooked up to insert_text
correctly.
*
* Gtk::Editable is an abstract class that is essentially stand alone,
but is inherited from
* Glib::TypeInstance so that it can have access to the GObject
instance pointer it needs,
* which it gets through multiple inheritance with Gtk::Entry.
*
* For simplicity, the class_init() and get_type() functions are only
in a separate
* class for Gtk::Editable and Gtk::EditableClass, which is the main
purpose of
* this example. In all the other classes, including GtkEntry, I put
them in the one class.
*
* Disclaimer :-) I needed to get this stuff working for my own
project. This was the actual test
* code I worked with a few months ago, I just cleaned it up a bit
before passing it on. This example
* is so far my only test of the code but it seems to work OK. If some
of the other code in the example
* doesn't seem connected to anything thats because it's not complete,
its only there to get the example
* up and running. The focus is intended to be on Glib::TypeInstance,
Glib::TypeInterface,
* Glib::Object, Gtk::Editable, Gtk::EditableClass and Gtk::Entry
classes only.
*
* I hope this is of some help,
* Jeff Franks.
*/
/* This example shows what I think is the basic C++ code needed to get the GTK+
* interface classes encapsulated correctly. This test includes the necessary
* skeleton framework of classes. As the example I've encapsulated GtkEditable,
* GtkEditableClass and GtkEntry and hooked them up to the GtkEditable insert_text
* signal.
*
* You can compile this test file example with:
*
* g++ -Wall -g test.cc -o test `pkg-config gtk+-2.0 --cflags --libs` -lstdc++
*
* Run test from the console. First you will see the line:
*
* Inside Gtk::EditableClass::init...
*
* showing you that in fact the init function inside Gtk::EditableClass was called.
*
* Then, after typing a letter into the entry widget you will see the following 3 lines
*
* Inside Gtk::EditableClass::insert_text_proxy...
* Inside Gtk::Editable::on_insert_text...
* Inside Gtk::Editable::on_insert_text's call to parent function...
*
* showing you that the correct sequence of functions were called and that Gtk::Editable,
* GtkEditableClass and Gtk::Entry are all hooked up with insert_text correctly.
*
* Gtk::Editable is an abstract class that is essentially stand alone, but is inherited from
* Glib::TypeInstance so that it can have access to the GObject instance pointer it needs,
* which it gets through multiple inheritance with Gtk::Entry.
*
* For simplicity, the class_init() and get_type() functions are only in a separate
* class for Gtk::Editable and Gtk::EditableClass, which is the main purpose of
* this example. In all the other classes, including GtkEntry, I put them in the one class.
*
* Disclaimer :-) I needed to get this stuff working for my own project. This was the actual test
* code I worked with a few months ago, I just cleaned it up a bit before passing it on. This example
* is so far my only test of the code but it seems to work OK. If some of the other code in the example
* doesn't seem connected to anything thats because it's not complete, its only there to get the example
* up and running. The focus is intended to be on the Glib::TypeInstance, Glib::TypeInterface,
* Glib::Object, Gtk::Editable, Gtk::EditableClass and Gtk::Entry classes only.
*
* I hope this is of some help,
* Jeff Franks.
*/
#include <gtk/gtk.h>
#include <glib-object.h>
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Header File Section //
/////////////////////////////////////////////////////////////////////////////////////////////////////
namespace Glib {
/* Glib::TypeInstance
*/
class TypeInstance
{
protected:
GTypeInstance *instance;
TypeInstance();
virtual ~TypeInstance() = 0;
};
/* Glib::TypeInterface
*/
class TypeInterface : protected virtual TypeInstance
{
public:
virtual ~TypeInterface() = 0;
};
/* Glib::Object
*/
class Object : public virtual TypeInstance
{
protected:
explicit Object(GObject *object);
public:
virtual ~Object();
static void class_init(GObjectClass *g_class);
static GType get_type();
GObject* g_object() const { return (GObject*)instance; }
};
} // namespace Glib
namespace Gtk {
/* Gtk::Object
*/
class Object : public Glib::Object
{
protected:
explicit Object(GtkObject *object);
public:
virtual ~Object();
static void class_init(GtkObjectClass *g_class);
static GType get_type();
GtkObject* gtk_object() const { return (GtkObject*)instance; }
};
/* Gtk::Widget
*/
class Widget : public Object
{
protected:
explicit Widget(GtkWidget *widget);
public:
virtual ~Widget();
static void class_init(GtkWidgetClass *g_class);
static GType get_type();
GtkWidget* gtk_widget() const { return (GtkWidget*)instance; }
void show();
};
////////////////////////////////////////// This starts the part of main interest to you //////////////////////////////////////////////
/* Gtk::EditableClass
*/
class EditableClass
{
public:
static void init(GtkEditableClass *g_iface);
static void insert_text_proxy(GtkEditable *editable, const gchar *text, gint length, gint *position);
};
/* Gtk::Editable
*/
class Editable : public Glib::TypeInterface
{
friend class EditableClass;
protected:
virtual void on_insert_text(const gchar *text, gint length, gint *position);
public:
GtkEditable* gtk_editable() const { return (GtkEditable*)instance; }
GtkEditableClass* gtk_editable_class() const { return GTK_EDITABLE_GET_CLASS(gtk_editable()); }
};
/* Gtk::Entry
*/
class Entry : public Widget, public Editable
{
protected:
explicit Entry(GtkEntry *entry);
public:
Entry();
virtual ~Entry();
static void class_init(GtkEntryClass *g_class);
static GType get_type();
GtkEntry* gtk_entry() const { return (GtkEntry*)instance; }
};
////////////////////////////////////////// This ends the part of main interest to you ///////////////////////////////////////////////
/* Gtk::Container
*/
class Container : public Widget
{
protected:
explicit Container(GtkContainer *container);
public:
virtual ~Container();
static void class_init(GtkContainerClass *g_class);
static GType get_type();
GtkContainer* gtk_container() const { return (GtkContainer*)instance; }
void add(Widget& widget);
};
/* Gtk::Bin
*/
class Bin : public Container
{
protected:
explicit Bin(GtkBin *bin);
public:
virtual ~Bin();
static void class_init(GtkBinClass *g_class);
static GType get_type();
};
/* GTk::Window
*/
class Window : public Bin
{
protected:
explicit Window(GtkWindow *window);
public:
Window();
virtual ~Window();
static void class_init(GtkWindowClass *g_class);
static GType get_type();
GtkWindow* gtk_window() const { return (GtkWindow*)instance; }
};
} // namespace Gtk
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Source File Section //
/////////////////////////////////////////////////////////////////////////////////////////////////////
/* Glib::TypeInstance
*/
Glib::TypeInstance::TypeInstance()
: instance(0)
{
}
Glib::TypeInstance::~TypeInstance()
{
}
/* Glib::TypeInterface
*/
Glib::TypeInterface::~TypeInterface()
{
}
/* Glib::Object
*/
void destroy_notifier(gpointer data)
{
Glib::Object *object = (Glib::Object*)data;
if (object)
{
delete object;
object = 0;
}
}
Glib::Object::Object(GObject *object)
{
if (!g_object_get_data(object, "test_pointer"))
g_object_set_data_full(object, "test_pointer", this, destroy_notifier);
instance = (GTypeInstance*)object;
}
Glib::Object::~Object()
{
if (instance)
{
g_object_steal_data(g_object(), "test_pointer");
instance = 0;
}
}
void
Glib::Object::class_init(GObjectClass *g_class)
{
}
GType
Glib::Object::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GObjectClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GObject),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(G_TYPE_OBJECT, "Test_G_Object", &info, GTypeFlags(0));
}
return type;
}
/* Gtk::Object
*/
Gtk::Object::Object(GtkObject *object)
: Glib::Object((GObject*)object)
{
gtk_object_ref(object);
gtk_object_sink(object);
}
Gtk::Object::~Object()
{
}
void
Gtk::Object::class_init(GtkObjectClass *g_class)
{
Glib::Object::class_init((GObjectClass*)g_class);
}
GType
Gtk::Object::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GtkObjectClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkObject),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_OBJECT, "Test_Gtk_Object", &info, GTypeFlags(0));
}
return type;
}
/* Gtk::Widget
*/
Gtk::Widget::Widget(GtkWidget *widget) : Object((GtkObject*)widget)
{
}
Gtk::Widget::~Widget()
{
}
void
Gtk::Widget::class_init(GtkWidgetClass *g_class)
{
Gtk::Object::class_init((GtkObjectClass*)g_class);
}
GType
Gtk::Widget::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GtkWidgetClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkWidget),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_WIDGET, "Test_Gtk_Widget", &info, GTypeFlags(0));
}
return type;
}
void
Gtk::Widget::show()
{
gtk_widget_show(gtk_widget());
}
/* Gtk::Editable
*/
void
Gtk::Editable::on_insert_text(const gchar *text, gint length, gint *position)
{
g_print("Inside Gtk::Editable::on_insert_text...\n");
GtkEditableClass *g_iface = (GtkEditableClass*)g_type_interface_peek_parent(gtk_editable_class());
if (g_iface->insert_text)
{
g_print("Inside Gtk::Editable::on_insert_text's call to parent function...\n");
g_iface->insert_text(gtk_editable(), text, length, position);
}
}
/* Gtk::EditableClass
*/
void
Gtk::EditableClass::init(GtkEditableClass *g_iface)
{
g_print("Inside Gtk::EditableClass::init...\n");
g_iface->insert_text = insert_text_proxy;
}
void
Gtk::EditableClass::insert_text_proxy(GtkEditable *editable, const gchar *text, gint length, gint *position)
{
g_print("Inside Gtk::EditableClass::insert_text_proxy...\n");
Glib::Object *object = static_cast<Glib::Object*>(g_object_get_data(G_OBJECT(editable), "test_pointer"));
Gtk::Editable *tmp_editable = dynamic_cast<Gtk::Editable*>(object); /* needed for multiple inheritance */
if (tmp_editable)
tmp_editable->on_insert_text(text, length, position);
else
{
GtkEditableClass *iface = static_cast<GtkEditableClass*>(g_type_interface_peek_parent(GTK_EDITABLE_GET_CLASS(editable)));
if (iface->insert_text)
{
g_print("Inside Gtk::EditableClass::insert_text_proxy's call to parent function...\n");
iface->insert_text(editable, text, length, position);
}
}
}
/* Gtk::Entry
*/
Gtk::Entry::Entry(GtkEntry *entry)
: Widget((GtkWidget*)entry)
{
}
Gtk::Entry::Entry()
: Widget((GtkWidget*)g_object_new(get_type(), 0))
{
}
Gtk::Entry::~Entry()
{
}
void
Gtk::Entry::class_init(GtkEntryClass *g_class)
{
Gtk::Widget::class_init((GtkWidgetClass*)g_class);
}
GType
Gtk::Entry::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo entry_info =
{
sizeof(GtkEntryClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkEntry),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_ENTRY, "Test_Gtk_Entry", &entry_info, GTypeFlags(0));
static const GInterfaceInfo editable_info =
{
(GInterfaceInitFunc)EditableClass::init,
(GInterfaceFinalizeFunc)0,
0
};
g_type_add_interface_static(type, GTK_TYPE_EDITABLE, &editable_info);
/* This is Gtk::CellEditable's bit but I didn't add it to the example. It and all the other interface
classes can been enacpsulated just like Gtk::Editable, and added to the appropriate widget's get_type().
static const GInterfaceInfo cell_editable_info =
{
(GInterfaceInitFunc)CellEditableClass::init,
(GInterfaceFinalizeFunc)0,
0
};
g_type_add_interface_static(type, GTK_TYPE_CELL_EDITABLE, &cell_editable_info);
*/
}
return type;
}
/* Gtk::Container
*/
Gtk::Container::Container(GtkContainer *container)
: Widget((GtkWidget*)container)
{
}
Gtk::Container::~Container()
{
}
void
Gtk::Container::class_init(GtkContainerClass *g_class)
{
Gtk::Widget::class_init((GtkWidgetClass*)g_class);
}
GType
Gtk::Container::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GtkContainerClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkContainer),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_CONTAINER, "Test_Gtk_Container", &info, GTypeFlags(0));
}
return type;
}
void
Gtk::Container::add(Widget& widget)
{
gtk_container_add(gtk_container(), widget.gtk_widget());
}
/* Gtk::Bin
*/
Gtk::Bin::Bin(GtkBin *bin)
: Container((GtkContainer*)bin)
{
}
Gtk::Bin::~Bin()
{
}
void
Gtk::Bin::class_init(GtkBinClass *g_class)
{
Gtk::Container::class_init((GtkContainerClass*)g_class);
}
GType
Gtk::Bin::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GtkBinClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkBin),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_BIN, "Test_Gtk_Bin", &info, GTypeFlags(0));
}
return type;
}
/* Gtk::Window
*/
Gtk::Window::Window(GtkWindow *window)
: Bin((GtkBin*)window)
{
g_object_unref(g_object());
}
Gtk::Window::Window()
: Bin((GtkBin*)g_object_new(get_type(), 0))
{
gtk_window()->type = GTK_WINDOW_TOPLEVEL;
g_object_unref(g_object());
}
Gtk::Window::~Window()
{
}
void
Gtk::Window::class_init(GtkWindowClass *g_class)
{
Gtk::Bin::class_init((GtkBinClass*)g_class);
}
GType
Gtk::Window::get_type()
{
static GType type = 0;
if (!type)
{
static const GTypeInfo info =
{
sizeof(GtkWindowClass),
(GBaseInitFunc)0,
(GBaseFinalizeFunc)0,
(GClassInitFunc)class_init,
0, 0,
sizeof(GtkWindow),
0, /* preallocs */
(GInstanceInitFunc)0
};
type = g_type_register_static(GTK_TYPE_WINDOW, "Test_Gtk_Window", &info, GTypeFlags(0));
}
return type;
}
/////////////////////////////////////////////////////////////////////////////////////////////////////
// Example //
/////////////////////////////////////////////////////////////////////////////////////////////////////
class TestWindow : public Gtk::Window
{
Gtk::Entry entry;
public:
TestWindow()
{
gtk_signal_connect(GTK_OBJECT(g_object()), "destroy", >k_main_quit, 0);
add(entry);
entry.show();
gtk_window_set_title(gtk_window(), "Interface Test");
gtk_window_resize(gtk_window(), 250, 28);
gtk_window_set_position(gtk_window(), GTK_WIN_POS_CENTER);
}
};
int main(int argc, char *argv[])
{
gtk_init(&argc, &argv);
TestWindow *window = new TestWindow;
window->show();
gtk_main();
return 0;
}
[
Date Prev][
Date Next] [
Thread Prev][
Thread Next]
[
Thread Index]
[
Date Index]
[
Author Index]