GtkWindow和GdkWindow之间的区别?

时间:2014-12-16 22:22:10

标签: gtk cairo gdk pango pangocairo

在我的Gtk-Gdk-Cairo-Pango应用程序的开头,我创建了窗口:

GtkWidget   *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

首先,有GtkWindow,但gtk_create_window返回GtkWidget,而不是GtkWindow,为什么?

然后,某些功能,例如gdk_window_process_updates(..)需要GdkWindow*

另一方面,

gtk_window_set_geometry_hints()需要GtkWindow*

在文档中,还有GdkWindow* gdk_window_new()返回GdkWindow

当然有documentation saying

  

GdkWindow是屏幕上的矩形区域。这是一个低级别的   object,用于实现高级对象,如GtkWidget和   GtkWindow在GTK +级别上。 GtkWindow是一个顶层窗户,   用户可能会认为是一个"窗口"标题栏等等;一个   GtkWindow可能包含许多GdkWindow。

但它仍然没有告诉我, 何时 为什么 我应该创建Gtk或Gdk窗口? 这里的模式是什么?

现在你问,我想解决什么特别的问题?当然,我尝试在gtk + gdk之上使用cairo + pango在鼠标移动后立即绘制文本。问题是虽然实际绘图似乎表现得很快,但我无法像鼠标移动那样完成它。在我的motion_notify_event我只是打电话给gtk_widget_queue_draw(GtkWidget),但实际的鼠标在屏幕上移动有明显的滞后,即使我画了单个字符,它在移动阶段没有与鼠标指针对齐,只抓住它鼠标停止后。

我尝试的是通过调用gdk_window_process_updates(GDK_WINDOW(window), false);加速更新,编译器吃它,但我得到了运行时断言:Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed。我找不到有关此宏的任何信息以及如何/何时使用它。

包括

#include <gtk/gtk.h>
#define TXT "1234567890"
int X = 0, Y = 0;
static void do_drawing(cairo_t *);
GtkWidget *window;
PangoLayout *layout = 0;

static gboolean on_draw_event(GtkWidget *widget, cairo_t *cr, 
              gpointer user_data) {
  do_drawing(cr);
  return FALSE;
}

static void do_drawing(cairo_t *cr) {
    if (layout == 0) {
        layout = pango_cairo_create_layout (cr);
        pango_layout_set_text (layout, TXT, -1);
    }
    for (int y = 0; y < 2; y++) {
        cairo_set_source_rgb (cr, 1, 0, 1);
        cairo_move_to (cr, 0+X, 0 + y * 20 + Y);
        pango_cairo_show_layout (cr, layout);
    }
    gtk_widget_queue_draw(window);
}

static gint onmouse(GtkWidget *widget, GdkEventMotion *event) {
    X = event->x; Y = event->y;
    gtk_widget_queue_draw(widget);
    gdk_window_process_updates(GDK_WINDOW(widget), false);
}


int main(int argc, char *argv[]) {
    GtkWidget *darea;
    gtk_init(&argc, &argv);
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    darea = gtk_drawing_area_new();
    gtk_container_add(GTK_CONTAINER(window), darea);
    gtk_widget_set_events (window, GDK_EXPOSURE_MASK
          | GDK_LEAVE_NOTIFY_MASK   | GDK_POINTER_MOTION_MASK);
    g_signal_connect(G_OBJECT(darea), "draw", G_CALLBACK(on_draw_event), NULL); 
    g_signal_connect(window, "destroy", G_CALLBACK(gtk_main_quit), NULL);  
    g_signal_connect(window, "motion_notify_event", G_CALLBACK(onmouse), NULL);
    gtk_window_set_position(GTK_WINDOW(window), GTK_WIN_POS_CENTER);
    gtk_window_set_default_size(GTK_WINDOW(window), 5000, 5000); 
    gtk_window_set_title(GTK_WINDOW(window), "Lines");
    gtk_widget_show_all(window);
    gtk_main();
    return 0;
}

2 个答案:

答案 0 :(得分:22)

