W tym krótkim tutorialu pokażę jak używać widget VTE
    we własnych programach. Najpierw utworzymy w programie Glade
    interfejs dla naszej przykładowej aplikacji a następnie w odpowiednie miejsce
    layoutu podepniemy wyżej wspomniany widget. Pokażę jak załadować
    shell do terminala i jak zabezpieczyć się przed opuszczeniem shella
    przy pomocy komendy exit  lub kombinacji klawiszy
    Ctrl+D.
    A więc do dzieła!
Zaczniemy od instalacji biblioteki developerskiej umożliwiającej wykorzystanie kontrolki VTE. W tym celu zainstaluj pakiet libvte-2.90-dev:
sudo apt-get install libvte-2.90-devNastępnie otwórz program Glade i utwórz layout według podanego poniżej opisu.
Po wykonaniu powyższych kroków nasze okno powinno wyglądać jak na screenshocie poniżej:
     
Zapiszmy teraz nasz plik interfejsu jako main_window.ui i przejdźmy do tworzenia kodu naszej aplikacji. Zacznijmy od zainkludowania potrzebnych plików nagłówkowych:
#include <gtk/gtk.h>
#include <vte/vte.h>
#include <vte/reaper.h>
    Plik gtk.h jest głównym plikiem nagłówkowym biblioteki gtk
    i jest wymagany dla każdej aplikacji korzystającej z tej biblioteki.
    
    Plik vte.h jest plikiem nagłówkowym definiującym kontrolkę
    vte i pozwalającym używać ją w naszych aplikacjach.
    
    Plik reaper.h pozwala przechwytywać zdarzenia zakończenia
    wykonywania się procesu załadowanego do widgeta vte.
Zdefiniujmy teraz zmienne globalne i funkcje, które wykorzystamy w naszej aplikacji:
GtkBuilder *builder;
GtkWidget *mainWindow;
GtkWidget *vte;
gboolean loadGui();
void create_terminal();
void run_shell_in_terminal();
void vte_child_exited(VteReaper *vtereaper, gint arg1, gint arg2, gpointer user_data);
void on_execute_command_click(GtkWidget *widget, gpointer user_data);
    Zmienna builder będzie przechowywała wskaźnik na obiekt
    odpowiedzialny za wczytanie interfejsu aplikacji z utworzonego wcześniej pliku
    main_window.ui.
    Zmienna mainWindow jest wskaźnikiem na okno główne naszej aplikacji.
    Natomiast zmienna vte będzie przechowywała wskaźnik na obiekt terminala VTE.
Funkcję główną możemy zdefiniować następująco:
gint main(gint argc, gchar *argv[])
{
    gtk_init(&argc, &argv);
    
    if (loadGui()) {
        mainWindow = GTK_WIDGET(gtk_builder_get_object(builder, "mainWindow"));
        GtkWidget *btnExecute = GTK_WIDGET(gtk_builder_get_object(builder, "btnExecute"));
        if (mainWindow && btnExecute) {
            g_signal_connect(G_OBJECT(mainWindow), "destroy", G_CALLBACK(gtk_main_quit), NULL);
            g_signal_connect(G_OBJECT(btnExecute), "clicked", G_CALLBACK(on_execute_command_click), NULL);
            create_terminal();            
            gtk_widget_show_all(mainWindow);
            gtk_main();
        }
    }
    
    if (builder) {
        g_object_unref(builder);
    }
    
    return 0;
}
    Za pomocą funkcji gtk_init inicjalizujemy bibliotekę GTK.
    Do funkcji tej przekazujemy zmienne argc i argv określające
    parametry aplikacji przekazane w linii poleceń oraz ich ilość.
    Następnie jeśli interfejs został poprawnie wczytany - pobieramy przy pomocy funkcji
    gtk_builder_get_object wskaźniki na widgety okna głównego i przycisku "Wykonaj".
    Jeśli udało się pobrać te wskaźniki podpinamy funkcję obsługi sygnału destroy
    okna głównego, odpowiedzialną za zakończenie aplikacji (funkcja systemowa gtk_main_quit) oraz
    funkcję obsługi sygnału clicked przycisku btnExecute -
    zdefiniowana przez nas funkcja on_execute_command_click.
    Następnie wywołujemy funkcję tworzącą terminal i pokazujemy okno główne na ekranie.
    Na koniec uruchamiamy funkcję systemową gtk_main odpowiedzialną za przetwarzanie
    w pętli wszystkich sygnałów i zdarzeń otrzymywanych przez aplikację.
    Przed opuszczeniem funkcji głównej pamiętamy o zwolnieniu obiektu buildera przy pomocy funkcji
    g_object_unref.
