优秀网页翻译:编写自己的终端模拟器

原文链接:
https://vincent.bernat.ch/en/blog/2017-write-own-terminal
作者:
文森特·伯纳特 2017 年 2 月 7 日
译者:
whstudio123
源代码位置:
https://github.com/vincentbernat/vbeterm

在我得到一台带有HiDPI显示器的笔记本电脑之前,我一直是rxvt-unicode的快乐用户。从LoDPI切换到HiDPI屏幕再切换回来很痛苦:我不得不手动调整所有终端上的字体大小或重新启动它们。

VTE是一个使用 GTK+ 工具包构建终端仿真器的库,用于处理 DPI 更改。许多终端仿真器都使用它,例如GNOME TerminalevilvtesakuratermitROXTerm。该库非常简单,如果您不需要很多功能,编写终端不会花费太多时间。

让我们看看如何写一个简单的。

一个简单的终端

让我们从具有默认设置的终端开始。我们将在 C 中编写它。另一个受支持的选项是Vala

#include <vte/vte.h>

static void
child_ready(VteTerminal *terminal, GPid pid, GError *error, gpointer user_data)
{
    if (!terminal) return;
    if (pid == -1) gtk_main_quit();
}

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

    /* Initialise GTK, the window and the 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,         /* cancellable */
        child_ready,  /* callback */
        NULL);        /* user_data */

    /* Connect some signals */
    g_signal_connect(window, "delete-event", gtk_main_quit, NULL);
    g_signal_connect(terminal, "child-exited", gtk_main_quit, NULL);

    /* Put widgets together and run the main loop */
    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 的终端

更多功能

从这里,您可以查看文档以更改行为或添加更多功能。这里有三个例子。

颜色

您可以使用以下代码定义 16 种基本颜色:

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

虽然您在屏幕截图上看不到它,但这也启用了背景透明度。
(透明度由合成器(在我的例子中是Compton )处理。)
在这里插入图片描述

其他设置

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);

这会:

禁用回滚缓冲区;
在新输出上不滚动到底部;
击键时滚动到底部;
键入时隐藏鼠标光标。

更新窗口标题

应用程序可以使用XTerm 控制序列(例如,使用printf “\e]2;${title}\a”)更改窗口标题。如果你想让实际的窗口标题反映这一点,你需要定义这个函数:

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));

写在最后

我不需要做更多了,因为我在每个终端内都使用tmux 。在我自己的拷贝中,我还添加了使用当前窗口或其他窗口中的单词补全单词的功能(也称为动态缩写扩展)。这需要实现一个终端守护进程来用一个进程处理所有终端窗口,类似于urxvtcd.

虽然“从头开始”编写终端符合我的需要,但它可能不值得。evilvte是完全可定制的,并且可以是轻量级的。将其视为第一选择。老实说,我不记得为什么我没有选择它。

(对于“从头开始”的一些定义,因为艰苦的工作是由VTE处理的。 )

更新 (2017-02):evilvte自 2014 年以来没有看到更新。它的 GTK+3 支持是错误的。它不支持最新版本的 VTE 库。因此,使用它不是一个好主意。

您还应该注意,VTE的主要目标是成为一个支持GNOME 终端的库。值得注意的是,如果GNOME Terminal不需要某个功能,则不会将其添加到VTE中。如果它已经存在,它可能会被弃用和删除。

© 2017–2022 文森特·伯纳特

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值