1 /* Copyright © 2007-2016 Evgeny Ratnikov
2  *
3  * This program is free software: you can redistribute it and/or modify
4  * it under the terms of the GNU General Public License as published by
5  * the Free Software Foundation, either version 3 of the License, or
6  * (at your option) any later version.
7  *
8  * This program is distributed in the hope that it will be useful,
9  * but WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
11  * GNU General Public License for more details.
12  *
13  * You should have received a copy of the GNU General Public License
14  * along with this program.  If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <string.h>
18 #include <gdk/gdk.h>
19 
20 #include "termit.h"
21 #include "keybindings.h"
22 #include "configs.h"
23 #include "lua_api.h"
24 
25 struct Configs configs = {};
26 
27 static struct {
28     const char* name;
29     VteEraseBinding val;
30 } erase_bindings[] = {
31     {"Auto", VTE_ERASE_AUTO},
32     {"AsciiBksp", VTE_ERASE_ASCII_BACKSPACE},
33     {"AsciiDel", VTE_ERASE_ASCII_DELETE},
34     {"EraseDel", VTE_ERASE_DELETE_SEQUENCE},
35     {"EraseTty", VTE_ERASE_TTY}
36 };
37 static guint EraseBindingsSz = sizeof(erase_bindings)/sizeof(erase_bindings[0]);
38 
termit_erase_binding_to_string(VteEraseBinding val)39 const char* termit_erase_binding_to_string(VteEraseBinding val)
40 {
41     return erase_bindings[val].name;
42 }
43 
termit_erase_binding_from_string(const char * str)44 VteEraseBinding termit_erase_binding_from_string(const char* str)
45 {
46     guint i = 0;
47     for (; i < EraseBindingsSz; ++i) {
48         if (strcmp(str, erase_bindings[i].name) == 0) {
49             return erase_bindings[i].val;
50         }
51     }
52     ERROR("unknown erase binding [%s], using Auto", str);
53     return VTE_ERASE_AUTO;
54 }
55 
56 static struct {
57     const char* name;
58     VteCursorBlinkMode val;
59 } cursor_blink_modes[] = {
60     {"System", VTE_CURSOR_BLINK_SYSTEM},
61     {"BlinkOn", VTE_CURSOR_BLINK_ON},
62     {"BlinkOff", VTE_CURSOR_BLINK_OFF}
63 };
64 static guint BlinkModesSz = sizeof(cursor_blink_modes)/sizeof(cursor_blink_modes[0]);
65 
termit_cursor_blink_mode_to_string(VteCursorBlinkMode val)66 const char* termit_cursor_blink_mode_to_string(VteCursorBlinkMode val)
67 {
68     return cursor_blink_modes[val].name;
69 }
70 
termit_cursor_blink_mode_from_string(const char * str)71 VteCursorBlinkMode termit_cursor_blink_mode_from_string(const char* str)
72 {
73     guint i = 0;
74     for (; i < BlinkModesSz; ++i) {
75         if (strcmp(str, cursor_blink_modes[i].name) == 0) {
76             return cursor_blink_modes[i].val;
77         }
78     }
79     ERROR("unknown blink mode [%s], using System", str);
80     return VTE_CURSOR_BLINK_SYSTEM;
81 }
82 
83 static struct {
84     const char* name;
85     VteCursorShape val;
86 } cursor_shapes[] = {
87     {"Block", VTE_CURSOR_SHAPE_BLOCK},
88     {"Ibeam", VTE_CURSOR_SHAPE_IBEAM},
89     {"Underline", VTE_CURSOR_SHAPE_UNDERLINE}
90 };
91 static guint ShapesSz = sizeof(cursor_shapes)/sizeof(cursor_shapes[0]);
92 
termit_cursor_shape_to_string(VteCursorShape val)93 const char* termit_cursor_shape_to_string(VteCursorShape val)
94 {
95     return cursor_shapes[val].name;
96 }
97 
termit_cursor_shape_from_string(const char * str)98 VteCursorShape termit_cursor_shape_from_string(const char* str)
99 {
100     guint i = 0;
101     for (; i < ShapesSz; ++i) {
102         if (strcmp(str, cursor_shapes[i].name) == 0) {
103             return cursor_shapes[i].val;
104         }
105     }
106     ERROR("unknown cursor shape [%s], using Block", str);
107     return VTE_CURSOR_SHAPE_BLOCK;
108 }
109 
termit_config_trace()110 void termit_config_trace()
111 {
112 #ifdef DEBUG
113     TRACE("   default_window_title          = %s", configs.default_window_title);
114     TRACE("   default_tab_name              = %s", configs.default_tab_name);
115     TRACE("   default_encoding              = %s", configs.default_encoding);
116     TRACE("   default_word_char_exceptions  = %s", configs.default_word_char_exceptions);
117     TRACE("   show_scrollbar                = %d", configs.show_scrollbar);
118     TRACE("   hide_menubar                  = %d", configs.hide_menubar);
119     TRACE("   hide_tabbar                   = %d", configs.hide_tabbar);
120     TRACE("   fill_tabbar                   = %d", configs.fill_tabbar);
121     TRACE("   show_border                   = %d", configs.show_border);
122     TRACE("   hide_single_tab               = %d", configs.hide_single_tab);
123     TRACE("   start_maximized               = %d", configs.start_maximized);
124     TRACE("   hide_titlebar_when_maximized  = %d", configs.hide_titlebar_when_maximized);
125     TRACE("   scrollback_lines              = %d", configs.scrollback_lines);
126     TRACE("   cols x rows                   = %d x %d", configs.cols, configs.rows);
127     TRACE("   backspace                     = %s", termit_erase_binding_to_string(configs.default_bksp));
128     TRACE("   delete                        = %s", termit_erase_binding_to_string(configs.default_delete));
129     TRACE("   blink                         = %s", termit_cursor_blink_mode_to_string(configs.default_blink));
130     TRACE("   shape                         = %s", termit_cursor_shape_to_string(configs.default_shape));
131     TRACE("   allow_changing_title          = %d", configs.allow_changing_title);
132     TRACE("   audible_bell                  = %d", configs.audible_bell);
133     TRACE("   scroll_on_output              = %d", configs.scroll_on_output);
134     TRACE("   scroll_on_keystroke           = %d", configs.scroll_on_keystroke);
135     TRACE("   get_window_title_callback     = %d", configs.get_window_title_callback);
136     TRACE("   get_tab_title_callback        = %d", configs.get_tab_title_callback);
137     TRACE("   get_statusbar_callback        = %d", configs.get_statusbar_callback);
138     TRACE("   kb_policy                     = %d", configs.kb_policy);
139     TRACE("   tab_pos                       = %d", configs.tab_pos);
140     TRACE("   style:");
141     TRACE("     font_name                   = %s", configs.style.font_name);
142     if (configs.style.foreground_color) {
143         gchar* tmpStr = gdk_rgba_to_string(configs.style.foreground_color);
144         TRACE("     foreground_color            = %s", tmpStr);
145         g_free(tmpStr);
146     }
147     if (configs.style.background_color) {
148         gchar* tmpStr = gdk_rgba_to_string(configs.style.background_color);
149         TRACE("     background_color            = %s", tmpStr);
150         g_free(tmpStr);
151     }
152 #endif
153 }
154 
termit_configs_set_defaults()155 void termit_configs_set_defaults()
156 {
157     configs.default_window_title = g_strdup("Termit");
158     configs.default_tab_name = g_strdup("Terminal");
159     termit_style_init(&configs.style);
160     configs.default_command = g_strdup(g_getenv("SHELL"));
161     configs.default_encoding = g_strdup("UTF-8");
162     configs.default_word_char_exceptions = g_strdup("-A-Za-z0-9,./?%&#_~");
163     configs.scrollback_lines = 4096;
164     configs.cols = 80;
165     configs.rows = 24;
166     configs.default_bksp = VTE_ERASE_AUTO;
167     configs.default_delete = VTE_ERASE_AUTO;
168     configs.default_blink = VTE_CURSOR_BLINK_SYSTEM;
169     configs.default_shape = VTE_CURSOR_SHAPE_BLOCK;
170 
171     configs.user_menus = g_array_new(FALSE, TRUE, sizeof(struct UserMenu));
172     configs.user_popup_menus = g_array_new(FALSE, TRUE, sizeof(struct UserMenu));
173     configs.key_bindings = g_array_new(FALSE, TRUE, sizeof(struct KeyBinding));
174     configs.mouse_bindings = g_array_new(FALSE, TRUE, sizeof(struct MouseBinding));
175     configs.matches = g_array_new(FALSE, TRUE, sizeof(struct Match));
176 
177     configs.start_maximized = FALSE;
178     configs.hide_titlebar_when_maximized = FALSE;
179     configs.hide_single_tab = FALSE;
180     configs.show_scrollbar = TRUE;
181     configs.fill_tabbar = FALSE;
182     configs.hide_menubar = FALSE;
183     configs.hide_tabbar = FALSE;
184     configs.show_border = TRUE;
185     configs.allow_changing_title = FALSE;
186     configs.audible_bell = FALSE;
187     configs.urgency_on_bell = FALSE;
188     configs.get_window_title_callback = 0;
189     configs.get_tab_title_callback = 0;
190     configs.get_statusbar_callback = 0;
191     configs.kb_policy = TermitKbUseKeysym;
192     configs.tab_pos = GTK_POS_TOP;
193     configs.scroll_on_output = FALSE;
194     configs.scroll_on_keystroke = TRUE;
195 }
196 
free_menu(GArray * menus)197 static void free_menu(GArray* menus)
198 {
199     guint i = 0;
200     for (; i<menus->len; ++i) {
201         struct UserMenu* um = &g_array_index(menus, struct UserMenu, i);
202         guint j = 0;
203         for (; j<um->items->len; ++j) {
204             struct UserMenuItem* umi = &g_array_index(um->items, struct UserMenuItem, j);
205             g_free(umi->name);
206             g_free(umi->accel);
207             termit_lua_unref(&umi->lua_callback);
208         }
209         g_free(um->name);
210         g_array_free(um->items, TRUE);
211     }
212 }
213 
termit_config_deinit()214 void termit_config_deinit()
215 {
216     g_free(configs.default_window_title);
217     g_free(configs.default_tab_name);
218     termit_style_free(&configs.style);
219     g_free(configs.default_command);
220     g_free(configs.default_encoding);
221     g_free(configs.default_word_char_exceptions);
222 
223     free_menu(configs.user_menus);
224     g_array_free(configs.user_menus, TRUE);
225     free_menu(configs.user_popup_menus);
226     g_array_free(configs.user_popup_menus, TRUE);
227 
228     // name and default_binding are static (e.g. can be in readonly mempage)
229     guint i = 0;
230     for (; i<configs.key_bindings->len; ++i) {
231         struct KeyBinding* kb = &g_array_index(configs.key_bindings, struct KeyBinding, i);
232         termit_lua_unref(&kb->lua_callback);
233     }
234     g_array_free(configs.key_bindings, TRUE);
235 
236     i = 0;
237     for (; i<configs.mouse_bindings->len; ++i) {
238         struct MouseBinding* mb = &g_array_index(configs.mouse_bindings, struct MouseBinding, i);
239         termit_lua_unref(&mb->lua_callback);
240     }
241     g_array_free(configs.mouse_bindings, TRUE);
242 
243     i = 0;
244     for (; i<configs.matches->len; ++i) {
245         struct Match* match = &g_array_index(configs.matches, struct Match, i);
246         vte_regex_unref(match->regex);
247         g_free(match->pattern);
248     }
249     g_array_free(configs.matches, TRUE);
250 
251     termit_lua_unref(&configs.get_window_title_callback);
252     termit_lua_unref(&configs.get_tab_title_callback);
253     termit_lua_unref(&configs.get_statusbar_callback);
254 }
255