It's turned out that the correctest way to destroy the GDK window you have created with Gdk::Window::create()
is.. guess what? to call Gtk::Widget::unrealize()
in on_unrealize()
method of your custom widget because apart from other things this base method calls gdk_window_destroy()
for the widget's GDK window. And for that your widget has to be "windowful" (i.e you should call set_has_window(true);
in the constructor and set_window(<your allocated GDK window>);
in on_realize()
callback. Very obvious approach, isn't it?
I should also say something about Gtk::Widget::realize()
. Unlike Gtk::Widget::unrealize()
you should call Gtk::Widget::realize()
only if your widget doesn't have a GDK window (the method assumes that as an assertion).
Unfortunately I didn't have time and wish to get to the very bottom of it and endevour to understand why it has been done so and what reasons and consequences this approach has. Otherwise I would provide more detailed explanation.
You can find an official example from GTK's tutorial on custom widgets here.
Also the code of my widget now looks like that:
class MyWidget : public Gtk::Widget
{
...
private:
Glib::RefPtr<Gdk::Window> _event_window;
...
};
void Gtk::MyWidget::on_realize()
{
GdkWindowAttr attributes;
const Allocation & allocation = get_allocation();
attributes.event_mask = GDK_BUTTON_PRESS_MASK | GDK_EXPOSURE;
attributes.x = allocation.get_x();
attributes.y = allocation.get_y();
attributes.width = allocation.get_width();
attributes.height = allocation.get_height();
attributes.wclass = GDK_INPUT_OUTPUT;
attributes.window_type = GDK_WINDOW_CHILD;
_event_window = Gdk::Window::create(get_parent_window(), &attributes, GDK_WA_X | GDK_WA_Y);
_event_window->set_user_data(Widget::gobj());
set_window(_event_window);
set_realized();
}
void Gtk::MyWidget::on_unrealize()
{
_event_window->set_user_data(NULL);
_event_window.reset();
Widget::unrealize();
// it will call gdk_destroy_window() and
// set_realized(false);
}