2014-12-16 11 views
7

All'inizio della mia Gtk-Gdk-Cairo-Pango app, ho creare la finestra:Differenza tra GtkWindow e GdkWindow?

GtkWidget *window = gtk_window_new(GTK_WINDOW_TOPLEVEL); 

In primo luogo, v'è GtkWindow, ma gtk_create_window rendimenti GtkWidget, non GtkWindow, perché?

Quindi, alcune funzioni, come gdk_window_process_updates(..), richiedono GdkWindow*.

gtk_window_set_geometry_hints() d'altra parte richiede GtkWindow*.

Nella documentazione è anche GdkWindow* gdk_window_new() che restituisce GdkWindow.

Certo c'è documentation saying:

Una GdkWindow è una regione rettangolare sullo schermo. È un oggetto di livello basso , utilizzato per implementare oggetti di livello elevato come GtkWidget e GtkWindow a livello di GTK +. Un GtkWindow è una finestra di livello superiore, la cosa che un utente potrebbe pensare come una "finestra" con una barra del titolo e così via; a GtkWindow può contenere molti GdkWindow.

Ma ancora non mi dice, quando e perché dovrei creare Gtk o GDK finestre? Qual è lo schema qui da seguire?

Ora si chiede, quale problema specifico sto cercando di risolvere? Certo, provo a disegnare il testo usando cairo + pango sopra gtk + gdk, subito dopo le mosse del mouse. Il problema è che anche se il disegno reale sembra essere veloce, non riesco a farlo accadere esattamente come le mosse del mouse. Nel mio motion_notify_event ho appena chiamato gtk_widget_queue_draw(GtkWidget) ma c'è un lag evidente dietro lo spostamento del mouse sullo schermo, anche se disegno un singolo carattere non è allineato con il puntatore del mouse durante la fase di spostamento e lo cattura solo dopo che il mouse è stato fermato.

Quello che ho provato è di velocizzare l'aggiornamento chiamando gdk_window_process_updates(GDK_WINDOW(window), false);, il compilatore lo mangia, ma ho ottenuto l'asserzione di runtime: Gdk-CRITICAL **: gdk_window_process_updates: assertion 'GDK_IS_WINDOW (window)' failed. Non riesco a trovare alcuna informazione su questa macro e su come/quando usarla.

includono

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

risposta

20

Window manager (X11, Wayland, user32.dll di Windows e quella di Mac OS X il cui nome non ricordo) non (necessariamente) forniscono funzionalità molto su il loro.Quello che ti danno è:

  • la possibilità di creare le regioni sullo schermo, chiamato finestre, che si può attingere, muoversi, ridimensionare, rimodellare, minimizzare, nascondere dietro altre finestre, e controllo in altre modi di base - ma la più importante di queste discussioni è "attuare"
  • gestione degli eventi del mouse per Windows: notifiche quando il mouse entra o esce da una finestra, all'interno di una finestra o quando si fa clic sui pulsanti del mouse quando il cursore del mouse si trova su una finestra
  • il concetto di una finestra che riceve l'input da tastiera (la finestra focalizzata ) e gli eventi di tastiera per questa finestra: quando l'utente digita in una finestra
  • vari altre funzioni (disegno cursori del mouse, per esempio)

In combinazione con la possibilità di fare grafica vettoriale e rendering del testo in un finestra (che è spesso fornita da altre librerie, come cairo e pango), il toolkit GUI entra in gioco. Questo è ciò che prende la finestra del window manager e la divide in tutti i piccoli controlli che ti sono familiari: pulsanti, campi di testo, elenchi, schede, renderer di pagine web, ecc.

GTK + è il toolkit GUI in questo caso . Fornisce la pletora di controlli che usi nei tuoi programmi.

Quando si utilizza un toolkit GUI, in genere non si interagisce direttamente con il gestore finestre. Quindi, invece, il toolkit GUI fornisce una propria finestra. Quando si crea una finestra del toolkit GUI, il toolkit della GUI crea la finestra del window manager sottostante, quindi prende il controllo di tutto il disegno e degli eventi in modo che possa gestire il lavoro di fornire tutti quei controlli accurati in quella finestra.

