1 /* vim: set ts=4 sts=4 sw=4 expandtab nowrap: */
2 /*
3  * This is free software; you can redistribute it and/or modify it under
4  * the terms of the GNU Library General Public License as published by
5  * the Free Software Foundation; either version 2 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, but
9  * WITHOUT ANY WARRANTY; without even the implied warranty of
10  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
11  * General Public License for more details.
12  *
13  * You should have received a copy of the GNU Library General Public
14  * License along with this library. If not, see <http://www.gnu.org/licenses/>.
15  */
16 
17 #include <tilda-config.h>
18 
19 #include <errno.h>
20 
21 #include "debug.h"
22 #include "tilda.h"
23 #include "wizard.h"
24 #include "key_grabber.h"
25 #include "configsys.h"
26 #include "screen-size.h"
27 #include "tilda-palettes.h"
28 #include "tilda_window.h"
29 #include "tilda-keybinding.h"
30 
31 #include <gtk/gtk.h>
32 #include <gdk/gdkkeysyms.h>
33 #include <glib.h>
34 #include <glib/gi18n.h>
35 #include <vte/vte.h> /* VTE_* constants, mostly */
36 #include <stdio.h>
37 #include <sys/types.h>
38 #include <sys/stat.h>
39 #include <stdlib.h>
40 
41 /* INT_MAX */
42 #include <limits.h>
43 
44 struct TildaWizard_
45 {
46     tilda_window            *tw;
47     TildaKeybindingTreeView *keybinding;
48     GtkBuilder              *builder;
49 };
50 
51 typedef struct TildaWizard_ TildaWizard;
52 
53 /* This will hold the GtkBuilder representation of the .ui file.
54  * We keep this global so that we can look up any element from any routine.
55  *
56  * Note that for GtkBuilder to autoconnect signals, the functions that it hooks
57  * to must NOT be marked static. I decided against the autoconnect just to
58  * keep things "in the code" so that they can be grepped for easily. */
59 static GtkBuilder *xml = NULL;
60 
61 /* Prototypes for use in the wizard() */
62 static void set_wizard_state_from_config (tilda_window *tw);
63 static void connect_wizard_signals (TildaWizard *wizard);
64 static void init_palette_scheme_menu (void);
65 static void update_palette_color_button(gint idx);
66 static void initialize_geometry_spinners(tilda_window *tw);
67 
68 /* Show the wizard. This will show the wizard, then exit immediately. */
wizard(tilda_window * tw)69 gint wizard (tilda_window *tw)
70 {
71     DEBUG_FUNCTION ("wizard");
72     DEBUG_ASSERT (tw != NULL);
73 
74     gchar *window_title;
75 
76     /* Make sure that there isn't already a wizard showing */
77     if (tw->wizard_window) {
78         gtk_window_present (GTK_WINDOW (tw->wizard_window));
79         return 0;
80     }
81 
82     TildaWizard *wizard = g_malloc (sizeof (TildaWizard));
83 
84     GError* error = NULL;
85     xml = gtk_builder_new ();
86 
87 #if ENABLE_NLS
88     gtk_builder_set_translation_domain (xml, PACKAGE);
89 #endif
90 
91     if(!gtk_builder_add_from_resource (xml, "/org/tilda/tilda.ui", &error)) {
92         g_prefix_error(&error, "Error:");
93         return EXIT_FAILURE;
94     }
95 
96     if (!xml) {
97         g_warning ("problem while loading the tilda.ui file");
98         return 2;
99     }
100 
101     wizard->builder = xml;
102     wizard->tw = tw;
103 
104     tw->wizard_window = GTK_WIDGET (
105         gtk_builder_get_object (xml, "wizard_window")
106     );
107 
108     /* GtkDialog windows need to have a transient parent or a warning will be logged. */
109     gtk_window_set_transient_for (GTK_WINDOW(tw->wizard_window), GTK_WINDOW(tw->window));
110 
111     init_palette_scheme_menu ();
112 
113     /* Copy the current program state into the wizard */
114     set_wizard_state_from_config (tw);
115 
116     wizard->keybinding = tilda_keybinding_init (wizard->builder);
117 
118     /* Connect all signal handlers. We do this after copying the state into
119      * the wizard so that all of the handlers don't get called as we copy in
120      * the values. This function manually connects the required signals for
121      * all the widgets */
122     connect_wizard_signals (wizard);
123 
124     /* Unbind the current keybinding. I'm aware that this opens up an opportunity to
125      * let "someone else" grab the key, but it also saves us some trouble, and makes
126      * validation easier. */
127     tilda_keygrabber_unbind (config_getstr ("key"));
128 
129     /* Adding widget title for CSS selection */
130     gtk_widget_set_name (GTK_WIDGET(tw->wizard_window), "Wizard");
131 
132     /* Set the icon for the wizard window to our tilda icon. */
133     gchar* filename = g_build_filename (DATADIR, "pixmaps", "tilda.png", NULL);
134     GdkPixbuf *pixbuf = gdk_pixbuf_new_from_file(filename, NULL);
135     g_free(filename);
136     gtk_window_set_icon(GTK_WINDOW(tw->wizard_window), pixbuf);
137 
138     window_title = g_strdup_printf (_("Tilda %d Config"), tw->instance);
139     gtk_window_set_title (GTK_WINDOW(tw->wizard_window), window_title);
140     gtk_window_set_type_hint (GTK_WINDOW(tw->wizard_window), GDK_WINDOW_TYPE_HINT_DIALOG);
141 
142     gtk_widget_show_all (tw->wizard_window);
143 
144     /* This is needed to ensure that the wizard appears above of the terminal window */
145     gtk_window_present(GTK_WINDOW(tw->wizard_window));
146 
147     g_free (window_title);
148 
149     /* Disable auto hide */
150     tw->disable_auto_hide = TRUE;
151 
152     return 0;
153 }
154 
155 # define GET_BUTTON_LABEL(BUTTON) ( gtk_button_get_label( GTK_BUTTON( \
156     gtk_builder_get_object (xml, BUTTON))))
157 
158 /* Gets called just after the wizard is closed. This should clean up after
159  * the wizard, and do anything that couldn't be done immediately during the
160  * wizard's lifetime. */
wizard_close_dialog(TildaWizard * wizard)161 static void wizard_close_dialog (TildaWizard *wizard)
162 {
163     DEBUG_FUNCTION ("wizard_close_dialog");
164 
165     tilda_window *tw = wizard->tw;
166 
167     const GtkWidget *entry_custom_command =
168         GTK_WIDGET (gtk_builder_get_object(xml, "entry_custom_command"));
169     const GtkWidget *wizard_window = tw->wizard_window;
170     const gchar *command = gtk_entry_get_text (GTK_ENTRY(entry_custom_command));
171 
172     if (!tilda_keybinding_save (wizard->keybinding, tw)) {
173         return;
174     }
175 
176     tilda_keybinding_apply (wizard->keybinding);
177 
178     tilda_keybinding_free (wizard->keybinding);
179 
180     wizard->keybinding = NULL;
181 
182     /* TODO: validate this?? */
183     config_setstr ("command", command);
184 
185     /* Free the GtkBuilder data structure */
186     g_object_unref (G_OBJECT(xml));
187     xml = NULL;
188 
189     /* Remove the wizard */
190     gtk_widget_destroy (GTK_WIDGET(wizard_window));
191     tw->wizard_window = NULL;
192 
193     /* Write the config, because it probably changed. This saves us in case
194      * of an XKill (or crash) later ... */
195     config_write (tw->config_file);
196 
197     /* Enables auto hide */
198     tw->disable_auto_hide = FALSE;
199 
200     wizard->tw = NULL;
201     wizard->builder = NULL;
202     g_free (wizard);
203 }
204 
205 /******************************************************************************/
206 /*                       Wizard set-up functions                              */
207 /******************************************************************************/
208 
209 /* The following macro definitions are used to make the process of loading the
210  * configuration values a lot easier. Each macro takes the name of a GtkBuilder object
211  * and the name of a configuration option and sets the value for that widget to the value
212  * that is stored in this configuration option. The macros are mainly used in the function
213  * set_wizard_state_from_config() but they are used in some callback functions as well, so
214  * we need to define before the callback functions.
215  */
216 
217 /** Setters */
218 #define CHECK_BUTTON(GLADE_NAME,CFG_BOOL) gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON( \
219     gtk_builder_get_object (xml, (GLADE_NAME))), config_getbool ((CFG_BOOL)))
220 #define COMBO_BOX(GLADE_NAME,CFG_INT) gtk_combo_box_set_active (GTK_COMBO_BOX( \
221     gtk_builder_get_object (xml, (GLADE_NAME))), config_getint ((CFG_INT)))
222 #define FONT_BUTTON(GLADE_NAME,CFG_STR) gtk_font_chooser_set_font (GTK_FONT_CHOOSER( \
223     gtk_builder_get_object (xml, (GLADE_NAME))), config_getstr ((CFG_STR)))
224 #define TEXT_ENTRY(GLADE_NAME,CFG_STR) gtk_entry_set_text (GTK_ENTRY( \
225     gtk_builder_get_object (xml, (GLADE_NAME))), config_getstr ((CFG_STR)))
226 #define BUTTON_LABEL_FROM_CFG(GLADE_NAME,CFG_STR) gtk_button_set_label (GTK_BUTTON( \
227     gtk_builder_get_object (xml, (GLADE_NAME))), config_getstr ((CFG_STR)))
228 #define SPIN_BUTTON(GLADE_NAME,CFG_INT) gtk_spin_button_set_value (GTK_SPIN_BUTTON( \
229     gtk_builder_get_object (xml, (GLADE_NAME))), config_getint ((CFG_INT)))
230 #define SPIN_BUTTON_SET_RANGE(GLADE_NAME,LOWER,UPPER) gtk_spin_button_set_range (GTK_SPIN_BUTTON( \
231     gtk_builder_get_object (xml, (GLADE_NAME))), (LOWER), (UPPER))
232 #define SPIN_BUTTON_SET_VALUE(GLADE_NAME,VALUE) gtk_spin_button_set_value (GTK_SPIN_BUTTON( \
233     gtk_builder_get_object (xml, (GLADE_NAME))), (VALUE))
234 #define FILE_BUTTON(GLADE_NAME, FILENAME) gtk_file_chooser_set_filename (GTK_FILE_CHOOSER( \
235     gtk_builder_get_object (xml, (GLADE_NAME))), FILENAME)
236 #define COLOR_CHOOSER(GLADE_NAME,COLOR) gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER( \
237     gtk_builder_get_object (xml, (GLADE_NAME))), (COLOR))
238 #define SET_SENSITIVE_BY_CONFIG_BOOL(GLADE_NAME,CFG_BOOL) gtk_widget_set_sensitive ( \
239     GTK_WIDGET (gtk_builder_get_object (xml, (GLADE_NAME))), config_getbool ((CFG_BOOL)))
240 #define SET_SENSITIVE_BY_CONFIG_NBOOL(GLADE_NAME,CFG_BOOL) gtk_widget_set_sensitive ( \
241     GTK_WIDGET (gtk_builder_get_object (xml, (GLADE_NAME))), !config_getbool ((CFG_BOOL)))
242 
243 /** Getters */
244 #define SPIN_BUTTON_GET_VALUE(GLADE_NAME) gtk_spin_button_get_value (GTK_SPIN_BUTTON( \
245     gtk_builder_get_object (xml, (GLADE_NAME))))
246 #define SPIN_BUTTON_GET_RANGE(GLADE_NAME,MIN_POINTER,MAX_POINTER) gtk_spin_button_get_range (GTK_SPIN_BUTTON( \
247     gtk_builder_get_object (xml, (GLADE_NAME))), MIN_POINTER, MAX_POINTER)
248 
249 /******************************************************************************/
250 /*      Utility functions to get the current monitors height and width        */
251 /******************************************************************************/
get_max_height()252 static int get_max_height() {
253     gdouble height_min;
254     gdouble height_max;
255     SPIN_BUTTON_GET_RANGE("spin_height_pixels", &height_min, &height_max);
256     return (int) height_max;
257 }
258 
get_max_width()259 static int get_max_width() {
260     gdouble width_min;
261     gdouble width_max;
262     SPIN_BUTTON_GET_RANGE("spin_width_pixels", &width_min, &width_max);
263     return (int) width_max;
264 }
265 
266 /******************************************************************************/
267 /*               ALL static callback helpers are below                        */
268 /******************************************************************************/
269 
270 /**
271  * Get the number of screens and load the monitor geometry for each screen,
272  * then set the position of the window according to the x and y offset
273  * of that monitor. This function does not actually move or resize the window
274  * but only changes the value of the spin buttons. The moving and resizing
275  * is then done by the callback functions of the respective widgets.
276  */
277 static int
combo_monitor_selection_changed_cb(GtkWidget * widget,tilda_window * tw)278 combo_monitor_selection_changed_cb (GtkWidget* widget, tilda_window *tw)
279 {
280     DEBUG_FUNCTION ("combo_monitor_selection_changed_cb");
281 
282     GdkDisplay *display          = gdk_display_get_default ();
283     GdkMonitor *original_monitor = tilda_window_find_monitor_number (tw);
284     GdkMonitor *new_monitor;
285 
286     GdkRectangle original_monitor_rectangle;
287     GdkRectangle selected_monitor_rectangle;
288 
289     gdk_monitor_get_workarea (original_monitor, &original_monitor_rectangle);
290 
291     GtkTreeIter active_iter;
292 
293     GtkComboBox* combo_choose_monitor = GTK_COMBO_BOX(widget);
294 
295     if(!gtk_combo_box_get_active_iter(combo_choose_monitor, &active_iter))
296     {
297         return FALSE;
298     }
299 
300     gchar* new_monitor_name = NULL;
301     gint new_monitor_number;
302 
303     gtk_tree_model_get(gtk_combo_box_get_model(combo_choose_monitor), &active_iter,
304                        0, &new_monitor_name,
305                        1, &new_monitor_number,
306                        -1);
307 
308     new_monitor = gdk_display_get_monitor (display, new_monitor_number);
309     gdk_monitor_get_workarea (new_monitor, &selected_monitor_rectangle);
310 
311     //Save the new monitor value
312     config_setstr("show_on_monitor", new_monitor_name);
313 
314     /* The dimensions of the monitor might have changed,
315      * so we need to update the spinner widgets for height,
316      * width, and their percentages as well as their ranges.
317      * Keep in mind that we use the max range of the pixel spinners
318      * to store the size of the screen.
319      */
320     GdkRectangle rectangle;
321     config_get_configured_window_size (&rectangle);
322 
323     if(selected_monitor_rectangle.width != original_monitor_rectangle.width)
324     {
325         gint new_max_width = selected_monitor_rectangle.width;
326 
327         SPIN_BUTTON_SET_RANGE ("spin_width_pixels", 0, new_max_width);
328         SPIN_BUTTON_SET_VALUE ("spin_width_pixels", rectangle.width);
329 
330         gtk_window_resize (GTK_WINDOW(tw->window),
331                            rectangle.width,
332                            rectangle.height);
333     }
334 
335     if(selected_monitor_rectangle.height != original_monitor_rectangle.height)
336     {
337         int new_max_height = selected_monitor_rectangle.height;
338 
339         SPIN_BUTTON_SET_RANGE ("spin_height_pixels", 0, new_max_height);
340         SPIN_BUTTON_SET_VALUE ("spin_height_pixels", rectangle.height);
341 
342         gtk_window_resize (GTK_WINDOW(tw->window),
343                            rectangle.width,
344                            rectangle.height);
345     }
346 
347     gint screen_width, screen_height;
348     screen_size_get_dimensions (&screen_width, &screen_height);
349     SPIN_BUTTON_SET_RANGE ("spin_x_position", 0, screen_width);
350     SPIN_BUTTON_SET_VALUE("spin_x_position", selected_monitor_rectangle.x);
351     SPIN_BUTTON_SET_RANGE ("spin_y_position", 0, screen_height);
352     SPIN_BUTTON_SET_VALUE("spin_y_position", selected_monitor_rectangle.y);
353 
354     tilda_window_update_window_position (tw);
355 
356     return GDK_EVENT_STOP;
357 }
358 
window_title_change_all(tilda_window * tw)359 static void window_title_change_all (tilda_window *tw)
360 {
361     DEBUG_FUNCTION ("window_title_change_all");
362 
363     GtkWidget *page;
364     GtkWidget *label;
365     tilda_term *tt;
366     gchar *title;
367     gint i, size, list_count;
368 
369     size = gtk_notebook_get_n_pages (GTK_NOTEBOOK(tw->notebook));
370     list_count = size-1;
371 
372     for (i=0;i<size;i++,list_count--)
373     {
374         tt = g_list_nth (tw->terms, list_count)->data;
375         title = tilda_terminal_get_title (tt);
376         page = gtk_notebook_get_nth_page (GTK_NOTEBOOK (tw->notebook), i);
377         label = gtk_notebook_get_tab_label (GTK_NOTEBOOK (tw->notebook), page);
378 
379         guint length = config_getint ("title_max_length");
380         guint title_behaviour = config_getint("title_behaviour");
381         if(title_behaviour && strlen(title) > length) {
382             gchar *shortTitle = NULL;
383             if(title_behaviour == 1) {
384                 shortTitle = g_strdup_printf ("%.*s...", length, title);
385             }
386             else {
387                 gchar *titleOffset = title + strlen(title) - length;
388                 shortTitle = g_strdup_printf ("...%s", titleOffset);
389             }
390             gtk_label_set_text (GTK_LABEL(label), shortTitle);
391             g_free(shortTitle);
392         } else {
393             gtk_label_set_text (GTK_LABEL(label), title);
394         }
395         if(config_getbool("show_title_tooltip"))
396           gtk_widget_set_tooltip_text(label, title);
397         else
398           gtk_widget_set_tooltip_text(label, "");
399 
400         g_free (title);
401     }
402 }
403 
set_spin_value_while_blocking_callback(GtkSpinButton * spin,void (* callback)(GtkWidget * w,tilda_window * tw),gdouble new_val,tilda_window * tw)404 static void set_spin_value_while_blocking_callback (GtkSpinButton *spin,
405                                                     void (*callback)(GtkWidget *w, tilda_window *tw),
406                                                     gdouble new_val,
407                                                     tilda_window *tw)
408 {
409     DEBUG_FUNCTION ("set_spin_value_while_blocking_callback");
410 
411     g_signal_handlers_block_by_func (spin, G_CALLBACK(*callback), tw);
412     gtk_spin_button_set_value (GTK_SPIN_BUTTON(spin), new_val);
413     g_signal_handlers_unblock_by_func (spin, G_CALLBACK(*callback), tw);
414 }
415 
416 /******************************************************************************/
417 /*                       ALL Callbacks are below                              */
418 /******************************************************************************/
419 
wizard_button_close_clicked_cb(GtkButton * button,TildaWizard * wizard)420 static void wizard_button_close_clicked_cb (GtkButton   *button,
421                                             TildaWizard *wizard)
422 {
423     /* Call the clean-up function */
424     wizard_close_dialog (wizard);
425 }
426 
wizard_window_delete_event_cb(GtkWidget * widget,GdkEvent * event,TildaWizard * wizard)427 static void wizard_window_delete_event_cb (GtkWidget   *widget,
428                                            GdkEvent    *event,
429                                            TildaWizard *wizard)
430 {
431     /* Call the clean-up function */
432     wizard_close_dialog (wizard);
433 }
434 
check_display_on_all_workspaces_toggled_cb(GtkWidget * w,tilda_window * tw)435 static void check_display_on_all_workspaces_toggled_cb (GtkWidget *w, tilda_window *tw)
436 {
437     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
438 
439     config_setbool ("pinned", status);
440 
441     if (status)
442         gtk_window_stick (GTK_WINDOW (tw->window));
443     else
444         gtk_window_unstick (GTK_WINDOW (tw->window));
445 }
446 
check_set_as_desktop_toggled_cb(GtkWidget * widget,tilda_window * tw)447 static void check_set_as_desktop_toggled_cb (GtkWidget *widget, tilda_window *tw)
448 {
449     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(widget));
450     GtkWidget *check_display_on_all_workspaces = GTK_WIDGET (gtk_builder_get_object (xml, "check_display_on_all_workspaces"));
451     config_setbool ("set_as_desktop", status);
452 
453     g_signal_handlers_block_by_func (check_display_on_all_workspaces, check_display_on_all_workspaces_toggled_cb, NULL);
454     gboolean status_display_on_all_workspaces = config_getbool ("pinned");
455     if (status) {
456 
457         gtk_widget_set_sensitive (check_display_on_all_workspaces, FALSE);
458         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_display_on_all_workspaces), TRUE);
459         gtk_window_stick (GTK_WINDOW (tw->window));
460     } else {
461         gtk_widget_set_sensitive (check_display_on_all_workspaces, TRUE);
462         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_display_on_all_workspaces), status_display_on_all_workspaces);
463         gtk_window_unstick (GTK_WINDOW (tw->window));
464     }
465     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), status);
466     g_signal_handlers_unblock_by_func (check_display_on_all_workspaces, check_display_on_all_workspaces_toggled_cb, NULL);
467 }
468 
check_do_not_show_in_taskbar_toggled_cb(GtkWidget * w,tilda_window * tw)469 static void check_do_not_show_in_taskbar_toggled_cb (GtkWidget *w, tilda_window *tw)
470 {
471     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
472 
473     config_setbool ("notaskbar", status);
474     gtk_window_set_skip_taskbar_hint (GTK_WINDOW(tw->window), status);
475 }
476 
check_show_notebook_border_toggled_cb(GtkWidget * w,tilda_window * tw)477 static void check_show_notebook_border_toggled_cb (GtkWidget *w, tilda_window *tw)
478 {
479     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
480 
481     config_setbool ("notebook_border", status);
482     gtk_notebook_set_show_border (GTK_NOTEBOOK (tw->notebook), status);
483 }
484 
check_always_on_top_toggled_cb(GtkWidget * w,tilda_window * tw)485 static void check_always_on_top_toggled_cb (GtkWidget *w, tilda_window *tw)
486 {
487     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
488 
489     config_setbool ("above", status);
490     gtk_window_set_keep_above (GTK_WINDOW (tw->window), status);
491 }
492 
493 
check_start_tilda_hidden_toggled_cb(GtkWidget * w,tilda_window * tw)494 static void check_start_tilda_hidden_toggled_cb (GtkWidget *w, tilda_window *tw)
495 {
496     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
497 
498     config_setbool ("hidden", status);
499 }
500 
check_terminal_bell_toggled_cb(GtkWidget * w,tilda_window * tw)501 static void check_terminal_bell_toggled_cb (GtkWidget *w, tilda_window *tw)
502 {
503     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
504     guint i;
505     tilda_term *tt;
506 
507     config_setbool ("bell", status);
508 
509     for (i=0; i<g_list_length (tw->terms); i++) {
510         tt = g_list_nth_data (tw->terms, i);
511         vte_terminal_set_audible_bell (VTE_TERMINAL(tt->vte_term), status);
512     }
513 }
514 
check_cursor_blinks_toggled_cb(GtkWidget * w,tilda_window * tw)515 static void check_cursor_blinks_toggled_cb (GtkWidget *w, tilda_window *tw)
516 {
517     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
518     guint i;
519     tilda_term *tt;
520 
521     config_setbool ("blinks", status);
522 
523     for (i=0; i<g_list_length (tw->terms); i++) {
524         tt = g_list_nth_data (tw->terms, i);
525         vte_terminal_set_cursor_blink_mode (VTE_TERMINAL(tt->vte_term),
526                 (status)?VTE_CURSOR_BLINK_ON:VTE_CURSOR_BLINK_OFF);
527     }
528 }
529 
spin_auto_hide_time_value_changed_cb(GtkWidget * w,tilda_window * tw)530 static void spin_auto_hide_time_value_changed_cb (GtkWidget *w, tilda_window *tw)
531 {
532     const gint auto_hide_time = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(w));
533     config_setint ("auto_hide_time", auto_hide_time);
534     tw->auto_hide_max_time = auto_hide_time;
535 }
536 
check_auto_hide_on_focus_lost_toggled_cb(GtkWidget * w,tilda_window * tw)537 static void check_auto_hide_on_focus_lost_toggled_cb (GtkWidget *w, tilda_window *tw)
538 {
539     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
540 
541     config_setbool ("auto_hide_on_focus_lost", status);
542     tw->auto_hide_on_focus_lost = status;
543 }
544 
check_auto_hide_on_mouse_leave_toggled_cb(GtkWidget * w,tilda_window * tw)545 static void check_auto_hide_on_mouse_leave_toggled_cb (GtkWidget *w, tilda_window *tw)
546 {
547     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
548 
549     config_setbool ("auto_hide_on_mouse_leave", status);
550     tw->auto_hide_on_mouse_leave = status;
551 }
552 
combo_cursor_shape_changed_cb(GtkWidget * w,tilda_window * tw)553 static void combo_cursor_shape_changed_cb(GtkWidget *w, tilda_window *tw)
554 {
555     guint i;
556     tilda_term *tt;
557     gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
558 
559     if (status < 0 || status > 2) {
560         DEBUG_ERROR ("Invalid Cursor Type");
561         g_printerr (_("Invalid Cursor Type, resetting to default\n"));
562         status = 0;
563     }
564     config_setint("cursor_shape", (VteCursorShape) status);
565 
566     for (i=0; i<g_list_length (tw->terms); i++) {
567         tt = g_list_nth_data (tw->terms, i);
568         vte_terminal_set_cursor_shape (VTE_TERMINAL(tt->vte_term),
569                                        (VteCursorShape) status);
570     }
571 }
572 
combo_non_focus_pull_up_behaviour_cb(GtkWidget * w,tilda_window * tw)573 static void combo_non_focus_pull_up_behaviour_cb (GtkWidget *w, tilda_window *tw)
574 {
575     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
576 
577     if (status < 0 || status > 1) {
578         DEBUG_ERROR ("Non-focus pull up behaviour invalid");
579         g_printerr (_("Invalid non-focus pull up behaviour, ignoring\n"));
580         return;
581     }
582 
583     if(1 == status) {
584         tw->hide_non_focused = TRUE;
585     }
586     else {
587         tw->hide_non_focused = FALSE;
588     }
589 
590     config_setint ("non_focus_pull_up_behaviour", status);
591 }
592 
button_font_font_set_cb(GtkWidget * w,tilda_window * tw)593 static void button_font_font_set_cb (GtkWidget *w, tilda_window *tw)
594 {
595     const gchar *font = gtk_font_chooser_get_font (GTK_FONT_CHOOSER (w));
596     guint i;
597     tilda_term *tt;
598 
599     config_setstr ("font", font);
600     PangoFontDescription *description = pango_font_description_from_string (font);
601     tw->unscaled_font_size = pango_font_description_get_size(description);
602 
603     for (i=0; i<g_list_length (tw->terms); i++) {
604         tt = g_list_nth_data (tw->terms, i);
605         vte_terminal_set_font (VTE_TERMINAL(tt->vte_term), description);
606         tilda_term_adjust_font_scale(tt, tw->current_scale_factor);
607     }
608 }
609 
entry_title_changed_cb(GtkWidget * w,tilda_window * tw)610 static void entry_title_changed_cb (GtkWidget *w, tilda_window *tw)
611 {
612     const gchar *title = gtk_entry_get_text (GTK_ENTRY(w));
613 
614     config_setstr ("title", title);
615     window_title_change_all (tw);
616 }
617 
combo_dynamically_set_title_changed_cb(GtkWidget * w,tilda_window * tw)618 static void combo_dynamically_set_title_changed_cb (GtkWidget *w, tilda_window *tw)
619 {
620     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
621 
622     config_setint ("d_set_title", status);
623     window_title_change_all (tw);
624 }
625 
combo_title_behaviour_changed_cb(GtkWidget * w,tilda_window * tw)626 static void combo_title_behaviour_changed_cb (GtkWidget *w, tilda_window *tw)
627 {
628     DEBUG_FUNCTION ("combo_title_behaviour_changed_cb");
629 
630     GtkWidget *entry = GTK_WIDGET(
631         gtk_builder_get_object (xml, ("spin_title_max_length"))
632     );
633     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
634     config_setint("title_behaviour", status);
635     if (status > 0) {
636         gtk_widget_set_sensitive (entry, TRUE);
637     } else {
638         gtk_widget_set_sensitive (entry, FALSE);
639     }
640 }
641 
spin_max_title_length_changed_cb(GtkWidget * w,tilda_window * tw)642 static void spin_max_title_length_changed_cb (GtkWidget *w, tilda_window *tw)
643 {
644     DEBUG_FUNCTION ("spin_max_title_length_changed_cb");
645 
646     int length = gtk_spin_button_get_value (GTK_SPIN_BUTTON (w));
647 
648     config_setint ("title_max_length", length);
649     window_title_change_all (tw);
650 }
651 
check_run_custom_command_toggled_cb(GtkWidget * w,tilda_window * tw)652 static void check_run_custom_command_toggled_cb (GtkWidget *w, tilda_window *tw)
653 {
654     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
655     GtkWidget *label_custom_command;
656     GtkWidget *entry_custom_command;
657     GtkWidget *check_command_login_shell;
658 
659     config_setbool ("run_command", status);
660 
661     label_custom_command =
662         GTK_WIDGET (gtk_builder_get_object (xml, "label_custom_command"));
663     entry_custom_command =
664         GTK_WIDGET (gtk_builder_get_object (xml, "entry_custom_command"));
665     check_command_login_shell =
666         GTK_WIDGET (gtk_builder_get_object (xml, "check_command_login_shell"));
667 
668     gtk_widget_set_sensitive (label_custom_command, status);
669     gtk_widget_set_sensitive (entry_custom_command, status);
670     gtk_widget_set_sensitive (check_command_login_shell, !status);
671 
672     if(!status) {
673         gtk_entry_set_icon_from_icon_name(GTK_ENTRY(entry_custom_command),
674                 GTK_ENTRY_ICON_SECONDARY,
675                 NULL);
676     }
677 
678     gtk_widget_grab_focus(entry_custom_command);
679 }
680 
681 
682 /**
683  * Check that the value entered into the GtkEntry is a valid command
684  * which is accessible from the users PATH environment variable.
685  * If the command is not found on the users PATH then a small error
686  * icon is displayed on the end of the entry.
687  * This function can only be registered to Widgets of (sub)type GtkEntry
688  */
validate_executable_command_cb(GtkWidget * w,G_GNUC_UNUSED GdkEvent * event,G_GNUC_UNUSED tilda_window * tw)689 static void validate_executable_command_cb (GtkWidget *w,
690                                             G_GNUC_UNUSED GdkEvent *event,
691                                             G_GNUC_UNUSED tilda_window *tw)
692 {
693     g_return_if_fail(w != NULL && GTK_IS_ENTRY(w));
694     const char* command = gtk_entry_get_text (GTK_ENTRY(w));
695     /* Check that the command exists */
696     int argc = 0;
697     gchar** argv = NULL;
698     GError *error = NULL;
699     gboolean success = g_shell_parse_argv(command, &argc, &argv, &error);
700     char *command_filename = NULL;
701     if(success && argc > 0) {
702         command_filename = g_find_program_in_path(argv[0]);
703     }
704     g_strfreev(argv);
705 
706     if (command_filename == NULL && gtk_widget_is_sensitive(w)) {
707         //wrong command
708         gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w),
709                 GTK_ENTRY_ICON_SECONDARY, "dialog-error");
710         gtk_entry_set_icon_tooltip_text(GTK_ENTRY(w),
711                 GTK_ENTRY_ICON_SECONDARY,
712                 "The command you have entered is not a valid command.\n"
713                         "Make sure that the specified executable is in your PATH environment variable."
714         );
715     } else {
716         gtk_entry_set_icon_from_icon_name(GTK_ENTRY(w),
717                 GTK_ENTRY_ICON_SECONDARY,
718                 NULL);
719         free(command_filename);
720     }
721 }
722 
check_confirm_close_tab_cb(GtkWidget * w,G_GNUC_UNUSED tilda_window * tw)723 static void check_confirm_close_tab_cb (GtkWidget *w,
724                                         G_GNUC_UNUSED tilda_window *tw)
725 {
726     const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
727 
728     config_setbool ("confirm_close_tab", active);
729 }
730 
combo_command_exit_changed_cb(GtkWidget * w,tilda_window * tw)731 static void combo_command_exit_changed_cb (GtkWidget *w, tilda_window *tw) {
732     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
733 
734     config_setint ("command_exit", status);
735 }
736 
check_command_login_shell_cb(GtkWidget * w,tilda_window * tw)737 static void check_command_login_shell_cb (GtkWidget *w, tilda_window *tw) {
738     const gboolean active = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
739 
740     config_setbool("command_login_shell", active);
741 }
742 
check_start_fullscreen_cb(GtkWidget * w,tilda_window * tw)743 static void check_start_fullscreen_cb(GtkWidget *w, tilda_window *tw) {
744     const gboolean start_fullscreen = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
745 
746     config_setbool("start_fullscreen", start_fullscreen);
747 }
748 
combo_on_last_terminal_exit_changed_cb(GtkWidget * w,tilda_window * tw)749 static void combo_on_last_terminal_exit_changed_cb (GtkWidget *w, tilda_window *tw)
750 {
751     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
752 
753     config_setint ("on_last_terminal_exit", status);
754 }
755 
check_prompt_on_exit_toggled_cb(GtkWidget * w,tilda_window * tw)756 static void check_prompt_on_exit_toggled_cb (GtkWidget *w, tilda_window *tw)
757 {
758     const gboolean prompt_on_exit = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
759 
760     config_setbool("prompt_on_exit", prompt_on_exit);
761 }
762 
check_show_title_tooltip_toggled_cb(GtkWidget * w,tilda_window * tw)763 static void check_show_title_tooltip_toggled_cb (GtkWidget *w, tilda_window *tw)
764 {
765     const gboolean show_title_tooltip = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(w));
766 
767     config_setbool("show_title_tooltip", show_title_tooltip);
768     window_title_change_all (tw);
769 }
770 
entry_web_browser_changed(GtkWidget * w,tilda_window * tw)771 static void entry_web_browser_changed (GtkWidget *w, tilda_window *tw) {
772     const gchar *web_browser = gtk_entry_get_text (GTK_ENTRY(w));
773 
774     config_setstr ("web_browser", web_browser);
775 }
776 
entry_word_chars_changed(GtkWidget * w,tilda_window * tw)777 static void entry_word_chars_changed (GtkWidget *w, tilda_window *tw)
778 {
779     guint i;
780     tilda_term *tt;
781     const gchar *word_chars = gtk_entry_get_text (GTK_ENTRY(w));
782 
783     /* restore to default value if user clears this setting */
784     if (NULL == word_chars || '\0' == word_chars[0])
785         word_chars = DEFAULT_WORD_CHARS;
786 
787     config_setstr ("word_chars", word_chars);
788 
789     for (i=0; i<g_list_length (tw->terms); i++) {
790         tt = g_list_nth_data (tw->terms, i);
791         vte_terminal_set_word_char_exceptions (VTE_TERMINAL (tt->vte_term), word_chars);
792     }
793 }
794 
795 /*
796  * Prototypes for the next 4 functions.
797  */
798 //Both height functions depend on each other
799 static void spin_height_percentage_value_changed_cb (GtkWidget *w, tilda_window *tw);
800 static void spin_height_pixels_value_changed_cb (GtkWidget *w, tilda_window *tw);
801 //Both width functions depend on each other
802 static void spin_width_percentage_value_changed_cb (GtkWidget *w, tilda_window *tw);
803 static void spin_width_pixels_value_changed_cb (GtkWidget *w, tilda_window *tw);
804 
805 static void initialize_scrollback_settings(void);
806 static void initialize_set_as_desktop_checkbox (void);
807 
spin_height_percentage_value_changed_cb(GtkWidget * spin_height_percentage,tilda_window * tw)808 static void spin_height_percentage_value_changed_cb (GtkWidget *spin_height_percentage,
809                                                      tilda_window *tw)
810 {
811     DEBUG_FUNCTION ("spin_height_percentage_value_changed_cb");
812 
813     const GtkWidget *spin_height_pixels =
814         GTK_WIDGET (gtk_builder_get_object (xml, "spin_height_pixels"));
815 
816     const gdouble height_percentage = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_height_percentage)) / 100;
817     const gint height_pixels = pixels_ratio_to_absolute (get_max_height(), height_percentage);
818 
819     config_setint ("height_percentage", GLONG_FROM_DOUBLE (height_percentage));
820 
821     set_spin_value_while_blocking_callback (GTK_SPIN_BUTTON(spin_height_pixels),
822                                             &spin_height_pixels_value_changed_cb,
823                                             height_pixels, tw);
824 
825     GdkRectangle rectangle;
826     config_get_configured_window_size (&rectangle);
827 
828     gtk_window_resize (GTK_WINDOW(tw->window), rectangle.width, height_pixels);
829 
830     if (config_getbool ("centered_vertically"))
831     {
832         config_setint ("y_pos", tilda_window_find_centering_coordinate (tw, HEIGHT));
833 
834         gtk_window_move (GTK_WINDOW(tw->window),
835                          config_getint ("x_pos"),
836                          config_getint ("y_pos"));
837     }
838 
839     /* Always regenerate animation positions when changing x or y position!
840      * Otherwise you get VERY strange things going on :) */
841     generate_animation_positions (tw);
842 }
843 
844 
spin_height_pixels_value_changed_cb(GtkWidget * spin_height_pixels,tilda_window * tw)845 static void spin_height_pixels_value_changed_cb (GtkWidget *spin_height_pixels,
846                                                  tilda_window *tw)
847 {
848     DEBUG_FUNCTION ("spin_height_pixels_value_changed_cb");
849 
850     const GtkWidget *spin_height_percentage =
851         GTK_WIDGET (gtk_builder_get_object (xml, "spin_height_percentage"));
852     const gint height_pixels = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_height_pixels));
853     const gdouble height_percentage = pixels_absolute_to_ratio (get_max_height(), height_pixels);
854 
855     config_setint ("height_percentage", GLONG_FROM_DOUBLE (height_percentage));
856 
857     set_spin_value_while_blocking_callback (GTK_SPIN_BUTTON(spin_height_percentage),
858                                             &spin_height_percentage_value_changed_cb,
859                                             height_percentage * 100, tw);
860 
861     GdkRectangle rectangle;
862     config_get_configured_window_size (&rectangle);
863 
864     gtk_window_resize (GTK_WINDOW(tw->window), rectangle.width, height_pixels);
865 
866     if (config_getbool ("centered_vertically"))
867     {
868         config_setint ("y_pos", tilda_window_find_centering_coordinate (tw, HEIGHT));
869 
870         gtk_window_move (GTK_WINDOW(tw->window),
871                          config_getint ("x_pos"),
872                          config_getint ("y_pos"));
873     }
874 
875     /* Always regenerate animation positions when changing x or y position!
876      * Otherwise you get VERY strange things going on :) */
877     generate_animation_positions (tw);
878 }
879 
spin_width_percentage_value_changed_cb(GtkWidget * spin_width_percentage,tilda_window * tw)880 static void spin_width_percentage_value_changed_cb (GtkWidget *spin_width_percentage,
881                                                     tilda_window *tw)
882 {
883     DEBUG_FUNCTION ("spin_width_percentage_value_changed_cb");
884 
885     const GtkWidget *spin_width_pixels =
886         GTK_WIDGET (gtk_builder_get_object (xml, "spin_width_pixels"));
887 
888     const gdouble width_percentage = gtk_spin_button_get_value (GTK_SPIN_BUTTON(spin_width_percentage)) / 100;
889     const gint width_pixels = pixels_ratio_to_absolute (get_max_width(), width_percentage);
890 
891     config_setint ("width_percentage", GLONG_FROM_DOUBLE(width_percentage));
892 
893     set_spin_value_while_blocking_callback (GTK_SPIN_BUTTON(spin_width_pixels),
894                                             &spin_width_pixels_value_changed_cb,
895                                             width_pixels, tw);
896 
897     GdkRectangle rectangle;
898     config_get_configured_window_size (&rectangle);
899 
900     gtk_window_resize (GTK_WINDOW(tw->window), width_pixels, rectangle.height);
901 
902     if (config_getbool ("centered_horizontally"))
903     {
904         config_setint ("x_pos", tilda_window_find_centering_coordinate (tw, WIDTH));
905 
906         gtk_window_move (GTK_WINDOW(tw->window),
907                          config_getint ("x_pos"),
908                          config_getint ("y_pos"));
909     }
910 
911     /* Always regenerate animation positions when changing x or y position!
912      * Otherwise you get VERY strange things going on :) */
913     generate_animation_positions (tw);
914 }
915 
spin_width_pixels_value_changed_cb(GtkWidget * spin_width_pixels,tilda_window * tw)916 static void spin_width_pixels_value_changed_cb (GtkWidget *spin_width_pixels, tilda_window *tw)
917 {
918     DEBUG_FUNCTION ("spin_width_pixels_value_changed_cb");
919 
920     const GtkWidget *spin_width_percentage =
921         GTK_WIDGET (gtk_builder_get_object (xml, "spin_width_percentage"));
922 
923     const gint width_pixels = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_width_pixels));
924     const gdouble width_percentage = pixels_absolute_to_ratio (get_max_width(), width_pixels);
925 
926     config_setint ("width_percentage", GLONG_FROM_DOUBLE(width_percentage));
927 
928     set_spin_value_while_blocking_callback (GTK_SPIN_BUTTON(spin_width_percentage),
929                                             &spin_width_percentage_value_changed_cb,
930                                             width_percentage * 100, tw);
931 
932     GdkRectangle rectangle;
933     config_get_configured_window_size (&rectangle);
934 
935     gtk_window_resize (GTK_WINDOW(tw->window), width_pixels, rectangle.height);
936 
937     if (config_getbool ("centered_horizontally"))
938     {
939         config_setint ("x_pos", tilda_window_find_centering_coordinate (tw, WIDTH));
940 
941         gtk_window_move (GTK_WINDOW(tw->window),
942                          config_getint ("x_pos"),
943                          config_getint ("y_pos"));
944     }
945 
946     /* Always regenerate animation positions when changing x or y position!
947      * Otherwise you get VERY strange things going on :) */
948     generate_animation_positions (tw);
949 }
950 
check_centered_horizontally_toggled_cb(GtkWidget * w,tilda_window * tw)951 static void check_centered_horizontally_toggled_cb (GtkWidget *w, tilda_window *tw)
952 {
953     DEBUG_FUNCTION ("check_centered_horizontally_toggled_cb");
954 
955     const gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
956     const GtkWidget *label_x_position =
957         GTK_WIDGET (gtk_builder_get_object (xml, "label_x_position"));
958     const GtkWidget *spin_x_position =
959         GTK_WIDGET (gtk_builder_get_object (xml, "spin_x_position"));
960 
961     config_setbool ("centered_horizontally", active);
962 
963     if (active)
964         config_setint ("x_pos", tilda_window_find_centering_coordinate (tw, WIDTH));
965     else
966         config_setint ("x_pos", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_x_position)));
967 
968     gtk_widget_set_sensitive (GTK_WIDGET(label_x_position), !active);
969     gtk_widget_set_sensitive (GTK_WIDGET(spin_x_position), !active);
970 
971     gtk_window_move (GTK_WINDOW(tw->window), config_getint ("x_pos"), config_getint ("y_pos"));
972 
973     /* Always regenerate animation positions when changing x or y position!
974      * Otherwise you get VERY strange things going on :) */
975     generate_animation_positions (tw);
976 }
977 
spin_x_position_value_changed_cb(GtkWidget * w,tilda_window * tw)978 static void spin_x_position_value_changed_cb (GtkWidget *w, tilda_window *tw)
979 {
980     DEBUG_FUNCTION ("spin_x_position_value_changed_cb");
981 
982     const gint x_pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w));
983     const gint y_pos = config_getint ("y_pos");
984 
985     config_setint ("x_pos", x_pos);
986     gtk_window_move (GTK_WINDOW(tw->window), x_pos, y_pos);
987 
988     /* Always regenerate animation positions when changing x or y position!
989      * Otherwise you get VERY strange things going on :) */
990     generate_animation_positions (tw);
991 }
992 
check_centered_vertically_toggled_cb(GtkWidget * w,tilda_window * tw)993 static void check_centered_vertically_toggled_cb (GtkWidget *w, tilda_window *tw)
994 {
995     DEBUG_FUNCTION ("check_centered_vertically_toggled_cb");
996 
997     const gboolean active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
998     const GtkWidget *label_y_position =
999         GTK_WIDGET (gtk_builder_get_object (xml, "label_y_position"));
1000     const GtkWidget *spin_y_position =
1001         GTK_WIDGET (gtk_builder_get_object (xml, "spin_y_position"));
1002 
1003     config_setbool ("centered_vertically", active);
1004 
1005     if (active)
1006         config_setint ("y_pos", tilda_window_find_centering_coordinate (tw, HEIGHT));
1007     else
1008         config_setint ("y_pos", gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spin_y_position)));
1009 
1010     gtk_widget_set_sensitive (GTK_WIDGET(label_y_position), !active);
1011     gtk_widget_set_sensitive (GTK_WIDGET(spin_y_position), !active);
1012 
1013     gtk_window_move (GTK_WINDOW(tw->window), config_getint ("x_pos"), config_getint ("y_pos"));
1014 
1015     /* Always regenerate animation positions when changing x or y position!
1016      * Otherwise you get VERY strange things going on :) */
1017     generate_animation_positions (tw);
1018 }
1019 
spin_y_position_value_changed_cb(GtkWidget * w,tilda_window * tw)1020 static void spin_y_position_value_changed_cb (GtkWidget *w, tilda_window *tw)
1021 {
1022     DEBUG_FUNCTION ("spin_y_position_value_changed_cb");
1023 
1024     const gint x_pos = config_getint ("x_pos");
1025     const gint y_pos = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w));
1026 
1027     config_setint ("y_pos", y_pos);
1028     gtk_window_move (GTK_WINDOW(tw->window), x_pos, y_pos);
1029 
1030     /* Always regenerate animation positions when changing x or y position!
1031      * Otherwise you get VERY strange things going on :) */
1032     generate_animation_positions (tw);
1033 }
1034 
combo_tab_pos_changed_cb(GtkWidget * w,tilda_window * tw)1035 static void combo_tab_pos_changed_cb (GtkWidget *w, tilda_window *tw)
1036 {
1037     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1038     const GtkPositionType positions[] = {
1039                              GTK_POS_TOP,
1040                              GTK_POS_BOTTOM,
1041                              GTK_POS_LEFT,
1042                              GTK_POS_RIGHT };
1043 
1044     if (status < 0 || status > 4) {
1045         DEBUG_ERROR ("Notebook tab position invalid");
1046         g_printerr (_("Invalid tab position setting, ignoring\n"));
1047         return;
1048     }
1049 
1050     config_setint ("tab_pos", status);
1051 
1052     if(NB_HIDDEN == status) {
1053         gtk_notebook_set_show_tabs (GTK_NOTEBOOK(tw->notebook), FALSE);
1054     }
1055     else {
1056         if (gtk_notebook_get_n_pages(GTK_NOTEBOOK (tw->notebook)) > 1) {
1057             gtk_notebook_set_show_tabs(GTK_NOTEBOOK(tw->notebook), TRUE);
1058         }
1059         gtk_notebook_set_tab_pos (GTK_NOTEBOOK(tw->notebook), positions[status]);
1060     }
1061 }
1062 
check_expand_tabs_toggled_cb(GtkWidget * w,tilda_window * tw)1063 static void check_expand_tabs_toggled_cb (GtkWidget *w, tilda_window *tw)
1064 {
1065     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1066 
1067     config_setbool ("expand_tabs", status);
1068 
1069     int page = 0;
1070     GtkWidget *child = NULL;
1071     while((child = gtk_notebook_get_nth_page(GTK_NOTEBOOK (tw->notebook),
1072                                              page++)))
1073     {
1074         gtk_container_child_set (GTK_CONTAINER(tw->notebook),
1075             child,
1076             "tab-expand", status,
1077             "tab-fill", status,
1078             NULL);
1079     }
1080 }
1081 
check_show_single_tab_toggled_cb(GtkWidget * w,tilda_window * tw)1082 static void check_show_single_tab_toggled_cb (GtkWidget *w, tilda_window *tw)
1083 {
1084     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1085 
1086     config_setbool ("show_single_tab", status);
1087 
1088     /* Only need to do something if the current number of tabs is 1 */
1089     if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (tw->notebook)) == 1)
1090         gtk_notebook_set_show_tabs (GTK_NOTEBOOK (tw->notebook), status);
1091 }
1092 
check_enable_transparency_toggled_cb(GtkWidget * w,tilda_window * tw)1093 static void check_enable_transparency_toggled_cb (GtkWidget *w, tilda_window *tw)
1094 {
1095     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1096 
1097     const GtkWidget *label_level_of_transparency =
1098         GTK_WIDGET (gtk_builder_get_object (xml, "label_level_of_transparency"));
1099     const GtkWidget *spin_level_of_transparency =
1100         GTK_WIDGET (gtk_builder_get_object (xml, "spin_level_of_transparency"));
1101 
1102     gtk_widget_set_sensitive (GTK_WIDGET(label_level_of_transparency), status);
1103     gtk_widget_set_sensitive (GTK_WIDGET(spin_level_of_transparency), status);
1104 
1105     tilda_window_toggle_transparency(tw);
1106 }
1107 
spin_level_of_transparency_value_changed_cb(GtkWidget * w,tilda_window * tw)1108 static void spin_level_of_transparency_value_changed_cb (GtkWidget *w, tilda_window *tw)
1109 {
1110     const gint status = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w));
1111     guint i;
1112     tilda_term *tt;
1113     GdkRGBA bg;
1114 
1115     bg.red   =    GUINT16_TO_FLOAT(config_getint ("back_red"));
1116     bg.green =    GUINT16_TO_FLOAT(config_getint ("back_green"));
1117     bg.blue  =    GUINT16_TO_FLOAT(config_getint ("back_blue"));
1118     bg.alpha =    1.0 - (status / 100.0);
1119 
1120     config_setint ("back_alpha", GUINT16_FROM_FLOAT (bg.alpha));
1121     for (i=0; i<g_list_length (tw->terms); i++) {
1122             tt = g_list_nth_data (tw->terms, i);
1123             vte_terminal_set_color_background(VTE_TERMINAL(tt->vte_term), &bg);
1124         }
1125 }
1126 
spin_animation_delay_value_changed_cb(GtkWidget * w,tilda_window * tw)1127 static void spin_animation_delay_value_changed_cb (GtkWidget *w, tilda_window *tw)
1128 {
1129     const gint status = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w));
1130 
1131     config_setint ("slide_sleep_usec", status);
1132 }
1133 
combo_animation_orientation_changed_cb(GtkWidget * w,tilda_window * tw)1134 static void combo_animation_orientation_changed_cb (GtkWidget *w, tilda_window *tw)
1135 {
1136     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1137 
1138     config_setint ("animation_orientation", status);
1139     generate_animation_positions (tw);
1140 }
1141 
check_animated_pulldown_toggled_cb(GtkWidget * w,tilda_window * tw)1142 static void check_animated_pulldown_toggled_cb (GtkWidget *w, tilda_window *tw)
1143 {
1144     const gint status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1145     const GtkWidget *label_animation_delay =
1146         GTK_WIDGET (gtk_builder_get_object (xml, "label_animation_delay"));
1147     const GtkWidget *spin_animation_delay =
1148         GTK_WIDGET (gtk_builder_get_object (xml, "spin_animation_delay"));
1149     const GtkWidget *label_animation_orientation =
1150         GTK_WIDGET (gtk_builder_get_object (xml, "label_animation_orientation"));
1151     const GtkWidget *combo_animation_orientation =
1152         GTK_WIDGET (gtk_builder_get_object (xml, "combo_animation_orientation"));
1153 
1154     gtk_widget_set_sensitive (GTK_WIDGET(label_animation_delay), status);
1155     gtk_widget_set_sensitive (GTK_WIDGET(spin_animation_delay), status);
1156     gtk_widget_set_sensitive (GTK_WIDGET(label_animation_orientation), status);
1157     gtk_widget_set_sensitive (GTK_WIDGET(combo_animation_orientation), status);
1158 
1159     config_setbool ("animation", status);
1160 
1161     /* If we just disabled animation, we have to reset the window size to the normal
1162      * size, since the animations change the size of the window, and pull() does nothing more
1163      * than show and place the window. */
1164     if (!status)
1165     {
1166         GdkRectangle rectangle;
1167         config_get_configured_window_size (&rectangle);
1168 
1169         guint width = rectangle.width;
1170         guint height = rectangle.height;
1171 
1172         gtk_window_resize (GTK_WINDOW(tw->window), width, height);
1173         gtk_window_move (GTK_WINDOW(tw->window), config_getint ("x_pos"), config_getint ("y_pos"));
1174     }
1175 
1176     /* Avoids a nasty looking glitch if you switch on animation while the window is
1177      * hidden. It will briefly show at full size, then shrink to the first animation
1178      * position. From there it works fine. */
1179     if (status && tw->current_state == STATE_UP)
1180     {
1181         /* I don't know why, but width=0, height=0 doesn't work. Width=1, height=1 works
1182          * exactly as expected, so I'm leaving it that way. */
1183         gtk_window_resize (GTK_WINDOW(tw->window), 1, 1);
1184     }
1185 }
1186 
combo_colorschemes_changed_cb(GtkWidget * w,tilda_window * tw)1187 static void combo_colorschemes_changed_cb (GtkWidget *w, tilda_window *tw)
1188 {
1189     const gint scheme = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1190     const GtkWidget *colorbutton_text =
1191         GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_text"));
1192     const GtkWidget *colorbutton_back =
1193         GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_back"));
1194     GdkRGBA gdk_text, gdk_back;
1195 
1196     tilda_term *tt;
1197     guint i;
1198     gboolean nochange = FALSE;
1199 
1200     config_setint ("scheme", scheme);
1201 
1202     gdk_text.alpha = 1.0;
1203     gdk_back.alpha = 1.0;
1204 
1205     switch (scheme) {
1206         /* Green on black */
1207         case 1:
1208             gdk_text.red = gdk_text.blue = 0.0;
1209             gdk_text.green = 1.0;
1210             gdk_back.red = gdk_back.green = gdk_back.blue = 0.0;
1211             break;
1212         /* Black on white */
1213         case 2:
1214             gdk_text.red = gdk_text.green = gdk_text.blue = 0.0;
1215             gdk_back.red = gdk_back.green = gdk_back.blue = 1.0;
1216             break;
1217         /* White on black */
1218         case 3:
1219             gdk_text.red = gdk_text.green = gdk_text.blue = 1.0;
1220             gdk_back.red = gdk_back.green = gdk_back.blue = 0.0;
1221             break;
1222         /* Zenburn */
1223         case 4:
1224             gdk_text.red = 0.86;
1225             gdk_text.green = gdk_text.blue = 0.64;
1226             gdk_back.red = gdk_back.green = gdk_back.blue = 0.25;
1227             break;
1228         /* Solarized Light */
1229         case 5:
1230             gdk_text.red = 0.4;
1231             gdk_text.green = 0.48;
1232             gdk_text.blue = 0.51;
1233             gdk_back.red = 0.99;
1234             gdk_back.green = 0.96;
1235             gdk_back.blue = 0.89;
1236             break;
1237         /* Solarized Dark */
1238         case 6:
1239             gdk_text.red = 0.51;
1240             gdk_text.green = 0.58;
1241             gdk_text.blue = 0.59;
1242             gdk_back.red = 0.0;
1243             gdk_back.green = 0.17;
1244             gdk_back.blue = 0.21;
1245             break;
1246         /* Snazzy */
1247         case 7:
1248             gdk_text.red = 0.94;
1249             gdk_text.green = 0.94;
1250             gdk_text.blue = 0.92;
1251             gdk_back.red = 0.16;
1252             gdk_back.green = 0.16;
1253             gdk_back.blue = 0.21;
1254             break;
1255         /* Custom */
1256         default:
1257             nochange = TRUE;
1258             break;
1259     }
1260 
1261     /* If we switched to "Custom", then don't do anything. Let the user continue
1262      * from the current color choice. */
1263     if (!nochange) {
1264         config_setint ("back_red",   GUINT16_FROM_FLOAT(gdk_back.red));
1265         config_setint ("back_green", GUINT16_FROM_FLOAT(gdk_back.green));
1266         config_setint ("back_blue",  GUINT16_FROM_FLOAT(gdk_back.blue));
1267         config_setint ("text_red",   GUINT16_FROM_FLOAT(gdk_text.red));
1268         config_setint ("text_green", GUINT16_FROM_FLOAT(gdk_text.green));
1269         config_setint ("text_blue",  GUINT16_FROM_FLOAT(gdk_text.blue));
1270 
1271         gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(colorbutton_text), &gdk_text);
1272         gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER(colorbutton_back), &gdk_back);
1273 
1274         for (i=0; i<g_list_length (tw->terms); i++) {
1275             tt = g_list_nth_data (tw->terms, i);
1276             vte_terminal_set_color_foreground (VTE_TERMINAL(tt->vte_term),
1277                                                &gdk_text);
1278             vte_terminal_set_color_background (VTE_TERMINAL(tt->vte_term),
1279                                                &gdk_back);
1280         }
1281 
1282         tilda_window_refresh_transparency(tw);
1283     }
1284 }
colorbutton_cursor_color_set_cb(GtkWidget * w,tilda_window * tw)1285 static void colorbutton_cursor_color_set_cb (GtkWidget *w, tilda_window *tw)
1286 {
1287     const GtkWidget *combo_colorschemes =
1288         GTK_WIDGET (gtk_builder_get_object (xml, "combo_colorschemes"));
1289 
1290     guint i;
1291     tilda_term *tt;
1292     GdkRGBA gdk_cursor_color;
1293 
1294     /* The user just changed colors manually, so set the scheme to "Custom" */
1295     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_colorschemes), 0);
1296     config_setint ("scheme", 0);
1297 
1298     /* Now get the color that was set, save it, then set it */
1299     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(w), &gdk_cursor_color);
1300     config_setint ("cursor_red", GUINT16_FROM_FLOAT(gdk_cursor_color.red));
1301     config_setint ("cursor_green", GUINT16_FROM_FLOAT(gdk_cursor_color.green));
1302     config_setint ("cursor_blue", GUINT16_FROM_FLOAT(gdk_cursor_color.blue));
1303 
1304     for (i=0; i<g_list_length (tw->terms); i++) {
1305         tt = g_list_nth_data (tw->terms, i);
1306         vte_terminal_set_color_cursor (VTE_TERMINAL(tt->vte_term),
1307                                        &gdk_cursor_color);
1308     }
1309 }
1310 
colorbutton_text_color_set_cb(GtkWidget * w,tilda_window * tw)1311 static void colorbutton_text_color_set_cb (GtkWidget *w, tilda_window *tw)
1312 {
1313     const GtkWidget *combo_colorschemes =
1314         GTK_WIDGET (gtk_builder_get_object (xml, "combo_colorschemes"));
1315 
1316     guint i;
1317     tilda_term *tt;
1318     GdkRGBA gdk_text_color;
1319 
1320     /* The user just changed colors manually, so set the scheme to "Custom" */
1321     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_colorschemes), 0);
1322     config_setint ("scheme", 0);
1323 
1324     /* Now get the color that was set, save it, then set it */
1325     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(w), &gdk_text_color);
1326     config_setint ("text_red",   GUINT16_FROM_FLOAT(gdk_text_color.red));
1327     config_setint ("text_green", GUINT16_FROM_FLOAT(gdk_text_color.green));
1328     config_setint ("text_blue",  GUINT16_FROM_FLOAT(gdk_text_color.blue));
1329 
1330     for (i=0; i<g_list_length (tw->terms); i++) {
1331         tt = g_list_nth_data (tw->terms, i);
1332         vte_terminal_set_color_foreground (VTE_TERMINAL(tt->vte_term),
1333                                            &gdk_text_color);
1334     }
1335 }
1336 
colorbutton_back_color_set_cb(GtkWidget * w,tilda_window * tw)1337 static void colorbutton_back_color_set_cb (GtkWidget *w, tilda_window *tw)
1338 {
1339     const GtkWidget *combo_colorschemes =
1340         GTK_WIDGET (gtk_builder_get_object (xml, "combo_colorschemes"));
1341     guint i;
1342     tilda_term *tt;
1343     GdkRGBA gdk_back_color;
1344 
1345     /* The user just changed colors manually, so set the scheme to "Custom" */
1346     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_colorschemes), 0);
1347     config_setint ("scheme", 0);
1348 
1349     /* Now get the color that was set, save it, then set it */
1350     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(w), &gdk_back_color);
1351     config_setint ("back_red",   GUINT16_FROM_FLOAT(gdk_back_color.red));
1352     config_setint ("back_green", GUINT16_FROM_FLOAT(gdk_back_color.green));
1353     config_setint ("back_blue",  GUINT16_FROM_FLOAT(gdk_back_color.blue));
1354 
1355     for (i=0; i<g_list_length (tw->terms); i++) {
1356         tt = g_list_nth_data (tw->terms, i);
1357         vte_terminal_set_color_background (VTE_TERMINAL(tt->vte_term),
1358                                            &gdk_back_color);
1359         vte_terminal_set_color_cursor_foreground (VTE_TERMINAL(tt->vte_term),
1360                                                   &gdk_back_color);
1361     }
1362 }
1363 
1364 
1365 /**
1366  * This function is called if a different color scheme is selected from the combo box.
1367  */
combo_palette_scheme_changed_cb(GtkWidget * w,tilda_window * tw)1368 static void combo_palette_scheme_changed_cb (GtkWidget *w, tilda_window *tw) {
1369     DEBUG_FUNCTION("combo_palette_scheme_changed_cb");
1370     gint i;
1371     guint j;
1372     tilda_term *tt;
1373     GdkRGBA fg, bg;
1374     GtkWidget *color_button;
1375 
1376     i = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1377     /* i = 0 means custom, in that case we do nothing */
1378     TildaColorScheme *tildaPaletteSchemes = tilda_palettes_get_palette_schemes ();
1379 
1380     if (i > 0 && i < tilda_palettes_get_n_palette_schemes ()) {
1381 
1382         const GdkRGBA *current_palette = tildaPaletteSchemes[i].palette;
1383 
1384         color_button =
1385             GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_text"));
1386         gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &fg);
1387         color_button =
1388             GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_back"));
1389         gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &bg);
1390 
1391         bg.alpha = (config_getbool("enable_transparency")
1392                     ? GUINT16_TO_FLOAT(config_getint ("back_alpha")) : 1.0);
1393 
1394         tilda_palettes_set_current_palette (current_palette);
1395 
1396         /* Set terminal palette. */
1397         for (j=0; j<g_list_length (tw->terms); j++) {
1398             tt = g_list_nth_data (tw->terms, j);
1399             vte_terminal_set_colors (VTE_TERMINAL(tt->vte_term),
1400                                      &fg,
1401                                      &bg,
1402                                      current_palette,
1403                                      TILDA_COLOR_PALETTE_SIZE);
1404         }
1405 
1406         for (j=0; j<TILDA_COLOR_PALETTE_SIZE; j++) {
1407             update_palette_color_button(j);
1408 
1409             /* Set palette in the config. */
1410             config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[j].red),   j*3);
1411             config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[j].green), j*3+1);
1412             config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[j].blue),  j*3+2);
1413         }
1414     }
1415 
1416     /* Set palette scheme in the config*/
1417     config_setint ("palette_scheme", i);
1418 }
1419 
1420 /**
1421  *  This function is called, if the user has changed a single color. The function
1422  *  handles this color change, and sets the color schema to "Custom".
1423  */
colorbutton_palette_n_set_cb(GtkWidget * w,tilda_window * tw)1424 static void colorbutton_palette_n_set_cb (GtkWidget *w, tilda_window *tw)
1425 {
1426     DEBUG_FUNCTION("colorbutton_palette_n_set_cb");
1427     const GtkWidget *combo_palette_scheme =
1428         GTK_WIDGET (gtk_builder_get_object (xml, "combo_palette_scheme"));
1429     const gchar* name = gtk_buildable_get_name(GTK_BUILDABLE(w));
1430     guint i;
1431     tilda_term *tt;
1432     GtkWidget *color_button;
1433     GdkRGBA fg, bg;
1434 
1435     /* The user just changed the palette manually, so we set the palette scheme to "Custom".
1436      * "Custom" is the 0th element in the palette_schemes.
1437      */
1438     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_palette_scheme), 0);
1439     config_setint ("palette_scheme", 0);
1440 
1441     /* We need the index part of the name string, which looks like this:
1442      * "colorbutton_palette_12", so we set the button_index_str to the
1443      * position of the first digit and then convert it into an integer.
1444      */
1445     const char* button_index_str = &name[sizeof("colorbutton_palette_")-1];
1446     i = atoi(button_index_str);
1447 
1448     /* Now get the color that was set, save it. */
1449     GdkRGBA *current_palette = tilda_palettes_get_current_palette ();
1450 
1451     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(w), &current_palette[i]);
1452 
1453     /* Why saving the whole palette, not the single color that was set,
1454      * is if the config file doesn't exist, and we save the single color,
1455      * then exit, the color always becomes the first color in the config file,
1456      * no matter which one it actually is, and leaves other colors unset.
1457      * Obviously this is not what we want.
1458      * However, maybe there is a better solution for this issue.
1459      */
1460     for (i=0; i<TILDA_COLOR_PALETTE_SIZE; i++)
1461     {
1462         config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[i].red),   i*3);
1463         config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[i].green), i*3+1);
1464         config_setnint ("palette", GUINT16_FROM_FLOAT(current_palette[i].blue),  i*3+2);
1465     }
1466 
1467     /* Set terminal palette. */
1468     color_button =
1469         GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_text"));
1470     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &fg);
1471     color_button =
1472         GTK_WIDGET (gtk_builder_get_object (xml, "colorbutton_back"));
1473     gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER(color_button), &bg);
1474 
1475     for (i=0; i<g_list_length (tw->terms); i++)
1476     {
1477         tt = g_list_nth_data (tw->terms, i);
1478         vte_terminal_set_colors (VTE_TERMINAL (tt->vte_term),
1479                                  &fg,
1480                                  &bg,
1481                                  current_palette,
1482                                  TILDA_COLOR_PALETTE_SIZE);
1483     }
1484 }
1485 
combo_scrollbar_position_changed_cb(GtkWidget * w,tilda_window * tw)1486 static void combo_scrollbar_position_changed_cb (GtkWidget *w, tilda_window *tw)
1487 {
1488     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1489     guint i;
1490     tilda_term *tt;
1491 
1492     config_setint ("scrollbar_pos", status);
1493 
1494     for (i=0; i<g_list_length (tw->terms); i++)
1495     {
1496         tt = g_list_nth_data (tw->terms, i);
1497         tilda_term_set_scrollbar_position (tt, status);
1498     }
1499 }
1500 
spin_scrollback_amount_value_changed_cb(GtkWidget * w,tilda_window * tw)1501 static void spin_scrollback_amount_value_changed_cb (GtkWidget *w, tilda_window *tw)
1502 {
1503     const gint status = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(w));
1504 
1505     guint i;
1506     tilda_term *tt;
1507 
1508     config_setint ("lines", status);
1509 
1510     for (i=0; i<g_list_length (tw->terms); i++) {
1511         tt = g_list_nth_data (tw->terms, i);
1512         vte_terminal_set_scrollback_lines (VTE_TERMINAL(tt->vte_term), status);
1513     }
1514 }
1515 
check_infinite_scrollback_toggled_cb(GtkWidget * w,tilda_window * tw)1516 static void check_infinite_scrollback_toggled_cb(GtkWidget *w, tilda_window *tw)
1517 {
1518     // if status is false then scrollback is infinite, otherwise the spinner is active
1519     const gboolean hasScrollbackLimit = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1520 
1521     config_setbool ("scroll_history_infinite", !hasScrollbackLimit);
1522 
1523     GtkWidget *spinner = (GtkWidget *) gtk_builder_get_object(xml, "spin_scrollback_amount");
1524     gint scrollback_lines = gtk_spin_button_get_value_as_int (GTK_SPIN_BUTTON(spinner));
1525     GtkWidget *label = (GtkWidget *) gtk_builder_get_object(xml, "label_scrollback_lines");
1526 
1527     gtk_widget_set_sensitive(spinner, hasScrollbackLimit);
1528     gtk_widget_set_sensitive(label, hasScrollbackLimit);
1529 
1530     guint i;
1531     tilda_term *tt;
1532 
1533     if(!hasScrollbackLimit) {
1534         scrollback_lines = -1;
1535     }
1536 
1537     for (i=0; i<g_list_length (tw->terms); i++) {
1538         tt = g_list_nth_data (tw->terms, i);
1539         vte_terminal_set_scrollback_lines(VTE_TERMINAL(tt->vte_term), scrollback_lines);
1540     }
1541 }
1542 
check_scroll_on_output_toggled_cb(GtkWidget * w,tilda_window * tw)1543 static void check_scroll_on_output_toggled_cb (GtkWidget *w, tilda_window *tw)
1544 {
1545     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1546     guint i;
1547     tilda_term *tt;
1548 
1549     config_setbool ("scroll_on_output", status);
1550 
1551     for (i=0; i<g_list_length (tw->terms); i++) {
1552         tt = g_list_nth_data (tw->terms, i);
1553         vte_terminal_set_scroll_on_output (VTE_TERMINAL(tt->vte_term), status);
1554     }
1555 }
1556 
check_scroll_on_keystroke_toggled_cb(GtkWidget * w,tilda_window * tw)1557 static void check_scroll_on_keystroke_toggled_cb (GtkWidget *w, tilda_window *tw)
1558 {
1559     const gboolean status = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON(w));
1560     guint i;
1561     tilda_term *tt;
1562 
1563     config_setbool ("scroll_on_key", status);
1564 
1565     for (i=0; i<g_list_length (tw->terms); i++) {
1566         tt = g_list_nth_data (tw->terms, i);
1567         vte_terminal_set_scroll_on_keystroke (VTE_TERMINAL(tt->vte_term), status);
1568     }
1569 }
1570 
combo_backspace_binding_changed_cb(GtkWidget * w,tilda_window * tw)1571 static void combo_backspace_binding_changed_cb (GtkWidget *w, tilda_window *tw)
1572 {
1573     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1574     const gint keys[] = { VTE_ERASE_ASCII_DELETE,
1575                           VTE_ERASE_DELETE_SEQUENCE,
1576                           VTE_ERASE_ASCII_BACKSPACE,
1577                           VTE_ERASE_AUTO };
1578     guint i;
1579     tilda_term *tt;
1580 
1581     config_setint ("backspace_key", status);
1582 
1583     for (i=0; i<g_list_length (tw->terms); i++) {
1584         tt = g_list_nth_data (tw->terms, i);
1585         vte_terminal_set_backspace_binding (VTE_TERMINAL(tt->vte_term), keys[status]);
1586     }
1587 }
1588 
combo_delete_binding_changed_cb(GtkWidget * w,tilda_window * tw)1589 static void combo_delete_binding_changed_cb (GtkWidget *w, tilda_window *tw)
1590 {
1591     const gint status = gtk_combo_box_get_active (GTK_COMBO_BOX(w));
1592     const gint keys[] = { VTE_ERASE_ASCII_DELETE,
1593                           VTE_ERASE_DELETE_SEQUENCE,
1594                           VTE_ERASE_ASCII_BACKSPACE,
1595                           VTE_ERASE_AUTO };
1596     guint i;
1597     tilda_term *tt;
1598 
1599     config_setint ("delete_key", status);
1600 
1601     for (i=0; i<g_list_length (tw->terms); i++) {
1602         tt = g_list_nth_data (tw->terms, i);
1603         vte_terminal_set_delete_binding (VTE_TERMINAL(tt->vte_term), keys[status]);
1604     }
1605 }
1606 
button_reset_compatibility_options_clicked_cb(tilda_window * tw)1607 static void button_reset_compatibility_options_clicked_cb (tilda_window *tw)
1608 {
1609     const GtkWidget *combo_backspace_binding =
1610         GTK_WIDGET (gtk_builder_get_object (xml, "combo_backspace_binding"));
1611     const GtkWidget *combo_delete_binding =
1612         GTK_WIDGET (gtk_builder_get_object (xml, "combo_delete_binding"));
1613 
1614     config_setint ("backspace_key", 0);
1615     config_setint ("delete_key", 1);
1616 
1617     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_backspace_binding), 0);
1618     gtk_combo_box_set_active (GTK_COMBO_BOX(combo_delete_binding), 1);
1619 }
1620 
1621 static void
initialize_combo_choose_monitor(tilda_window * tw)1622 initialize_combo_choose_monitor(tilda_window *tw)
1623 {
1624     DEBUG_FUNCTION ("initialize_combo_choose_monitor");
1625 
1626     /**
1627      * First we need to initialize the "combo_choose_monitor" widget,
1628      * with the numbers of each monitor attached to the system.
1629      */
1630     GdkDisplay *display = gdk_display_get_default ();
1631     int num_monitors = gdk_display_get_n_monitors (display);
1632     GdkMonitor *active_monitor = tilda_window_find_monitor_number(tw);
1633 
1634     GtkComboBox* combo_choose_monitor =
1635             GTK_COMBO_BOX(gtk_builder_get_object(xml,"combo_choose_monitor"));
1636     GtkListStore* monitor_model =
1637             GTK_LIST_STORE(gtk_combo_box_get_model(combo_choose_monitor));
1638     GtkTreeIter iter;
1639     gint i;
1640 
1641     gtk_list_store_clear(monitor_model);
1642 
1643     for (i = 0; i < num_monitors; i++) {
1644         GdkMonitor *monitor;
1645 
1646         gtk_list_store_append(monitor_model, &iter);
1647         monitor = gdk_display_get_monitor (display, i);
1648 
1649         const gchar *monitor_model_name = gdk_monitor_get_model (monitor);
1650         gchar *display_name = g_strdup_printf ("%d    <i>(%s)</i>", i, monitor_model_name);
1651 
1652         gtk_list_store_set(monitor_model, &iter,
1653                            0, monitor_model_name,
1654                            1, i,
1655                            2, display_name,
1656                            -1);
1657 
1658         if(monitor == active_monitor) {
1659           gtk_combo_box_set_active_iter(combo_choose_monitor, &iter);
1660         }
1661 
1662         g_free (display_name);
1663     }
1664 }
1665 
1666 /**
1667  * Here the geometry options in the appearance tab get initialized. The options are:
1668  * height and width (both absolute and in percentage), x and y positions as well as the
1669  * check boxes for centering.
1670  * Because we might have multiple monitors we first need to get the monitor that
1671  * is currently selected to show the window and then load its geometry information.
1672  */
initialize_geometry_spinners(tilda_window * tw)1673 static void initialize_geometry_spinners(tilda_window *tw) {
1674     DEBUG_FUNCTION ("initialize_geometry_spinners");
1675 
1676     GdkMonitor *monitor = tilda_window_find_monitor_number(tw);
1677     GdkRectangle rectangle;
1678 
1679     gdk_monitor_get_workarea (monitor, &rectangle);
1680     int monitor_height = rectangle.height;
1681     int monitor_width = rectangle.width;
1682 
1683     /* Update range and value of height spinners */
1684     GdkRectangle tilda_rectangle;
1685     config_get_configured_window_size (&tilda_rectangle);
1686 
1687     gint width = tilda_rectangle.width;
1688     gint height = tilda_rectangle.height;
1689 
1690     gdouble height_percentage =
1691             GLONG_TO_DOUBLE (config_getint("height_percentage")) * 100;
1692 
1693     gdouble width_percentage =
1694             GLONG_TO_DOUBLE (config_getint("width_percentage")) * 100;
1695 
1696     SPIN_BUTTON_SET_RANGE("spin_height_percentage", 0, 100);
1697     SPIN_BUTTON_SET_VALUE ("spin_height_percentage", height_percentage);
1698     SPIN_BUTTON_SET_RANGE("spin_height_pixels", 0, monitor_height);
1699     SPIN_BUTTON_SET_VALUE("spin_height_pixels", height);
1700 
1701     /* Update range and value of width spinners */
1702     SPIN_BUTTON_SET_RANGE("spin_width_percentage", 0, 100);
1703     SPIN_BUTTON_SET_VALUE ("spin_width_percentage", width_percentage);
1704     SPIN_BUTTON_SET_RANGE("spin_width_pixels", 0, monitor_width);
1705     SPIN_BUTTON_SET_VALUE("spin_width_pixels", width);
1706 
1707     CHECK_BUTTON("check_centered_horizontally", "centered_horizontally");
1708     CHECK_BUTTON("check_centered_vertically", "centered_vertically");
1709     CHECK_BUTTON("check_start_fullscreen", "start_fullscreen");
1710 
1711     gint xpos = config_getint("x_pos");
1712     if(xpos < rectangle.x) {
1713         xpos = rectangle.x;
1714         config_setint("x_pos", xpos);
1715     }
1716 
1717     gint screen_width, screen_height;
1718     screen_size_get_dimensions (&screen_width, &screen_height);
1719     SPIN_BUTTON_SET_RANGE("spin_x_position", 0, screen_width);
1720     SPIN_BUTTON_SET_VALUE("spin_x_position", xpos); /* TODO: Consider x in rectange.x for monitor displacement */
1721 
1722     gint ypos = config_getint("y_pos");
1723     if(ypos < rectangle.y) {
1724         ypos = rectangle.y;
1725         config_setint("y_pos", ypos);
1726     }
1727     SPIN_BUTTON_SET_RANGE("spin_y_position", 0, screen_height);
1728     SPIN_BUTTON_SET_VALUE("spin_y_position", ypos);
1729 
1730     SET_SENSITIVE_BY_CONFIG_NBOOL("spin_x_position", "centered_horizontally");
1731     SET_SENSITIVE_BY_CONFIG_NBOOL("label_x_position", "centered_horizontally");
1732     SET_SENSITIVE_BY_CONFIG_NBOOL("spin_y_position", "centered_vertically");
1733     SET_SENSITIVE_BY_CONFIG_NBOOL("label_y_position", "centered_vertically");
1734 }
1735 
1736 /* Read all state from the config system, and put it into
1737  * its visual representation in the wizard. */
set_wizard_state_from_config(tilda_window * tw)1738 static void set_wizard_state_from_config (tilda_window *tw) {
1739     GdkRGBA text_color, back_color, cursor_color;
1740     guint i;
1741     GdkRGBA *current_palette;
1742 
1743     /* General Tab */
1744     CHECK_BUTTON ("check_display_on_all_workspaces", "pinned");
1745     initialize_set_as_desktop_checkbox ();
1746     CHECK_BUTTON ("check_always_on_top", "above");
1747     CHECK_BUTTON ("check_do_not_show_in_taskbar", "notaskbar");
1748     CHECK_BUTTON ("check_start_tilda_hidden", "hidden");
1749     CHECK_BUTTON ("check_show_notebook_border", "notebook_border");
1750     COMBO_BOX ("combo_non_focus_pull_up_behaviour", "non_focus_pull_up_behaviour");
1751 
1752     CHECK_BUTTON ("check_terminal_bell", "bell");
1753     CHECK_BUTTON ("check_cursor_blinks", "blinks");
1754     COMBO_BOX ("vte_cursor_shape", "cursor_shape");
1755 
1756     FONT_BUTTON ("button_font", "font");
1757 
1758     SPIN_BUTTON_SET_RANGE ("spin_auto_hide_time", 0, 99999);
1759     SPIN_BUTTON_SET_VALUE ("spin_auto_hide_time", config_getint ("auto_hide_time"));
1760     CHECK_BUTTON ("check_auto_hide_on_focus_lost", "auto_hide_on_focus_lost");
1761     CHECK_BUTTON ("check_auto_hide_on_mouse_leave", "auto_hide_on_mouse_leave");
1762 
1763     /* Title and Command Tab */
1764     TEXT_ENTRY ("entry_title", "title");
1765     COMBO_BOX ("combo_dynamically_set_title", "d_set_title");
1766     // Whether to limit the length of the title
1767     COMBO_BOX ("combo_title_behaviour", "title_behaviour");
1768     // The maximum length of the title
1769     SPIN_BUTTON_SET_RANGE ("spin_title_max_length", 0, 99999);
1770     SPIN_BUTTON_SET_VALUE ("spin_title_max_length", config_getint ("title_max_length"));
1771 
1772     CHECK_BUTTON ("check_run_custom_command", "run_command");
1773     TEXT_ENTRY ("entry_custom_command", "command");
1774     CHECK_BUTTON ("check_command_login_shell", "command_login_shell");
1775     COMBO_BOX ("combo_command_exit", "command_exit");
1776     COMBO_BOX ("combo_on_last_terminal_exit", "on_last_terminal_exit");
1777     CHECK_BUTTON ("check_prompt_on_exit", "prompt_on_exit");
1778     SET_SENSITIVE_BY_CONFIG_BOOL ("entry_custom_command","run_command");
1779     SET_SENSITIVE_BY_CONFIG_BOOL ("label_custom_command", "run_command");
1780 
1781     TEXT_ENTRY ("entry_web_browser", "web_browser");
1782 
1783     CHECK_BUTTON ("check_confirm_close_tab", "confirm_close_tab");
1784 
1785     /* Appearance Tab */
1786     /* Initialize the monitor chooser combo box with the numbers of the monitor */
1787     initialize_combo_choose_monitor(tw);
1788 
1789 
1790     initialize_geometry_spinners(tw);
1791     CHECK_BUTTON ("check_enable_transparency", "enable_transparency");
1792     CHECK_BUTTON ("check_animated_pulldown", "animation");
1793     SPIN_BUTTON ("spin_animation_delay", "slide_sleep_usec");
1794     COMBO_BOX ("combo_animation_orientation", "animation_orientation");
1795 
1796     COMBO_BOX ("combo_tab_pos", "tab_pos");
1797     CHECK_BUTTON ("check_expand_tabs", "expand_tabs");
1798     CHECK_BUTTON ("check_show_single_tab", "show_single_tab");
1799     CHECK_BUTTON ("check_show_title_tooltip", "show_title_tooltip");
1800 
1801     SET_SENSITIVE_BY_CONFIG_BOOL ("label_level_of_transparency","enable_transparency");
1802     SET_SENSITIVE_BY_CONFIG_BOOL ("spin_level_of_transparency","enable_transparency");
1803     SET_SENSITIVE_BY_CONFIG_BOOL ("label_animation_delay","animation");
1804     SET_SENSITIVE_BY_CONFIG_BOOL ("spin_animation_delay","animation");
1805     SET_SENSITIVE_BY_CONFIG_BOOL ("label_animation_orientation","animation");
1806     SET_SENSITIVE_BY_CONFIG_BOOL ("combo_animation_orientation","animation");
1807 
1808     /* Colors Tab */
1809     COMBO_BOX ("combo_colorschemes", "scheme");
1810     text_color.red =   GUINT16_TO_FLOAT(config_getint ("text_red"));
1811     text_color.green = GUINT16_TO_FLOAT(config_getint ("text_green"));
1812     text_color.blue =  GUINT16_TO_FLOAT(config_getint ("text_blue"));
1813     text_color.alpha = 1.0;
1814     COLOR_CHOOSER ("colorbutton_text", &text_color);
1815     back_color.red =   GUINT16_TO_FLOAT(config_getint ("back_red"));
1816     back_color.green = GUINT16_TO_FLOAT(config_getint ("back_green"));
1817     back_color.blue =  GUINT16_TO_FLOAT(config_getint ("back_blue"));
1818     back_color.alpha = 1.0;
1819     COLOR_CHOOSER ("colorbutton_back", &back_color);
1820     cursor_color.red = GUINT16_TO_FLOAT(config_getint ("cursor_red"));
1821     cursor_color.green = GUINT16_TO_FLOAT(config_getint ("cursor_green"));
1822     cursor_color.blue = GUINT16_TO_FLOAT(config_getint ("cursor_blue"));
1823     cursor_color.alpha = 1.0;
1824     COLOR_CHOOSER ("colorbutton_cursor", &cursor_color);
1825 
1826     COMBO_BOX ("combo_palette_scheme", "palette_scheme");
1827 
1828     current_palette = tilda_palettes_get_current_palette ();
1829 
1830     for(i = 0;i < TILDA_COLOR_PALETTE_SIZE; i++) {
1831         current_palette[i].red   = GUINT16_TO_FLOAT (config_getnint ("palette", i*3));
1832         current_palette[i].green = GUINT16_TO_FLOAT (config_getnint ("palette", i*3+1));
1833         current_palette[i].blue  = GUINT16_TO_FLOAT (config_getnint ("palette", i*3+2));
1834         current_palette[i].alpha = 1.0;
1835 
1836         update_palette_color_button(i);
1837     }
1838 
1839     /* Scrolling Tab */
1840     initialize_scrollback_settings();
1841 
1842     /* Compatibility Tab */
1843     COMBO_BOX ("combo_backspace_binding", "backspace_key");
1844     COMBO_BOX ("combo_delete_binding", "delete_key");
1845 
1846     TEXT_ENTRY ("entry_word_chars", "word_chars");
1847 
1848     gtk_spin_button_set_value(GTK_SPIN_BUTTON(gtk_builder_get_object(xml, ("spin_level_of_transparency"))),
1849                               (100 - 100*GUINT16_TO_FLOAT(config_getint("back_alpha"))));
1850 }
1851 
initialize_scrollback_settings(void)1852 static void initialize_scrollback_settings(void) {
1853     COMBO_BOX ("combo_scrollbar_position", "scrollbar_pos");
1854     SPIN_BUTTON ("spin_scrollback_amount", "lines");
1855 
1856     /* For historical reasons the config value is named "scrollback_history_infinite", but we have changed the
1857      * UI semantics such that the checkbox is activated to limit the scrollback and deactivated to use an infinite
1858      * buffer. Therefore we need to negate the value from the config here. */
1859     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (gtk_builder_get_object (xml, "check_infinite_scrollback")),
1860                                   !config_getbool ("scroll_history_infinite"));
1861     gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (xml, ("label_scrollback_lines"))),
1862                               !config_getbool ("scroll_history_infinite"));
1863     gtk_widget_set_sensitive (GTK_WIDGET (gtk_builder_get_object (xml, ("spin_scrollback_amount"))),
1864                               !config_getbool ("scroll_history_infinite"));
1865 
1866     CHECK_BUTTON ("check_scroll_on_output", "scroll_on_output");
1867     CHECK_BUTTON ("check_scroll_on_keystroke", "scroll_on_key");
1868 }
1869 
initialize_set_as_desktop_checkbox(void)1870 static void initialize_set_as_desktop_checkbox (void) {
1871     CHECK_BUTTON ("check_set_as_desktop", "set_as_desktop");
1872 
1873     GtkWidget *check_set_as_desktop =            GTK_WIDGET(gtk_builder_get_object (xml, "check_set_as_desktop"));
1874     GtkWidget *check_display_on_all_workspaces = GTK_WIDGET(gtk_builder_get_object (xml, "check_display_on_all_workspaces"));
1875 
1876     gboolean status = config_getbool("set_as_desktop");
1877     gboolean status_display_on_all_workspaces = config_getbool ("pinned");
1878     if (status) {
1879         gtk_widget_set_sensitive (check_display_on_all_workspaces, FALSE);
1880         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_display_on_all_workspaces), TRUE);
1881     } else {
1882         gtk_widget_set_sensitive (check_display_on_all_workspaces, TRUE);
1883         gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_display_on_all_workspaces), status_display_on_all_workspaces);
1884     }
1885     gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (check_set_as_desktop), status);
1886 }
1887 
1888 #define CONNECT_SIGNAL(GLADE_WIDGET,SIGNAL_NAME,SIGNAL_HANDLER,DATA) g_signal_connect ( \
1889     gtk_builder_get_object (xml, (GLADE_WIDGET)), (SIGNAL_NAME), G_CALLBACK((SIGNAL_HANDLER)), DATA)
1890 
1891 /* Connect all signals in the wizard. This should be done after setting all
1892  * values, that way all of the signal handlers don't get called */
connect_wizard_signals(TildaWizard * wizard)1893 static void connect_wizard_signals (TildaWizard *wizard)
1894 {
1895     gint i;
1896     tilda_window *tw = wizard->tw;
1897 
1898     /* General Tab */
1899     CONNECT_SIGNAL ("check_display_on_all_workspaces","toggled",check_display_on_all_workspaces_toggled_cb, tw);
1900     CONNECT_SIGNAL ("check_set_as_desktop","toggled",check_set_as_desktop_toggled_cb, tw);
1901     CONNECT_SIGNAL ("check_do_not_show_in_taskbar","toggled",check_do_not_show_in_taskbar_toggled_cb, tw);
1902     CONNECT_SIGNAL ("check_show_notebook_border","toggled",check_show_notebook_border_toggled_cb, tw);
1903     CONNECT_SIGNAL ("check_always_on_top","toggled",check_always_on_top_toggled_cb, tw);
1904     CONNECT_SIGNAL ("check_start_tilda_hidden","toggled",check_start_tilda_hidden_toggled_cb, tw);
1905     CONNECT_SIGNAL ("combo_non_focus_pull_up_behaviour","changed",combo_non_focus_pull_up_behaviour_cb, tw);
1906 
1907     CONNECT_SIGNAL ("check_terminal_bell","toggled",check_terminal_bell_toggled_cb, tw);
1908     CONNECT_SIGNAL ("check_cursor_blinks","toggled",check_cursor_blinks_toggled_cb, tw);
1909     CONNECT_SIGNAL ("vte_cursor_shape","changed", combo_cursor_shape_changed_cb, tw);
1910 
1911     CONNECT_SIGNAL ("check_start_fullscreen", "toggled", check_start_fullscreen_cb, tw);
1912 
1913     CONNECT_SIGNAL ("button_font","font-set",button_font_font_set_cb, tw);
1914 
1915     CONNECT_SIGNAL ("spin_auto_hide_time","value-changed",spin_auto_hide_time_value_changed_cb, tw);
1916     CONNECT_SIGNAL ("check_auto_hide_on_focus_lost","toggled",check_auto_hide_on_focus_lost_toggled_cb, tw);
1917     CONNECT_SIGNAL ("check_auto_hide_on_mouse_leave","toggled",check_auto_hide_on_mouse_leave_toggled_cb, tw);
1918 
1919     CONNECT_SIGNAL ("combo_on_last_terminal_exit","changed",combo_on_last_terminal_exit_changed_cb, tw);
1920     CONNECT_SIGNAL ("check_prompt_on_exit","toggled",check_prompt_on_exit_toggled_cb, tw);
1921 
1922     /* Title and Command Tab */
1923     CONNECT_SIGNAL ("entry_title","changed",entry_title_changed_cb, tw);
1924     CONNECT_SIGNAL ("combo_dynamically_set_title","changed",combo_dynamically_set_title_changed_cb, tw);
1925     CONNECT_SIGNAL ("combo_title_behaviour","changed",combo_title_behaviour_changed_cb, tw);
1926     CONNECT_SIGNAL ("spin_title_max_length","value-changed", spin_max_title_length_changed_cb, tw);
1927 
1928     CONNECT_SIGNAL ("check_run_custom_command","toggled",check_run_custom_command_toggled_cb, tw);
1929     CONNECT_SIGNAL ("entry_custom_command","focus-out-event", validate_executable_command_cb, tw);
1930     CONNECT_SIGNAL ("combo_command_exit","changed",combo_command_exit_changed_cb, tw);
1931     CONNECT_SIGNAL ("check_command_login_shell", "toggled", check_command_login_shell_cb, tw);
1932 
1933     CONNECT_SIGNAL ("entry_web_browser","changed",entry_web_browser_changed, tw);
1934     CONNECT_SIGNAL ("entry_web_browser","focus-out-event", validate_executable_command_cb, tw);
1935 
1936     CONNECT_SIGNAL ("check_confirm_close_tab", "toggled", check_confirm_close_tab_cb, tw);
1937 
1938     /* Appearance Tab */
1939     CONNECT_SIGNAL ("combo_choose_monitor", "changed", combo_monitor_selection_changed_cb, tw);
1940     CONNECT_SIGNAL ("spin_height_percentage","value-changed",spin_height_percentage_value_changed_cb, tw);
1941     CONNECT_SIGNAL ("spin_height_pixels","value-changed",spin_height_pixels_value_changed_cb, tw);
1942     CONNECT_SIGNAL ("spin_width_percentage","value-changed",spin_width_percentage_value_changed_cb, tw);
1943     CONNECT_SIGNAL ("spin_width_pixels","value-changed",spin_width_pixels_value_changed_cb, tw);
1944 
1945     CONNECT_SIGNAL ("check_centered_horizontally","toggled",check_centered_horizontally_toggled_cb, tw);
1946     CONNECT_SIGNAL ("check_centered_vertically","toggled",check_centered_vertically_toggled_cb, tw);
1947     CONNECT_SIGNAL ("spin_x_position","value-changed",spin_x_position_value_changed_cb, tw);
1948     CONNECT_SIGNAL ("spin_y_position","value-changed",spin_y_position_value_changed_cb, tw);
1949 
1950     CONNECT_SIGNAL ("combo_tab_pos","changed",combo_tab_pos_changed_cb, tw);
1951     CONNECT_SIGNAL ("check_expand_tabs","toggled",check_expand_tabs_toggled_cb, tw);
1952     CONNECT_SIGNAL ("check_show_single_tab","toggled",check_show_single_tab_toggled_cb, tw);
1953     CONNECT_SIGNAL ("check_show_title_tooltip","toggled",check_show_title_tooltip_toggled_cb, tw);
1954 
1955     CONNECT_SIGNAL ("check_enable_transparency","toggled",check_enable_transparency_toggled_cb, tw);
1956     CONNECT_SIGNAL ("check_animated_pulldown","toggled",check_animated_pulldown_toggled_cb, tw);
1957     CONNECT_SIGNAL ("spin_level_of_transparency","value-changed",spin_level_of_transparency_value_changed_cb, tw);
1958     CONNECT_SIGNAL ("spin_animation_delay","value-changed",spin_animation_delay_value_changed_cb, tw);
1959     CONNECT_SIGNAL ("combo_animation_orientation","changed",combo_animation_orientation_changed_cb, tw);
1960 
1961     /* Colors Tab */
1962     CONNECT_SIGNAL ("combo_colorschemes","changed",combo_colorschemes_changed_cb, tw);
1963     CONNECT_SIGNAL ("colorbutton_text","color-set",colorbutton_text_color_set_cb, tw);
1964     CONNECT_SIGNAL ("colorbutton_back","color-set",colorbutton_back_color_set_cb, tw);
1965     CONNECT_SIGNAL ("colorbutton_cursor","color-set",colorbutton_cursor_color_set_cb, tw);
1966     CONNECT_SIGNAL ("combo_palette_scheme","changed",combo_palette_scheme_changed_cb, tw);
1967     for(i = 0; i < TILDA_COLOR_PALETTE_SIZE; i++)
1968     {
1969         char *s = g_strdup_printf ("colorbutton_palette_%d", i);
1970         CONNECT_SIGNAL (s,"color-set",colorbutton_palette_n_set_cb, tw);
1971         g_free (s);
1972     }
1973 
1974     /* Scrolling Tab */
1975     CONNECT_SIGNAL ("combo_scrollbar_position","changed",combo_scrollbar_position_changed_cb, tw);
1976     CONNECT_SIGNAL ("spin_scrollback_amount","value-changed",spin_scrollback_amount_value_changed_cb, tw);
1977     CONNECT_SIGNAL ("check_infinite_scrollback", "toggled", check_infinite_scrollback_toggled_cb, tw);
1978     CONNECT_SIGNAL ("check_scroll_on_output","toggled",check_scroll_on_output_toggled_cb, tw);
1979     CONNECT_SIGNAL ("check_scroll_on_keystroke","toggled",check_scroll_on_keystroke_toggled_cb, tw);
1980 
1981     /* Compatibility Tab */
1982     CONNECT_SIGNAL ("combo_backspace_binding","changed",combo_backspace_binding_changed_cb, tw);
1983     CONNECT_SIGNAL ("combo_delete_binding","changed",combo_delete_binding_changed_cb, tw);
1984     CONNECT_SIGNAL ("button_reset_compatibility_options","clicked",button_reset_compatibility_options_clicked_cb, tw);
1985 
1986     /* Close Button */
1987     CONNECT_SIGNAL ("button_wizard_close","clicked", wizard_button_close_clicked_cb, wizard);
1988     CONNECT_SIGNAL ("wizard_window","delete_event", wizard_window_delete_event_cb, wizard);
1989 
1990     CONNECT_SIGNAL ("entry_word_chars", "changed", entry_word_chars_changed, tw);
1991 }
1992 
1993 /* Initialize the palette scheme menu.
1994  * Add the predefined schemes to the combo box.*/
init_palette_scheme_menu(void)1995 static void init_palette_scheme_menu (void)
1996 {
1997     gint i;
1998     TildaColorScheme *paletteSchemes;
1999     GtkWidget *combo_palette;
2000 
2001     combo_palette = GTK_WIDGET (gtk_builder_get_object (xml,
2002                                                         "combo_palette_scheme"));
2003 
2004     i = tilda_palettes_get_n_palette_schemes ();
2005     paletteSchemes = tilda_palettes_get_palette_schemes ();
2006 
2007     while (i > 0) {
2008         --i;
2009         const char *palette_name = paletteSchemes[i].name;
2010         gtk_combo_box_text_prepend_text (GTK_COMBO_BOX_TEXT (combo_palette),
2011                                          _(palette_name));
2012     }
2013 }
2014 
update_palette_color_button(gint idx)2015 static void update_palette_color_button(gint idx)
2016 {
2017     GdkRGBA * current_palette;
2018     char *s = g_strdup_printf ("colorbutton_palette_%d", idx);
2019     GtkWidget *color_button =
2020         GTK_WIDGET (gtk_builder_get_object (xml, s));
2021 
2022     g_free (s);
2023 
2024     current_palette = tilda_palettes_get_current_palette ();
2025 
2026     const GdkRGBA *color = tilda_palettes_get_palette_color (current_palette, idx);
2027     gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (color_button),
2028                                 color);
2029 }
2030