2014-12-16 23 views
7

Zu Beginn meiner Gtk-Gdk-Kairo-Pango App schaffe ich das Fenster:Unterschied zwischen GtkWindow und GdkWindow?

GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 

Erstens gibt es GtkWindow, aber gtk_create_window kehrt GtkWidget, nicht GtkWindow, warum?

Dann erfordern einige Funktionen wie gdk_window_process_updates(..)GdkWindow*.

gtk_window_set_geometry_hints() auf der anderen Seite erfordert GtkWindow*. In der Dokumentation gibt es auch GdkWindow* gdk_window_new(), GdkWindow zurückgegeben.

Sicher gibt es documentation saying:

A GdkWindow ein rechteckiger Bereich auf dem Bildschirm ist. Es handelt sich um ein Low-Level-Objekt , mit dem High-Level-Objekte wie GtkWidget und GtkWindow auf der GTK + -Ebene implementiert werden. Ein GtkWindow ist ein Toplevel-Fenster, das Ding, das ein Benutzer als "Fenster" mit einer Titelleiste und so weiter denken könnte; a GtkWindow kann viele GdkWindow enthalten.

Aber es sagt mir immer noch nicht, wenn und warum Ich soll Gtk oder Gdk Fenster schaffen? Was ist das Muster hier zu folgen?

Jetzt fragen Sie, welches spezielle Problem versuche ich zu lösen? Klar, ich versuche Text mit cairo + pango auf gtk + gdk zu zeichnen, direkt nach der Mausbewegung. Das Problem ist, dass, obwohl die tatsächliche Zeichnung scheint schnell zu sein, ich kann es nicht passieren, genau wie die Maus bewegt. In meinem motion_notify_event Ich rufe gerade gtk_widget_queue_draw(GtkWidget), aber es gibt offensichtliche Verzögerung hinter der tatsächlichen Maus, die auf Bildschirm bewegt, selbst wenn ich einzelnes Zeichen zeichnet, ist es nicht mit dem Mauszeiger während der Bewegungsphase ausgerichtet und fängt es nur, nachdem die Maus gestoppt wird.

Was ich versuchte ist, um das Update zu beschleunigen, indem Sie gdk_window_process_updates(GDK_WINDOW(window), false); aufrufen, der Compiler isst es, aber ich habe Runtime Assertion: Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed. Ich kann keine Informationen zu diesem Makro finden und wie/wann es zu verwenden ist.

umfassen

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

Antwort

20

Fenstermanager (X11, Wayland, Fenster der user32.dll, und der in Mac OS X, dessen Namen ich mich nicht erinnern) nicht (unbedingt) auf viel Funktionalität ihre eigenen.Was geben sie dir ist:

  • die Fähigkeit, Bildschirm-Regionen zu schaffen, die so genannte Fenster, die Sie zurückgreifen können, bewegen, Größe, Form, minimieren, verstecken sich hinter anderen Fenstern und Kontrolle in anderen grundlegende Möglichkeiten - aber die wichtigste von diesen für unsere Diskussion ist "Zeichnen auf"
  • Maus Ereignisbehandlung für Windows: Benachrichtigungen, wenn die Maus in oder aus einem Fenster bewegt wird, in einem Fenster oder wenn die Maustasten geklickt werden wenn sich der Mauszeiger über einem Fenster befindet
  • das Konzept eines Fensters, das Tastatureingabe empfängt (das fokussierte Fenster) und Tastatur-Ereignisse für dieses Fenster: wenn der Benutzer in ein Fenster
  • verschiedene andere Funktionen (Maus-Cursor zeichnen, zum Beispiel)

Wenn mit einer Anlage kombiniert Vektorgrafiken und Text-Rendering in eine zu tun Fenster (das oft von anderen Bibliotheken wie Cairo und Pango bereitgestellt wird), kommt das GUI Toolkit ins Spiel. Dies nimmt das Window-Manager-Fenster und teilt es in alle kleinen Steuerelemente auf, die Sie kennen:

GTK + ist das GUI-Toolkit in diesem Fall . Es bietet eine Fülle von Steuerelementen, die Sie in Ihren Programmen verwenden.

Wenn Sie ein GUI-Toolkit verwenden, interagieren Sie normalerweise nicht direkt mit dem Fenstermanager. Stattdessen bietet das GUI-Toolkit ein eigenes Fenster. Wenn Sie ein GUI-Toolkit-Fenster erstellen, erstellt das GUI-Toolkit das zugrunde liegende Window-Manager-Fenster und übernimmt dann die Kontrolle über alle Zeichnungen und Ereignisse, sodass es die Arbeit übernehmen kann, Ihnen alle sauberen Steuerelemente in diesem Fenster zur Verfügung zu stellen.

