我用 LinuxLinux SourceUnix/Linux服务器技术分享

编写你自己的Terminal emulator

2020-01-16  本文已影响0人  霡霂976447044

原文: https://vincent.bernat.ch/en/blog/2017-write-own-terminal

安装开发依赖环境

在apt包管理器系中,使用以下命令安装

apt install libvte-2.91-dev

介绍

VTE是一个使用GTK构建的一个终端模拟器库, 能够处理DPI的更改。很多终端模拟器软件都基于VTE库,包括GNOME Terminal, XFCE Terminal, Deepin Terminal,Guake等等。这个库非常简洁,你可以很快就写出来一个自己终端模拟器。

下面就来写一个例子。

一个简单的终端

我们先写一个默认的终端,会使用C语言编写。另一个可选的是使用Vala。

#include <vte/vte.h>

int
main(int argc, char *argv[])
{
    GtkWidget *window, *terminal;

    /* 初始化GTK,窗口和terminal */
    gtk_init(&argc, &argv);
    terminal = vte_terminal_new();
    window = gtk_window_new(GTK_WINDOW_TOPLEVEL);
    gtk_window_set_title(GTK_WINDOW(window), "myterm");

    /* Start a new shell */
    gchar **envp = g_get_environ();
    gchar **command = (gchar *[]){g_strdup(g_environ_getenv(envp, "SHELL")), NULL };
    g_strfreev(envp);
    vte_terminal_spawn_async(VTE_TERMINAL(terminal),
        VTE_PTY_DEFAULT,
        NULL,       /* working directory  */
        command,    /* command */
        NULL,       /* environment */
        0,          /* spawn flags */
        NULL, NULL, /* child setup */
        NULL,       /* child pid */
        -1,         /* timeout */
        NULL, NULL, NULL);

    /* 连接一些信号 */
    g_signal_connect(window, "delete-event", gtk_main_quit, NULL);
    g_signal_connect(terminal, "child-exited", gtk_main_quit, NULL);

    /* 将组件添加到窗口, 然后进入事件循环 */
    gtk_container_add(GTK_CONTAINER(window), terminal);
    gtk_widget_show_all(window);
    gtk_main();
}

使用以下命令进行编译:

gcc -O2 -Wall $(pkg-config --cflags vte-2.91) term.c -o term $(pkg-config --libs vte-2.91)

然后运行./term

基于VTE的Terminal

更多定制

你可以在VTE文档更改终端默认特性,下面有三个例子。

颜色配置

使用以下代码定义自己的颜色

#define CLR_R(x)   (((x) & 0xff0000) >> 16)
#define CLR_G(x)   (((x) & 0x00ff00) >>  8)
#define CLR_B(x)   (((x) & 0x0000ff) >>  0)
#define CLR_16(x)  ((double)(x) / 0xff)
#define CLR_GDK(x) (const GdkRGBA){ .red = CLR_16(CLR_R(x)), \
                                    .green = CLR_16(CLR_G(x)), \
                                    .blue = CLR_16(CLR_B(x)), \
                                    .alpha = 0 }
vte_terminal_set_colors(VTE_TERMINAL(terminal),
    &CLR_GDK(0xffffff),
    &(GdkRGBA){ .alpha = 0.85 },
    (const GdkRGBA[]){
        CLR_GDK(0x111111),
        CLR_GDK(0xd36265),
        CLR_GDK(0xaece91),
        CLR_GDK(0xe7e18c),
        CLR_GDK(0x5297cf),
        CLR_GDK(0x963c59),
        CLR_GDK(0x5E7175),
        CLR_GDK(0xbebebe),
        CLR_GDK(0x666666),
        CLR_GDK(0xef8171),
        CLR_GDK(0xcfefb3),
        CLR_GDK(0xfff796),
        CLR_GDK(0x74b8ef),
        CLR_GDK(0xb85e7b),
        CLR_GDK(0xA3BABF),
        CLR_GDK(0xffffff)
}, 16);

效果如下


截图_2020-01-16_16-43-29.png

杂项设置

VTE可以设置很多选项来来改变默认的配置

vte_terminal_set_scrollback_lines(VTE_TERMINAL(terminal), 0);
vte_terminal_set_scroll_on_output(VTE_TERMINAL(terminal), FALSE);
vte_terminal_set_scroll_on_keystroke(VTE_TERMINAL(terminal), TRUE);
vte_terminal_set_mouse_autohide(VTE_TERMINAL(terminal), TRUE);

分别可以设置

改变标题

static gboolean
on_title_changed(GtkWidget *terminal, gpointer user_data)
{
    GtkWindow *window = user_data;
    gtk_window_set_title(window,
        vte_terminal_get_window_title(VTE_TERMINAL(terminal))?:"Terminal");
    return TRUE;
}

然后,在main方法里连接信号,让程序一旦运行就调用改变标题

g_signal_connect(terminal, "window-title-changed", 
    G_CALLBACK(on_title_changed), GTK_WINDOW(window));
上一篇下一篇

猜你喜欢

热点阅读