From a605c88ba3a0180d5783722c2c877f2ab8b01659 Mon Sep 17 00:00:00 2001 From: Samuel Fadel Date: Wed, 1 Apr 2015 22:43:44 -0300 Subject: Rewritten as a client-server application, similar to urxvt{d,c}. --- T.c | 241 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ 1 file changed, 241 insertions(+) create mode 100644 T.c (limited to 'T.c') diff --git a/T.c b/T.c new file mode 100644 index 0000000..dc62c3d --- /dev/null +++ b/T.c @@ -0,0 +1,241 @@ +/* + * T.c + * T is a lean Terminal emulator. + * + * This file is part of T. + * + * T is free software: you can redistribute it and/or modify it under the terms + * of the GNU General Public License as published by the Free Software + * Foundation, either version 3 of the License, or (at your option) any later + * version. + * + * T is distributed in the hope that it will be useful, but WITHOUT ANY + * WARRANTY; without even the implied warranty of MERCHANTABILITY or FITNESS FOR + * A PARTICULAR PURPOSE. See the GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License along with + * T. If not, see . + */ + +#include +#include +#include +#include +#include +#include + +#include "T.h" + +static int window_count = 0; + +/* Event callbacks */ +static void window_destroy_callback(GtkWidget *widget, gpointer data); +static gboolean key_press_callback(GtkWidget *widget, GdkEvent *event, gpointer data); +static void terminal_child_exited_callback(VteTerminal *terminal, gpointer data); +static void terminal_window_title_changed_callback(VteTerminal *terminal, gpointer data); + +/* Helper functions */ +static void change_font_size(VteTerminal *terminal, int delta); +static void set_preferences(VteTerminal *terminal); +static void setup_terminal(GtkWindow *window, VteTerminal *terminal); + +static void +window_destroy_callback(GtkWidget *widget, gpointer data) +{ + /* Keeping track of the open windows */ + window_count--; +} + +static gboolean +key_press_callback(GtkWidget *widget, GdkEvent *event, gpointer data) +{ + GdkEventKey *key_event = (GdkEventKey *) event; + VteTerminal *terminal = VTE_TERMINAL(widget); + + gboolean has_shift = (key_event->state & GDK_SHIFT_MASK) != 0; + gboolean has_control = (key_event->state & GDK_CONTROL_MASK) != 0; + + if (!has_control) + return FALSE; + + switch (key_event->keyval) { + case GDK_KEY_minus: + change_font_size(terminal, -1); + return TRUE; + case GDK_KEY_plus: + change_font_size(terminal, 1); + return TRUE; + } + + if (!has_shift) + return FALSE; + + /* Handles ctrl + shift + {c,v,n} */ + switch (key_event->keyval) { + case GDK_KEY_C: + case GDK_KEY_c: + /* turn this event into a Control+Insert and delegate it */ + key_event->keyval = GDK_KEY_Insert; + key_event->state &= ~GDK_SHIFT_MASK; + break; + case GDK_KEY_V: + case GDK_KEY_v: + /* turn this event into a Shift+Insert and delegate it */ + key_event->keyval = GDK_KEY_Insert; + key_event->state &= ~GDK_CONTROL_MASK; + break; + case GDK_KEY_N: + case GDK_KEY_n: + new_window(); + return TRUE; + } + + return FALSE; +} + +static void +terminal_child_exited_callback(VteTerminal *terminal, gpointer data) +{ + /* The forked process exited; issue destruction of the terminal window */ + gtk_widget_destroy(GTK_WIDGET(GTK_WINDOW(data))); +} + +static void +terminal_window_title_changed_callback(VteTerminal *terminal, gpointer data) +{ + GtkWindow *window = GTK_WINDOW(data); + gtk_window_set_title(window, vte_terminal_get_window_title(terminal)); +} + +static void +change_font_size(VteTerminal *terminal, int delta) +{ + PangoFontDescription *desc = (PangoFontDescription *) vte_terminal_get_font(terminal); + gint font_size = pango_font_description_get_size(desc) + delta * PANGO_SCALE; + pango_font_description_set_size(desc, font_size); + vte_terminal_set_font(terminal, desc); +} + +static void +set_preferences(VteTerminal *terminal) +{ + /* + * Options set here can (and should) be configured in config.h + */ + + /* + * These are static because this function is called every time a new window + * is created and we don't want to parse the colors all over again + */ + static gboolean colors_parsed = FALSE; + static GdkColor palette[CONFIG_PALETTE_SIZE], bg_color, fg_color; + static const char *CONFIG_COLOR_PALETTE[CONFIG_PALETTE_SIZE] = { + CONFIG_PALLETE_0, + CONFIG_PALLETE_1, + CONFIG_PALLETE_2, + CONFIG_PALLETE_3, + CONFIG_PALLETE_4, + CONFIG_PALLETE_5, + CONFIG_PALLETE_6, + CONFIG_PALLETE_7, + CONFIG_PALLETE_8, + CONFIG_PALLETE_9, + CONFIG_PALLETE_10, + CONFIG_PALLETE_11, + CONFIG_PALLETE_12, + CONFIG_PALLETE_13, + CONFIG_PALLETE_14, + CONFIG_PALLETE_15, + }; + + if (!colors_parsed) { + int i; + + gdk_color_parse(CONFIG_FOREGROUND_COLOR, &fg_color); + gdk_color_parse(CONFIG_BACKGROUND_COLOR, &bg_color); + for (i = 0; i < CONFIG_PALETTE_SIZE; ++i) + gdk_color_parse(CONFIG_COLOR_PALETTE[i], &palette[i]); + + colors_parsed = TRUE; + } + + /* Set preferences */ + vte_terminal_set_audible_bell(terminal, CONFIG_AUDIBLE_BELL); + vte_terminal_set_colors(terminal, &fg_color, &bg_color, palette, CONFIG_PALETTE_SIZE); + vte_terminal_set_cursor_blink_mode(terminal, CONFIG_CURSOR_BLINK_MODE); + vte_terminal_set_font_from_string(terminal, CONFIG_FONT_NAME); + vte_terminal_set_mouse_autohide(terminal, CONFIG_MOUSE_AUTOHIDE); + vte_terminal_set_scrollback_lines(terminal, CONFIG_SCROLLBACK_LINES); + vte_terminal_set_visible_bell(terminal, CONFIG_VISIBLE_BELL); +} + +static void +setup_terminal(GtkWindow *window, VteTerminal *terminal) +{ + char *argv[] = { vte_get_user_shell(), NULL }; + GPid child_pid; + + vte_terminal_fork_command_full(terminal, + VTE_PTY_DEFAULT, + NULL, /* wd; NULL for cwd */ + argv, /* the program to fork into and its args */ + NULL, /* env vars */ + G_SPAWN_DO_NOT_REAP_CHILD, + NULL, /* setup func */ + NULL, /* custom data to setup func */ + &child_pid, + NULL); /* TODO: error handling */ + + g_signal_connect(terminal, "child-exited", G_CALLBACK(terminal_child_exited_callback), window); + g_signal_connect(terminal, "key-press-event", G_CALLBACK(key_press_callback), window); + g_signal_connect(terminal, "window-title-changed", G_CALLBACK(terminal_window_title_changed_callback), window); + + set_preferences(terminal); +} + +int +num_open_windows() +{ + return window_count; +} + +void +new_window() +{ + GtkWindow *window = (GtkWindow *) gtk_window_new(GTK_WINDOW_TOPLEVEL); + VteTerminal *terminal = (VteTerminal *) vte_terminal_new(); + setup_terminal(window, terminal); + + GdkGeometry hints; + hints.base_width = vte_terminal_get_char_width(terminal); + hints.base_height = vte_terminal_get_char_height(terminal); + hints.min_width = hints.base_width * CONFIG_MIN_WIDTH; + hints.min_height = hints.base_height * CONFIG_MIN_HEIGHT; + hints.width_inc = hints.base_width; + hints.height_inc = hints.base_height; + gtk_window_set_geometry_hints(window, GTK_WIDGET(terminal), &hints, GDK_HINT_RESIZE_INC | GDK_HINT_MIN_SIZE | GDK_HINT_BASE_SIZE); + gtk_window_set_icon_name(window, "utilities-terminal"); + + g_signal_connect(window, "delete-event", G_CALLBACK(gtk_false), NULL); + g_signal_connect(window, "destroy", G_CALLBACK(window_destroy_callback), NULL); + + gtk_container_add(GTK_CONTAINER(window), GTK_WIDGET(terminal)); + + gtk_widget_show(GTK_WIDGET(terminal)); + gtk_widget_show(GTK_WIDGET(window)); + + window_count++; +} + +void +wrn(const char *message) +{ + fprintf(stderr, "%s: %s\n", PROGRAM_NAME, message); +} + +void +err(const char *message, int ecode) +{ + wrn(message); + exit(ecode); +} -- cgit v1.2.3