Gdkmm:如何破坏GDK窗口

gdkmm: how to destroy gdk window?

本文关键字:GDK 窗口 何破坏 Gdkmm      更新时间:2023-10-16

现状:我有一个带有事件窗口的自定义小部件(MyWidget)。问题:如果我创建,显示,然后,稍后,隐藏和销毁小部件,我从应用程序得到以下消息:

Gdk-WARNING **: losing last reference to undestroyed window

我发现了什么:我已经在gdkwindow.c文件中查看了一下,当GDK_WINDOW_DESTROYED(window) == FALSE时报告了此消息。所以我不明白的是我应该如何正确地破坏我的窗口,以便最终调用gdk_window_destroy()函数。我认为调用它的最佳位置是Gdk::~Window()析构函数。但它是空的。而且gdkwindow.cc文件中根本没有gdk_window_destroy()

on_realize()on_unrealize()回调如下:

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;
    attributes.x = allocation.get_x();
    attributes.y = allocation.get_y();
    attributes.width = allocation.get_width();
    attributes.height = allocation.get_height();
    attributes.wclass = GDK_INPUT_ONLY;
    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(get_parent_window());
    set_realized();
}
void Gtk::MyWidget::on_unrealize()
{
    _event_window->set_user_data(NULL);
    _event_window.reset();
    set_realized(false);
}

事实证明,破坏您使用Gdk::Window::create()创建的GDK窗口的正确方法是…你猜怎么着?在您的自定义小部件的on_unrealize()方法中调用Gtk::Widget::unrealize(),因为除了其他事情之外,这个基本方法为小部件的GDK窗口调用gdk_window_destroy()。对于你的小部件是"窗口"(即你应该调用set_has_window(true);在构造函数和set_window(<your allocated GDK window>);on_realize()回调。很明显的方法,不是吗?

我也应该说一些关于Gtk::Widget::realize()。与Gtk::Widget::unrealize()不同,如果您的小部件没有 GDK窗口(该方法假设这是一个断言),您应该只调用Gtk::Widget::realize()

不幸的是,我没有时间,也不希望深入了解它,努力理解为什么会这样做,以及这种方法有什么原因和后果。否则我会提供更详细的解释。

您可以在GTK的自定义小部件教程中找到一个官方示例在这里。

我的小部件代码现在看起来像这样:

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);
}