窗口管理器(X11,Wayland,Windows的user32.dll以及Mac OS X中我不记得的那个)不一定(必然)提供很多功能。他们给你的是:

  • 能够创建屏幕上的区域,称为 windows ,您可以在其中绘制,移动,调整大小,重塑,最小化,隐藏在其他窗口后面,并以其他基本方式进行控制 - 但是我们讨论中最重要的是“借鉴”
  • Windows的鼠标事件处理:当鼠标移入或移出窗口,窗口内部或鼠标光标在窗口上方时单击鼠标按钮时的通知
  • 接收该窗口的键盘输入(聚焦窗口)和键盘事件的窗口的概念:当用户键入窗口时
  • 其他各种功能(例如绘制鼠标光标)

当与设施结合使用矢量图形和文本渲染到窗口(通常由其他库提供,例如cairo和pango)时, GUI工具包开始起作用。这就是窗口管理器窗口并将其划分为您熟悉的所有小控件:按钮,文本字段,列表,选项卡,网页渲染器等。

在这种情况下,GTK +是GUI工具包。它提供了您在程序中使用的大量控件。

使用GUI工具包时,通常不直接与窗口管理器交互。相反,GUI工具包提供了自己的窗口。当您创建GUI工具包窗口时,GUI工具包会创建基础窗口管理器窗口,然后控制所有绘图和事件,以便它可以处理在该窗口中为您提供所有那些整洁控件的工作。

对于GTK +,这是GtkWindow。

GTK +的设计者不希望拥有GTK +在GTK +中支持的每个平台的所有窗口管理器交互代码。相反,他们创建了一个单独的库(包含在GTK +源代码中),称为GDK。 GDK围绕低级平台特定的窗口管理器功能提供一致的可移植API。

因此GdkWindow是一个包装窗口管理器窗口并提供GTK +使用的可移植接口的类型。当您创建GdkWindow时,您将创建其中一个低级窗口管理器窗口,而不是您放置控件的更丰富的GtkWindow。

X11在历史上一直非常受资源限制。 GTK +不为每个控件创建一个窗口管理器窗口;它只为GtkWindow,GtkPopover和其他类似控件创建这些控件,这些控件充当了我们用户认为的窗口。

拥有所有这些知识,您现在可以找到问题的答案:您几乎总是想要使用GtkWindow,而且几乎从不想使用GdkWindow。 GdkWindow仅对实现某些GTK +控件非常有用。

GdkWindow和GtkWindow不可互换。

(对于正在发生的事情,这仍然是相当准确的过度简化。它并不适用于所有环境。例如,编写本机Windows程序的人通常创建窗口管理器窗口对于每个控件,窗口管理器提供了一些基本的控件,比如按钮。我可能也在上面的解释中得到了一些错误的细节。)

GDK和GTK +之间的分离还有其他几个优点。例如,添加Wayland支持(据我所知,我很可能错误)需要对GTK +本身进行许多更改,并且有一个名为broadway的GDK层可以让普通的GTK +程序渲染在网络浏览器中。


更新,因为我似乎将此链接起来了很多:

  • 曾经有一段时间大多数GtkWidgets实际拥有自己的GdkWindows; here's what happened。现在,我描述的情况就是这样。

答案 1 :(得分:1)

那里有很多问题,我不打算全部回答。

关于绘图的延迟:最有可能的选择是你的实现中存在一个错误或未经优化的代码:绘制周期在应用程序代码中非常独特,因为它确实需要快速...

注意事项:

  • 你从绘图事件处理程序中调用gtk_widget_queue_draw(window):这似乎是不必要的
  • 你总是在鼠标事件上重绘而不检查它是否真的有必要(可能你想在所有动作事件上排队绘制:尽管如此,请确保这一点)
  • 你总是重绘整个小部件:这可能非常昂贵,如果你只需要一次改变一个小区域并且像你一样经常重绘,你就不应该这样做。见gtk_widget_queue_draw_region ()
  • 绘图文字可能很昂贵:我不熟悉您使用的功能,但您可能只想绘制一个框或其他内容以查看问题所在