1 /*
2 * Copyright © 2002 Havoc Pennington
3 * Copyright © 2002 Mathias Hasselmann
4 * Copyright © 2008 Christian Persch
5 * Copyright (C) 2012-2021 MATE Developers
6 *
7 * Mate-terminal is free software; you can redistribute it and/or modify
8 * it under the terms of the GNU General Public License as published by
9 * the Free Software Foundation; either version 3 of the License, or
10 * (at your option) any later version.
11 *
12 * Mate-terminal is distributed in the hope that it will be useful,
13 * but WITHOUT ANY WARRANTY; without even the implied warranty of
14 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
15 * GNU General Public License for more details.
16 *
17 * You should have received a copy of the GNU General Public License
18 * along with this program. If not, see <http://www.gnu.org/licenses/>.
19 */
20
21 #include <config.h>
22
23 #include <string.h>
24 #include <math.h>
25
26 #include <glib.h>
27 #include <gio/gio.h>
28
29 #include "terminal-intl.h"
30 #include "profile-editor.h"
31 #include "terminal-util.h"
32
33 typedef struct _TerminalColorScheme TerminalColorScheme;
34
35 struct _TerminalColorScheme
36 {
37 const char *name;
38 const GdkRGBA foreground;
39 const GdkRGBA background;
40 };
41
42 static const TerminalColorScheme color_schemes[] =
43 {
44 {
45 N_("Black on light yellow"),
46 { 0, 0, 0, 1 },
47 { 1, 1, 0.866667, 1 }
48 },
49 {
50 N_("Black on white"),
51 { 0, 0, 0, 1 },
52 { 1, 1, 1, 1 }
53 },
54 {
55 N_("Gray on black"),
56 { 0.666667, 0.666667, 0.666667, 1 },
57 { 0, 0, 0, 1 }
58 },
59 {
60 N_("Green on black"),
61 { 0, 1, 0, 1 },
62 { 0, 0, 0, 1 }
63 },
64 {
65 N_("White on black"),
66 { 1, 1, 1, 1 },
67 { 0, 0, 0, 1 }
68 },
69 /* Translators: "Solarized" is the name of a colour scheme, "light" can be translated */
70 { N_("Solarized light"),
71 { 0.396078, 0.482352, 0.513725, 1 },
72 { 0.992156, 0.964705, 0.890196, 1 }
73 },
74 /* Translators: "Solarized" is the name of a colour scheme, "dark" can be translated */
75 { N_("Solarized dark"),
76 { 0.513725, 0.580392, 0.588235, 1 },
77 { 0, 0.168627, 0.211764, 1 }
78 },
79 };
80
81 static void profile_forgotten_cb (TerminalProfile *profile,
82 GtkWidget *editor);
83
84 static void profile_notify_sensitivity_cb (TerminalProfile *profile,
85 GParamSpec *pspec,
86 GtkWidget *editor);
87
88 static void profile_colors_notify_scheme_combo_cb (TerminalProfile *profile,
89 GParamSpec *pspec,
90 GtkComboBox *combo);
91
92 static void profile_palette_notify_scheme_combo_cb (TerminalProfile *profile,
93 GParamSpec *pspec,
94 GtkComboBox *combo);
95
96 static void profile_palette_notify_colorpickers_cb (TerminalProfile *profile,
97 GParamSpec *pspec,
98 GtkWidget *editor);
99
100 static GtkWidget*
profile_editor_get_widget(GtkWidget * editor,const char * widget_name)101 profile_editor_get_widget (GtkWidget *editor,
102 const char *widget_name)
103 {
104 GtkBuilder *builder;
105
106 builder = g_object_get_data (G_OBJECT (editor), "builder");
107 g_assert (builder != NULL);
108
109 return (GtkWidget *) gtk_builder_get_object (builder, widget_name);
110 }
111
112 static void
widget_and_labels_set_sensitive(GtkWidget * widget,gboolean sensitive)113 widget_and_labels_set_sensitive (GtkWidget *widget, gboolean sensitive)
114 {
115 GList *labels, *i;
116
117 labels = gtk_widget_list_mnemonic_labels (widget);
118 for (i = labels; i; i = i->next)
119 {
120 gtk_widget_set_sensitive (GTK_WIDGET (i->data), sensitive);
121 }
122 g_list_free (labels);
123
124 gtk_widget_set_sensitive (widget, sensitive);
125 }
126
127 static void
profile_forgotten_cb(TerminalProfile * profile,GtkWidget * editor)128 profile_forgotten_cb (TerminalProfile *profile,
129 GtkWidget *editor)
130 {
131 gtk_widget_destroy (editor);
132 }
133
134 static void
profile_notify_sensitivity_cb(TerminalProfile * profile,GParamSpec * pspec,GtkWidget * editor)135 profile_notify_sensitivity_cb (TerminalProfile *profile,
136 GParamSpec *pspec,
137 GtkWidget *editor)
138 {
139 TerminalBackgroundType bg_type;
140 const char *prop_name;
141
142 if (pspec)
143 prop_name = pspec->name;
144 else
145 prop_name = NULL;
146
147 #define SET_SENSITIVE(name, setting) widget_and_labels_set_sensitive (profile_editor_get_widget (editor, name), setting)
148
149 if (!prop_name ||
150 prop_name == I_(TERMINAL_PROFILE_USE_CUSTOM_COMMAND) ||
151 prop_name == I_(TERMINAL_PROFILE_CUSTOM_COMMAND))
152 {
153 gboolean use_custom_command_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND);
154 SET_SENSITIVE ("use-custom-command-checkbutton", !use_custom_command_locked);
155 SET_SENSITIVE ("custom-command-box",
156 terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND) &&
157 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_CUSTOM_COMMAND));
158 }
159
160 gtk_widget_hide (profile_editor_get_widget (editor, "darken-background-transparent-or-image-scale-label"));
161 gtk_widget_show (profile_editor_get_widget (editor, "darken-background-transparent-scale-label"));
162 gtk_widget_hide (profile_editor_get_widget (editor, "scroll-background-checkbutton"));
163 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKGROUND_TYPE))
164 {
165 gboolean bg_type_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
166 SET_SENSITIVE ("solid-radiobutton", !bg_type_locked);
167 SET_SENSITIVE ("transparent-radiobutton", !bg_type_locked);
168
169 bg_type = terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
170 if (bg_type == TERMINAL_BACKGROUND_TRANSPARENT)
171 {
172 SET_SENSITIVE ("darken-background-vbox", !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS));
173 }
174 else
175 {
176 SET_SENSITIVE ("darken-background-vbox", FALSE);
177 }
178 }
179
180 if (!prop_name ||
181 prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT) ||
182 prop_name == I_(TERMINAL_PROFILE_FONT))
183 {
184 SET_SENSITIVE ("font-hbox",
185 !terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT) &&
186 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_FONT));
187 SET_SENSITIVE ("system-font-checkbutton",
188 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT));
189 }
190
191 if (!prop_name ||
192 prop_name == I_(TERMINAL_PROFILE_FOREGROUND_COLOR) ||
193 prop_name == I_(TERMINAL_PROFILE_BACKGROUND_COLOR) ||
194 prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
195 prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
196 prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
197 {
198 gboolean bg_locked, use_theme_colors, fg_locked;
199
200 use_theme_colors = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS);
201 fg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
202 bg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
203
204 SET_SENSITIVE ("foreground-colorpicker", !use_theme_colors && !fg_locked);
205 SET_SENSITIVE ("foreground-colorpicker-label", !use_theme_colors && !fg_locked);
206 SET_SENSITIVE ("background-colorpicker", !use_theme_colors && !bg_locked);
207 SET_SENSITIVE ("background-colorpicker-label", !use_theme_colors && !bg_locked);
208 SET_SENSITIVE ("color-scheme-combobox", !use_theme_colors && !fg_locked && !bg_locked);
209 SET_SENSITIVE ("color-scheme-combobox-label", !use_theme_colors && !fg_locked && !bg_locked);
210 }
211
212 if (!prop_name ||
213 prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
214 prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
215 prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
216 {
217 gboolean bold_locked, bold_same_as_fg_locked, bold_same_as_fg, use_theme_colors;
218
219 use_theme_colors = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS);
220 bold_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BOLD_COLOR);
221 bold_same_as_fg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
222 bold_same_as_fg = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
223
224 SET_SENSITIVE ("bold-color-same-as-fg-checkbox", !use_theme_colors && !bold_same_as_fg_locked);
225 SET_SENSITIVE ("bold-colorpicker", !use_theme_colors && !bold_locked && !bold_same_as_fg);
226 SET_SENSITIVE ("bold-colorpicker-label", !use_theme_colors && ((!bold_same_as_fg && !bold_locked) || !bold_same_as_fg_locked));
227 }
228
229 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_VISIBLE_NAME))
230 SET_SENSITIVE ("profile-name-entry",
231 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_VISIBLE_NAME));
232
233 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR))
234 SET_SENSITIVE ("show-menubar-checkbutton",
235 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR));
236
237 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_TITLE))
238 SET_SENSITIVE ("title-entry",
239 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_TITLE));
240
241 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_TITLE_MODE))
242 SET_SENSITIVE ("title-mode-combobox",
243 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_TITLE_MODE));
244
245 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ALLOW_BOLD))
246 SET_SENSITIVE ("allow-bold-checkbutton",
247 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_ALLOW_BOLD));
248
249 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SILENT_BELL))
250 SET_SENSITIVE ("bell-checkbutton",
251 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SILENT_BELL));
252
253 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_COPY_SELECTION))
254 SET_SENSITIVE ("copy-checkbutton",
255 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_COPY_SELECTION));
256
257 #ifdef ENABLE_SKEY
258 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_SKEY))
259 SET_SENSITIVE ("use-skey-checkbutton",
260 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_SKEY));
261 #endif
262 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_URLS))
263 SET_SENSITIVE ("use-urls-checkbutton",
264 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_URLS));
265
266 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_WORD_CHARS))
267 SET_SENSITIVE ("word-chars-entry",
268 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_WORD_CHARS));
269
270 if (!prop_name ||
271 prop_name == I_(TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE) ||
272 prop_name == I_(TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS) ||
273 prop_name == I_(TERMINAL_PROFILE_DEFAULT_SIZE_ROWS))
274 {
275 gboolean use_custom_default_size_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
276 gboolean use_custom_default_size = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
277 gboolean columns_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS);
278 gboolean rows_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS);
279
280 SET_SENSITIVE ("use-custom-default-size-checkbutton", !use_custom_default_size_locked);
281 SET_SENSITIVE ("default-size-hbox", use_custom_default_size);
282 SET_SENSITIVE ("default-size-label", (!columns_locked || !rows_locked));
283 SET_SENSITIVE ("default-size-columns-label", !columns_locked);
284 SET_SENSITIVE ("default-size-columns-spinbutton", !columns_locked);
285 SET_SENSITIVE ("default-size-rows-label", !rows_locked);
286 SET_SENSITIVE ("default-size-rows-spinbutton", !rows_locked);
287 }
288
289 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLLBAR_POSITION))
290 SET_SENSITIVE ("scrollbar-position-combobox",
291 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBAR_POSITION));
292
293 if (!prop_name ||
294 prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_LINES) ||
295 prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_UNLIMITED))
296 {
297 gboolean scrollback_lines_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBACK_LINES);
298 gboolean scrollback_unlimited_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
299 gboolean scrollback_unlimited = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
300
301 SET_SENSITIVE ("scrollback-label", !scrollback_lines_locked);
302 SET_SENSITIVE ("scrollback-box", !scrollback_lines_locked && !scrollback_unlimited);
303 SET_SENSITIVE ("scrollback-unlimited-checkbutton", !scrollback_lines_locked && !scrollback_unlimited_locked);
304 }
305
306 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE))
307 SET_SENSITIVE ("scroll-on-keystroke-checkbutton",
308 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE));
309
310 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_OUTPUT))
311 SET_SENSITIVE ("scroll-on-output-checkbutton",
312 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT));
313
314 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_EXIT_ACTION))
315 SET_SENSITIVE ("exit-action-combobox",
316 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_EXIT_ACTION));
317
318 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_LOGIN_SHELL))
319 SET_SENSITIVE ("login-shell-checkbutton",
320 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_LOGIN_SHELL));
321
322 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_PALETTE))
323 {
324 gboolean palette_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_PALETTE);
325 SET_SENSITIVE ("palette-combobox", !palette_locked);
326 SET_SENSITIVE ("palette-table", !palette_locked);
327 }
328
329 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING))
330 SET_SENSITIVE ("backspace-binding-combobox",
331 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKSPACE_BINDING));
332
333 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING))
334 SET_SENSITIVE ("delete-binding-combobox",
335 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_DELETE_BINDING));
336
337 if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
338 SET_SENSITIVE ("use-theme-colors-checkbutton",
339 !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_THEME_COLORS));
340
341 #undef SET_INSENSITIVE
342 }
343
344 static void
color_scheme_combo_changed_cb(GtkWidget * combo,GParamSpec * pspec,TerminalProfile * profile)345 color_scheme_combo_changed_cb (GtkWidget *combo,
346 GParamSpec *pspec,
347 TerminalProfile *profile)
348 {
349 guint i;
350
351 i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
352
353 if (i < G_N_ELEMENTS (color_schemes))
354 {
355 g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo);
356 g_object_set (profile,
357 TERMINAL_PROFILE_FOREGROUND_COLOR, &color_schemes[i].foreground,
358 TERMINAL_PROFILE_BACKGROUND_COLOR, &color_schemes[i].background,
359 NULL);
360 g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo);
361 }
362 else
363 {
364 /* "custom" selected, no change */
365 }
366 }
367
368 static void
profile_colors_notify_scheme_combo_cb(TerminalProfile * profile,GParamSpec * pspec,GtkComboBox * combo)369 profile_colors_notify_scheme_combo_cb (TerminalProfile *profile,
370 GParamSpec *pspec,
371 GtkComboBox *combo)
372 {
373 const GdkRGBA *fg, *bg;
374 guint i;
375
376 fg = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
377 bg = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
378
379 if (fg && bg)
380 {
381 for (i = 0; i < G_N_ELEMENTS (color_schemes); ++i)
382 {
383 if (gdk_rgba_equal (&fg, &color_schemes[i].foreground) &&
384 gdk_rgba_equal (&bg, &color_schemes[i].background))
385 break;
386 }
387 }
388 else
389 {
390 i = G_N_ELEMENTS (color_schemes);
391 }
392 /* If we didn't find a match, then we get the last combo box item which is "custom" */
393
394 g_signal_handlers_block_by_func (combo, G_CALLBACK (color_scheme_combo_changed_cb), profile);
395 gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i);
396 g_signal_handlers_unblock_by_func (combo, G_CALLBACK (color_scheme_combo_changed_cb), profile);
397 }
398
399 static void
palette_scheme_combo_changed_cb(GtkComboBox * combo,GParamSpec * pspec,TerminalProfile * profile)400 palette_scheme_combo_changed_cb (GtkComboBox *combo,
401 GParamSpec *pspec,
402 TerminalProfile *profile)
403 {
404 int i;
405
406 i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo));
407
408 g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo);
409 if (i < TERMINAL_PALETTE_N_BUILTINS)
410 terminal_profile_set_palette_builtin (profile, i);
411 else
412 {
413 /* "custom" selected, no change */
414 }
415 g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo);
416 }
417
418 static void
profile_palette_notify_scheme_combo_cb(TerminalProfile * profile,GParamSpec * pspec,GtkComboBox * combo)419 profile_palette_notify_scheme_combo_cb (TerminalProfile *profile,
420 GParamSpec *pspec,
421 GtkComboBox *combo)
422 {
423 guint i;
424
425 if (!terminal_profile_get_palette_is_builtin (profile, &i))
426 /* If we didn't find a match, then we want the last combo
427 * box item which is "custom"
428 */
429 i = TERMINAL_PALETTE_N_BUILTINS;
430
431 g_signal_handlers_block_by_func (combo, G_CALLBACK (palette_scheme_combo_changed_cb), profile);
432 gtk_combo_box_set_active (combo, i);
433 g_signal_handlers_unblock_by_func (combo, G_CALLBACK (palette_scheme_combo_changed_cb), profile);
434 }
435
436 static void
palette_color_notify_cb(GtkColorChooser * button,GParamSpec * pspec,TerminalProfile * profile)437 palette_color_notify_cb (GtkColorChooser *button,
438 GParamSpec *pspec,
439 TerminalProfile *profile)
440 {
441 GtkWidget *editor;
442 GdkRGBA color;
443 guint i;
444
445 gtk_color_chooser_get_rgba (button, &color);
446 i = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button), "palette-entry-index"));
447
448 editor = gtk_widget_get_toplevel (GTK_WIDGET (button));
449 g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), editor);
450 terminal_profile_modify_palette_entry (profile, i, &color);
451 g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), editor);
452 }
453
454 static void
profile_palette_notify_colorpickers_cb(TerminalProfile * profile,GParamSpec * pspec,GtkWidget * editor)455 profile_palette_notify_colorpickers_cb (TerminalProfile *profile,
456 GParamSpec *pspec,
457 GtkWidget *editor)
458 {
459 GtkWidget *w;
460 GdkRGBA colors[TERMINAL_PALETTE_SIZE];
461 guint n_colors, i;
462
463 n_colors = G_N_ELEMENTS (colors);
464 terminal_profile_get_palette (profile, colors, &n_colors);
465
466 n_colors = MIN (n_colors, TERMINAL_PALETTE_SIZE);
467 for (i = 0; i < n_colors; i++)
468 {
469 char name[32];
470
471 g_snprintf (name, sizeof (name), "palette-colorpicker-%d", i + 1);
472 w = profile_editor_get_widget (editor, name);
473
474 g_signal_handlers_block_by_func (w, G_CALLBACK (palette_color_notify_cb), profile);
475 gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (w), &colors[i]);
476 g_signal_handlers_unblock_by_func (w, G_CALLBACK (palette_color_notify_cb), profile);
477 }
478 }
479
480 static void
custom_command_entry_changed_cb(GtkEntry * entry)481 custom_command_entry_changed_cb (GtkEntry *entry)
482 {
483 const char *command;
484 GError *error = NULL;
485
486 command = gtk_entry_get_text (entry);
487
488 if (g_shell_parse_argv (command, NULL, NULL, &error))
489 {
490 gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL);
491 }
492 else
493 {
494 char *tooltip;
495
496 gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning");
497
498 tooltip = g_strdup_printf (_("Error parsing command: %s"), error->message);
499 gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, tooltip);
500 g_free (tooltip);
501
502 g_error_free (error);
503 }
504 }
505
506 static void
visible_name_entry_changed_cb(GtkEntry * entry,GtkWindow * window)507 visible_name_entry_changed_cb (GtkEntry *entry,
508 GtkWindow *window)
509 {
510 const char *visible_name;
511 char *text;
512
513 visible_name = gtk_entry_get_text (entry);
514
515 text = g_strdup_printf (_("Editing Profile “%s”"), visible_name);
516 gtk_window_set_title (window, text);
517 g_free (text);
518 }
519
520 static void
reset_compat_defaults_cb(GtkWidget * button,TerminalProfile * profile)521 reset_compat_defaults_cb (GtkWidget *button,
522 TerminalProfile *profile)
523 {
524 terminal_profile_reset_property (profile, TERMINAL_PROFILE_DELETE_BINDING);
525 terminal_profile_reset_property (profile, TERMINAL_PROFILE_BACKSPACE_BINDING);
526 }
527
528 /*
529 * initialize widgets
530 */
531
532 static void
init_color_scheme_menu(GtkWidget * widget)533 init_color_scheme_menu (GtkWidget *widget)
534 {
535 GtkCellRenderer *renderer;
536 GtkTreeIter iter;
537 GtkListStore *store;
538 gsize i;
539
540 store = gtk_list_store_new (1, G_TYPE_STRING);
541 for (i = 0; i < G_N_ELEMENTS (color_schemes); ++i)
542 gtk_list_store_insert_with_values (store, &iter, -1,
543 0, _(color_schemes[i].name),
544 -1);
545 gtk_list_store_insert_with_values (store, &iter, -1,
546 0, _("Custom"),
547 -1);
548
549 gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store));
550 g_object_unref (store);
551
552 renderer = gtk_cell_renderer_text_new ();
553 gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE);
554 gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL);
555 }
556
557 static char*
format_percent_value(GtkScale * scale,double val,void * data)558 format_percent_value (GtkScale *scale,
559 double val,
560 void *data)
561 {
562 return g_strdup_printf ("%d%%", (int) (val * 100.0 + 0.5));
563 }
564
565 static void
init_background_darkness_scale(GtkWidget * scale)566 init_background_darkness_scale (GtkWidget *scale)
567 {
568 g_signal_connect (scale, "format-value",
569 G_CALLBACK (format_percent_value),
570 NULL);
571 }
572
573 static void
editor_response_cb(GtkWidget * editor,int response,gpointer use_data)574 editor_response_cb (GtkWidget *editor,
575 int response,
576 gpointer use_data)
577 {
578 if (response == GTK_RESPONSE_HELP)
579 {
580 terminal_util_show_help ("mate-terminal-prefs", GTK_WINDOW (editor));
581 return;
582 }
583
584 gtk_widget_destroy (editor);
585 }
586
587 static void
setup_background_filechooser(GtkWidget * filechooser,TerminalProfile * profile)588 setup_background_filechooser (GtkWidget *filechooser,
589 TerminalProfile *profile)
590 {
591 GtkFileFilter *filter;
592 const char *home_dir;
593
594 filter = gtk_file_filter_new ();
595 gtk_file_filter_add_pixbuf_formats (filter);
596 gtk_file_filter_set_name (filter, _("Images"));
597 gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (filechooser), filter);
598
599 gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filechooser), TRUE);
600
601 /* Start filechooser in $HOME instead of the current dir of the factory which is "/" */
602 home_dir = g_get_home_dir ();
603 if (home_dir)
604 gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser), home_dir);
605 }
606
607 static void
profile_editor_destroyed(GtkWidget * editor,TerminalProfile * profile)608 profile_editor_destroyed (GtkWidget *editor,
609 TerminalProfile *profile)
610 {
611 g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_forgotten_cb), editor);
612 g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_notify_sensitivity_cb), editor);
613 g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
614 G_CALLBACK (profile_colors_notify_scheme_combo_cb), NULL);
615 g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
616 G_CALLBACK (profile_palette_notify_scheme_combo_cb), NULL);
617 g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
618 G_CALLBACK (profile_palette_notify_colorpickers_cb), NULL);
619
620 g_object_set_data (G_OBJECT (profile), "editor-window", NULL);
621 g_object_set_data (G_OBJECT (editor), "builder", NULL);
622 }
623
624 static void
terminal_profile_editor_focus_widget(GtkWidget * editor,const char * widget_name)625 terminal_profile_editor_focus_widget (GtkWidget *editor,
626 const char *widget_name)
627 {
628 GtkBuilder *builder;
629 GtkWidget *widget, *page, *page_parent;
630
631 if (widget_name == NULL)
632 return;
633
634 builder = g_object_get_data (G_OBJECT (editor), "builder");
635 widget = GTK_WIDGET (gtk_builder_get_object (builder, widget_name));
636 if (widget == NULL)
637 return;
638
639 page = widget;
640 while (page != NULL &&
641 (page_parent = gtk_widget_get_parent (page)) != NULL &&
642 !GTK_IS_NOTEBOOK (page_parent))
643 page = page_parent;
644
645 page_parent = gtk_widget_get_parent (page);
646 if (page != NULL && GTK_IS_NOTEBOOK (page_parent))
647 {
648 GtkNotebook *notebook;
649
650 notebook = GTK_NOTEBOOK (page_parent);
651 gtk_notebook_set_current_page (notebook, gtk_notebook_page_num (notebook, page));
652 }
653
654 if (gtk_widget_is_sensitive (widget))
655 gtk_widget_grab_focus (widget);
656 }
657
658 static gboolean
on_profile_editor_notebook_scroll_event(GtkWidget * widget,GdkEventScroll * event)659 on_profile_editor_notebook_scroll_event (GtkWidget *widget,
660 GdkEventScroll *event)
661 {
662 GtkNotebook *notebook = GTK_NOTEBOOK (widget);
663 GtkWidget *child, *event_widget, *action_widget;
664
665 child = gtk_notebook_get_nth_page (notebook, gtk_notebook_get_current_page (notebook));
666 if (child == NULL)
667 return FALSE;
668
669 event_widget = gtk_get_event_widget ((GdkEvent*) event);
670
671 /* Ignore scroll events from the content of the page */
672 if (event_widget == NULL || event_widget == child || gtk_widget_is_ancestor (event_widget, child))
673 return FALSE;
674
675 /* And also from the action widgets */
676 action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_START);
677 if (event_widget == action_widget || (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
678 return FALSE;
679
680 action_widget = gtk_notebook_get_action_widget (notebook, GTK_PACK_END);
681 if (event_widget == action_widget || (action_widget != NULL && gtk_widget_is_ancestor (event_widget, action_widget)))
682 return FALSE;
683
684 switch (event->direction) {
685 case GDK_SCROLL_RIGHT:
686 case GDK_SCROLL_DOWN:
687 gtk_notebook_next_page (notebook);
688 break;
689 case GDK_SCROLL_LEFT:
690 case GDK_SCROLL_UP:
691 gtk_notebook_prev_page (notebook);
692 break;
693 case GDK_SCROLL_SMOOTH:
694 switch (gtk_notebook_get_tab_pos (notebook)) {
695 case GTK_POS_LEFT:
696 case GTK_POS_RIGHT:
697 if (event->delta_y > 0)
698 gtk_notebook_next_page (notebook);
699 else if (event->delta_y < 0)
700 gtk_notebook_prev_page (notebook);
701 break;
702 case GTK_POS_TOP:
703 case GTK_POS_BOTTOM:
704 if (event->delta_x > 0)
705 gtk_notebook_next_page (notebook);
706 else if (event->delta_x < 0)
707 gtk_notebook_prev_page (notebook);
708 break;
709 }
710 break;
711 }
712
713 return TRUE;
714 }
715
716 /**
717 * terminal_profile_edit:
718 * @profile: a #TerminalProfile
719 * @transient_parent: a #GtkWindow, or %NULL
720 * @widget_name: a widget name in the profile editor's UI, or %NULL
721 *
722 * Shows the profile editor with @profile, anchored to @transient_parent.
723 * If @widget_name is non-%NULL, focuses the corresponding widget and
724 * switches the notebook to its containing page.
725 */
726 void
terminal_profile_edit(TerminalProfile * profile,GtkWindow * transient_parent,const char * widget_name)727 terminal_profile_edit (TerminalProfile *profile,
728 GtkWindow *transient_parent,
729 const char *widget_name)
730 {
731 GtkBuilder *builder;
732 GError *error = NULL;
733 GtkWidget *editor, *w;
734 guint i;
735
736 editor = g_object_get_data (G_OBJECT (profile), "editor-window");
737 if (editor)
738 {
739 terminal_profile_editor_focus_widget (editor, widget_name);
740
741 gtk_window_set_transient_for (GTK_WINDOW (editor),
742 GTK_WINDOW (transient_parent));
743 gtk_window_present (GTK_WINDOW (editor));
744 return;
745 }
746
747 builder = gtk_builder_new ();
748 gtk_builder_add_from_resource (builder, TERMINAL_RESOURCES_PATH_PREFIX G_DIR_SEPARATOR_S "ui/profile-preferences.ui", &error);
749 g_assert_no_error (error);
750
751 editor = (GtkWidget *) gtk_builder_get_object (builder, "profile-editor-dialog");
752 g_object_set_data_full (G_OBJECT (editor), "builder",
753 builder, (GDestroyNotify) g_object_unref);
754 #ifndef ENABLE_SKEY
755 gtk_widget_hide (profile_editor_get_widget (editor, "use-skey-checkbutton"));
756 #endif
757 /* Store the dialogue on the profile, so we can acccess it above to check if
758 * there's already a profile editor for this profile.
759 */
760 g_object_set_data (G_OBJECT (profile), "editor-window", editor);
761
762 g_signal_connect (editor, "destroy",
763 G_CALLBACK (profile_editor_destroyed),
764 profile);
765
766 g_signal_connect (editor, "response",
767 G_CALLBACK (editor_response_cb),
768 NULL);
769
770 w = (GtkWidget *) gtk_builder_get_object (builder, "color-scheme-combobox");
771 init_color_scheme_menu (w);
772
773 w = (GtkWidget *) gtk_builder_get_object (builder, "darken-background-scale");
774 init_background_darkness_scale (w);
775
776 w = (GtkWidget *) gtk_builder_get_object (builder, "background-image-filechooser");
777 setup_background_filechooser (w, profile);
778
779 /* Hook up the palette colorpickers and combo box */
780
781 for (i = 0; i < TERMINAL_PALETTE_SIZE; ++i)
782 {
783 char name[32];
784 char *text;
785
786 g_snprintf (name, sizeof (name), "palette-colorpicker-%u", i + 1);
787 w = (GtkWidget *) gtk_builder_get_object (builder, name);
788
789 g_object_set_data (G_OBJECT (w), "palette-entry-index", GUINT_TO_POINTER (i));
790
791 text = g_strdup_printf (_("Choose Palette Color %d"), i + 1);
792 gtk_color_button_set_title (GTK_COLOR_BUTTON (w), text);
793 g_free (text);
794
795 text = g_strdup_printf (_("Palette entry %d"), i + 1);
796 gtk_widget_set_tooltip_text (w, text);
797 g_free (text);
798
799 g_signal_connect (w, "notify::rgba",
800 G_CALLBACK (palette_color_notify_cb),
801 profile);
802 }
803
804 profile_palette_notify_colorpickers_cb (profile, NULL, editor);
805 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_PALETTE,
806 G_CALLBACK (profile_palette_notify_colorpickers_cb),
807 editor);
808
809 w = (GtkWidget *) gtk_builder_get_object (builder, "palette-combobox");
810 g_signal_connect (w, "notify::active",
811 G_CALLBACK (palette_scheme_combo_changed_cb),
812 profile);
813
814 profile_palette_notify_scheme_combo_cb (profile, NULL, GTK_COMBO_BOX (w));
815 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_PALETTE,
816 G_CALLBACK (profile_palette_notify_scheme_combo_cb),
817 w);
818
819 /* Hook up the color scheme pickers and combo box */
820 w = (GtkWidget *) gtk_builder_get_object (builder, "color-scheme-combobox");
821 g_signal_connect (w, "notify::active",
822 G_CALLBACK (color_scheme_combo_changed_cb),
823 profile);
824
825 profile_colors_notify_scheme_combo_cb (profile, NULL, GTK_COMBO_BOX (w));
826 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_FOREGROUND_COLOR,
827 G_CALLBACK (profile_colors_notify_scheme_combo_cb),
828 w);
829 g_signal_connect (profile, "notify::" TERMINAL_PROFILE_BACKGROUND_COLOR,
830 G_CALLBACK (profile_colors_notify_scheme_combo_cb),
831 w);
832
833 #define CONNECT_WITH_FLAGS(name, prop, flags) terminal_util_bind_object_property_to_widget (G_OBJECT (profile), prop, (GtkWidget *) gtk_builder_get_object (builder, name), flags)
834 #define CONNECT(name, prop) CONNECT_WITH_FLAGS (name, prop, 0)
835 #define SET_ENUM_VALUE(name, value) g_object_set_data (gtk_builder_get_object (builder, name), "enum-value", GINT_TO_POINTER (value))
836
837 w = GTK_WIDGET (gtk_builder_get_object (builder, "custom-command-entry"));
838 custom_command_entry_changed_cb (GTK_ENTRY (w));
839 g_signal_connect (w, "changed",
840 G_CALLBACK (custom_command_entry_changed_cb), NULL);
841 w = GTK_WIDGET (gtk_builder_get_object (builder, "profile-name-entry"));
842 g_signal_connect (w, "changed",
843 G_CALLBACK (visible_name_entry_changed_cb), editor);
844
845 g_signal_connect (gtk_builder_get_object (builder, "reset-compat-defaults-button"),
846 "clicked",
847 G_CALLBACK (reset_compat_defaults_cb),
848 profile);
849
850 SET_ENUM_VALUE ("image-radiobutton", TERMINAL_BACKGROUND_IMAGE);
851 SET_ENUM_VALUE ("solid-radiobutton", TERMINAL_BACKGROUND_SOLID);
852 SET_ENUM_VALUE ("transparent-radiobutton", TERMINAL_BACKGROUND_TRANSPARENT);
853 CONNECT ("allow-bold-checkbutton", TERMINAL_PROFILE_ALLOW_BOLD);
854 CONNECT ("background-colorpicker", TERMINAL_PROFILE_BACKGROUND_COLOR);
855 CONNECT ("background-image-filechooser", TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE);
856 CONNECT ("backspace-binding-combobox", TERMINAL_PROFILE_BACKSPACE_BINDING);
857 CONNECT ("bold-color-same-as-fg-checkbox", TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
858 CONNECT ("bold-colorpicker", TERMINAL_PROFILE_BOLD_COLOR);
859 CONNECT ("cursor-shape-combobox", TERMINAL_PROFILE_CURSOR_SHAPE);
860 CONNECT ("cursor-blink-combobox", TERMINAL_PROFILE_CURSOR_BLINK_MODE);
861 CONNECT ("custom-command-entry", TERMINAL_PROFILE_CUSTOM_COMMAND);
862 CONNECT ("darken-background-scale", TERMINAL_PROFILE_BACKGROUND_DARKNESS);
863 CONNECT ("default-size-columns-spinbutton", TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS);
864 CONNECT ("default-size-rows-spinbutton", TERMINAL_PROFILE_DEFAULT_SIZE_ROWS);
865 CONNECT ("delete-binding-combobox", TERMINAL_PROFILE_DELETE_BINDING);
866 CONNECT ("exit-action-combobox", TERMINAL_PROFILE_EXIT_ACTION);
867 CONNECT ("font-selector", TERMINAL_PROFILE_FONT);
868 CONNECT ("foreground-colorpicker", TERMINAL_PROFILE_FOREGROUND_COLOR);
869 CONNECT ("image-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
870 CONNECT ("login-shell-checkbutton", TERMINAL_PROFILE_LOGIN_SHELL);
871 CONNECT ("profile-name-entry", TERMINAL_PROFILE_VISIBLE_NAME);
872 CONNECT ("scrollback-lines-spinbutton", TERMINAL_PROFILE_SCROLLBACK_LINES);
873 CONNECT ("scrollback-unlimited-checkbutton", TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
874 CONNECT ("scroll-background-checkbutton", TERMINAL_PROFILE_SCROLL_BACKGROUND);
875 CONNECT ("scrollbar-position-combobox", TERMINAL_PROFILE_SCROLLBAR_POSITION);
876 CONNECT ("scroll-on-keystroke-checkbutton", TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE);
877 CONNECT ("scroll-on-output-checkbutton", TERMINAL_PROFILE_SCROLL_ON_OUTPUT);
878 CONNECT ("show-menubar-checkbutton", TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR);
879 CONNECT ("solid-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
880 CONNECT ("system-font-checkbutton", TERMINAL_PROFILE_USE_SYSTEM_FONT);
881 CONNECT ("title-entry", TERMINAL_PROFILE_TITLE);
882 CONNECT ("title-mode-combobox", TERMINAL_PROFILE_TITLE_MODE);
883 CONNECT ("transparent-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
884 CONNECT ("use-custom-command-checkbutton", TERMINAL_PROFILE_USE_CUSTOM_COMMAND);
885 CONNECT ("use-custom-default-size-checkbutton", TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
886 CONNECT ("use-theme-colors-checkbutton", TERMINAL_PROFILE_USE_THEME_COLORS);
887 CONNECT ("word-chars-entry", TERMINAL_PROFILE_WORD_CHARS);
888 CONNECT_WITH_FLAGS ("bell-checkbutton", TERMINAL_PROFILE_SILENT_BELL, FLAG_INVERT_BOOL);
889 /* CONNECT_WITH_FLAGS ("copy-checkbutton", TERMINAL_PROFILE_COPY_SELECTION, FLAG_INVERT_BOOL); */
890 CONNECT ("copy-checkbutton", TERMINAL_PROFILE_COPY_SELECTION);
891 #ifdef ENABLE_SKEY
892 CONNECT ("use-skey-checkbutton", TERMINAL_PROFILE_USE_SKEY);
893 #endif
894 CONNECT ("use-urls-checkbutton", TERMINAL_PROFILE_USE_URLS);
895
896 #undef CONNECT
897 #undef CONNECT_WITH_FLAGS
898 #undef SET_ENUM_VALUE
899
900 profile_notify_sensitivity_cb (profile, NULL, editor);
901 g_signal_connect (profile, "notify",
902 G_CALLBACK (profile_notify_sensitivity_cb),
903 editor);
904 g_signal_connect (profile,
905 "forgotten",
906 G_CALLBACK (profile_forgotten_cb),
907 editor);
908
909 terminal_profile_editor_focus_widget (editor, widget_name);
910
911 w = GTK_WIDGET (gtk_builder_get_object (builder, "profile-editor-notebook"));
912 gtk_widget_add_events (w, GDK_SCROLL_MASK);
913 g_signal_connect (w,
914 "scroll-event",
915 G_CALLBACK (on_profile_editor_notebook_scroll_event),
916 NULL);
917
918 gtk_window_set_transient_for (GTK_WINDOW (editor),
919 GTK_WINDOW (transient_parent));
920 gtk_window_present (GTK_WINDOW (editor));
921 }
922