Let's Build the Terminal Pt. 3

April 27, 2026

This is the third article in the series of the articles where we are going to build the terminal in C using GTK4 and VTE. The series is divided into three articles.

  1. Let's Build the Terminal Pt. 1
  2. Let's Build the Terminal Pt. 2
  3. Let's Build the Terminal Pt. 3

tl;dc: Refer this gist to get the final version of terminal.c code.

---

Let's continue from where we left off in the last article. Following is the code we have in terminal.c file.

#include <gtk/gtk.h>

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

And we know the command to compile and run the program.

gcc terminal.c `pkg-config --cflags --libs gtk4` && ./a.out

In this article, we're now going to add actual terminal within Notebook tabs. To load the terminal, we're going to use VTE library header file as vte/vte.h.

#include <gtk/gtk.h>
#include <vte/vte.h>

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

When we start the application, it should load with terminal session in the focused tab. When we click on 'Add Tab', we expect that it should add a new tab with terminal session in it. In other words, we are going to create terminal from few places. So, we are going to create a common function create_terminal() for the same and call it from where it is needed. This function should return a widget so that it can be added inside the Notebook page.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {

}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

Let's create a terminal instance using vte_terminal_new() function.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

Terminal start with the default shell and with few other things (theme, font, etc). We can get this info via calling g_get_environ() function.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());

    char** env = g_get_environ();
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

From this env, get the default shell by calling g_environ_getenv() function and telling that we're interested in fetching the SHELL value, and if there is no, then default to Bash.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());

    char** env = g_get_environ();

    const char* shell = g_environ_getenv(env, "SHELL");
    if (!shell) {
        shell = "/bin/bash";
    }
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

We have all the needed info (surprise!). We are ready to spawn the terminal process using vte_terminal_spawn_async() function, It accept so many arguments (13) that I'll only comments for the important one and leave on you to explore further.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());

    char** env = g_get_environ();

    const char* shell = g_environ_getenv(env, "SHELL");
    if (!shell) {
        shell = "/bin/bash";
    }

    vte_terminal_spawn_async(
        terminal,
        VTE_PTY_DEFAULT,
        NULL, // working directory, NULL being the current one.
        (char* []){ (char *)shell, NULL },
        env,
        G_SPAWN_DEFAULT,
        NULL, NULL,
        NULL,
        -1,
        NULL,
        NULL,
        NULL // any user data we want to pass.
    );
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

This create a terminal process and attach it to the terminal widget with given shell.

Finally, we need to free the memory that was allocated to env using g_strfreev() function and return a terminal widget as GtkWidget*. We need to cast the terminal using GTK_WIDGET() macro as it is type of VteTerminal*.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());

    char** env = g_get_environ();

    const char* shell = g_environ_getenv(env, "SHELL");
    if (!shell) {
        shell = "/bin/bash";
    }

    vte_terminal_spawn_async( 
        terminal,
        VTE_PTY_DEFAULT,
        NULL, // working directory, NULL being the current one.
        (char* []){ (char *)shell, NULL },
        env,
        G_SPAWN_DEFAULT,
        NULL, NULL,
        NULL,
        -1,
        NULL,
        NULL,
        NULL // any user data we want to pass.
    );

    g_strfreev(env);

    return GTK_WIDGET(terminal);
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, gtk_label_new("New tab content goes here"), gtk_label_new(title)); 

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 1 content goes here"), gtk_label_new("Page 1")); 
    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), gtk_label_new("Page 2 content goes here"), gtk_label_new("Page 2")); 
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

With these changes in create_terminal() function, we are now ready to load the terminal. We just need to replace the tab content with this function call at two places - in "Tab 1", and in _on_new_tab_clicked() function. We can remove the "Tab 2" as we don't need it for now.

#include <gtk/gtk.h>
#include <vte/vte.h>

static GtkWidget* create_terminal() {
    VteTerminal* terminal = VTE_TERMINAL(vte_terminal_new());

    char** env = g_get_environ();

    const char* shell = g_environ_getenv(env, "SHELL");
    if (!shell) {
        shell = "/bin/bash";
    }

    vte_terminal_spawn_async( 
        terminal,
        VTE_PTY_DEFAULT,
        NULL, // working directory, NULL being the current one.
        (char* []){ (char *)shell, NULL },
        env,
        G_SPAWN_DEFAULT,
        NULL, NULL,
        NULL,
        -1,
        NULL,
        NULL,
        NULL // any user data we want to pass.
    );

    g_strfreev(env);

    return GTK_WIDGET(terminal);
}

static void _on_new_tab_clicked(GtkWidget* widget, gpointer data) {
    GtkNotebook* notebook = GTK_NOTEBOOK(data);

    int pages = gtk_notebook_get_n_pages(notebook);

    char title[32];
    g_snprintf(title, sizeof(title), "Tab %d", pages + 1);

    int new_page = gtk_notebook_append_page(notebook, create_terminal(), gtk_label_new(title));

    gtk_notebook_set_current_page(notebook, new_page);
} 

static void activate(GtkApplication* app, gpointer data) {
    GtkWidget* window = gtk_application_window_new(app);
    gtk_window_set_title(GTK_WINDOW(window), "Terminal");
    gtk_window_set_default_size(GTK_WINDOW(window), 600, 800);

    // Container.
    GtkWidget* box = gtk_box_new(GTK_ORIENTATION_VERTICAL, 0);

    // Notebook.
    GtkWidget* notebook = gtk_notebook_new();
    gtk_widget_set_vexpand(notebook, TRUE);
    gtk_widget_set_hexpand(notebook, TRUE);

    gtk_notebook_append_page(GTK_NOTEBOOK(notebook), create_terminal(), gtk_label_new("Page 1"));
    gtk_box_append(GTK_BOX(box), notebook);

    gtk_window_set_child(GTK_WINDOW(window), box); 

    // Header bar.
    GtkWidget* header_bar = gtk_header_bar_new();
    gtk_header_bar_set_title_widget(GTK_HEADER_BAR(header_bar), gtk_label_new("Terminal"));

    GtkWidget* button = gtk_button_new_with_label("New Tab");
    g_signal_connect(button, "clicked", G_CALLBACK(_on_new_tab_clicked), notebook);
    gtk_header_bar_pack_end(GTK_HEADER_BAR(header_bar), button);

    gtk_window_set_titlebar(GTK_WINDOW(window), header_bar);

    gtk_window_present(GTK_WINDOW(window));
}

int main(int argc, char** argv) {
    GtkApplication* app = gtk_application_new("dev.marichi.terminal", G_APPLICATION_DEFAULT_FLAGS);
    g_signal_connect(app, "activate", G_CALLBACK(activate), NULL);
    int status = g_application_run(G_APPLICATION(app), argc, argv);
    g_object_unref(app);

    return status;
}

Let's run the program and confirm the output. We need to adjust the command as we are now using one more library - VTE - which we need to include in compilation process.

gcc temrinal-4.c `pkg-config --cflags --libs gtk4 vte-2.91-gtk4` && ./a.out

You should see the output like this. Clicking on "New Tab" button should add a new tab with terminal.

Yay!

No comments:

Post a Comment