为什么要暴露我的 GTK 事件+小部件会在很长一段时间后被冻结吗?它是 GTK+漏洞?

发布于 2024-09-14 00:50:24 字数 2865 浏览 3 评论 0原文

这是我的代码:

#include <gtk/gtk.h>

static int counter = 0;
static PangoLayout* layout;
static GdkGC* gc1;
static GdkGC* gc2;
//**/static GMutex* mu;

static gboolean on_expose_event(GtkWidget* widget, GdkEventExpose* event)
{
    gchar the_string[20];

    //**/g_mutex_lock(mu);
    gdk_draw_rectangle(GDK_DRAWABLE(widget->window), gc1, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
    snprintf(the_string, 20, "%d", counter);
    pango_layout_set_text(layout, the_string, -1);
    gdk_draw_layout(GDK_DRAWABLE(widget->window), gc2, 180, 120, layout);
    //**/g_mutex_unlock(mu);

    g_print (".");
    return FALSE;
}

gpointer func(gpointer data)
{
    //**/g_usleep(10000);
    GdkWindow* window = GDK_WINDOW(data);
    while(TRUE)
    {
        gdk_window_invalidate_rect(window, NULL, FALSE);
        //**/gdk_window_process_updates(window, FALSE);
        if(counter % 100 == 0) g_print("X");
        g_usleep(10);
        ++counter;
    }
    return FALSE;
}

int main(int argc, char** argv)
{
    GtkWidget* window;
    GtkWidget* drawer;
    GdkColormap* colormap;
    GdkColor color;

    g_thread_init(NULL);
    gdk_threads_init();
    gtk_init(&argc, &argv);

    //:Create widgets and 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    drawer = gtk_drawing_area_new();
    gtk_widget_set_size_request(drawer, 400, 300);
    gtk_container_add(GTK_CONTAINER(window), drawer);
    //.

    gtk_widget_show_all(window);

    //:Initializing Graphic Contexts
    colormap = gtk_widget_get_colormap(GTK_WIDGET(drawer));
    layout = gtk_widget_create_pango_layout(GTK_WIDGET(drawer), NULL);
    gc1 = gdk_gc_new(GDK_DRAWABLE(GTK_WIDGET(drawer)->window));
    gc2 = gdk_gc_new(GDK_DRAWABLE(GTK_WIDGET(drawer)->window));
    gdk_color_parse("#000", &color);
    gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
    gdk_gc_set_background(gc1, &color);
    gdk_color_parse("#fff", &color);
    gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
    gdk_gc_set_foreground(gc2, &color);
    //.

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(drawer), "expose_event", G_CALLBACK(on_expose_event), NULL);

    //**/mu = g_mutex_new();
    //Run the problematic thread!
    g_thread_create(func, GTK_WIDGET(drawer)->window, TRUE, NULL);

    gdk_threads_enter();
    gtk_main();
    gdk_threads_leave();

    //**/g_mutex_free(mu);
    return 0;
}

这是一个多线程程序,并且没有做任何特别的事情!它只是强制 GtkDrawingArea 从主线程(GTK+ 主循环)重新绘制自身。

我的问题(或 GTK+ 问题!)是在长时间运行后(可能是 0.5、1 或 4 分钟!),暴露事件将不起作用(在我调整整个窗口大小之前不会响应我的请求!)!请编译并运行代码来检查这种情况。我添加了一些可能有帮助的打印命令!但由于我的经验很少,我无法发现问题。

我希望这个程序几乎总是可以重绘其上下文,但它没有(或不能)。我可以做什么来解决这个问题?也许我应该向 GTK+ 开发人员报告错误?

我正在使用 Debian + GCC + GTK2.20

Here is my code:

#include <gtk/gtk.h>

static int counter = 0;
static PangoLayout* layout;
static GdkGC* gc1;
static GdkGC* gc2;
//**/static GMutex* mu;

static gboolean on_expose_event(GtkWidget* widget, GdkEventExpose* event)
{
    gchar the_string[20];

    //**/g_mutex_lock(mu);
    gdk_draw_rectangle(GDK_DRAWABLE(widget->window), gc1, TRUE, 0, 0, widget->allocation.width, widget->allocation.height);
    snprintf(the_string, 20, "%d", counter);
    pango_layout_set_text(layout, the_string, -1);
    gdk_draw_layout(GDK_DRAWABLE(widget->window), gc2, 180, 120, layout);
    //**/g_mutex_unlock(mu);

    g_print (".");
    return FALSE;
}