Für GTK + ist dies GtkWindow.

Die Entwickler von GTK + wollten nicht den gesamten Interaktionscode des Fenstermanagers für jede einzelne Plattform haben, die GTK + in GTK + selbst unterstützt. Stattdessen erstellten sie eine separate Bibliothek (im Lieferumfang des GTK + Quellcodes enthalten), GDK genannt. GDK stellt eine konsistente portable API um die plattformspezifischen Low-Level-Fenstermanagerfunktionen bereit.

Also GdkWindow ist der Typ, der ein Fenstermanagerfenster umschließt und die portable Schnittstelle bereitstellt, die GTK + verwendet. Wenn Sie ein GdkWindow erstellen, erstellen Sie eines dieser Low-Level-Window-Manager-Fenster, nicht das umfangreichere GtkWindow, dem Sie Steuerelemente zuweisen.

X11 war historisch sehr restriktiv. GTK + erstellt kein Fenstermanagerfenster für jedes Steuerelement; Es erstellt nur diese für GtkWindow, GtkPopover und andere ähnliche Steuerelemente, die als das fungieren, was wir als Benutzer als Fenster betrachten.

Mit all diesen Kenntnissen ausgestattet, können Sie jetzt die Antwort auf Ihre Frage finden: Sie wollen fast immer GtkWindow verwenden und fast nie GdkWindow verwenden. GdkWindow ist nur für die Implementierung bestimmter GTK + Steuerelemente wirklich nützlich.

Und GdkWindow und GtkWindow sind nicht austauschbar.

(Dies ist eine noch recht genaue Simplifizierung von dem, was vor sich geht. Es ist nicht für alle Umgebungen hält wahr. Leute, die native Windows-Programme zu schreiben, zum Beispiel, in der Regel tun erstellen Window-Manager-Fenster für jede Steuerung, Der Fenstermanager bietet einige grundlegende Steuerelemente, z. B. Schaltflächen.Ich habe auch einige Details in der obigen Erklärung falsch verstanden.)

Die Trennung zwischen GDK und GTK + auch einige andere Vorteile. Hinzufügen von Wayland Unterstützung, zum Beispiel, nicht (soweit ich weiß, ich sehr gut falsch sein könnte darüber) erfordern viele Änderungen an GTK + selbst, und es gibt eine GDK Schicht broadway genannt, welche Programme normale GTK + kann in einem Web-Browser machen .


Updates, da ich viel dies zu verknüpfen scheinen:

  • Es gab eine Zeit, als die meisten GtkWidgets tatsächlich ihre eigenen GdkWindows hatte; here's what happened. Nun, die Situation, die ich beschrieben habe, ist der Fall.
+3

X11 ist ein Windowing-System gestartet werden soll (bei zumindest nennt das Wikipedia es), kein Fenstermanager. Wayland ist etwas anderes, aber kein Fenstermanager. Fenstermanager sind z.B. i3wm und xfwm. – Powersource

+0

Fantastische Antwort! Die Dokumentation sollte grundlegende Architektur und Beziehungen haben, die im ersten Kapitel erläutert werden. –

0

Da sind so viele Fragen drin, dass ich nicht versuchen werde, alle zu beantworten.

über Latenz der Zeichnung: wahrscheinlichste Option ist, dass ein Bug oder nicht optimiert Code in Ihrer Implementierung gibt es: der Zyklus Unentschieden ist in im Anwendungscode ziemlich einzigartig, dass es wirklich, wirklich braucht, um schnell zu sein ...

Dinge zu beachten:

  • Sie gtk_widget_queue_draw(window) von Ihren Einzug Event-Handler rufen: die
  • Sie immer auf einem Maus-Ereignisse neu zu zeichnen, ohne zu überprüfen unnötig erscheint, wenn es wirklich notwendig ist (möglicherweise Draw auf aller Bewegung in der Warteschlange Sie wollen Veranstaltungen: Bitte stellen Sie sicher, dass aber)
  • Sie das gesamte Widget immer neu zu zeichnen: Dies kann sehr teuer sein und Sie sollten es nicht tun, wenn Sie nur einen kleinen Bereich zu einer Zeit und machen häufig redraws ändern müssen, wie Sie sind. Siehe gtk_widget_queue_draw_region().
  • Zeichnung Text kann teuer sein: ich mit den Funktionen nicht vertraut bin Sie verwenden, aber Sie können mit nur Ziehen einer Box oder etwas zu sehen, wo das Problem