Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Welcome To Ask or Share your Answers For Others

Categories

0 votes
348 views
in Technique[技术] by (71.8m points)

gtk - Difference between GtkWindow and GdkWindow?

At the beginning of my Gtk-Gdk-Cairo-Pango app, I create the window:

GtkWidget   *window = gtk_window_new(GTK_WINDOW_TOPLEVEL);

First, there is GtkWindow, but gtk_create_window returns GtkWidget, not GtkWindow, why?

Then, some functions, like gdk_window_process_updates(..) require GdkWindow*.

gtk_window_set_geometry_hints() on the other hand requires GtkWindow*.

In documentation there is also GdkWindow* gdk_window_new() that returns GdkWindow.

Sure there is documentation saying:

A GdkWindow is a rectangular region on the screen. It's a low-level object, used to implement high-level objects such as GtkWidget and GtkWindow on the GTK+ level. A GtkWindow is a toplevel window, the thing a user might think of as a "window" with a titlebar and so on; a GtkWindow may contain many GdkWindow.

But it still does not tell me, when and why I should create Gtk or Gdk windows? What is the pattern here to follow?

Now you ask, what particular problem I am trying to solve? Sure, I try to draw text using cairo+pango on top of gtk+gdk, right after mouse moves. The problem is that although the actual drawing seems to be fast performing, I cannot get it happen exactly as mouse moves. In my motion_notify_event I just call gtk_widget_queue_draw(GtkWidget) but there is obvious lag behind the actual mouse moving on screen, even if I draw single character it is not aligned with the mouse pointer during the move phase and only catches it after the mouse is stopped.

What I tried is to speed up the update by calling gdk_window_process_updates(GDK_WINDOW(window), false);, the compiler eats it, but I got runtime assertion: Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed. I cannot find any information on this macro and how/when to use it.

#include <cairo.h>

#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;
}
See Question&Answers more detail:os

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
Welcome To Ask or Share your Answers For Others

1 Reply

0 votes
by (71.8m points)

Window managers (X11, Wayland, Windows's user32.dll, and the one in Mac OS X whose name I don't remember) do not (necessarily) provide much functionality on their own. What they give you is:

  • the ability to create on-screen regions, called windows, which you can draw on, move around, resize, reshape, minimize, hide behind other windows, and control in other basic ways — but the most important of these for our discussion is "draw on"
  • mouse event handling for windows: notifications when the mouse moves into or out of a window, around inside a window, or when the mouse buttons are clicked when the mouse cursor is over a window
  • the concept of a window which receives keyboard input (the focused window) and keyboard events for this window: when the user types into a window
  • miscellaneous other functions (drawing mouse cursors, for instance)

When combined with a facility to do vector graphics and text rendering into a window (which is often provided by other libraries, such as cairo and pango), the GUI toolkit comes into play. This is what takes the window manager window and divides it into all the little controls that you're familiar with: buttons, text fields, lists, tabs, web page renderers, etc.

GTK+ is the GUI toolkit in this case. It provides the plethora of controls that you use in your programs.

When you use a GUI toolkit, you don't typically interact with the window manager directly. So instead, the GUI toolkit provides its own window. When you create a GUI toolkit window, the GUI toolkit creates the underlying window manager window, then takes control of all the drawing and events so that it can handle the work of giving you all those neat controls in that window.

For GTK+, this is GtkWindow.

The designers of GTK+ did not want to have all the window manager interaction code for each individual platform that GTK+ supports in GTK+ itself. Instead, they created a separate library (included with the GTK+ source code), called GDK. GDK provides a consistent portable API around the low-level platform-specific window manager functions.

So GdkWindow is the type that wraps around a window manager window and provides the portable interface that GTK+ uses. When you create a GdkWindow, you're creating one of these low-level window manager windows, not the richer GtkWindow that you place controls on.

X11 has historically been very resource-constraining. GTK+ doesn't create a window manager window for every control; it only creates these for GtkWindow, GtkPopover, and other similar controls that act as what we as users think of as windows.

Armed with all this knowledge, you can now figure the answer to your question: you almost always want to use GtkWindow, and almost never want to use GdkWindow. GdkWindow is only really useful for the implementation of certain GTK+ controls.

And GdkWindow and GtkWindow are NOT interchangeable.

(This is a still-reasonably-accurate oversimplification of what's going on. It does not hold true for all environments. People who write native Windows programs, for instance, generally do create window manager windows for each control, and the window manager provides some basic controls, such as buttons. I may have also gotten some details in the above explanation wrong.)

The separation between GDK and GTK+ also has several other advantages. Adding Wayland support, for instance, did not (as far as I know; I could very well be wrong about this) require many changes to GTK+ itself, and there is a GDK layer called broadway which lets normal GTK+ programs render in a web browser.


Updates, since I seem to be linking this a lot:

  • There was a time when most GtkWidgets actually had their own GdkWindows; here's what happened. Now, the situation I described is the case.

与恶龙缠斗过久,自身亦成为恶龙;凝视深渊过久,深渊将回以凝视…
OGeek|极客中国-欢迎来到极客的世界,一个免费开放的程序员编程交流平台!开放,进步,分享!让技术改变生活,让极客改变未来! Welcome to OGeek Q&A Community for programmer and developer-Open, Learning and Share
Click Here to Ask a Question

...