gboolean loadGui() {
    GError *error;
    
    builder = gtk_builder_new();
	error = NULL;
	gtk_builder_add_from_file(builder, "main_window.ui", &error);
	if (error) {
		g_print("Wystąpił błąd: %s\n", error->message);
		g_error_free(error);
		return FALSE;
	}
    return TRUE;
}Funkcja loadGui odpowiada za utworzenie interfejsu aplikacji. Zwraca TRUE w przypadku sukcesu i FALSE w przypadku niepowodzenia. W funkcji tej najpierw tworzymy obiekt buildera przy pomocy funkcji gtk_builder_new a następnie wywołując funkcję gtk_builder_add_from_file próbujemy wczytać interfejs z pliku main_window.ui (z bieżącego katalogu roboczego). Jeśli wystąpił błąd, to wyświetlamy stosowny komunikat na standardowym wyjściu.
void run_shell_in_terminal() {
    GError *error;        
    char *startterm[2] = {0, 0};
    startterm[0] = vte_get_user_shell();
    
    error = NULL;
    vte_terminal_fork_command_full(VTE_TERMINAL(vte),
           VTE_PTY_DEFAULT, // Tryb uruchomienia shella
           NULL,  // Katalog roboczy; ustawiony na NULL przyjmuje wartość bieżącego katalogu roboczego
           startterm, // Polecenie do wykonania
           NULL, // NULL lub lista zmiennych środowiskowych ustawianych w terminalu
           (GSpawnFlags)(G_SPAWN_DO_NOT_REAP_CHILD | G_SPAWN_SEARCH_PATH),  // Flagi dla tworzonego procesu
           NULL, // Funkcja konfiguracyjna wywoływana przed wykonaniem funkcji exec
           NULL, // Dane przekazywane do funkcji konfiguracyjnej
           NULL, // NULL albo zmienna przechowująca PID potomka
           &error // Zmienna przechowująca informację o błędzie
           );
    if (error) {
        g_print("Wystąpił błąd: %s\n", error->message);
        g_error_free(error);
    }
    g_free(startterm[0]);
}Funkcja run_shell_in_terminal odpowiada za uruchomienie w terminalu bieżącego shella użytkownika. Pełną ścieżkę do tego shella otrzymujemy przy pomocy funkcji vte_get_user_shell i przechowujemy w tablicy startterm. Następnie uruchamiamy ten shell przy pomocy funkcji vte_terminal_fork_command_full. Poszczególne parametry tej funkcji opisałem w komentarzach przy wywołaniu.
void create_terminal() {
    GtkWidget *frame_alignment = GTK_WIDGET(gtk_builder_get_object(builder, "alignment1"));
    if (frame_alignment) {
        vte = vte_terminal_new();
        g_signal_connect(G_OBJECT(vte), "child-exited", G_CALLBACK(vte_child_exited), NULL);
        gtk_container_add(GTK_CONTAINER(frame_alignment), vte);
        
        run_shell_in_terminal();
    }
}Funkcja create_terminal odpowiada za utworzenie widgeta terminala VTE i dodanie go do załadowanego wcześniej interfejsu użytkownika. Najpierw pobieramy przy pomocy funkcji gtk_builder_get_object pobieramy widget-pojemnik, do którego dodamy obiekt terminala. Jest to widget alignment1. Następnie tworzymy terminal funkcją vte_terminal_new, podpinamu obsługę sygnału "child-exited" (wywoływany w momencie opuszczenia procesu shella) oraz dodajemy terminal do pojemnika. Na koniec uruchamiamy w terminalu shell użytkownika.
void vte_child_exited(VteReaper *vtereaper, gint arg1, gint arg2, gpointer user_data) {
    // if user exits shell by pressing Ctrl+D or executing "exit" command run shell again
    run_shell_in_terminal();
}Funkcja vte_child_exited wywoływana po zamknięciu shella uruchamia go po prostu jeszcze raz. Dzięki temu blokujemy użytkownikowi możliwość całkowitego zamknięcia shella w terminalu.
void on_execute_command_click(GtkWidget *widget, gpointer user_data) {
    GtkWidget *edtCommand = GTK_WIDGET(gtk_builder_get_object(builder, "edtCommand"));
    if (edtCommand) {
        const gchar *command = gtk_entry_get_text(GTK_ENTRY(edtCommand));
        gchar *command_with_newline = g_strdup_printf("%s\r", command);
        
        vte_terminal_feed_child(VTE_TERMINAL(vte), command_with_newline, -1);
        
        g_free(command_with_newline);
    }
}Na koniec definiujemy funkcję obsługi kliknięcia przycisku. Funkcja ta najpierw pobiera wskaźnik na pole tekstowe z komendą do uruchomienia a następnie pobiera tę komendę przy pomocy funkcji gtk_entry_get_text, dokleja do niej znacznik wciśnięcia klawisza ENTER (\r) i wywołuje w terminalu (funkcja vte_terminal_feed_child). Na koniec oczywiście pamiętamy o zwolnieniu zasobów.
Kompletny kod aplikacji można pobrać poniżej lub na samej górze strony.