girara
 All Data Structures Files Functions Variables Typedefs Enumerations Enumerator Macros
config.c
Go to the documentation of this file.
1 /* See LICENSE file for license and copyright information */
2 
3 #include <stdlib.h>
4 #include <string.h>
5 #include <glib/gi18n-lib.h>
6 
7 #include "config.h"
8 #include "commands.h"
9 #include "datastructures.h"
10 #include "internal.h"
11 #include "session.h"
12 #include "settings.h"
13 #include "shortcuts.h"
14 #include "utils.h"
15 
16 #define COMMENT_PREFIX "\"#"
17 
18 static void
19 cb_window_icon(girara_session_t* session, const char* UNUSED(name),
20  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
21 {
22  g_return_if_fail(session != NULL && value != NULL);
23 
24  if (session->gtk.window != NULL) {
25  char* path = girara_fix_path(value); // value != NULL
26 
27  GError* error = NULL;
28  gtk_window_set_icon_from_file(GTK_WINDOW(session->gtk.window), path, &error);
29  if (error != NULL) {
30  girara_error("failed to load window icon: %s", error->message);
31  g_error_free(error);
32  }
33 
34  free(path);
35  }
36 }
37 
38 static void
39 cb_font(girara_session_t* session, const char* UNUSED(name),
40  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
41 {
42  g_return_if_fail(session != NULL && value != NULL);
43 
44  pango_font_description_free(session->style.font);
45 
46  /* parse font */
47  PangoFontDescription* font = pango_font_description_from_string(value);
48  session->style.font = font;
49 
50  /* inputbar */
51  if (session->gtk.inputbar_entry != NULL) {
52  gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_entry), font);
53  }
54 
55  if (session->gtk.inputbar_dialog != NULL) {
56  gtk_widget_override_font(GTK_WIDGET(session->gtk.inputbar_dialog), font);
57  }
58 
59  /* notification area */
60  if (session->gtk.notification_text != NULL) {
61  gtk_widget_override_font(GTK_WIDGET(session->gtk.notification_text), font);
62  }
63 
64  GIRARA_LIST_FOREACH(session->elements.statusbar_items, girara_statusbar_item_t *, iter, item)
65  if (item != NULL){
66  gtk_widget_override_font(GTK_WIDGET(item->text), font);
67  }
68  GIRARA_LIST_FOREACH_END(session->elements.statusbar_items, girara_statusbar_item_t *, iter, item);
69 }
70 
71 static void
72 cb_guioptions(girara_session_t* session, const char* UNUSED(name),
73  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
74 {
75  g_return_if_fail(session != NULL && value != NULL);
76 
77  /* set default values */
78  bool show_commandline = false;
79  bool show_statusbar = false;
80 
81  /* evaluate input */
82  char* input = (char*) value;
83  int input_length = strlen(input);
84 
85  for (int i = 0; i < input_length; i++) {
86  switch (input[i]) {
87  /* command line */
88  case 'c':
89  show_commandline = true;
90  break;
91  /* statusbar */
92  case 's':
93  show_statusbar = true;
94  break;
95  }
96  }
97 
98  /* apply settings */
99  if (show_commandline == true) {
100  session->global.autohide_inputbar = false;
101  gtk_widget_show(session->gtk.inputbar);
102  } else {
103  session->global.autohide_inputbar = true;
104  gtk_widget_hide(session->gtk.inputbar);
105  }
106 
107  if (show_statusbar == true) {
108  session->global.hide_statusbar = false;
109  gtk_widget_show(session->gtk.statusbar);
110  } else {
111  session->global.hide_statusbar = true;
112  gtk_widget_hide(session->gtk.statusbar);
113  }
114 }
115 
116 static void
117 cb_scrollbars(girara_session_t* session, const char* name,
118  girara_setting_type_t UNUSED(type), void* value, void* UNUSED(data))
119 {
120  g_return_if_fail(session != NULL && value != NULL);
121 
122  bool val = *(bool*) value;
123  bool show_hscrollbar = false;
124  bool show_vscrollbar = false;
125 
126 #if (GTK_MAJOR_VERSION == 3)
127  GtkWidget *vscrollbar = gtk_scrolled_window_get_vscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
128  GtkWidget *hscrollbar = gtk_scrolled_window_get_hscrollbar(GTK_SCROLLED_WINDOW(session->gtk.view));
129 
130  if (vscrollbar != NULL) {
131  show_vscrollbar = gtk_widget_get_visible(vscrollbar);
132  }
133 
134  if (hscrollbar != NULL) {
135  show_hscrollbar = gtk_widget_get_visible(hscrollbar);
136  }
137 #else
138  GtkPolicyType h_policy, v_policy;
139  gtk_scrolled_window_get_policy(GTK_SCROLLED_WINDOW(session->gtk.view), &h_policy, &v_policy);
140  show_vscrollbar = (v_policy == GTK_POLICY_AUTOMATIC);
141  show_hscrollbar = (h_policy == GTK_POLICY_AUTOMATIC);
142 #endif
143 
144  if (!strcmp(name, "show-scrollbars")) {
145  show_hscrollbar = show_vscrollbar = val;
146 
147  girara_setting_set(session, "show-h-scrollbar", &val);
148  girara_setting_set(session, "show-v-scrollbar", &val);
149 
150  } else if (!strcmp(name, "show-h-scrollbar")) {
151  show_hscrollbar = val;
152 
153  } else if (!strcmp(name, "show-v-scrollbar")) {
154  show_vscrollbar = val;
155  }
156 
157 #if (GTK_MAJOR_VERSION == 3)
158  if (vscrollbar != NULL) {
159  gtk_widget_set_visible(vscrollbar, show_vscrollbar);
160  }
161 
162  if (hscrollbar != NULL) {
163  gtk_widget_set_visible(hscrollbar, show_hscrollbar);
164  }
165 #else
166  h_policy = show_hscrollbar ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER;
167  v_policy = show_vscrollbar ? GTK_POLICY_AUTOMATIC : GTK_POLICY_NEVER;
168  gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(session->gtk.view), h_policy, v_policy);
169 #endif
170 
171  /* be careful to avoid infinite recursion as changing settings triggers
172  cb_scrollbars call */
173  girara_setting_get(session, "show-scrollbars", &val);
174  if (show_hscrollbar && show_vscrollbar && !val) {
175  val = true;
176  girara_setting_set(session, "show-scrollbars", &val);
177  } else if (!show_hscrollbar && !show_vscrollbar && val) {
178  val = false;
179  girara_setting_set(session, "show-scrollbars", &val);
180  }
181 }
182 
183 void
184 girara_config_load_default(girara_session_t* session)
185 {
186  if (session == NULL) {
187  return;
188  }
189 
190  /* values */
191  int statusbar_padding = 2;
192  int window_width = 800;
193  int window_height = 600;
194  int n_completion_items = 15;
195  bool show_scrollbars = false;
196  girara_mode_t normal_mode = session->modes.normal;
197 
198  /* other values */
199  session->global.autohide_inputbar = true;
200 
201  /* settings */
202  girara_setting_add(session, "font", "monospace normal 9", STRING, FALSE, _("Font"), cb_font, NULL);
203  girara_setting_add(session, "default-fg", "#DDDDDD", STRING, TRUE, _("Default foreground color"), NULL, NULL);
204  girara_setting_add(session, "default-bg", "#000000", STRING, TRUE, _("Default background color"), NULL, NULL);
205  girara_setting_add(session, "inputbar-fg", "#9FBC00", STRING, TRUE, _("Inputbar foreground color"), NULL, NULL);
206  girara_setting_add(session, "inputbar-bg", "#131313", STRING, TRUE, _("Inputbar background color"), NULL, NULL);
207  girara_setting_add(session, "statusbar-fg", "#FFFFFF", STRING, TRUE, _("Statusbar foreground color"), NULL, NULL);
208  girara_setting_add(session, "statusbar-bg", "#000000", STRING, TRUE, _("Statsubar background color"), NULL, NULL);
209  girara_setting_add(session, "completion-fg", "#DDDDDD", STRING, TRUE, _("Completion foreground color"), NULL, NULL);
210  girara_setting_add(session, "completion-bg", "#232323", STRING, TRUE, _("Completion background color"), NULL, NULL);
211  girara_setting_add(session, "completion-group-fg", "#DEDEDE", STRING, TRUE, _("Completion group foreground color"), NULL, NULL);
212  girara_setting_add(session, "completion-group-bg", "#000000", STRING, TRUE, _("Completion group background color"), NULL, NULL);
213  girara_setting_add(session, "completion-highlight-fg", "#232323", STRING, TRUE, _("Completion highlight foreground color"), NULL, NULL);
214  girara_setting_add(session, "completion-highlight-bg", "#9FBC00", STRING, TRUE, _("Completion highlight background color"), NULL, NULL);
215  girara_setting_add(session, "notification-error-fg", "#FFFFFF", STRING, TRUE, _("Error notification foreground color"), NULL, NULL);
216  girara_setting_add(session, "notification-error-bg", "#FF1212", STRING, TRUE, _("Error notification background color"), NULL, NULL);
217  girara_setting_add(session, "notification-warning-fg", "#000000", STRING, TRUE, _("Warning notification foreground color"), NULL, NULL);
218  girara_setting_add(session, "notification-warning-bg", "#F3F000", STRING, TRUE, _("Warning notifaction background color"), NULL, NULL);
219  girara_setting_add(session, "notification-fg", "#000000", STRING, TRUE, _("Notification foreground color"), NULL, NULL);
220  girara_setting_add(session, "notification-bg", "#FFFFFF", STRING, TRUE, _("Notification background color"), NULL, NULL);
221  girara_setting_add(session, "tabbar-fg", "#939393", STRING, TRUE, _("Tab bar foreground color"), NULL, NULL);
222  girara_setting_add(session, "tabbar-bg", "#000000", STRING, TRUE, _("Tab bar background color"), NULL, NULL);
223  girara_setting_add(session, "tabbar-focus-fg", "#9FBC00", STRING, TRUE, _("Tab bar foreground color (active)"), NULL, NULL);
224  girara_setting_add(session, "tabbar-focus-bg", "#000000", STRING, TRUE, _("Tab bar background color (active)"), NULL, NULL);
225  girara_setting_add(session, "word-separator", " /.-=&#?", STRING, TRUE, NULL, NULL, NULL);
226  girara_setting_add(session, "window-width", &window_width, INT, TRUE, _("Initial window width"), NULL, NULL);
227  girara_setting_add(session, "window-height", &window_height, INT, TRUE, _("Initial window height"), NULL, NULL);
228  girara_setting_add(session, "statusbar-padding", &statusbar_padding, INT, TRUE, _("Vertical padding for the status input and notification bars"), NULL, NULL);
229  girara_setting_add(session, "n-completion-items", &n_completion_items, INT, TRUE, _("Number of completion items"), NULL, NULL);
230  girara_setting_add(session, "show-scrollbars", &show_scrollbars, BOOLEAN, FALSE, _("Show both the horizontal and vertical scrollbars"), cb_scrollbars, NULL);
231  girara_setting_add(session, "show-h-scrollbar", &show_scrollbars, BOOLEAN, FALSE, _("Show the horizontal scrollbar"), cb_scrollbars, NULL);
232  girara_setting_add(session, "show-v-scrollbar", &show_scrollbars, BOOLEAN, FALSE, _("Show the vertical scrollbar"), cb_scrollbars, NULL);
233  girara_setting_add(session, "window-icon", "", STRING, FALSE, _("Window icon"), cb_window_icon, NULL);
234  girara_setting_add(session, "exec-command", "", STRING, FALSE, _("Command to execute in :exec"), NULL, NULL);
235  girara_setting_add(session, "guioptions", "s", STRING, FALSE, _("Show or hide certain GUI elements"), cb_guioptions, NULL);
236 
237  /* shortcuts */
238  girara_shortcut_add(session, 0, GDK_KEY_Escape, NULL, girara_sc_abort, normal_mode, 0, NULL);
239  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_c, NULL, girara_sc_abort, normal_mode, 0, NULL);
240  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_q, NULL, girara_sc_quit, normal_mode, 0, NULL);
241  girara_shortcut_add(session, 0, GDK_KEY_colon, NULL, girara_sc_focus_inputbar, normal_mode, 0, ":");
242  girara_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_w, NULL, girara_sc_tab_close, normal_mode, 0, NULL);
243  girara_shortcut_add(session, 0, 0, "gt", girara_sc_tab_navigate, normal_mode, GIRARA_NEXT, NULL);
244  girara_shortcut_add(session, 0, 0, "gT", girara_sc_tab_navigate, normal_mode, GIRARA_PREVIOUS, NULL);
245 
246  /* inputbar shortcuts */
247  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Escape, girara_isc_abort, 0, NULL);
248  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_c, girara_isc_abort, 0, NULL);
249  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Tab, girara_isc_completion, GIRARA_NEXT, NULL);
250  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_Tab, girara_isc_completion, GIRARA_NEXT_GROUP, NULL);
251  girara_inputbar_shortcut_add(session, 0, GDK_KEY_ISO_Left_Tab, girara_isc_completion, GIRARA_PREVIOUS, NULL);
252  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_ISO_Left_Tab, girara_isc_completion, GIRARA_PREVIOUS_GROUP, NULL);
254  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_h, girara_isc_string_manipulation, GIRARA_DELETE_LAST_CHAR, NULL);
256  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_k, girara_isc_string_manipulation, GIRARA_DELETE_TO_LINE_END, NULL);
257  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_d, girara_isc_string_manipulation, GIRARA_DELETE_CURR_CHAR, NULL);
258  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_w, girara_isc_string_manipulation, GIRARA_DELETE_LAST_WORD, NULL);
259  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_f, girara_isc_string_manipulation, GIRARA_NEXT_CHAR, NULL);
260  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_b, girara_isc_string_manipulation, GIRARA_PREVIOUS_CHAR, NULL);
263  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_a, girara_isc_string_manipulation, GIRARA_GOTO_START, NULL);
264  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_e, girara_isc_string_manipulation, GIRARA_GOTO_END, NULL);
266  girara_inputbar_shortcut_add(session, 0, GDK_KEY_Down, girara_isc_command_history, GIRARA_NEXT, NULL);
267  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_p, girara_isc_command_history, GIRARA_PREVIOUS, NULL);
268  girara_inputbar_shortcut_add(session, GDK_CONTROL_MASK, GDK_KEY_n, girara_isc_command_history, GIRARA_NEXT, NULL);
269 
270  /* commands */
271  girara_inputbar_command_add(session, "exec", NULL, girara_cmd_exec, NULL, _("Execute a command"));
272  girara_inputbar_command_add(session, "map", "m", girara_cmd_map, NULL, _("Map a key sequence"));
273  girara_inputbar_command_add(session, "quit", "q", girara_cmd_quit, NULL, _("Quit the program"));
274  girara_inputbar_command_add(session, "set", "s", girara_cmd_set, girara_cc_set, _("Set an option"));
275  girara_inputbar_command_add(session, "unmap", NULL, girara_cmd_unmap, NULL, _("Unmap a key sequence"));
276 
277  /* config handle */
278  girara_config_handle_add(session, "map", girara_cmd_map);
279  girara_config_handle_add(session, "set", girara_cmd_set);
280  girara_config_handle_add(session, "unmap", girara_cmd_unmap);
281 
282  /* shortcut mappings */
283  girara_shortcut_mapping_add(session, "focus_inputbar", girara_sc_focus_inputbar);
286  girara_shortcut_mapping_add(session, "feedkeys", girara_sc_feedkeys);
289 }
290 
291 bool
292 girara_config_handle_add(girara_session_t* session, const char* identifier, girara_command_function_t handle)
293 {
294  g_return_val_if_fail(session != NULL, false);
295  g_return_val_if_fail(identifier != NULL, false);
296 
297  /* search for existing config handle */
298  GIRARA_LIST_FOREACH(session->config.handles, girara_config_handle_t*, iter, data)
299  if (strcmp(data->identifier, identifier) == 0) {
300  data->handle = handle;
302  return true;
303  }
304  GIRARA_LIST_FOREACH_END(session->config.handles, girara_config_handle_t*, iter, data);
305 
306  /* add new config handle */
307  girara_config_handle_t* config_handle = g_slice_new(girara_config_handle_t);
308 
309  config_handle->identifier = g_strdup(identifier);
310  config_handle->handle = handle;
311  girara_list_append(session->config.handles, config_handle);
312 
313  return true;
314 }
315 
316 void
317 girara_config_handle_free(girara_config_handle_t* handle)
318 {
319  if (handle == NULL) {
320  return;
321  }
322 
323  g_free(handle->identifier);
324  g_slice_free(girara_config_handle_t, handle);
325 }
326 
327 static bool
328 config_parse(girara_session_t* session, const char* path)
329 {
330  /* open file */
331  FILE* file = girara_file_open(path, "r");
332 
333  if (file == NULL) {
334  return false;
335  }
336 
337  /* read lines */
338  char* line = NULL;
339  unsigned int line_number = 1;
340  while ((line = girara_file_read_line(file)) != NULL) {
341  /* skip empty lines and comments */
342  if (strlen(line) == 0 || strchr(COMMENT_PREFIX, line[0]) != NULL) {
343  free(line);
344  continue;
345  }
346 
347  gchar** argv = NULL;
348  gint argc = 0;
349 
350  girara_list_t* argument_list = girara_list_new();
351  if (argument_list == NULL) {
352  free(line);
353  fclose(file);
354  return false;
355  }
356 
357  girara_list_set_free_function(argument_list, g_free);
358  if (g_shell_parse_argv(line, &argc, &argv, NULL) != FALSE) {
359  for(int i = 1; i < argc; i++) {
360  char* argument = g_strdup(argv[i]);
361  girara_list_append(argument_list, (void*) argument);
362  }
363  } else {
364  girara_list_free(argument_list);
365  fclose(file);
366  free(line);
367  return false;
368  }
369 
370  /* include gets a special treatment */
371  if (strcmp(argv[0], "include") == 0) {
372  if (argc != 2) {
373  girara_warning("Could not process line %d in '%s': usage: include path.", line_number, path);
374  } else {
375  char* newpath = NULL;
376  if (g_path_is_absolute(argv[1]) == TRUE) {
377  newpath = g_strdup(argv[1]);
378  } else {
379  char* basename = g_path_get_dirname(path);
380  char* tmp = g_build_filename(basename, argv[1], NULL);
381  newpath = girara_fix_path(tmp);
382  g_free(tmp);
383  g_free(basename);
384  }
385 
386  if (strcmp(newpath, path) == 0) {
387  girara_warning("Could not process line %d in '%s': trying to include itself.", line_number, path);
388  } else {
389  girara_debug("Loading config file '%s'.", newpath);
390  if (config_parse(session, newpath) == FALSE) {
391  girara_warning("Could not process line %d in '%s': failed to load '%s'.", line_number, path, newpath);
392  }
393  }
394  g_free(newpath);
395  }
396  } else {
397  /* search for config handle */
398  girara_config_handle_t* handle = NULL;
399  GIRARA_LIST_FOREACH(session->config.handles, girara_config_handle_t*, iter, tmp)
400  handle = tmp;
401  if (strcmp(handle->identifier, argv[0]) == 0) {
402  handle->handle(session, argument_list);
403  break;
404  } else {
405  handle = NULL;
406  }
407  GIRARA_LIST_FOREACH_END(session->config.handles, girara_config_handle_t*, iter, tmp);
408 
409  if (handle == NULL) {
410  girara_warning("Could not process line %d in '%s': Unknown handle '%s'", line_number, path, argv[0]);
411  }
412  }
413 
414  line_number++;
415  girara_list_free(argument_list);
416  g_strfreev(argv);
417  free(line);
418  }
419 
420  fclose(file);
421  return true;
422 }
423 
424 void
425 girara_config_parse(girara_session_t* session, const char* path)
426 {
427  config_parse(session, path);
428 }