Per GTK +, questo è GtkWindow.

I progettisti di GTK + non desideravano avere tutto il codice di interazione del gestore di finestre per ogni singola piattaforma supportata da GTK + in GTK +. Invece, hanno creato una libreria separata (inclusa con il codice sorgente GTK +), chiamata GDK. GDK fornisce un'API portatile coerente attorno alle funzioni di gestione finestre specifiche per piattaforma di basso livello.

Quindi GdkWindow è il tipo che avvolge una finestra di window manager e fornisce l'interfaccia portatile utilizzata da GTK +. Quando crei una GdkWindow, crei una di queste finestre di gestione finestre di basso livello, non la GtkWindow più ricca su cui metti i controlli.

X11 è stato storicamente molto vincolante in termini di risorse. GTK + non crea una finestra di gestione finestre per ogni controllo; crea solo questi per GtkWindow, GtkPopover e altri controlli simili che agiscono come ciò che noi utenti consideriamo come Windows.

Armati di tutte queste conoscenze, ora puoi capire la risposta alla tua domanda: quasi sempre vuoi usare GtkWindow e quasi mai usare GdkWindow. GdkWindow è davvero utile solo per l'implementazione di alcuni controlli GTK +.

E GdkWindow e GtkWindow NON sono intercambiabili.

(questa è una semplificazione eccessiva ancora ragionevolmente accurata di quello che sta succedendo. E non vale per tutti gli ambienti. Le persone che scrivono programmi nativi di Windows, per esempio, in genere fanno creare finestre window manager per ogni controllo, e il gestore delle finestre fornisce alcuni controlli di base, come i pulsanti.Potrei aver anche sbagliato alcuni dettagli nella spiegazione sopra.)

La separazione tra GDK e GTK + ha anche molti altri vantaggi. Ad esempio, l'aggiunta del supporto Wayland (per quanto ne so, potrei sbagliarmi) richiede molte modifiche allo stesso GTK +, e c'è un livello GDK chiamato broadway che consente il rendering dei normali programmi GTK + in un browser web .


aggiornamenti, in quanto mi sembra di essere collegando questo molto:

  • C'è stato un tempo in cui la maggior parte delle GtkWidgets in realtà avevano i loro GdkWindow; here's what happened. Ora, la situazione che ho descritto è il caso.
+3

X11 è un sistema a finestre (in almeno questo è ciò che lo chiama wikipedia), non un gestore di finestre. Wayland è qualcos'altro ma non un gestore di finestre. I gestori di finestre sono ad es. i3wm e xfwm. – Powersource

+0

Risposta fantastica! La documentazione dovrebbe avere l'architettura di base e le relazioni spiegate nel primo capitolo. –

0

Ci sono così tante domande in là che io non ho intenzione di provare a rispondere a tutte.

A proposito di latenza del disegno: opzione più probabile è che ci sia un bug o un codice non ottimizzato nell'implementazione: il ciclo di pareggio è abbastanza unico nel codice dell'applicazione, in quanto in realtà, ha davvero bisogno di essere veloce ...

Cose da notare:

  • si chiamano gtk_widget_queue_draw(window) dal vostro gestore draw-eventi: che sembra inutile
  • di ridisegnare sempre su un evento del mouse senza controllare se è veramente necessario (forse si vuole fare la coda pareggio su ogni movimento eventi: per favore assicurati di quello però)
  • si ridisegna sempre l'intero widget: questo può essere molto costoso e non si dovrebbe farlo se si ha solo bisogno di cambiare una piccola area alla volta e si stanno facendo ripetizioni frequenti come si. Vedi gtk_widget_queue_draw_region().
  • testo disegno può essere costoso: Non ho familiarità con le funzioni utilizzate, ma si consiglia di iniziare con solo disegnare una scatola o qualcosa da vedere dove il problema è