gpointer func(gpointer data)
{
    //**/g_usleep(10000);
    GdkWindow* window = GDK_WINDOW(data);
    while(TRUE)
    {
        gdk_window_invalidate_rect(window, NULL, FALSE);
        //**/gdk_window_process_updates(window, FALSE);
        if(counter % 100 == 0) g_print("X");
        g_usleep(10);
        ++counter;
    }
    return FALSE;
}

int main(int argc, char** argv)
{
    GtkWidget* window;
    GtkWidget* drawer;
    GdkColormap* colormap;
    GdkColor color;

    g_thread_init(NULL);
    gdk_threads_init();
    gtk_init(&argc, &argv);

    //:Create widgets and 
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    drawer = gtk_drawing_area_new();
    gtk_widget_set_size_request(drawer, 400, 300);
    gtk_container_add(GTK_CONTAINER(window), drawer);
    //.

    gtk_widget_show_all(window);

    //:Initializing Graphic Contexts
    colormap = gtk_widget_get_colormap(GTK_WIDGET(drawer));
    layout = gtk_widget_create_pango_layout(GTK_WIDGET(drawer), NULL);
    gc1 = gdk_gc_new(GDK_DRAWABLE(GTK_WIDGET(drawer)->window));
    gc2 = gdk_gc_new(GDK_DRAWABLE(GTK_WIDGET(drawer)->window));
    gdk_color_parse("#000", &color);
    gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
    gdk_gc_set_background(gc1, &color);
    gdk_color_parse("#fff", &color);
    gdk_colormap_alloc_color(colormap, &color, FALSE, TRUE);
    gdk_gc_set_foreground(gc2, &color);
    //.

    g_signal_connect(G_OBJECT(window), "destroy", G_CALLBACK(gtk_main_quit), NULL);
    g_signal_connect(G_OBJECT(drawer), "expose_event", G_CALLBACK(on_expose_event), NULL);

    //**/mu = g_mutex_new();
    //Run the problematic thread!
    g_thread_create(func, GTK_WIDGET(drawer)->window, TRUE, NULL);

    gdk_threads_enter();
    gtk_main();
    gdk_threads_leave();

    //**/g_mutex_free(mu);
    return 0;
}

It's a multithreaded program, and did nothing so especial! It just force a GtkDrawingArea to redraw itself from the main thread (GTK+ main loop).

My problem (or GTK+ problem!) is that after a long time running (maybe 0.5, 1 or 4 minutes!), the expose event will not work (does not response to my requests until I'm resizing the whole window!)! Please, compile and run the code to check this situation. I added some print commands which may help! but i can't detect the problem, because of my little experience.

I hoped this program can redraws its context for almost always, but it didn't (or couldn't). What can i do to solve this problem? Maybe i should report a bug to GTK+ developers?

I'm using Debian + GCC + GTK2.20

如果你对这篇内容有疑问,欢迎到本站社区发帖提问 参与讨论,获取更多帮助,或者扫码二维码加入 Web 技术交流群。

扫码二维码加入Web技术交流群

发布评论

需要 登录 才能够评论, 你可以免费 注册 一个本站的账号。

评论(2

第几種人 2024-09-21 00:50:24

最有可能的是,您需要使用 gdk_threads_enter()/gdk_threads_leave() 对包围 gdk_window_invalidate_rect() 调用。有关 gtk 和线程的更多信息,请阅读 gdk 线程。看看那里的例子。

Most likely, you need to surround your gdk_window_invalidate_rect() call with gdk_threads_enter()/gdk_threads_leave() pair. Read the gdk threads for more information about gtk and threads. Look at the example there.

别忘他 2024-09-21 00:50:24

您应该将 g_timeout_add 与您的回调一起使用,并且使用会扰乱 UI 的第二个线程。

You should use g_timeout_add with your callback and NOT use a second thread that is messing with the UI.

~没有更多了~
我们使用 Cookies 和其他技术来定制您的体验包括您的登录状态等。通过阅读我们的 隐私政策 了解更多相关信息。 单击 接受 或继续使用网站,即表示您同意使用 Cookies 和您的相关数据。
原文