Difference between GtkWindow and GdkWindow?

At the beginning of my Gtk-Gdk-Cairo-Pango application, I create a 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, such as gdk_window_process_updates(..) , require GdkWindow* .

gtk_window_set_geometry_hints() , on the other hand, requires GtkWindow* .

There is also GdkWindow* gdk_window_new() in the documentation that returns GdkWindow .

Of course there is documentation saying :

A GdkWindow is a rectangular area on the screen. This is a low-level object used to implement high-level objects such as GtkWidget and GtkWindow at the GTK + level. GtkWindow is a top-level window, a thing that a user can imagine as a β€œwindow” with a title, etc .; GtkWindow can contain a lot of GdkWindow.

But he still doesn't tell me when and why I need to create Gtk or Gdk windows? What is the picture here?

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

I tried to speed up the update by calling gdk_window_process_updates(GDK_WINDOW(window), false); , the compiler eats it, but I got a runtime statement: Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed . I can not find information about this macro and how to use it.

turn on

 #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; } 
+7
gtk cairo pango pangocairo gdk
source share
2 answers

Window managers (X11, Wayland, Windows user32.dll and one on Mac OS X, whose name I don’t remember) do not (provide) a lot of functionality. What they give you is:

  • the ability to create screen areas called windows onto which you can draw, move, resize, resize, minimize, hide behind other windows and manage other basic ways - but the most important of these for our discussion is β€œdraw”
  • mouse event processing for windows: notifications when the mouse moves to or inside a window, inside a window, or when the mouse buttons are pressed when the mouse cursor is over the window
  • the concept of the window that receives keyboard input (focused window) and the keyboard events for that window: when the user enters the window
  • various other functions (e.g. drawing mouse cursors)

In combination with the ability to do vector graphics and render text in a window (which is often provided by other libraries such as cairo and pango), a GUI toolkit comes into play. This is what occupies the window of the window manager and divides it into all the small controls that you are familiar with: buttons, text fields, lists, tabs, means of displaying web pages, etc.

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

When using GUI tools, you usually don’t interact directly with the window manager. Therefore, instead, the GUI toolkit provides its own window. When you create a GUI toolbox window, the GUI toolbox creates a window manager window window, then takes control of all the drawings and events so that it can handle the work of providing you with all these neat controls in this window.

For GTK +, this is GtkWindow.

GTK + designers did not want to have a window manager interaction code for each individual platform supported by GTK + in GTK +. Instead, they created a separate library (included in the GTK + source code) called GDK. The GDK provides a compatible portable API around the low-level window manager functions defined by the platform.

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

X11 has historically been a very limited resource. GTK + does not create a window manager window for each control; it only creates them for GtkWindow, GtkPopover and other similar controls that act like what we, as users, perceive as windows.

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

Both GdkWindow and GtkWindow are NOT interchangeable.

(This is still a fairly accurate simplification of what is happening. This does not apply to all environments. For example, people who write their own Windows programs usually create window manager windows for each control, and the window manager provides some basic controls, such as like buttons. Maybe I also got some details in the above explanation.)

The separation between GDK and GTK + also has a number of other advantages. For example, adding Wayland support did not help (as far as I know, I’m very mistaken) it requires a lot of changes in GTK +, and there is a GDK layer called broadway that allows you to run normal GTK + programs in a web browser.


Updates, since I seem to be connecting a lot:

  • There was a time when most GtkWidgets did have their own GdkWindows; that's what happened . Now I have described the situation.
+20
source share

There are so many questions that I will not try to answer all.

About drawing latency: most likely, the option is that your implementation has an error or non-optimized code: the drawing cycle is completely unique in the application code, since it really should really be fast ...

Notes:

  • you call gtk_widget_queue_draw(window) from the draw-event handler: this seems unnecessary
  • you always redraw the mouse event without checking if it is really necessary (perhaps you want the queue to execute all motion events: please make sure).
  • you always redraw the entire widget: it can be very expensive, and you should not do this if you only need to change a small area at a time and do frequent redraws like you do. See gtk_widget_queue_draw_region () .
  • drawing text can be expensive: I am not familiar with the functions you use, but you can start by drawing a window or something to see where the problem is.
0
source share

All Articles