1 /*-
2 * Copyright (c) 2004-2007 os-cillation e.K.
3 *
4 * Written by Benedikt Meurer <benny@xfce.org>.
5 *
6 * This program is free software; you can redistribute it and/or modify it
7 * under the terms of the GNU General Public License as published by the Free
8 * Software Foundation; either version 2 of the License, or (at your option)
9 * any later version.
10 *
11 * This program is distributed in the hope that it will be useful, but WITHOUT
12 * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
13 * FITNESS FOR A PARTICULAR PURPOSE. See the GNU General Public License for
14 * more details.
15 *
16 * You should have received a copy of the GNU General Public License
17 * along with this program. If not, see <http://www.gnu.org/licenses/>.
18 */
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #ifdef HAVE_MEMORY_H
25 #include <memory.h>
26 #endif
27 #ifdef HAVE_PWD_H
28 #include <pwd.h>
29 #endif
30 #include <stdlib.h>
31 #ifdef HAVE_STRING_H
32 #include <string.h>
33 #endif
34 #ifdef HAVE_UNISTD_H
35 #include <unistd.h>
36 #endif
37 #ifdef HAVE_TIME_H
38 #include <time.h>
39 #endif
40 #ifdef HAVE_LIBUTEMPTER
41 #include <utempter.h>
42 #endif
43
44 #include <sys/wait.h>
45
46 #include <libxfce4ui/libxfce4ui.h>
47 #include <xfconf/xfconf.h>
48
49 #include <terminal/terminal-util.h>
50 #include <terminal/terminal-enum-types.h>
51 #include <terminal/terminal-image-loader.h>
52 #include <terminal/terminal-marshal.h>
53 #include <terminal/terminal-screen.h>
54 #include <terminal/terminal-widget.h>
55 #include <terminal/terminal-window.h>
56
57 #if defined(GDK_WINDOWING_X11)
58 #include <gdk/gdkx.h>
59 #endif
60 #include <glib/gstdio.h>
61
62 /* offset of saturation random value */
63 #define SATURATION_WINDOW 0.20
64
65 /* taken from gnome-terminal (terminal-screen.c) */
66 #define SPAWN_TIMEOUT (30 * 1000 /* 30 s*/)
67
68 /* minimum terminal dimensions */
69 #define MIN_COLUMNS 4
70 #define MIN_ROWS 1
71
72
73
74 enum
75 {
76 PROP_0,
77 PROP_CUSTOM_TITLE,
78 PROP_TITLE
79 };
80
81 enum
82 {
83 GET_CONTEXT_MENU,
84 SELECTION_CHANGED,
85 CLOSE_TAB,
86 LAST_SIGNAL
87 };
88
89 enum
90 {
91 HSV_HUE,
92 HSV_SATURATION,
93 HSV_VALUE,
94 N_HSV
95 };
96
97
98
99 static void terminal_screen_finalize (GObject *object);
100 static void terminal_screen_get_property (GObject *object,
101 guint prop_id,
102 GValue *value,
103 GParamSpec *pspec);
104 static void terminal_screen_set_property (GObject *object,
105 guint prop_id,
106 const GValue *value,
107 GParamSpec *pspec);
108 static void terminal_screen_realize (GtkWidget *widget);
109 static void terminal_screen_unrealize (GtkWidget *widget);
110 static void terminal_screen_style_updated (GtkWidget *widget);
111 static gboolean terminal_screen_draw (GtkWidget *widget,
112 cairo_t *cr,
113 gpointer user_data);
114 static void terminal_screen_preferences_changed (TerminalPreferences *preferences,
115 GParamSpec *pspec,
116 TerminalScreen *screen);
117 static gboolean terminal_screen_get_child_command (TerminalScreen *screen,
118 gchar **command,
119 gchar ***argv,
120 GError **error);
121 static gchar *terminal_screen_parse_title (TerminalScreen *screen,
122 const gchar *title);
123 static gchar **terminal_screen_get_child_environment (TerminalScreen *screen);
124 static void terminal_screen_update_background (TerminalScreen *screen);
125 static void terminal_screen_update_binding_backspace (TerminalScreen *screen);
126 static void terminal_screen_update_binding_delete (TerminalScreen *screen);
127 static void terminal_screen_update_binding_ambiguous_width(TerminalScreen *screen);
128 static void terminal_screen_update_encoding (TerminalScreen *screen);
129 static void terminal_screen_update_colors (TerminalScreen *screen);
130 static void terminal_screen_update_misc_bell (TerminalScreen *screen);
131 static void terminal_screen_update_misc_cursor_blinks (TerminalScreen *screen);
132 static void terminal_screen_update_misc_cursor_shape (TerminalScreen *screen);
133 static void terminal_screen_update_misc_mouse_autohide (TerminalScreen *screen);
134 static void terminal_screen_update_misc_rewrap_on_resize (TerminalScreen *screen);
135 static void terminal_screen_update_scrolling_lines (TerminalScreen *screen);
136 static void terminal_screen_update_scrolling_on_output (TerminalScreen *screen);
137 static void terminal_screen_update_scrolling_on_keystroke (TerminalScreen *screen);
138 static void terminal_screen_update_text_blink_mode (TerminalScreen *screen);
139 static void terminal_screen_update_title (TerminalScreen *screen);
140 static void terminal_screen_update_word_chars (TerminalScreen *screen);
141 static void terminal_screen_vte_child_exited (VteTerminal *terminal,
142 gint status,
143 TerminalScreen *screen);
144 static void terminal_screen_vte_eof (VteTerminal *terminal,
145 TerminalScreen *screen);
146 static GtkWidget *terminal_screen_vte_get_context_menu (TerminalWidget *widget,
147 TerminalScreen *screen);
148 static void terminal_screen_vte_selection_changed (VteTerminal *terminal,
149 TerminalScreen *screen);
150 static void terminal_screen_vte_window_title_changed (VteTerminal *terminal,
151 TerminalScreen *screen);
152 static void terminal_screen_vte_resize_window (VteTerminal *terminal,
153 guint width,
154 guint height,
155 TerminalScreen *screen);
156 static void terminal_screen_vte_window_contents_changed (TerminalScreen *screen);
157 static void terminal_screen_vte_window_contents_resized (TerminalScreen *screen);
158 static void terminal_screen_update_label_orientation (TerminalScreen *screen);
159 static void terminal_screen_urgent_bell (TerminalWidget *widget,
160 TerminalScreen *screen);
161 static void terminal_screen_set_custom_command (TerminalScreen *screen,
162 gchar **command);
163 static void terminal_screen_set_tab_label_color (TerminalScreen *screen,
164 const GdkRGBA *color);
165 static GtkWidget* terminal_screen_unsafe_paste_dialog_new (TerminalScreen *screen,
166 const gchar *text);
167 static void terminal_screen_paste_unsafe_text (TerminalScreen *screen,
168 const gchar *text,
169 GdkAtom original_clipboard);
170
171
172
173 struct _TerminalScreenClass
174 {
175 GtkOverlayClass parent_class;
176 };
177
178 struct _TerminalScreen
179 {
180 GtkOverlay parent_instance;
181 TerminalPreferences *preferences;
182 TerminalImageLoader *loader;
183 GtkWidget *hbox;
184 GtkWidget *terminal;
185 GtkWidget *scrollbar;
186 GtkWidget *tab_label;
187
188 GdkRGBA background_color;
189
190 guint session_id;
191
192 GPid pid;
193 gchar *working_directory;
194
195 gchar **custom_command;
196 gchar *custom_title;
197 gchar *initial_title;
198
199 gchar *custom_fg_color;
200 gchar *custom_bg_color;
201 gchar *custom_title_color;
202
203 TerminalTitle dynamic_title_mode;
204 guint hold : 1;
205 guint has_random_bg_color : 1;
206 #if !VTE_CHECK_VERSION (0, 51, 1)
207 guint scroll_on_output : 1;
208 #endif
209
210 guint activity_timeout_id;
211 time_t activity_resize_time;
212 };
213
214
215
216 static guint screen_signals[LAST_SIGNAL];
217 static guint screen_last_session_id = 0;
218
219
220
G_DEFINE_TYPE(TerminalScreen,terminal_screen,GTK_TYPE_OVERLAY)221 G_DEFINE_TYPE (TerminalScreen, terminal_screen, GTK_TYPE_OVERLAY)
222
223
224
225 static void
226 terminal_screen_class_init (TerminalScreenClass *klass)
227 {
228 GtkWidgetClass *gtkwidget_class;
229 GObjectClass *gobject_class;
230
231 gobject_class = G_OBJECT_CLASS (klass);
232 gobject_class->finalize = terminal_screen_finalize;
233 gobject_class->get_property = terminal_screen_get_property;
234 gobject_class->set_property = terminal_screen_set_property;
235
236 gtkwidget_class = GTK_WIDGET_CLASS (klass);
237 gtkwidget_class->realize = terminal_screen_realize;
238 gtkwidget_class->unrealize = terminal_screen_unrealize;
239 gtkwidget_class->style_updated = terminal_screen_style_updated;
240
241 /**
242 * TerminalScreen:custom-title:
243 **/
244 g_object_class_install_property (gobject_class,
245 PROP_CUSTOM_TITLE,
246 g_param_spec_string ("custom-title",
247 "custom-title",
248 "custom-title",
249 NULL,
250 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
251
252 /**
253 * TerminalScreen:title:
254 **/
255 g_object_class_install_property (gobject_class,
256 PROP_TITLE,
257 g_param_spec_string ("title",
258 "title",
259 "title",
260 NULL,
261 G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS));
262
263 /**
264 * TerminalScreen::get-context-menu
265 **/
266 screen_signals[GET_CONTEXT_MENU] =
267 g_signal_new (I_("get-context-menu"),
268 G_TYPE_FROM_CLASS (gobject_class),
269 G_SIGNAL_RUN_LAST,
270 0, NULL, NULL,
271 _terminal_marshal_OBJECT__VOID,
272 GTK_TYPE_MENU, 0);
273
274 /**
275 * TerminalScreen::selection-changed
276 **/
277 screen_signals[SELECTION_CHANGED] =
278 g_signal_new (I_("selection-changed"),
279 G_TYPE_FROM_CLASS (gobject_class),
280 G_SIGNAL_RUN_LAST,
281 0, NULL, NULL,
282 g_cclosure_marshal_VOID__VOID,
283 G_TYPE_NONE, 0);
284
285 /**
286 * TerminalScreen::close-tab-request
287 **/
288 screen_signals[CLOSE_TAB] =
289 g_signal_new (I_("close-tab-request"),
290 G_TYPE_FROM_CLASS (gobject_class),
291 G_SIGNAL_RUN_LAST,
292 0, NULL, NULL,
293 g_cclosure_marshal_VOID__VOID,
294 G_TYPE_NONE, 0);
295 }
296
297
298
299 static void
terminal_screen_init(TerminalScreen * screen)300 terminal_screen_init (TerminalScreen *screen)
301 {
302 screen->loader = NULL;
303 screen->working_directory = g_get_current_dir ();
304 screen->dynamic_title_mode = TERMINAL_TITLE_DEFAULT;
305 screen->session_id = ++screen_last_session_id;
306 screen->pid = -1;
307
308 screen->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
309 gtk_container_add (GTK_CONTAINER (screen), screen->hbox);
310
311 screen->terminal = g_object_new (TERMINAL_TYPE_WIDGET, NULL);
312 g_signal_connect (G_OBJECT (screen->terminal), "child-exited",
313 G_CALLBACK (terminal_screen_vte_child_exited), screen);
314 g_signal_connect (G_OBJECT (screen->terminal), "eof",
315 G_CALLBACK (terminal_screen_vte_eof), screen);
316 g_signal_connect (G_OBJECT (screen->terminal), "context-menu",
317 G_CALLBACK (terminal_screen_vte_get_context_menu), screen);
318 g_signal_connect (G_OBJECT (screen->terminal), "selection-changed",
319 G_CALLBACK (terminal_screen_vte_selection_changed), screen);
320 g_signal_connect (G_OBJECT (screen->terminal), "window-title-changed",
321 G_CALLBACK (terminal_screen_vte_window_title_changed), screen);
322 g_signal_connect (G_OBJECT (screen->terminal), "resize-window",
323 G_CALLBACK (terminal_screen_vte_resize_window), screen);
324 g_signal_connect (G_OBJECT (screen->terminal), "draw",
325 G_CALLBACK (terminal_screen_draw), screen);
326 g_signal_connect_swapped (G_OBJECT (screen->terminal), "paste-selection-request",
327 G_CALLBACK (terminal_screen_paste_primary), screen);
328 gtk_box_pack_start (GTK_BOX (screen->hbox), screen->terminal, TRUE, TRUE, 0);
329
330 screen->scrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL,
331 gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (screen->terminal)));
332 gtk_box_pack_start (GTK_BOX (screen->hbox), screen->scrollbar, FALSE, FALSE, 0);
333 g_signal_connect_after (G_OBJECT (screen->scrollbar), "button-press-event", G_CALLBACK (gtk_true), NULL);
334
335 /* watch preferences changes */
336 screen->preferences = terminal_preferences_get ();
337 g_signal_connect (G_OBJECT (screen->preferences), "notify",
338 G_CALLBACK (terminal_screen_preferences_changed), screen);
339
340 /* show the terminal */
341 gtk_widget_show_all (screen->hbox);
342
343 /* apply current settings */
344 terminal_screen_update_binding_backspace (screen);
345 terminal_screen_update_binding_delete (screen);
346 terminal_screen_update_binding_ambiguous_width (screen);
347 terminal_screen_update_encoding (screen);
348 terminal_screen_update_font (screen);
349 terminal_screen_update_misc_bell (screen);
350 terminal_screen_update_misc_cursor_blinks (screen);
351 terminal_screen_update_misc_cursor_shape (screen);
352 terminal_screen_update_misc_mouse_autohide (screen);
353 terminal_screen_update_misc_rewrap_on_resize (screen);
354 terminal_screen_update_scrolling_bar (screen);
355 terminal_screen_update_scrolling_lines (screen);
356 terminal_screen_update_scrolling_on_output (screen);
357 terminal_screen_update_scrolling_on_keystroke (screen);
358 terminal_screen_update_text_blink_mode (screen);
359 terminal_screen_update_word_chars (screen);
360 terminal_screen_update_background (screen);
361 terminal_screen_update_colors (screen);
362
363 /* last, connect contents-changed to avoid a race with updates above */
364 g_signal_connect_swapped (G_OBJECT (screen->terminal), "contents-changed",
365 G_CALLBACK (terminal_screen_vte_window_contents_changed), screen);
366 g_signal_connect_swapped (G_OBJECT (screen->terminal), "size-allocate",
367 G_CALLBACK (terminal_screen_vte_window_contents_resized), screen);
368 }
369
370
371
372 static void
terminal_screen_finalize(GObject * object)373 terminal_screen_finalize (GObject *object)
374 {
375 TerminalScreen *screen = TERMINAL_SCREEN (object);
376
377 if (screen->activity_timeout_id != 0)
378 g_source_remove (screen->activity_timeout_id);
379
380 /* detach from preferences */
381 g_signal_handlers_disconnect_by_func (screen->preferences,
382 G_CALLBACK (terminal_screen_preferences_changed), screen);
383 g_object_unref (G_OBJECT (screen->preferences));
384
385 if (screen->loader != NULL)
386 g_object_unref (G_OBJECT (screen->loader));
387
388 g_strfreev (screen->custom_command);
389 g_free (screen->working_directory);
390 g_free (screen->custom_title);
391 g_free (screen->initial_title);
392 g_free (screen->custom_fg_color);
393 g_free (screen->custom_bg_color);
394 g_free (screen->custom_title_color);
395
396 (*G_OBJECT_CLASS (terminal_screen_parent_class)->finalize) (object);
397 }
398
399
400
401 static void
terminal_screen_get_property(GObject * object,guint prop_id,GValue * value,GParamSpec * pspec)402 terminal_screen_get_property (GObject *object,
403 guint prop_id,
404 GValue *value,
405 GParamSpec *pspec)
406 {
407 TerminalScreen *screen = TERMINAL_SCREEN (object);
408 const gchar *title = NULL;
409 TerminalTitle mode;
410 gchar *initial;
411 gchar *parsed_title = NULL;
412 gchar *custom_title;
413
414 switch (prop_id)
415 {
416 case PROP_CUSTOM_TITLE:
417 if (screen->custom_title != NULL)
418 g_value_set_string (value, screen->custom_title);
419 else
420 g_value_set_static_string (value, "");
421 break;
422
423 case PROP_TITLE:
424 if (G_UNLIKELY (screen->custom_title != NULL))
425 {
426 custom_title = terminal_screen_parse_title (screen, screen->custom_title);
427 g_value_take_string (value, custom_title);
428 }
429 else
430 {
431 if (G_UNLIKELY (screen->dynamic_title_mode != TERMINAL_TITLE_DEFAULT))
432 mode = screen->dynamic_title_mode;
433 else
434 g_object_get (G_OBJECT (screen->preferences), "title-mode", &mode, NULL);
435
436 if (G_UNLIKELY (mode == TERMINAL_TITLE_HIDE))
437 {
438 /* show the initial title if the dynamic title is set to hidden */
439 if (G_UNLIKELY (screen->initial_title != NULL))
440 initial = g_strdup (screen->initial_title);
441 else
442 g_object_get (G_OBJECT (screen->preferences), "title-initial", &initial, NULL);
443 parsed_title = terminal_screen_parse_title (screen, initial);
444 title = parsed_title;
445 g_free (initial);
446 }
447 else if (G_LIKELY (screen->terminal != NULL))
448 {
449 title = vte_terminal_get_window_title (VTE_TERMINAL (screen->terminal));
450 }
451
452 /* TRANSLATORS: title for the tab/window used when all other
453 * possible titles were empty strings */
454 if (title == NULL || *title == '\0')
455 title = _("Untitled");
456
457 g_value_set_string (value, title);
458
459 g_free (parsed_title);
460 }
461 break;
462
463 default:
464 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
465 break;
466 }
467 }
468
469
470
471 static void
terminal_screen_set_property(GObject * object,guint prop_id,const GValue * value,GParamSpec * pspec)472 terminal_screen_set_property (GObject *object,
473 guint prop_id,
474 const GValue *value,
475 GParamSpec *pspec)
476 {
477 TerminalScreen *screen = TERMINAL_SCREEN (object);
478
479 switch (prop_id)
480 {
481 case PROP_CUSTOM_TITLE:
482 terminal_screen_set_custom_title (screen, g_value_get_string (value));
483 break;
484
485 default:
486 G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
487 break;
488 }
489 }
490
491
492
493 static void
terminal_screen_realize(GtkWidget * widget)494 terminal_screen_realize (GtkWidget *widget)
495 {
496 GdkScreen *screen;
497
498 (*GTK_WIDGET_CLASS (terminal_screen_parent_class)->realize) (widget);
499
500 /* make sure the TerminalWidget is realized as well */
501 if (!gtk_widget_get_realized (TERMINAL_SCREEN (widget)->terminal))
502 gtk_widget_realize (TERMINAL_SCREEN (widget)->terminal);
503
504 /* connect to the "composited-changed" signal */
505 screen = gtk_widget_get_screen (widget);
506 g_signal_connect_swapped (G_OBJECT (screen), "composited-changed", G_CALLBACK (terminal_screen_update_background), widget);
507 }
508
509
510
511 static void
terminal_screen_unrealize(GtkWidget * widget)512 terminal_screen_unrealize (GtkWidget *widget)
513 {
514 GdkScreen *screen;
515
516 /* disconnect the "composited-changed" handler */
517 screen = gtk_widget_get_screen (widget);
518 g_signal_handlers_disconnect_by_func (G_OBJECT (screen), terminal_screen_update_background, widget);
519
520 (*GTK_WIDGET_CLASS (terminal_screen_parent_class)->unrealize) (widget);
521 }
522
523
524
525 static void
terminal_screen_style_updated(GtkWidget * widget)526 terminal_screen_style_updated (GtkWidget *widget)
527 {
528 (*GTK_WIDGET_CLASS (terminal_screen_parent_class)->style_updated) (widget);
529
530 terminal_screen_update_colors (TERMINAL_SCREEN (widget));
531 }
532
533
534
535 static gboolean
terminal_screen_draw(GtkWidget * widget,cairo_t * cr,gpointer user_data)536 terminal_screen_draw (GtkWidget *widget,
537 cairo_t *cr,
538 gpointer user_data)
539 {
540 TerminalScreen *screen = TERMINAL_SCREEN (user_data);
541 TerminalBackground background_mode;
542 GdkPixbuf *image;
543 gint width, height;
544 cairo_surface_t *surface;
545 cairo_t *ctx;
546
547 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE);
548 terminal_return_val_if_fail (VTE_IS_TERMINAL (screen->terminal), FALSE);
549
550 g_object_get (G_OBJECT (screen->preferences), "background-mode", &background_mode, NULL);
551
552 if (G_LIKELY (background_mode != TERMINAL_BACKGROUND_IMAGE))
553 return FALSE;
554
555 width = gtk_widget_get_allocated_width (screen->terminal);
556 height = gtk_widget_get_allocated_height (screen->terminal);
557
558 if (screen->loader == NULL)
559 screen->loader = terminal_image_loader_get ();
560 image = terminal_image_loader_load (screen->loader, width, height);
561
562 if (G_UNLIKELY (image == NULL))
563 return FALSE;
564
565 g_signal_handlers_disconnect_by_func (G_OBJECT (screen->terminal),
566 G_CALLBACK (terminal_screen_draw), screen);
567
568 cairo_save (cr);
569
570 /* draw background image; cairo_set_operator() allows PNG transparency */
571 gdk_cairo_set_source_pixbuf (cr, image, 0, 0);
572 cairo_set_operator (cr, CAIRO_OPERATOR_SOURCE);
573 cairo_paint (cr);
574 g_object_unref (G_OBJECT (image));
575
576 /* draw vte terminal */
577 surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, width, height);
578 ctx = cairo_create (surface);
579 gtk_widget_draw (screen->terminal, ctx);
580 cairo_set_source_surface (cr, surface, 0, 0);
581 cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
582 cairo_paint (cr);
583 cairo_destroy (ctx);
584 cairo_surface_destroy (surface);
585
586 cairo_restore (cr);
587
588 g_signal_connect (G_OBJECT (screen->terminal), "draw",
589 G_CALLBACK (terminal_screen_draw), screen);
590
591 return TRUE;
592 }
593
594
595
596 static void
terminal_screen_preferences_changed(TerminalPreferences * preferences,GParamSpec * pspec,TerminalScreen * screen)597 terminal_screen_preferences_changed (TerminalPreferences *preferences,
598 GParamSpec *pspec,
599 TerminalScreen *screen)
600 {
601 const gchar *name;
602
603 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
604 terminal_return_if_fail (TERMINAL_IS_PREFERENCES (preferences));
605 terminal_return_if_fail (screen->preferences == preferences);
606
607 /* get name */
608 name = g_param_spec_get_name (pspec);
609 terminal_assert (name != NULL);
610
611 if (strncmp ("background-", name, strlen ("background-")) == 0)
612 terminal_screen_update_background (screen);
613 else if (strcmp ("binding-backspace", name) == 0)
614 terminal_screen_update_binding_backspace (screen);
615 else if (strcmp ("binding-delete", name) == 0)
616 terminal_screen_update_binding_delete (screen);
617 else if (strcmp ("binding-ambiguous-width", name) == 0)
618 terminal_screen_update_binding_ambiguous_width (screen);
619 #if VTE_CHECK_VERSION (0, 51, 3)
620 else if (strcmp ("cell-width-scale", name) == 0 || strcmp ("cell-height-scale", name) == 0)
621 terminal_screen_update_font (screen);
622 #endif
623 else if (strncmp ("color-", name, strlen ("color-")) == 0)
624 terminal_screen_update_colors (screen);
625 else if (strncmp ("font-", name, strlen ("font-")) == 0)
626 terminal_screen_update_font (screen);
627 else if (strncmp ("misc-bell", name, strlen ("misc-bell")) == 0)
628 terminal_screen_update_misc_bell (screen);
629 else if (strcmp ("misc-cursor-blinks", name) == 0)
630 terminal_screen_update_misc_cursor_blinks (screen);
631 else if (strcmp ("misc-cursor-shape", name) == 0)
632 terminal_screen_update_misc_cursor_shape (screen);
633 else if (strcmp ("misc-mouse-autohide", name) == 0)
634 terminal_screen_update_misc_mouse_autohide (screen);
635 else if (strcmp ("misc-rewrap-on-resize", name) == 0)
636 terminal_screen_update_misc_rewrap_on_resize (screen);
637 else if (strcmp ("scrolling-bar", name) == 0)
638 terminal_screen_update_scrolling_bar (screen);
639 else if (strcmp ("scrolling-lines", name) == 0 || strcmp ("scrolling-unlimited", name) == 0)
640 terminal_screen_update_scrolling_lines (screen);
641 else if (strcmp ("scrolling-on-output", name) == 0)
642 terminal_screen_update_scrolling_on_output (screen);
643 else if (strcmp ("scrolling-on-keystroke", name) == 0)
644 terminal_screen_update_scrolling_on_keystroke (screen);
645 else if (strcmp ("text-blink-mode", name) == 0)
646 terminal_screen_update_text_blink_mode (screen);
647 else if (strncmp ("title-", name, strlen ("title-")) == 0)
648 terminal_screen_update_title (screen);
649 else if (strcmp ("word-chars", name) == 0)
650 terminal_screen_update_word_chars (screen);
651 else if (strcmp ("misc-tab-position", name) == 0)
652 terminal_screen_update_label_orientation (screen);
653 }
654
655
656
657 static gboolean
terminal_screen_get_child_command(TerminalScreen * screen,gchar ** command,gchar *** argv,GError ** error)658 terminal_screen_get_child_command (TerminalScreen *screen,
659 gchar **command,
660 gchar ***argv,
661 GError **error)
662 {
663 struct passwd *pw;
664 const gchar *shell_name;
665 const gchar *shell_fullpath = NULL;
666 gchar *custom_command = NULL;
667 gboolean command_login_shell;
668 gboolean run_custom_command;
669 guint i;
670 const gchar *shells[] = { "/bin/sh",
671 "/bin/bash", "/usr/bin/bash",
672 "/bin/dash", "/usr/bin/dash",
673 "/bin/zsh", "/usr/bin/zsh",
674 "/bin/tcsh", "/usr/bin/tcsh",
675 "/bin/csh", "/usr/bin/csh",
676 "/bin/ksh", "/usr/bin/ksh" };
677
678 if (screen->custom_command != NULL)
679 {
680 *command = g_strdup (screen->custom_command[0]);
681 *argv = g_strdupv (screen->custom_command);
682 }
683 else
684 {
685 g_object_get (G_OBJECT (screen->preferences),
686 "command-login-shell", &command_login_shell,
687 "run-custom-command", &run_custom_command,
688 NULL);
689
690 if (run_custom_command)
691 {
692 /* use custom command specified in preferences */
693 g_object_get (G_OBJECT (screen->preferences),
694 "custom-command", &custom_command,
695 NULL);
696 shell_fullpath = custom_command;
697 }
698 else
699 {
700 /* use the SHELL environement variable if we're in
701 * non-setuid mode and the path is executable */
702 if (geteuid () == getuid ()
703 && getegid () == getgid ())
704 {
705 shell_fullpath = g_getenv ("SHELL");
706 if (shell_fullpath != NULL
707 && g_access (shell_fullpath, X_OK) != 0)
708 shell_fullpath = NULL;
709 }
710
711 if (shell_fullpath == NULL)
712 {
713 pw = getpwuid (getuid ());
714 if (pw != NULL
715 && pw->pw_shell != NULL
716 && g_access (pw->pw_shell, X_OK) == 0)
717 {
718 /* set the shell from the password database */
719 shell_fullpath = pw->pw_shell;
720 }
721 else
722 {
723 /* lookup a good fallback */
724 for (i = 0; i < G_N_ELEMENTS (shells); i++)
725 {
726 if (access (shells [i], X_OK) == 0)
727 {
728 shell_fullpath = shells [i];
729 break;
730 }
731 }
732
733 if (G_UNLIKELY (shell_fullpath == NULL))
734 {
735 /* the system is truly broken */
736 g_set_error (error, G_FILE_ERROR, G_FILE_ERROR_INVAL,
737 _("Unable to determine your login shell."));
738 return FALSE;
739 }
740 }
741 }
742 }
743
744 terminal_assert (shell_fullpath != NULL);
745 shell_name = strrchr (shell_fullpath, '/');
746 if (shell_name != NULL)
747 ++shell_name;
748 else
749 shell_name = shell_fullpath;
750 *command = g_strdup (shell_fullpath);
751
752 *argv = g_new (gchar *, 2);
753 if (command_login_shell)
754 (*argv)[0] = g_strconcat ("-", shell_name, NULL);
755 else
756 (*argv)[0] = g_strdup (shell_name);
757 (*argv)[1] = NULL;
758
759 if (custom_command != NULL)
760 g_free (custom_command);
761 }
762
763 return TRUE;
764 }
765
766
767
768 static gchar *
terminal_screen_parse_title(TerminalScreen * screen,const gchar * title)769 terminal_screen_parse_title (TerminalScreen *screen,
770 const gchar *title)
771 {
772 GString *string;
773 const gchar *remainder;
774 const gchar *percent;
775 const gchar *directory = NULL;
776 gchar *base_name;
777 const gchar *vte_title;
778
779 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
780
781 if (G_UNLIKELY (title == NULL))
782 return g_strdup ("");
783
784 string = g_string_new (NULL);
785 remainder = title;
786
787 /* walk from % character to % character */
788 for (;;)
789 {
790 /* look out for the next % character */
791 percent = strchr (remainder, '%');
792 if (percent == NULL)
793 {
794 /* we parsed the whole string */
795 g_string_append (string, remainder);
796 break;
797 }
798
799 /* append the characters in between */
800 g_string_append_len (string, remainder, percent - remainder);
801 remainder = percent + 1;
802
803 /* handle the "%" character */
804 switch (*remainder)
805 {
806 case '#':
807 g_string_append_printf (string, "%u", screen->session_id);
808 break;
809
810 case 'd':
811 case 'D':
812 if (directory == NULL)
813 directory = terminal_screen_get_working_directory (screen);
814
815 if (G_LIKELY (directory != NULL))
816 {
817 if (*remainder == 'D')
818 {
819 /* long directory name */
820 g_string_append (string, directory);
821 }
822 else
823 {
824 /* short directory name */
825 base_name = g_path_get_basename (directory);
826 g_string_append (string, base_name);
827 g_free (base_name);
828 }
829 }
830 break;
831
832 case 'w':
833 /* window title from vte */
834 vte_title = vte_terminal_get_window_title (VTE_TERMINAL (screen->terminal));
835 if (G_UNLIKELY (vte_title == NULL))
836 vte_title = _("Untitled");
837 g_string_append (string, vte_title);
838 break;
839
840 default:
841 g_string_append_c (string, '%');
842 continue;
843 }
844
845 remainder++;
846 }
847
848 return g_string_free (string, FALSE);
849 }
850
851
852
853 static gchar**
terminal_screen_get_child_environment(TerminalScreen * screen)854 terminal_screen_get_child_environment (TerminalScreen *screen)
855 {
856 GtkWidget *toplevel;
857 const gchar *display_name;
858 gchar **result;
859 gchar **p;
860 guint n;
861 gchar **env;
862 const gchar *value;
863
864 /* get all the environ variables */
865 env = g_listenv ();
866
867 n = g_strv_length (env);
868 result = g_new (gchar *, n + 4);
869
870 for (n = 0, p = env; *p != NULL; ++p)
871 {
872 /* do not copy the following variables */
873 if (strcmp (*p, "COLUMNS") == 0
874 || strcmp (*p, "LINES") == 0
875 || strcmp (*p, "WINDOWID") == 0
876 || strcmp (*p, "GNOME_DESKTOP_ICON") == 0
877 || strcmp (*p, "COLORTERM") == 0
878 || strcmp (*p, "DISPLAY") == 0
879 || strcmp (*p, "TERM") == 0)
880 continue;
881
882 #if !VTE_CHECK_VERSION (0, 51, 90)
883 /* copy working directory to $PWD, to preserve symlinks
884 * see https://bugzilla.gnome.org/show_bug.cgi?id=758452 */
885 if (strcmp (*p, "PWD") == 0)
886 {
887 result[n++] = g_strconcat (*p, "=", screen->working_directory, NULL);
888 continue;
889 }
890 #endif
891
892 /* copy the variable */
893 value = g_getenv (*p);
894 if (G_LIKELY (value != NULL))
895 result[n++] = g_strconcat (*p, "=", value, NULL);
896 }
897
898 g_strfreev (env);
899
900 result[n++] = g_strdup_printf ("COLORTERM=%s", PACKAGE_NAME);
901
902 #ifdef GDK_WINDOWING_X11
903 /* determine the toplevel widget */
904 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (screen));
905 if (toplevel != NULL && gtk_widget_get_realized (toplevel) && GDK_IS_X11_WINDOW (gtk_widget_get_window (toplevel)))
906 {
907 result[n++] = g_strdup_printf ("WINDOWID=%ld", (glong) gdk_x11_window_get_xid (gtk_widget_get_window (toplevel)));
908
909 /* determine the DISPLAY value for the command */
910 display_name = gdk_display_get_name (gdk_screen_get_display (gtk_widget_get_screen (toplevel)));
911 result[n++] = g_strdup_printf ("DISPLAY=%s", display_name);
912 }
913 #endif
914
915 result[n] = NULL;
916
917 return result;
918 }
919
920
921
922 static void
terminal_screen_update_background(TerminalScreen * screen)923 terminal_screen_update_background (TerminalScreen *screen)
924 {
925 TerminalBackground background_mode;
926 gdouble background_alpha;
927
928 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
929 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
930
931 g_object_get (G_OBJECT (screen->preferences), "background-mode", &background_mode, NULL);
932
933 if (G_UNLIKELY (background_mode == TERMINAL_BACKGROUND_TRANSPARENT))
934 g_object_get (G_OBJECT (screen->preferences), "background-darkness", &background_alpha, NULL);
935 else if (G_UNLIKELY (background_mode == TERMINAL_BACKGROUND_IMAGE))
936 g_object_get (G_OBJECT (screen->preferences), "background-image-shading", &background_alpha, NULL);
937 else
938 background_alpha = 1.0;
939
940 screen->background_color.alpha = background_alpha;
941 vte_terminal_set_color_background (VTE_TERMINAL (screen->terminal), &screen->background_color);
942
943 gtk_widget_queue_draw (GTK_WIDGET (screen));
944 }
945
946
947
948 static VteEraseBinding
terminal_screen_binding_vte(TerminalEraseBinding binding)949 terminal_screen_binding_vte (TerminalEraseBinding binding)
950 {
951 switch (binding)
952 {
953 case TERMINAL_ERASE_BINDING_AUTO:
954 return VTE_ERASE_AUTO;
955
956 case TERMINAL_ERASE_BINDING_ASCII_BACKSPACE:
957 return VTE_ERASE_ASCII_BACKSPACE;
958
959 case TERMINAL_ERASE_BINDING_ASCII_DELETE:
960 return VTE_ERASE_ASCII_DELETE;
961
962 case TERMINAL_ERASE_BINDING_DELETE_SEQUENCE:
963 return VTE_ERASE_DELETE_SEQUENCE;
964
965 case TERMINAL_ERASE_BINDING_ERASE_TTY:
966 return VTE_ERASE_TTY;
967
968 default:
969 terminal_assert_not_reached ();
970 }
971
972 return VTE_ERASE_AUTO;
973 }
974
975
976
977 static void
terminal_screen_update_binding_backspace(TerminalScreen * screen)978 terminal_screen_update_binding_backspace (TerminalScreen *screen)
979 {
980 TerminalEraseBinding binding;
981
982 g_object_get (G_OBJECT (screen->preferences), "binding-backspace", &binding, NULL);
983 vte_terminal_set_backspace_binding (VTE_TERMINAL (screen->terminal),
984 terminal_screen_binding_vte (binding));
985 }
986
987
988
989 static void
terminal_screen_update_binding_delete(TerminalScreen * screen)990 terminal_screen_update_binding_delete (TerminalScreen *screen)
991 {
992 TerminalEraseBinding binding;
993
994 g_object_get (G_OBJECT (screen->preferences), "binding-delete", &binding, NULL);
995 vte_terminal_set_delete_binding (VTE_TERMINAL (screen->terminal),
996 terminal_screen_binding_vte (binding));
997 }
998
999
1000
1001 static void
terminal_screen_update_binding_ambiguous_width(TerminalScreen * screen)1002 terminal_screen_update_binding_ambiguous_width (TerminalScreen *screen)
1003 {
1004 TerminalAmbiguousWidthBinding binding;
1005
1006 g_object_get (G_OBJECT (screen->preferences), "binding-ambiguous-width", &binding, NULL);
1007 vte_terminal_set_cjk_ambiguous_width (VTE_TERMINAL (screen->terminal),
1008 binding == TERMINAL_AMBIGUOUS_WIDTH_BINDING_NARROW ? 1 : 2);
1009 }
1010
1011
1012
1013 static void
terminal_screen_update_encoding(TerminalScreen * screen)1014 terminal_screen_update_encoding (TerminalScreen *screen)
1015 {
1016 gchar *encoding;
1017
1018 g_object_get (G_OBJECT (screen->preferences), "encoding", &encoding, NULL);
1019 terminal_screen_set_encoding (screen, encoding);
1020 g_free (encoding);
1021 }
1022
1023
1024
1025 static void
terminal_screen_update_colors(TerminalScreen * screen)1026 terminal_screen_update_colors (TerminalScreen *screen)
1027 {
1028 GdkRGBA palette[16];
1029 GdkRGBA bg;
1030 GdkRGBA fg;
1031 GdkRGBA cursor;
1032 GdkRGBA selection;
1033 GdkRGBA bold;
1034 gboolean cursor_use_default;
1035 gboolean selection_use_default;
1036 gboolean bold_use_default;
1037 guint n = 0;
1038 gboolean has_bg;
1039 gboolean has_fg;
1040 gboolean valid_palette = FALSE;
1041 gchar *palette_str;
1042 gchar **colors;
1043 gboolean vary_bg;
1044 gdouble hsv[N_HSV];
1045 gdouble sat_min, sat_max;
1046 gboolean bold_is_bright;
1047 gboolean use_theme;
1048
1049 GtkStyleContext *context = gtk_widget_get_style_context (gtk_widget_get_toplevel (GTK_WIDGET (screen)));
1050
1051 g_object_get (screen->preferences,
1052 "color-palette", &palette_str,
1053 "color-cursor-use-default", &cursor_use_default,
1054 "color-selection-use-default", &selection_use_default,
1055 "color-bold-use-default", &bold_use_default,
1056 "color-background-vary", &vary_bg,
1057 "color-bold-is-bright", &bold_is_bright,
1058 "color-use-theme", &use_theme,
1059 NULL);
1060
1061 if (G_LIKELY (palette_str != NULL))
1062 {
1063 colors = g_strsplit (palette_str, ";", -1);
1064 g_free (palette_str);
1065
1066 if (colors != NULL)
1067 for (; n < 16 && colors[n] != NULL; n++)
1068 if (!gdk_rgba_parse (palette + n, colors[n]))
1069 {
1070 g_warning ("Unable to parse color \"%s\".", colors[n]);
1071 break;
1072 }
1073
1074 g_strfreev (colors);
1075 valid_palette = (n == 16);
1076 }
1077
1078 if (G_LIKELY (screen->custom_fg_color == NULL))
1079 {
1080 has_fg = terminal_preferences_get_color (screen->preferences, "color-foreground", &fg);
1081 if (use_theme || !has_fg)
1082 {
1083 gtk_style_context_get_color (context, GTK_STATE_FLAG_ACTIVE, &fg);
1084 has_fg = TRUE;
1085 }
1086 }
1087 else
1088 has_fg = gdk_rgba_parse (&fg, screen->custom_fg_color);
1089
1090 if (G_LIKELY (screen->custom_bg_color == NULL))
1091 {
1092 has_bg = terminal_preferences_get_color (screen->preferences, "color-background", &bg);
1093 if (use_theme || !has_bg)
1094 {
1095 gtk_style_context_get_background_color (context, GTK_STATE_FLAG_ACTIVE, &bg);
1096 has_bg = TRUE;
1097 }
1098
1099 /* we pick a random hue value to keep readability */
1100 if (vary_bg && !screen->has_random_bg_color)
1101 {
1102 gtk_rgb_to_hsv (bg.red, bg.green, bg.blue,
1103 NULL, &hsv[HSV_SATURATION], &hsv[HSV_VALUE]);
1104
1105 /* pick random hue */
1106 hsv[HSV_HUE] = g_random_double_range (0.00, 1.00);
1107
1108 /* saturation moving window, depending on the value */
1109 if (hsv[HSV_SATURATION] <= SATURATION_WINDOW)
1110 {
1111 sat_min = 0.00;
1112 sat_max = (2 * SATURATION_WINDOW);
1113 }
1114 else if (hsv[HSV_SATURATION] >= (1.00 - SATURATION_WINDOW))
1115 {
1116 sat_min = 1.00 - (2 * SATURATION_WINDOW);
1117 sat_max = 1.00;
1118 }
1119 else
1120 {
1121 sat_min = hsv[HSV_SATURATION] - SATURATION_WINDOW;
1122 sat_max = hsv[HSV_SATURATION] + SATURATION_WINDOW;
1123 }
1124
1125 hsv[HSV_SATURATION] = g_random_double_range (sat_min, sat_max);
1126
1127 /* and back to a rgb color */
1128 gtk_hsv_to_rgb (hsv[HSV_HUE], hsv[HSV_SATURATION], hsv[HSV_VALUE],
1129 &bg.red, &bg.green, &bg.blue);
1130
1131 /* save the color */
1132 screen->background_color.red = bg.red;
1133 screen->background_color.green = bg.green;
1134 screen->background_color.blue = bg.blue;
1135
1136 /* it seems that random color may not be generated on the first run
1137 * so add a check here */
1138 if (bg.red != 0 && bg.green != 0 && bg.blue != 0)
1139 screen->has_random_bg_color = 1;
1140 }
1141 else if (vary_bg && screen->has_random_bg_color)
1142 {
1143 /* we already have a random bg color - do nothing */
1144 }
1145 else if (!vary_bg)
1146 {
1147 /* update the color if the vary setting is unchecked */
1148 screen->background_color.red = bg.red;
1149 screen->background_color.green = bg.green;
1150 screen->background_color.blue = bg.blue;
1151 screen->has_random_bg_color = 0;
1152 }
1153 }
1154 else if ((has_bg = gdk_rgba_parse (&bg, screen->custom_bg_color)))
1155 {
1156 /* preserve the alpha value which is responsible for transparency */
1157 screen->background_color.red = bg.red;
1158 screen->background_color.green = bg.green;
1159 screen->background_color.blue = bg.blue;
1160 }
1161
1162 if (G_LIKELY (valid_palette))
1163 {
1164 vte_terminal_set_colors (VTE_TERMINAL (screen->terminal),
1165 has_fg ? &fg : NULL,
1166 has_bg ? &screen->background_color : NULL,
1167 palette, 16);
1168 }
1169 else
1170 {
1171 vte_terminal_set_default_colors (VTE_TERMINAL (screen->terminal));
1172 g_warning ("One of the terminal colors was not parsed successfully. "
1173 "The default palette has been applied.");
1174 }
1175
1176 /* cursor color */
1177 if (!cursor_use_default)
1178 {
1179 cursor_use_default = !terminal_preferences_get_color (screen->preferences, "color-cursor-foreground", &cursor);
1180 vte_terminal_set_color_cursor_foreground (VTE_TERMINAL (screen->terminal), cursor_use_default ? NULL : &cursor);
1181 cursor_use_default = !terminal_preferences_get_color (screen->preferences, "color-cursor", &cursor);
1182 vte_terminal_set_color_cursor (VTE_TERMINAL (screen->terminal), cursor_use_default ? NULL : &cursor);
1183 }
1184
1185 /* selection color */
1186 if (!selection_use_default)
1187 {
1188 selection_use_default = !terminal_preferences_get_color (screen->preferences, "color-selection", &selection);
1189 vte_terminal_set_color_highlight_foreground (VTE_TERMINAL (screen->terminal), selection_use_default ? NULL : &selection);
1190 selection_use_default = !terminal_preferences_get_color (screen->preferences, "color-selection-background", &selection);
1191 vte_terminal_set_color_highlight (VTE_TERMINAL (screen->terminal), selection_use_default ? NULL : &selection);
1192 }
1193
1194 /* bold color */
1195 if (!bold_use_default)
1196 bold_use_default = !terminal_preferences_get_color (screen->preferences, "color-bold", &bold);
1197 #if VTE_CHECK_VERSION (0, 52, 0)
1198 /* the meaning of NULL for bold color changed in vte 0.52: see bug #15019 */
1199 vte_terminal_set_color_bold (VTE_TERMINAL (screen->terminal), bold_use_default ? NULL : &bold);
1200 #else
1201 /* avoid computed bold color for older vte versions */
1202 if (!bold_use_default || has_fg)
1203 vte_terminal_set_color_bold (VTE_TERMINAL (screen->terminal), bold_use_default ? &fg : &bold);
1204 #endif
1205
1206 #if VTE_CHECK_VERSION (0, 51, 3)
1207 /* "bold-is-bright" supported since vte 0.51.3 */
1208 vte_terminal_set_bold_is_bright (VTE_TERMINAL (screen->terminal), bold_is_bright);
1209 #endif
1210 }
1211
1212
1213
1214 static void
terminal_screen_update_misc_bell(TerminalScreen * screen)1215 terminal_screen_update_misc_bell (TerminalScreen *screen)
1216 {
1217 gboolean bval;
1218 g_object_get (G_OBJECT (screen->preferences), "misc-bell", &bval, NULL);
1219 vte_terminal_set_audible_bell (VTE_TERMINAL (screen->terminal), bval);
1220 g_signal_connect (screen->terminal, "bell", G_CALLBACK (terminal_screen_urgent_bell), screen);
1221 }
1222
1223
1224
1225 static void
terminal_screen_update_misc_cursor_blinks(TerminalScreen * screen)1226 terminal_screen_update_misc_cursor_blinks (TerminalScreen *screen)
1227 {
1228 gboolean bval;
1229 g_object_get (G_OBJECT (screen->preferences), "misc-cursor-blinks", &bval, NULL);
1230 vte_terminal_set_cursor_blink_mode (VTE_TERMINAL (screen->terminal),
1231 bval ? VTE_CURSOR_BLINK_ON : VTE_CURSOR_BLINK_OFF);
1232 }
1233
1234
1235
1236 static void
terminal_screen_update_misc_cursor_shape(TerminalScreen * screen)1237 terminal_screen_update_misc_cursor_shape (TerminalScreen *screen)
1238 {
1239 TerminalCursorShape val;
1240 VteCursorShape shape = VTE_CURSOR_SHAPE_BLOCK;
1241
1242 g_object_get (G_OBJECT (screen->preferences), "misc-cursor-shape", &val, NULL);
1243
1244 switch (val)
1245 {
1246 case TERMINAL_CURSOR_SHAPE_BLOCK:
1247 break;
1248
1249 case TERMINAL_CURSOR_SHAPE_IBEAM:
1250 shape = VTE_CURSOR_SHAPE_IBEAM;
1251 break;
1252
1253 case TERMINAL_CURSOR_SHAPE_UNDERLINE:
1254 shape = VTE_CURSOR_SHAPE_UNDERLINE;
1255 break;
1256
1257 default:
1258 terminal_assert_not_reached ();
1259 }
1260
1261 vte_terminal_set_cursor_shape (VTE_TERMINAL (screen->terminal), shape);
1262 }
1263
1264
1265 static void
terminal_screen_update_misc_mouse_autohide(TerminalScreen * screen)1266 terminal_screen_update_misc_mouse_autohide (TerminalScreen *screen)
1267 {
1268 gboolean bval;
1269 g_object_get (G_OBJECT (screen->preferences), "misc-mouse-autohide", &bval, NULL);
1270 vte_terminal_set_mouse_autohide (VTE_TERMINAL (screen->terminal), bval);
1271 }
1272
1273
1274
1275 static void
terminal_screen_update_misc_rewrap_on_resize(TerminalScreen * screen)1276 terminal_screen_update_misc_rewrap_on_resize (TerminalScreen *screen)
1277 {
1278 gboolean bval;
1279 g_object_get (G_OBJECT (screen->preferences), "misc-rewrap-on-resize", &bval, NULL);
1280 #if !VTE_CHECK_VERSION (0, 58, 0)
1281 vte_terminal_set_rewrap_on_resize (VTE_TERMINAL (screen->terminal), bval);
1282 #endif
1283 }
1284
1285
1286
1287 static void
terminal_screen_update_scrolling_lines(TerminalScreen * screen)1288 terminal_screen_update_scrolling_lines (TerminalScreen *screen)
1289 {
1290 guint lines;
1291 gboolean unlimited;
1292 g_object_get (G_OBJECT (screen->preferences),
1293 "scrolling-lines", &lines,
1294 "scrolling-unlimited", &unlimited,
1295 NULL);
1296 vte_terminal_set_scrollback_lines (VTE_TERMINAL (screen->terminal),
1297 unlimited ? -1 : (glong) lines);
1298 }
1299
1300
1301
1302 static void
terminal_screen_update_scrolling_on_output(TerminalScreen * screen)1303 terminal_screen_update_scrolling_on_output (TerminalScreen *screen)
1304 {
1305 gboolean scroll;
1306 g_object_get (G_OBJECT (screen->preferences), "scrolling-on-output", &scroll, NULL);
1307 terminal_screen_set_scroll_on_output (screen, scroll);
1308 }
1309
1310
1311
1312 static void
terminal_screen_update_scrolling_on_keystroke(TerminalScreen * screen)1313 terminal_screen_update_scrolling_on_keystroke (TerminalScreen *screen)
1314 {
1315 gboolean scroll;
1316 g_object_get (G_OBJECT (screen->preferences), "scrolling-on-keystroke", &scroll, NULL);
1317 vte_terminal_set_scroll_on_keystroke (VTE_TERMINAL (screen->terminal), scroll);
1318 }
1319
1320
1321
1322 static void
terminal_screen_update_text_blink_mode(TerminalScreen * screen)1323 terminal_screen_update_text_blink_mode (TerminalScreen *screen)
1324 {
1325 #if VTE_CHECK_VERSION (0, 51, 3)
1326 TerminalTextBlinkMode val;
1327 VteTextBlinkMode mode = VTE_TEXT_BLINK_ALWAYS;
1328
1329 g_object_get (G_OBJECT (screen->preferences), "text-blink-mode", &val, NULL);
1330
1331 switch (val)
1332 {
1333 case TERMINAL_TEXT_BLINK_MODE_ALWAYS:
1334 break;
1335
1336 case TERMINAL_TEXT_BLINK_MODE_NEVER:
1337 mode = VTE_TEXT_BLINK_NEVER;
1338 break;
1339
1340 case TERMINAL_TEXT_BLINK_MODE_FOCUSED:
1341 mode = VTE_TEXT_BLINK_FOCUSED;
1342 break;
1343
1344 case TERMINAL_TEXT_BLINK_MODE_UNFOCUSED:
1345 mode = VTE_TEXT_BLINK_UNFOCUSED;
1346 break;
1347
1348 default:
1349 terminal_assert_not_reached ();
1350 }
1351
1352 vte_terminal_set_text_blink_mode (VTE_TERMINAL (screen->terminal), mode);
1353 #endif
1354 }
1355
1356
1357
1358 static void
terminal_screen_update_title(TerminalScreen * screen)1359 terminal_screen_update_title (TerminalScreen *screen)
1360 {
1361 g_object_notify (G_OBJECT (screen), "title");
1362 }
1363
1364
1365
1366 static void
terminal_screen_update_word_chars(TerminalScreen * screen)1367 terminal_screen_update_word_chars (TerminalScreen *screen)
1368 {
1369 gchar *word_chars;
1370
1371 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1372 terminal_return_if_fail (TERMINAL_IS_PREFERENCES (screen->preferences));
1373 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
1374
1375 g_object_get (G_OBJECT (screen->preferences), "word-chars", &word_chars, NULL);
1376 if (G_LIKELY (word_chars != NULL))
1377 {
1378 vte_terminal_set_word_char_exceptions (VTE_TERMINAL (screen->terminal), word_chars);
1379 g_free (word_chars);
1380 }
1381 }
1382
1383
1384
1385 static void
relaunch_bar_response(GtkInfoBar * info_bar,gint response_id,TerminalScreen * screen)1386 relaunch_bar_response (GtkInfoBar *info_bar,
1387 gint response_id,
1388 TerminalScreen *screen)
1389 {
1390 /* relaunch the process or remember to not show it anymore */
1391 if (response_id == GTK_RESPONSE_YES)
1392 {
1393 terminal_screen_launch_child (screen);
1394 terminal_screen_focus (screen);
1395 }
1396 else
1397 {
1398 GtkWidget *content_area = gtk_info_bar_get_content_area (info_bar);
1399 GList *children = gtk_container_get_children (GTK_CONTAINER (content_area));
1400 GtkToggleButton *checkbox = g_list_nth_data (children, 1);
1401
1402 if (GTK_IS_TOGGLE_BUTTON (checkbox) && gtk_toggle_button_get_active (checkbox))
1403 g_object_set (G_OBJECT (screen->preferences), "misc-show-relaunch-dialog", FALSE, NULL);
1404 }
1405
1406 gtk_widget_destroy (GTK_WIDGET (info_bar));
1407 }
1408
1409
1410
1411 static void
terminal_screen_vte_child_exited(VteTerminal * terminal,gint status,TerminalScreen * screen)1412 terminal_screen_vte_child_exited (VteTerminal *terminal,
1413 gint status,
1414 TerminalScreen *screen)
1415 {
1416 gboolean show_relaunch_dialog;
1417
1418 terminal_return_if_fail (VTE_IS_TERMINAL (terminal));
1419 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1420
1421 g_object_get (G_OBJECT (screen->preferences), "misc-show-relaunch-dialog", &show_relaunch_dialog, NULL);
1422
1423 if (G_LIKELY (!screen->hold))
1424 gtk_widget_destroy (GTK_WIDGET (screen));
1425 else if (show_relaunch_dialog)
1426 {
1427 /* create "Relaunch" bar */
1428 GtkWidget *relaunch_bar, *content_area, *label, *checkbox;
1429 gchar *message;
1430
1431 relaunch_bar = gtk_info_bar_new_with_buttons (_("_Relaunch"), GTK_RESPONSE_YES, NULL);
1432 gtk_info_bar_set_message_type (GTK_INFO_BAR (relaunch_bar), GTK_MESSAGE_INFO);
1433 gtk_info_bar_set_show_close_button (GTK_INFO_BAR (relaunch_bar), TRUE);
1434 content_area = gtk_info_bar_get_content_area (GTK_INFO_BAR (relaunch_bar));
1435
1436 if (WIFEXITED (status))
1437 message = g_strdup_printf (_("The child process exited normally with status %d."), WEXITSTATUS (status));
1438 else if (WIFSIGNALED (status))
1439 message = g_strdup_printf (_("The child process was aborted by signal %d."), WTERMSIG (status));
1440 else
1441 message = g_strdup (_("The child process was aborted."));
1442
1443 label = gtk_label_new (message);
1444 g_free (message);
1445 gtk_container_add (GTK_CONTAINER (content_area), label);
1446
1447 checkbox = gtk_check_button_new_with_mnemonic (_("Do _not ask me again"));
1448 gtk_container_add (GTK_CONTAINER (content_area), checkbox);
1449
1450 g_signal_connect (G_OBJECT (relaunch_bar), "response", G_CALLBACK (relaunch_bar_response), screen);
1451
1452 gtk_widget_set_halign (relaunch_bar, GTK_ALIGN_FILL);
1453 gtk_widget_set_valign (relaunch_bar, GTK_ALIGN_START);
1454 gtk_overlay_add_overlay (GTK_OVERLAY (screen), relaunch_bar);
1455 gtk_widget_show_all (relaunch_bar);
1456 }
1457 }
1458
1459
1460
1461 static void
terminal_screen_vte_eof(VteTerminal * terminal,TerminalScreen * screen)1462 terminal_screen_vte_eof (VteTerminal *terminal,
1463 TerminalScreen *screen)
1464 {
1465 terminal_return_if_fail (VTE_IS_TERMINAL (terminal));
1466 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1467
1468 if (G_LIKELY (!screen->hold))
1469 gtk_widget_destroy (GTK_WIDGET (screen));
1470 }
1471
1472
1473
1474 static GtkWidget*
terminal_screen_vte_get_context_menu(TerminalWidget * widget,TerminalScreen * screen)1475 terminal_screen_vte_get_context_menu (TerminalWidget *widget,
1476 TerminalScreen *screen)
1477 {
1478 GtkWidget *menu = NULL;
1479 g_signal_emit (G_OBJECT (screen), screen_signals[GET_CONTEXT_MENU], 0, &menu);
1480 return menu;
1481 }
1482
1483
1484
1485 static void
terminal_screen_vte_selection_changed(VteTerminal * terminal,TerminalScreen * screen)1486 terminal_screen_vte_selection_changed (VteTerminal *terminal,
1487 TerminalScreen *screen)
1488 {
1489 gboolean copy_on_select;
1490
1491 terminal_return_if_fail (VTE_IS_TERMINAL (terminal));
1492 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1493
1494 /* copy vte selection to GDK_SELECTION_CLIPBOARD if option is set */
1495 g_object_get (G_OBJECT (screen->preferences),
1496 "misc-copy-on-select", ©_on_select, NULL);
1497 if (copy_on_select && vte_terminal_get_has_selection (terminal))
1498 terminal_screen_copy_clipboard (screen);
1499
1500 g_signal_emit (G_OBJECT (screen), screen_signals[SELECTION_CHANGED], 0);
1501 }
1502
1503
1504
1505 static void
terminal_screen_vte_window_title_changed(VteTerminal * terminal,TerminalScreen * screen)1506 terminal_screen_vte_window_title_changed (VteTerminal *terminal,
1507 TerminalScreen *screen)
1508 {
1509 terminal_return_if_fail (VTE_IS_TERMINAL (terminal));
1510 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1511
1512 terminal_screen_update_title (screen);
1513 }
1514
1515
1516
1517 static void
terminal_screen_vte_resize_window(VteTerminal * terminal,guint width,guint height,TerminalScreen * screen)1518 terminal_screen_vte_resize_window (VteTerminal *terminal,
1519 guint width,
1520 guint height,
1521 TerminalScreen *screen)
1522 {
1523 GtkWidget *toplevel;
1524
1525 terminal_return_if_fail (VTE_IS_TERMINAL (terminal));
1526 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1527
1528 /* don't do anything if the window is already fullscreen/maximized */
1529 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (screen));
1530 if (!gtk_widget_get_realized (toplevel)
1531 || (gdk_window_get_state (gtk_widget_get_window (toplevel))
1532 & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) != 0)
1533 return;
1534
1535 /* set the terminal size and resize the window if it is active */
1536 vte_terminal_set_size (terminal, width, height);
1537 if (screen == terminal_window_get_active (TERMINAL_WINDOW (toplevel)))
1538 terminal_screen_force_resize_window (screen, GTK_WINDOW (toplevel), width, height);
1539 }
1540
1541
1542
1543 static gboolean
terminal_screen_reset_activity_timeout(gpointer user_data)1544 terminal_screen_reset_activity_timeout (gpointer user_data)
1545 {
1546 TerminalScreen *screen = TERMINAL_SCREEN (user_data);
1547 GdkRGBA active_color;
1548 GdkRGBA fg_color;
1549 GdkRGBA label_color;
1550
1551 if (G_UNLIKELY (screen->tab_label == NULL))
1552 return FALSE;
1553
1554 /* unset */
1555 if (G_LIKELY (screen->custom_title_color == NULL))
1556 gtk_label_set_attributes (GTK_LABEL (screen->tab_label), NULL);
1557 else if (gdk_rgba_parse (&label_color, screen->custom_title_color))
1558 terminal_screen_set_tab_label_color (screen, &label_color);
1559
1560 if (terminal_preferences_get_color (screen->preferences, "tab-activity-color", &active_color))
1561 {
1562 /* calculate color between fg and active color */
1563 gtk_style_context_get_color (gtk_widget_get_style_context (screen->tab_label),
1564 gtk_widget_get_state_flags (screen->tab_label),
1565 &fg_color);
1566 active_color.red = (active_color.red + fg_color.red) / 2;
1567 active_color.green = (active_color.green + fg_color.green) / 2;
1568 active_color.blue = (active_color.blue + fg_color.blue) / 2;
1569
1570 terminal_screen_set_tab_label_color (screen, &active_color);
1571 }
1572
1573 return FALSE;
1574 }
1575
1576
1577
1578 static void
terminal_screen_reset_activity_destroyed(gpointer user_data)1579 terminal_screen_reset_activity_destroyed (gpointer user_data)
1580 {
1581 TERMINAL_SCREEN (user_data)->activity_timeout_id = 0;
1582 }
1583
1584
1585
1586 static void
terminal_screen_vte_window_contents_changed(TerminalScreen * screen)1587 terminal_screen_vte_window_contents_changed (TerminalScreen *screen)
1588 {
1589 guint timeout;
1590 GdkRGBA color;
1591 GdkRGBA label_color;
1592 gboolean has_color;
1593
1594 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1595 terminal_return_if_fail (GTK_IS_LABEL (screen->tab_label));
1596 terminal_return_if_fail (TERMINAL_IS_PREFERENCES (screen->preferences));
1597
1598 /* leave if we should not start an update */
1599 if (screen->tab_label == NULL
1600 || (gtk_widget_get_state_flags (screen->terminal) & GTK_STATE_FLAG_FOCUSED) != 0
1601 || time (NULL) - screen->activity_resize_time <= 1)
1602 return;
1603
1604 /* get the reset time, leave if this feature is disabled */
1605 g_object_get (G_OBJECT (screen->preferences), "tab-activity-timeout", &timeout, NULL);
1606 if (timeout < 1)
1607 return;
1608
1609 /* set label color */
1610 has_color = terminal_preferences_get_color (screen->preferences, "tab-activity-color", &color);
1611 if (G_LIKELY (has_color))
1612 terminal_screen_set_tab_label_color (screen, &color);
1613 else if (G_LIKELY (screen->custom_title_color == NULL))
1614 gtk_label_set_attributes (GTK_LABEL (screen->tab_label), NULL);
1615 else if (gdk_rgba_parse (&label_color, screen->custom_title_color))
1616 terminal_screen_set_tab_label_color (screen, &label_color);
1617
1618 /* stop running reset timeout */
1619 if (screen->activity_timeout_id != 0)
1620 g_source_remove (screen->activity_timeout_id);
1621
1622 /* start new timeout to unset the activity */
1623 screen->activity_timeout_id =
1624 gdk_threads_add_timeout_seconds_full (G_PRIORITY_DEFAULT, timeout,
1625 terminal_screen_reset_activity_timeout,
1626 screen, terminal_screen_reset_activity_destroyed);
1627 }
1628
1629
1630
1631 static void
terminal_screen_vte_window_contents_resized(TerminalScreen * screen)1632 terminal_screen_vte_window_contents_resized (TerminalScreen *screen)
1633 {
1634 /* avoid a content changed when the window is resized */
1635 screen->activity_resize_time = time (NULL);
1636 }
1637
1638
1639
1640 static void
terminal_screen_update_label_orientation(TerminalScreen * screen)1641 terminal_screen_update_label_orientation (TerminalScreen *screen)
1642 {
1643 GtkPositionType position;
1644 gdouble angle;
1645 PangoEllipsizeMode ellipsize;
1646 GtkWidget *box;
1647
1648 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1649 terminal_return_if_fail (screen->tab_label == NULL || GTK_IS_LABEL (screen->tab_label));
1650
1651 if (G_UNLIKELY (screen->tab_label == NULL))
1652 return;
1653
1654 g_object_get (G_OBJECT (screen->preferences), "misc-tab-position", &position, NULL);
1655
1656 if (G_LIKELY (position == GTK_POS_TOP || position == GTK_POS_BOTTOM))
1657 {
1658 angle = 0.0;
1659 ellipsize = PANGO_ELLIPSIZE_END;
1660 gtk_widget_set_halign (screen->tab_label, GTK_ALIGN_START);
1661 gtk_widget_set_valign (screen->tab_label, GTK_ALIGN_CENTER);
1662
1663 /* reset size request, ellipsize works now */
1664 gtk_widget_set_size_request (screen->tab_label, -1, -1);
1665 }
1666 else
1667 {
1668 angle = position == GTK_POS_LEFT ? 90.0 : 270.0;
1669 ellipsize = PANGO_ELLIPSIZE_NONE;
1670 gtk_widget_set_halign (screen->tab_label, GTK_ALIGN_CENTER);
1671 gtk_widget_set_valign (screen->tab_label, GTK_ALIGN_START);
1672
1673 /* set a minimum height of 30px, because ellipsize does not work */
1674 gtk_widget_set_size_request (screen->tab_label, -1, 30);
1675 }
1676
1677 gtk_label_set_angle (GTK_LABEL (screen->tab_label), angle);
1678 gtk_label_set_ellipsize (GTK_LABEL (screen->tab_label), ellipsize);
1679
1680 box = gtk_widget_get_parent (screen->tab_label);
1681 terminal_return_if_fail (GTK_IS_ORIENTABLE (box));
1682 gtk_orientable_set_orientation (GTK_ORIENTABLE (box),
1683 angle == 0.0 ? GTK_ORIENTATION_HORIZONTAL : GTK_ORIENTATION_VERTICAL);
1684 }
1685
1686
1687
1688 static void
terminal_screen_urgent_bell(TerminalWidget * widget,TerminalScreen * screen)1689 terminal_screen_urgent_bell (TerminalWidget *widget,
1690 TerminalScreen *screen)
1691 {
1692 gboolean enabled;
1693
1694 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1695
1696 g_object_get (G_OBJECT (screen->preferences), "misc-bell-urgent", &enabled, NULL);
1697
1698 if (enabled)
1699 gtk_window_set_urgency_hint (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen))), TRUE);
1700 }
1701
1702
1703
1704 static void
terminal_screen_set_custom_command(TerminalScreen * screen,gchar ** command)1705 terminal_screen_set_custom_command (TerminalScreen *screen,
1706 gchar **command)
1707 {
1708 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1709
1710 if (G_UNLIKELY (screen->custom_command != NULL))
1711 g_strfreev (screen->custom_command);
1712
1713 if (G_LIKELY (command != NULL && *command != NULL))
1714 screen->custom_command = g_strdupv (command);
1715 else
1716 screen->custom_command = NULL;
1717 }
1718
1719
1720
1721 static void
terminal_screen_set_tab_label_color(TerminalScreen * screen,const GdkRGBA * color)1722 terminal_screen_set_tab_label_color (TerminalScreen *screen,
1723 const GdkRGBA *color)
1724 {
1725 PangoAttrList *attrs = pango_attr_list_new ();
1726 PangoAttribute *foreground = pango_attr_foreground_new ((guint16)(color->red*65535),
1727 (guint16)(color->green*65535),
1728 (guint16)(color->blue*65535));
1729 pango_attr_list_insert (attrs, foreground);
1730 gtk_label_set_attributes (GTK_LABEL (screen->tab_label), attrs);
1731 pango_attr_list_unref (attrs);
1732 }
1733
1734
1735
1736 static gboolean
terminal_screen_is_text_unsafe(const gchar * text)1737 terminal_screen_is_text_unsafe (const gchar *text)
1738 {
1739 return text != NULL && strchr (text, '\n') != NULL;
1740 }
1741
1742
1743
1744 static GtkWidget*
terminal_screen_unsafe_paste_dialog_new(TerminalScreen * screen,const gchar * text)1745 terminal_screen_unsafe_paste_dialog_new (TerminalScreen *screen,
1746 const gchar *text)
1747 {
1748 GtkWindow *parent = GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen)));
1749 GtkTextBuffer *buffer = gtk_text_buffer_new (gtk_text_tag_table_new ());
1750 GtkWidget *tv = gtk_text_view_new_with_buffer (buffer);
1751 GtkWidget *sw = gtk_scrolled_window_new (NULL, NULL);
1752 GtkWidget *dialog = xfce_titled_dialog_new ();
1753 GtkWidget *button;
1754
1755 gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
1756 gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
1757 gtk_window_set_title (GTK_WINDOW (dialog), _("Warning: Unsafe Paste"));
1758 xfce_titled_dialog_set_subtitle (XFCE_TITLED_DIALOG (dialog),
1759 _("Pasting this text to the terminal may be dangerous as it looks like\n"
1760 "some commands may be executed, potentially involving root access ('sudo')."));
1761
1762 button = xfce_gtk_button_new_mixed ("gtk-cancel", _("_Cancel"));
1763 gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_CANCEL);
1764 button = xfce_gtk_button_new_mixed ("gtk-ok", _("_Paste"));
1765 gtk_dialog_add_action_widget (GTK_DIALOG (dialog), button, GTK_RESPONSE_YES);
1766
1767 gtk_text_view_set_cursor_visible (GTK_TEXT_VIEW (tv), TRUE);
1768 gtk_text_view_set_monospace (GTK_TEXT_VIEW (tv), TRUE);
1769 gtk_text_view_set_top_margin (GTK_TEXT_VIEW (tv), 6);
1770 gtk_text_view_set_bottom_margin (GTK_TEXT_VIEW (tv), 6);
1771 gtk_text_view_set_right_margin (GTK_TEXT_VIEW (tv), 6);
1772 gtk_text_view_set_left_margin (GTK_TEXT_VIEW (tv), 6);
1773
1774 gtk_scrolled_window_set_min_content_width (GTK_SCROLLED_WINDOW (sw), 400);
1775 gtk_scrolled_window_set_min_content_height (GTK_SCROLLED_WINDOW (sw), 150);
1776
1777 gtk_container_add (GTK_CONTAINER (sw), tv);
1778 gtk_container_add (GTK_CONTAINER (gtk_dialog_get_content_area (GTK_DIALOG (dialog))), sw);
1779
1780 gtk_text_buffer_set_text (buffer, text, -1);
1781
1782 return dialog;
1783 }
1784
1785
1786
1787 static void
terminal_screen_paste_unsafe_text(TerminalScreen * screen,const gchar * text,GdkAtom original_clipboard)1788 terminal_screen_paste_unsafe_text (TerminalScreen *screen,
1789 const gchar *text,
1790 GdkAtom original_clipboard)
1791 {
1792 GtkWidget *dialog;
1793
1794 terminal_return_if_fail (original_clipboard != GDK_SELECTION_CLIPBOARD && original_clipboard != GDK_SELECTION_PRIMARY);
1795
1796 dialog = terminal_screen_unsafe_paste_dialog_new (screen, text);
1797 gtk_widget_show_all (dialog);
1798 /* set focus to the Paste button */
1799 gtk_widget_grab_focus (gtk_dialog_get_widget_for_response (GTK_DIALOG (dialog), GTK_RESPONSE_YES));
1800
1801 if (gtk_dialog_run (GTK_DIALOG (dialog)) == GTK_RESPONSE_YES)
1802 {
1803 GtkWidget *content_area = gtk_dialog_get_content_area (GTK_DIALOG (dialog));
1804 GtkWidget *sw = g_list_first (gtk_container_get_children (GTK_CONTAINER (content_area)))->data;
1805 GtkTextView *tv = GTK_TEXT_VIEW (gtk_bin_get_child (GTK_BIN (sw)));
1806 GtkTextBuffer *buffer = gtk_text_view_get_buffer (tv);
1807 GtkTextIter start, end;
1808 char *res_text;
1809
1810 gtk_text_buffer_get_bounds (buffer, &start, &end);
1811 res_text = gtk_text_buffer_get_text (buffer, &start, &end, FALSE);
1812
1813 if (res_text != NULL)
1814 {
1815 /* Modify the content of the clipboard as required, and then paste it.
1816 * Using the builtin pasting function enables bracketed paste mode when applicable.
1817 */
1818 GtkClipboard *clipboard = gtk_clipboard_get (original_clipboard);
1819 gtk_clipboard_set_text (clipboard, res_text, strlen (res_text));
1820 g_free (res_text);
1821
1822 if (original_clipboard == GDK_SELECTION_CLIPBOARD) {
1823 vte_terminal_paste_clipboard (VTE_TERMINAL (screen->terminal));
1824 } else {
1825 vte_terminal_paste_primary (VTE_TERMINAL (screen->terminal));
1826 }
1827
1828 /* restore original clipboard contents */
1829 gtk_clipboard_set_text (clipboard, text, strlen (text));
1830 }
1831 }
1832
1833 gtk_widget_destroy (dialog);
1834 }
1835
1836
1837
1838 #if VTE_CHECK_VERSION (0, 48, 0)
1839 static void
terminal_screen_spawn_async_cb(VteTerminal * terminal,GPid pid,GError * error,gpointer user_data)1840 terminal_screen_spawn_async_cb (VteTerminal *terminal,
1841 GPid pid,
1842 GError *error,
1843 gpointer user_data)
1844 {
1845 TerminalScreen *screen = TERMINAL_SCREEN (user_data);
1846
1847 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1848 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
1849
1850 screen->pid = pid;
1851
1852 if (error)
1853 {
1854 xfce_dialog_show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen))),
1855 error, _("Failed to execute child"));
1856 }
1857 #ifdef HAVE_LIBUTEMPTER
1858 else
1859 {
1860 gboolean update_records;
1861 g_object_get (G_OBJECT (screen->preferences), "command-update-records", &update_records, NULL);
1862 if (update_records)
1863 utempter_add_record (vte_pty_get_fd (vte_terminal_get_pty (VTE_TERMINAL (screen->terminal))), NULL);
1864 }
1865 #endif // HAVE_LIBUTEMPTER
1866 }
1867 #endif
1868
1869
1870
1871 /**
1872 * terminal_screen_new:
1873 * @attr : Terminal attributes.
1874 * @columns : Columns (width).
1875 * @rows : Rows (height).
1876 *
1877 * Creates a terminal screen object.
1878 **/
1879 TerminalScreen *
terminal_screen_new(TerminalTabAttr * attr,glong columns,glong rows)1880 terminal_screen_new (TerminalTabAttr *attr,
1881 glong columns,
1882 glong rows)
1883 {
1884 TerminalScreen *screen = g_object_new (TERMINAL_TYPE_SCREEN, NULL);
1885
1886 if (attr->command != NULL)
1887 terminal_screen_set_custom_command (screen, attr->command);
1888 if (attr->directory != NULL)
1889 terminal_screen_set_working_directory (screen, attr->directory);
1890 if (attr->title != NULL)
1891 terminal_screen_set_custom_title (screen, attr->title);
1892 if (attr->initial_title != NULL)
1893 screen->initial_title = g_strdup (attr->initial_title);
1894 screen->dynamic_title_mode = attr->dynamic_title_mode;
1895 screen->hold = attr->hold;
1896 vte_terminal_set_size (VTE_TERMINAL (screen->terminal), columns, rows);
1897
1898 if (attr->color_text != NULL)
1899 screen->custom_fg_color = g_strdup (attr->color_text);
1900 if (attr->color_bg != NULL)
1901 screen->custom_bg_color = g_strdup (attr->color_bg);
1902 if (attr->color_text != NULL || attr->color_bg != NULL)
1903 terminal_screen_update_colors (screen);
1904
1905 return screen;
1906 }
1907
1908
1909
1910 /**
1911 * terminal_screen_launch_child:
1912 * @screen : A #TerminalScreen.
1913 *
1914 * Starts the terminal child process.
1915 **/
1916 void
terminal_screen_launch_child(TerminalScreen * screen)1917 terminal_screen_launch_child (TerminalScreen *screen)
1918 {
1919 GError *error = NULL;
1920 gchar *command;
1921 gchar **argv;
1922 gchar **env;
1923 gchar **argv2;
1924 guint i, argc;
1925 VtePtyFlags pty_flags = VTE_PTY_DEFAULT;
1926 GSpawnFlags spawn_flags = G_SPAWN_SEARCH_PATH;
1927
1928 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
1929
1930 #ifdef G_ENABLE_DEBUG
1931 if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
1932 g_error ("Tried to launch command in a TerminalScreen that is not realized");
1933 #endif
1934
1935 if (!terminal_screen_get_child_command (screen, &command, &argv, &error))
1936 {
1937 /* tell the user that we were unable to execute the command */
1938 xfce_dialog_show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen))),
1939 error, _("Failed to execute child"));
1940 g_error_free (error);
1941 }
1942 else
1943 {
1944 env = terminal_screen_get_child_environment (screen);
1945
1946 argc = argv != NULL ? g_strv_length (argv) : 0;
1947 argv2 = g_new0 (gchar *, argc + 2);
1948 argv2[0] = command;
1949
1950 if (argv != NULL)
1951 {
1952 for (i = 0; argv[i] != NULL; i++)
1953 argv2[i + 1] = argv[i];
1954
1955 spawn_flags |= G_SPAWN_FILE_AND_ARGV_ZERO;
1956 }
1957
1958 #if VTE_CHECK_VERSION (0, 48, 0)
1959 vte_terminal_spawn_async (VTE_TERMINAL (screen->terminal),
1960 pty_flags,
1961 screen->working_directory, argv2, env,
1962 spawn_flags,
1963 NULL, NULL,
1964 NULL, SPAWN_TIMEOUT,
1965 NULL,
1966 terminal_screen_spawn_async_cb,
1967 screen);
1968 #else
1969 if (!vte_terminal_spawn_sync (VTE_TERMINAL (screen->terminal),
1970 pty_flags,
1971 screen->working_directory, argv2, env,
1972 spawn_flags,
1973 NULL, NULL,
1974 &screen->pid, NULL, &error))
1975 {
1976 xfce_dialog_show_error (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (screen))),
1977 error, _("Failed to execute child"));
1978 g_error_free (error);
1979 }
1980 #ifdef HAVE_LIBUTEMPTER
1981 else
1982 {
1983 gboolean update_records;
1984 g_object_get (G_OBJECT (screen->preferences), "command-update-records", &update_records, NULL);
1985 if (update_records)
1986 utempter_add_record (vte_pty_get_fd (vte_terminal_get_pty (VTE_TERMINAL (screen->terminal))), NULL);
1987 }
1988 #endif // HAVE_LIBUTEMPTER
1989 #endif
1990
1991 g_free (argv2);
1992
1993 g_strfreev (argv);
1994 g_strfreev (env);
1995 g_free (command);
1996 }
1997 }
1998
1999
2000
2001 /**
2002 * terminal_screen_get_custom_title:
2003 * @screen : A #TerminalScreen.
2004 **/
2005 const gchar *
terminal_screen_get_custom_title(TerminalScreen * screen)2006 terminal_screen_get_custom_title (TerminalScreen *screen)
2007 {
2008 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2009
2010 return screen->custom_title;
2011 }
2012
2013
2014
2015 /**
2016 * terminal_screen_set_custom_title:
2017 * @screen : A #TerminalScreen.
2018 * @title : Title string.
2019 **/
2020 void
terminal_screen_set_custom_title(TerminalScreen * screen,const gchar * title)2021 terminal_screen_set_custom_title (TerminalScreen *screen,
2022 const gchar *title)
2023 {
2024 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2025
2026 if (g_strcmp0 (screen->custom_title, title) != 0)
2027 {
2028 g_free (screen->custom_title);
2029 if (IS_STRING (title))
2030 screen->custom_title = g_strdup (title);
2031 else
2032 screen->custom_title = NULL;
2033 g_object_notify (G_OBJECT (screen), "custom-title");
2034 terminal_screen_update_title (screen);
2035 }
2036 }
2037
2038
2039
2040 /**
2041 **/
2042 void
terminal_screen_get_size(TerminalScreen * screen,glong * width_chars,glong * height_chars)2043 terminal_screen_get_size (TerminalScreen *screen,
2044 glong *width_chars,
2045 glong *height_chars)
2046 {
2047 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2048
2049 if (width_chars)
2050 *width_chars = vte_terminal_get_column_count (VTE_TERMINAL (screen->terminal));
2051
2052 if (height_chars)
2053 *height_chars = vte_terminal_get_row_count (VTE_TERMINAL (screen->terminal));
2054 }
2055
2056
2057
2058 /**
2059 **/
2060 void
terminal_screen_set_size(TerminalScreen * screen,glong width_chars,glong height_chars)2061 terminal_screen_set_size (TerminalScreen *screen,
2062 glong width_chars,
2063 glong height_chars)
2064 {
2065 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2066
2067 vte_terminal_set_size (VTE_TERMINAL (screen->terminal),
2068 width_chars, height_chars);
2069 }
2070
2071
2072
2073 void
terminal_screen_get_geometry(TerminalScreen * screen,glong * char_width,glong * char_height,gint * xpad,gint * ypad)2074 terminal_screen_get_geometry (TerminalScreen *screen,
2075 glong *char_width,
2076 glong *char_height,
2077 gint *xpad,
2078 gint *ypad)
2079 {
2080 GtkBorder border;
2081
2082 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2083 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
2084
2085 if (char_width != NULL)
2086 *char_width = vte_terminal_get_char_width (VTE_TERMINAL (screen->terminal));
2087 if (char_height != NULL)
2088 *char_height = vte_terminal_get_char_height (VTE_TERMINAL (screen->terminal));
2089
2090 if (xpad != NULL || ypad != NULL)
2091 {
2092 gtk_style_context_get_padding (gtk_widget_get_style_context (screen->terminal),
2093 gtk_widget_get_state_flags (screen->terminal),
2094 &border);
2095 if (xpad != NULL)
2096 *xpad = border.left + border.right;
2097 if (ypad != NULL)
2098 *ypad = border.top + border.bottom;
2099 }
2100 }
2101
2102
2103
2104 /**
2105 * terminal_screen_set_window_geometry_hints:
2106 *
2107 * I don't like this way, but its required to work-around a Gtk+
2108 * bug (maybe also caused by a Vte bug, not sure).
2109 *
2110 * Code for GTK > 3.19.5 borrowed from gnome-terminal
2111 * (terminal_window_update_geometry).
2112 **/
2113 void
terminal_screen_set_window_geometry_hints(TerminalScreen * screen,GtkWindow * window)2114 terminal_screen_set_window_geometry_hints (TerminalScreen *screen,
2115 GtkWindow *window)
2116 {
2117 GdkGeometry hints;
2118 glong char_width, char_height;
2119 GtkRequisition vbox_request;
2120 GtkAllocation toplevel_allocation, vbox_allocation;
2121 glong grid_width, grid_height;
2122 glong chrome_width, chrome_height;
2123 gint csd_width, csd_height;
2124
2125 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2126 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
2127 terminal_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (screen)));
2128 terminal_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (window)));
2129
2130 terminal_screen_get_geometry (screen, &char_width, &char_height, NULL, NULL);
2131 terminal_screen_get_size (screen, &grid_width, &grid_height);
2132
2133 gtk_widget_get_preferred_size (terminal_window_get_vbox (TERMINAL_WINDOW (window)), NULL, &vbox_request);
2134 chrome_width = vbox_request.width - (char_width * grid_width);
2135 chrome_height = vbox_request.height - (char_height * grid_height);
2136
2137 gtk_widget_get_allocation (terminal_window_get_vbox (TERMINAL_WINDOW (window)), &vbox_allocation);
2138 gtk_widget_get_allocation (GTK_WIDGET (window), &toplevel_allocation);
2139 csd_width = toplevel_allocation.width - vbox_allocation.width;
2140 csd_height = toplevel_allocation.height - vbox_allocation.height;
2141
2142 hints.base_width = chrome_width + csd_width;
2143 hints.base_height = chrome_height + csd_height;
2144
2145 hints.width_inc = char_width;
2146 hints.height_inc = char_height;
2147 hints.min_width = hints.base_width + hints.width_inc * MIN_COLUMNS;
2148 hints.min_height = hints.base_height + hints.height_inc * MIN_ROWS;
2149
2150 gtk_window_set_geometry_hints (window,
2151 NULL,
2152 &hints,
2153 GDK_HINT_RESIZE_INC
2154 | GDK_HINT_MIN_SIZE
2155 | GDK_HINT_BASE_SIZE);
2156 }
2157
2158
2159
2160 /**
2161 * terminal_screen_force_resize_window:
2162 *
2163 * I don't like this way, but its required to work-around a Gtk+
2164 * bug (maybe also caused by a Vte bug, not sure).
2165 **/
2166 void
terminal_screen_force_resize_window(TerminalScreen * screen,GtkWindow * window,glong columns,glong rows)2167 terminal_screen_force_resize_window (TerminalScreen *screen,
2168 GtkWindow *window,
2169 glong columns,
2170 glong rows)
2171 {
2172 GtkRequisition terminal_requisition;
2173 GtkRequisition vbox_requisition;
2174 gint width;
2175 gint height;
2176 gint xpad, ypad;
2177 glong char_width;
2178 glong char_height;
2179
2180 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2181 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
2182 terminal_return_if_fail (GTK_IS_WINDOW (window));
2183
2184 terminal_screen_set_window_geometry_hints (screen, window);
2185
2186 gtk_widget_get_preferred_size (terminal_window_get_vbox (TERMINAL_WINDOW (window)), NULL, &vbox_requisition);
2187 gtk_widget_get_preferred_size (screen->terminal, NULL, &terminal_requisition);
2188
2189 if (columns < 1)
2190 columns = vte_terminal_get_column_count (VTE_TERMINAL (screen->terminal));
2191 if (rows < 1)
2192 rows = vte_terminal_get_row_count (VTE_TERMINAL (screen->terminal));
2193
2194 terminal_screen_get_geometry (screen,
2195 &char_width, &char_height,
2196 &xpad, &ypad);
2197
2198 width = vbox_requisition.width - terminal_requisition.width;
2199 if (width < 0)
2200 width = 0;
2201 width += xpad + char_width * columns;
2202
2203 height = vbox_requisition.height - terminal_requisition.height;
2204 if (height < 0)
2205 height = 0;
2206 height += ypad + char_height * rows;
2207
2208 if (gtk_widget_get_mapped (GTK_WIDGET (window)))
2209 gtk_window_resize (window, width, height);
2210 else
2211 gtk_window_set_default_size (window, width, height);
2212 }
2213
2214
2215
2216 /**
2217 * terminal_screen_get_title:
2218 * @screen : A #TerminalScreen.
2219 *
2220 * Return value : The title to set for this terminal screen.
2221 * The returned string should be freed when
2222 * no longer needed.
2223 **/
2224 gchar*
terminal_screen_get_title(TerminalScreen * screen)2225 terminal_screen_get_title (TerminalScreen *screen)
2226 {
2227 TerminalTitle mode;
2228 const gchar *vte_title;
2229 gchar *initial, *tmp;
2230 gchar *title;
2231
2232 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2233
2234 if (G_UNLIKELY (screen->custom_title != NULL))
2235 return terminal_screen_parse_title (screen, screen->custom_title);
2236
2237 vte_title = vte_terminal_get_window_title (VTE_TERMINAL (screen->terminal));
2238
2239 if (G_UNLIKELY (screen->initial_title != NULL))
2240 initial = terminal_screen_parse_title (screen, screen->initial_title);
2241 else
2242 {
2243 g_object_get (G_OBJECT (screen->preferences), "title-initial", &tmp, NULL);
2244 initial = terminal_screen_parse_title (screen, tmp);
2245 g_free (tmp);
2246 }
2247
2248 if (G_UNLIKELY (screen->dynamic_title_mode != TERMINAL_TITLE_DEFAULT))
2249 mode = screen->dynamic_title_mode;
2250 else
2251 g_object_get (G_OBJECT (screen->preferences), "title-mode", &mode, NULL);
2252
2253 switch (mode)
2254 {
2255 case TERMINAL_TITLE_REPLACE:
2256 if (G_LIKELY (vte_title != NULL))
2257 title = g_strdup (vte_title);
2258 else if (initial != NULL)
2259 return initial;
2260 else
2261 title = g_strdup (_("Untitled"));
2262 break;
2263
2264 case TERMINAL_TITLE_PREPEND:
2265 if (G_LIKELY (vte_title != NULL))
2266 title = g_strconcat (vte_title, " - ", initial, NULL);
2267 else
2268 return initial;
2269 break;
2270
2271 case TERMINAL_TITLE_APPEND:
2272 if (G_LIKELY (vte_title != NULL))
2273 title = g_strconcat (initial, " - ", vte_title, NULL);
2274 else
2275 return initial;
2276 break;
2277
2278 case TERMINAL_TITLE_HIDE:
2279 return initial;
2280 break;
2281
2282 default:
2283 terminal_assert_not_reached ();
2284 title = NULL;
2285 }
2286
2287 g_free (initial);
2288
2289 return title;
2290 }
2291
2292
2293
2294 /**
2295 * terminal_screen_get_working_directory:
2296 * @screen : A #TerminalScreen.
2297 *
2298 * Determinies the working directory using various OS-specific mechanisms.
2299 *
2300 * Return value : The current working directory of @screen.
2301 **/
2302 const gchar*
terminal_screen_get_working_directory(TerminalScreen * screen)2303 terminal_screen_get_working_directory (TerminalScreen *screen)
2304 {
2305 gchar buffer[4096 + 1];
2306 gchar *file;
2307 gchar *cwd;
2308 const gchar *uri;
2309 gint length;
2310
2311 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2312
2313 /* try to use vte functionality first: see bug #13902 */
2314 uri = vte_terminal_get_current_directory_uri (VTE_TERMINAL (screen->terminal));
2315 if (uri != NULL)
2316 {
2317 g_free (screen->working_directory);
2318 screen->working_directory = g_filename_from_uri (uri, NULL, NULL);
2319 }
2320 else if (screen->pid >= 0)
2321 {
2322 /* make sure that we use linprocfs on all systems */
2323 #if defined(__FreeBSD__)
2324 file = g_strdup_printf ("/compat/linux/proc/%d/cwd", screen->pid);
2325 #elif defined(__NetBSD__) || defined(__OpenBSD__)
2326 file = g_strdup_printf ("/emul/linux/proc/%d/cwd", screen->pid);
2327 #else
2328 file = g_strdup_printf ("/proc/%d/cwd", screen->pid);
2329 #endif
2330
2331 length = readlink (file, buffer, sizeof (buffer) - 1);
2332 if (length > 0 && *buffer == '/')
2333 {
2334 buffer[length] = '\0';
2335 g_free (screen->working_directory);
2336 screen->working_directory = g_strdup (buffer);
2337 }
2338 else if (length == 0)
2339 {
2340 cwd = g_get_current_dir ();
2341 if (G_LIKELY (cwd != NULL))
2342 {
2343 if (chdir (file) == 0)
2344 {
2345 g_free (screen->working_directory);
2346 screen->working_directory = g_get_current_dir ();
2347 if (chdir (cwd) == 0) {};
2348 }
2349
2350 g_free (cwd);
2351 }
2352 }
2353
2354 g_free (file);
2355 }
2356
2357 return screen->working_directory;
2358 }
2359
2360
2361
2362 /**
2363 * terminal_screen_set_working_directory:
2364 * @screen : A #TerminalScreen.
2365 * @directory :
2366 **/
2367 void
terminal_screen_set_working_directory(TerminalScreen * screen,const gchar * directory)2368 terminal_screen_set_working_directory (TerminalScreen *screen,
2369 const gchar *directory)
2370 {
2371 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2372 terminal_return_if_fail (directory != NULL);
2373
2374 g_free (screen->working_directory);
2375 screen->working_directory = g_strdup (directory);
2376 }
2377
2378
2379
2380 /**
2381 * terminal_screen_has_selection:
2382 * @screen : A #TerminalScreen.
2383 *
2384 * Checks if the terminal currently contains selected text. Note that this is different from
2385 * determining if the terminal is the owner of any GtkClipboard items.
2386 *
2387 * Return value : %TRUE if part of the text in the terminal is selected.
2388 **/
2389 gboolean
terminal_screen_has_selection(TerminalScreen * screen)2390 terminal_screen_has_selection (TerminalScreen *screen)
2391 {
2392 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE);
2393 return vte_terminal_get_has_selection (VTE_TERMINAL (screen->terminal));
2394 }
2395
2396
2397
2398 /**
2399 * terminal_screen_copy_clipboard:
2400 * @screen : A #TerminalScreen.
2401 *
2402 * Places the selected text in the terminal in the #GDK_SELECTION_CLIPBOARD selection.
2403 **/
2404 void
terminal_screen_copy_clipboard(TerminalScreen * screen)2405 terminal_screen_copy_clipboard (TerminalScreen *screen)
2406 {
2407 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2408 #if VTE_CHECK_VERSION (0, 49, 2)
2409 vte_terminal_copy_clipboard_format (VTE_TERMINAL (screen->terminal), VTE_FORMAT_TEXT);
2410 #else
2411 vte_terminal_copy_clipboard (VTE_TERMINAL (screen->terminal));
2412 #endif
2413 }
2414
2415
2416
2417 /**
2418 * terminal_screen_copy_clipboard_html:
2419 * @screen : A #TerminalScreen.
2420 *
2421 * Places the selected text in the terminal in the #GDK_SELECTION_CLIPBOARD selection
2422 * as HTML (preserving colors, bold font, etc).
2423 **/
2424 #if VTE_CHECK_VERSION (0, 49, 2)
2425 void
terminal_screen_copy_clipboard_html(TerminalScreen * screen)2426 terminal_screen_copy_clipboard_html (TerminalScreen *screen)
2427 {
2428 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2429 vte_terminal_copy_clipboard_format (VTE_TERMINAL (screen->terminal), VTE_FORMAT_HTML);
2430 }
2431 #endif
2432
2433
2434
2435 /**
2436 * terminal_screen_paste_clipboard:
2437 * @screen : A #TerminalScreen.
2438 *
2439 * Sends the contents of the #GDK_SELECTION_CLIPBOARD selection to the terminal's
2440 * child. If neccessary, the data is converted from UTF-8 to the terminal's current
2441 * encoding.
2442 **/
2443 void
terminal_screen_paste_clipboard(TerminalScreen * screen)2444 terminal_screen_paste_clipboard (TerminalScreen *screen)
2445 {
2446 gboolean show_dialog;
2447 gchar *text = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_CLIPBOARD));
2448
2449 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2450
2451 g_object_get (G_OBJECT (screen->preferences), "misc-show-unsafe-paste-dialog", &show_dialog, NULL);
2452
2453 if (show_dialog && terminal_screen_is_text_unsafe (text))
2454 terminal_screen_paste_unsafe_text (screen, text, GDK_SELECTION_CLIPBOARD);
2455 else
2456 vte_terminal_paste_clipboard (VTE_TERMINAL (screen->terminal));
2457
2458 g_free (text);
2459 }
2460
2461
2462
2463 /**
2464 * terminal_screen_paste_primary:
2465 * @screen : A #TerminalScreen.
2466 *
2467 * Sends the contents of the #GDK_SELECTION_PRIMARY selection to the terminal's child.
2468 * If necessary, the data is converted from UTF-8 to the terminal's current encoding.
2469 * The terminal will call also paste the #GDK_SELECTION_PRIMARY selection when the user
2470 * clicks with the the second mouse button.
2471 **/
2472 void
terminal_screen_paste_primary(TerminalScreen * screen)2473 terminal_screen_paste_primary (TerminalScreen *screen)
2474 {
2475 gboolean show_dialog;
2476 gchar *text = gtk_clipboard_wait_for_text (gtk_clipboard_get (GDK_SELECTION_PRIMARY));
2477
2478 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2479
2480 g_object_get (G_OBJECT (screen->preferences), "misc-show-unsafe-paste-dialog", &show_dialog, NULL);
2481
2482 if (show_dialog && terminal_screen_is_text_unsafe (text))
2483 terminal_screen_paste_unsafe_text (screen, text, GDK_SELECTION_PRIMARY);
2484 else
2485 vte_terminal_paste_primary (VTE_TERMINAL (screen->terminal));
2486
2487 g_free (text);
2488 }
2489
2490
2491
2492 /**
2493 * terminal_screen_select_all:
2494 * @screen : A #TerminalScreen.
2495 *
2496 * Selects all text in the terminal.
2497 **/
2498 void
terminal_screen_select_all(TerminalScreen * screen)2499 terminal_screen_select_all (TerminalScreen *screen)
2500 {
2501 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2502 vte_terminal_select_all (VTE_TERMINAL (screen->terminal));
2503 }
2504
2505
2506
2507 /**
2508 * terminal_screen_reset:
2509 * @screen : A #TerminalScreen.
2510 * @clear : %TRUE to also clear the terminal screen.
2511 *
2512 * Resets the terminal.
2513 **/
2514 void
terminal_screen_reset(TerminalScreen * screen,gboolean clear)2515 terminal_screen_reset (TerminalScreen *screen,
2516 gboolean clear)
2517 {
2518 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2519 vte_terminal_reset (VTE_TERMINAL (screen->terminal), TRUE, clear);
2520
2521 if (clear)
2522 vte_terminal_search_set_regex (VTE_TERMINAL (screen->terminal), NULL, 0);
2523 }
2524
2525
2526
2527 /**
2528 * terminal_screen_get_restart_command:
2529 * @screen : A #TerminalScreen.
2530 *
2531 * Return value: Command to restore @screen, arguments are in reversed order.
2532 **/
2533 GSList*
terminal_screen_get_restart_command(TerminalScreen * screen)2534 terminal_screen_get_restart_command (TerminalScreen *screen)
2535 {
2536 const gchar *directory;
2537 GSList *result = NULL;
2538
2539 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2540
2541 if (screen->custom_command != NULL)
2542 {
2543 result = g_slist_prepend (result, g_strdup ("-e"));
2544 result = g_slist_prepend (result, g_strjoinv (" ", screen->custom_command));
2545 }
2546
2547 if (screen->custom_title != NULL)
2548 {
2549 result = g_slist_prepend (result, g_strdup ("--title"));
2550 result = g_slist_prepend (result, g_strdup (screen->custom_title));
2551 }
2552
2553 directory = terminal_screen_get_working_directory (screen);
2554 if (G_LIKELY (directory != NULL))
2555 {
2556 result = g_slist_prepend (result, g_strdup ("--working-directory"));
2557 result = g_slist_prepend (result, g_strdup (directory));
2558 }
2559
2560 if (G_UNLIKELY (screen->hold))
2561 result = g_slist_prepend (result, g_strdup ("--hold"));
2562
2563 return result;
2564 }
2565
2566
2567
2568 void
terminal_screen_reset_activity(TerminalScreen * screen)2569 terminal_screen_reset_activity (TerminalScreen *screen)
2570 {
2571 GdkRGBA label_color;
2572
2573 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2574
2575 if (screen->activity_timeout_id != 0)
2576 g_source_remove (screen->activity_timeout_id);
2577
2578 if (screen->tab_label != NULL)
2579 {
2580 if (G_LIKELY (screen->custom_title_color == NULL))
2581 gtk_label_set_attributes (GTK_LABEL (screen->tab_label), NULL);
2582 else if (gdk_rgba_parse (&label_color, screen->custom_title_color))
2583 terminal_screen_set_tab_label_color (screen, &label_color);
2584 }
2585 }
2586
2587
2588
2589 static void
terminal_screen_close_tab_cb(TerminalScreen * screen)2590 terminal_screen_close_tab_cb (TerminalScreen *screen)
2591 {
2592 g_signal_emit (G_OBJECT (screen), screen_signals[CLOSE_TAB], 0);
2593 }
2594
2595
2596
2597 GtkWidget *
terminal_screen_get_tab_label(TerminalScreen * screen)2598 terminal_screen_get_tab_label (TerminalScreen *screen)
2599 {
2600 GtkWidget *hbox, *button, *image;
2601
2602 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2603
2604 /* create the box */
2605 hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0);
2606 gtk_container_set_border_width (GTK_CONTAINER (hbox), 2);
2607
2608 screen->tab_label = gtk_label_new (NULL);
2609 gtk_widget_set_margin_start (screen->tab_label, 2);
2610 gtk_box_pack_start (GTK_BOX (hbox), screen->tab_label, TRUE, TRUE, 0);
2611 g_object_bind_property (G_OBJECT (screen), "title",
2612 G_OBJECT (screen->tab_label), "label",
2613 G_BINDING_SYNC_CREATE);
2614 g_object_bind_property (G_OBJECT (screen->tab_label), "label",
2615 G_OBJECT (screen->tab_label), "tooltip-text",
2616 G_BINDING_SYNC_CREATE);
2617 gtk_widget_set_has_tooltip (screen->tab_label, TRUE);
2618
2619 button = gtk_button_new ();
2620 gtk_widget_set_focus_on_click (button, FALSE);
2621 gtk_button_set_relief (GTK_BUTTON (button), GTK_RELIEF_NONE);
2622 gtk_widget_set_can_focus (button, FALSE);
2623 gtk_widget_set_can_default (button, FALSE);
2624 gtk_widget_set_tooltip_text (button, _("Close this tab"));
2625 gtk_widget_set_halign (button, GTK_ALIGN_CENTER);
2626 gtk_widget_set_valign (button, GTK_ALIGN_CENTER);
2627 gtk_container_add (GTK_CONTAINER (hbox), button);
2628 g_signal_connect_swapped (G_OBJECT (button), "clicked",
2629 G_CALLBACK (terminal_screen_close_tab_cb), screen);
2630
2631 /* button image */
2632 image = gtk_image_new_from_icon_name ("window-close-symbolic", GTK_ICON_SIZE_MENU);
2633 gtk_container_add (GTK_CONTAINER (button), image);
2634
2635 /* show the box and all its widgets */
2636 gtk_widget_show_all (hbox);
2637
2638 /* update orientation */
2639 terminal_screen_update_label_orientation (screen);
2640
2641 /* respect the show/hide buttons option */
2642 g_object_bind_property (G_OBJECT (screen->preferences), "misc-tab-close-buttons",
2643 G_OBJECT (button), "visible",
2644 G_BINDING_SYNC_CREATE);
2645
2646 return hbox;
2647 }
2648
2649
2650
2651 void
terminal_screen_focus(TerminalScreen * screen)2652 terminal_screen_focus (TerminalScreen *screen)
2653 {
2654 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2655 gtk_widget_grab_focus (GTK_WIDGET (screen->terminal));
2656 }
2657
2658
2659
2660 const gchar *
terminal_screen_get_encoding(TerminalScreen * screen)2661 terminal_screen_get_encoding (TerminalScreen *screen)
2662 {
2663 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
2664 return vte_terminal_get_encoding (VTE_TERMINAL (screen->terminal));
2665 }
2666
2667
2668
2669 void
terminal_screen_set_encoding(TerminalScreen * screen,const gchar * charset)2670 terminal_screen_set_encoding (TerminalScreen *screen,
2671 const gchar *charset)
2672 {
2673 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2674 if (charset == NULL)
2675 g_get_charset (&charset);
2676 if (!vte_terminal_set_encoding (VTE_TERMINAL (screen->terminal), charset, NULL))
2677 g_printerr (_("Failed to set encoding %s\n"), charset);
2678 }
2679
2680
2681
2682 void
terminal_screen_search_set_gregex(TerminalScreen * screen,VteRegex * regex,gboolean wrap_around)2683 terminal_screen_search_set_gregex (TerminalScreen *screen,
2684 VteRegex *regex,
2685 gboolean wrap_around)
2686 {
2687 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2688 vte_terminal_search_set_regex (VTE_TERMINAL (screen->terminal), regex, 0);
2689 vte_terminal_search_set_wrap_around (VTE_TERMINAL (screen->terminal), wrap_around);
2690 }
2691
2692
2693
2694 gboolean
terminal_screen_search_has_gregex(TerminalScreen * screen)2695 terminal_screen_search_has_gregex (TerminalScreen *screen)
2696 {
2697 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE);
2698 return vte_terminal_search_get_regex (VTE_TERMINAL (screen->terminal)) != NULL;
2699 }
2700
2701
2702
2703 void
terminal_screen_search_find_next(TerminalScreen * screen)2704 terminal_screen_search_find_next (TerminalScreen *screen)
2705 {
2706 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2707 vte_terminal_search_find_next (VTE_TERMINAL (screen->terminal));
2708 }
2709
2710
2711
2712 void
terminal_screen_search_find_previous(TerminalScreen * screen)2713 terminal_screen_search_find_previous (TerminalScreen *screen)
2714 {
2715 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2716 vte_terminal_search_find_previous (VTE_TERMINAL (screen->terminal));
2717 }
2718
2719
2720
2721 void
terminal_screen_update_scrolling_bar(TerminalScreen * screen)2722 terminal_screen_update_scrolling_bar (TerminalScreen *screen)
2723 {
2724 TerminalScrollbar scrollbar;
2725 TerminalVisibility visibility = TERMINAL_VISIBILITY_DEFAULT;
2726 glong grid_w = 0, grid_h = 0;
2727 GtkWidget *toplevel;
2728
2729 g_object_get (G_OBJECT (screen->preferences), "scrolling-bar", &scrollbar, NULL);
2730
2731 if (gtk_widget_get_realized (GTK_WIDGET (screen)))
2732 terminal_screen_get_size (screen, &grid_w, &grid_h);
2733
2734 toplevel = gtk_widget_get_toplevel (GTK_WIDGET (screen));
2735 if (TERMINAL_IS_WINDOW (toplevel))
2736 visibility = terminal_window_get_scrollbar_visibility (TERMINAL_WINDOW (toplevel));
2737
2738 if (G_LIKELY (visibility == TERMINAL_VISIBILITY_DEFAULT))
2739 {
2740 switch (scrollbar)
2741 {
2742 case TERMINAL_SCROLLBAR_NONE:
2743 gtk_widget_hide (screen->scrollbar);
2744 break;
2745
2746 case TERMINAL_SCROLLBAR_LEFT:
2747 gtk_box_reorder_child (GTK_BOX (screen->hbox), screen->scrollbar, 0);
2748 gtk_widget_show (screen->scrollbar);
2749 break;
2750
2751 default: /* TERMINAL_SCROLLBAR_RIGHT */
2752 gtk_box_reorder_child (GTK_BOX (screen->hbox), screen->scrollbar, 1);
2753 gtk_widget_show (screen->scrollbar);
2754 break;
2755 }
2756 }
2757 else if (visibility == TERMINAL_VISIBILITY_HIDE)
2758 {
2759 gtk_widget_hide (screen->scrollbar);
2760 }
2761 else /* show */
2762 {
2763 gtk_box_reorder_child (GTK_BOX (screen), screen->scrollbar,
2764 scrollbar == TERMINAL_SCROLLBAR_LEFT ? 0 : 1);
2765 gtk_widget_show (screen->scrollbar);
2766 }
2767
2768 /* update window geometry it required */
2769 if (grid_w > 0 && grid_h > 0)
2770 terminal_screen_force_resize_window (screen, GTK_WINDOW (toplevel), grid_w, grid_h);
2771 }
2772
2773
2774
2775 void
terminal_screen_update_font(TerminalScreen * screen)2776 terminal_screen_update_font (TerminalScreen *screen)
2777 {
2778 GtkWidget *toplevel = gtk_widget_get_toplevel (GTK_WIDGET (screen));
2779 gboolean font_use_system, font_allow_bold;
2780 gchar *font_name = NULL;
2781 PangoFontDescription *font_desc;
2782 glong grid_w = 0, grid_h = 0;
2783 GSettings *settings;
2784 XfconfChannel *channel;
2785 gdouble font_scale = PANGO_SCALE_MEDIUM;
2786 #if VTE_CHECK_VERSION (0, 51, 3)
2787 gdouble cell_width_scale, cell_height_scale;
2788 #endif
2789
2790 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2791 terminal_return_if_fail (TERMINAL_IS_PREFERENCES (screen->preferences));
2792 terminal_return_if_fail (VTE_IS_TERMINAL (screen->terminal));
2793
2794 g_object_get (G_OBJECT (screen->preferences),
2795 "font-use-system", &font_use_system,
2796 "font-allow-bold", &font_allow_bold,
2797 NULL);
2798
2799 if (font_use_system)
2800 {
2801 /* read Xfce settings */
2802 xfconf_init (NULL);
2803 channel = xfconf_channel_get ("xsettings");
2804 if (xfconf_channel_has_property (channel, "/Gtk/MonospaceFontName"))
2805 font_name = xfconf_channel_get_string (channel, "/Gtk/MonospaceFontName", "");
2806 xfconf_shutdown ();
2807
2808 /* if font isn't set, read GNOME settings */
2809 if (!IS_STRING (font_name))
2810 {
2811 g_free (font_name);
2812 settings = g_settings_new ("org.gnome.desktop.interface");
2813 font_name = g_settings_get_string (settings, "monospace-font-name");
2814 g_object_unref (settings);
2815 }
2816 }
2817 else
2818 g_object_get (G_OBJECT (screen->preferences), "font-name", &font_name, NULL);
2819
2820 if (TERMINAL_IS_WINDOW (toplevel))
2821 {
2822 if (terminal_window_get_font (TERMINAL_WINDOW (toplevel)))
2823 {
2824 g_free (font_name);
2825 font_name = g_strdup (terminal_window_get_font (TERMINAL_WINDOW (toplevel)));
2826 }
2827
2828 switch (terminal_window_get_zoom_level (TERMINAL_WINDOW (toplevel)))
2829 {
2830 case TERMINAL_ZOOM_LEVEL_MINIMUM: font_scale = PANGO_SCALE_XX_SMALL/1.2/1.2/1.2/1.2; break;
2831 case TERMINAL_ZOOM_LEVEL_XXXXX_SMALL: font_scale = PANGO_SCALE_XX_SMALL/1.2/1.2/1.2; break;
2832 case TERMINAL_ZOOM_LEVEL_XXXX_SMALL: font_scale = PANGO_SCALE_XX_SMALL/1.2/1.2; break;
2833 case TERMINAL_ZOOM_LEVEL_XXX_SMALL: font_scale = PANGO_SCALE_XX_SMALL/1.2; break;
2834 case TERMINAL_ZOOM_LEVEL_XX_SMALL: font_scale = PANGO_SCALE_XX_SMALL; break;
2835 case TERMINAL_ZOOM_LEVEL_X_SMALL: font_scale = PANGO_SCALE_X_SMALL; break;
2836 case TERMINAL_ZOOM_LEVEL_SMALL: font_scale = PANGO_SCALE_SMALL; break;
2837 case TERMINAL_ZOOM_LEVEL_LARGE: font_scale = PANGO_SCALE_LARGE; break;
2838 case TERMINAL_ZOOM_LEVEL_X_LARGE: font_scale = PANGO_SCALE_X_LARGE; break;
2839 case TERMINAL_ZOOM_LEVEL_XX_LARGE: font_scale = PANGO_SCALE_XX_LARGE; break;
2840 case TERMINAL_ZOOM_LEVEL_XXX_LARGE: font_scale = PANGO_SCALE_XX_LARGE*1.2; break;
2841 case TERMINAL_ZOOM_LEVEL_XXXX_LARGE: font_scale = PANGO_SCALE_XX_LARGE*1.2*1.2; break;
2842 case TERMINAL_ZOOM_LEVEL_XXXXX_LARGE: font_scale = PANGO_SCALE_XX_LARGE*1.2*1.2*1.2; break;
2843 case TERMINAL_ZOOM_LEVEL_MAXIMUM: font_scale = PANGO_SCALE_XX_LARGE*1.2*1.2*1.2*1.2; break;
2844 default: font_scale = PANGO_SCALE_MEDIUM; break;
2845 }
2846 }
2847
2848 if (gtk_widget_get_realized (GTK_WIDGET (screen)))
2849 terminal_screen_get_size (screen, &grid_w, &grid_h);
2850
2851 if (G_LIKELY (font_name != NULL))
2852 {
2853 font_desc = pango_font_description_from_string (font_name);
2854 vte_terminal_set_allow_bold (VTE_TERMINAL (screen->terminal), font_allow_bold);
2855 vte_terminal_set_font (VTE_TERMINAL (screen->terminal), font_desc);
2856 vte_terminal_set_font_scale (VTE_TERMINAL (screen->terminal), font_scale);
2857 pango_font_description_free (font_desc);
2858 g_free (font_name);
2859 }
2860
2861 #if VTE_CHECK_VERSION (0, 51, 3)
2862 g_object_get (G_OBJECT (screen->preferences),
2863 "cell-width-scale", &cell_width_scale,
2864 "cell-height-scale", &cell_height_scale,
2865 NULL);
2866
2867 vte_terminal_set_cell_width_scale (VTE_TERMINAL (screen->terminal), cell_width_scale);
2868 vte_terminal_set_cell_height_scale (VTE_TERMINAL (screen->terminal), cell_height_scale);
2869 #endif
2870
2871 /* update window geometry it required (not needed for drop-down) */
2872 if (TERMINAL_IS_WINDOW (toplevel) && !terminal_window_is_drop_down (TERMINAL_WINDOW (toplevel)) && grid_w > 0 && grid_h > 0)
2873 terminal_screen_force_resize_window (screen, GTK_WINDOW (toplevel), grid_w, grid_h);
2874 }
2875
2876
2877
2878 gboolean
terminal_screen_get_input_enabled(TerminalScreen * screen)2879 terminal_screen_get_input_enabled (TerminalScreen *screen)
2880 {
2881 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE);
2882 return vte_terminal_get_input_enabled (VTE_TERMINAL (screen->terminal));
2883 }
2884
2885
2886
2887 void
terminal_screen_set_input_enabled(TerminalScreen * screen,gboolean enabled)2888 terminal_screen_set_input_enabled (TerminalScreen *screen,
2889 gboolean enabled)
2890 {
2891 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2892 vte_terminal_set_input_enabled (VTE_TERMINAL (screen->terminal), enabled);
2893 }
2894
2895
2896
2897 gboolean
terminal_screen_get_scroll_on_output(TerminalScreen * screen)2898 terminal_screen_get_scroll_on_output (TerminalScreen *screen)
2899 {
2900 terminal_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE);
2901 #if !VTE_CHECK_VERSION (0, 51, 1)
2902 return screen->scroll_on_output;
2903 #else
2904 return vte_terminal_get_scroll_on_output (VTE_TERMINAL (screen->terminal));
2905 #endif
2906 }
2907
2908
2909
2910 void
terminal_screen_set_scroll_on_output(TerminalScreen * screen,gboolean enabled)2911 terminal_screen_set_scroll_on_output (TerminalScreen *screen,
2912 gboolean enabled)
2913 {
2914 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2915 #if !VTE_CHECK_VERSION (0, 51, 1)
2916 screen->scroll_on_output = enabled;
2917 #endif
2918 vte_terminal_set_scroll_on_output (VTE_TERMINAL (screen->terminal), enabled);
2919 }
2920
2921
2922
2923 void
terminal_screen_save_contents(TerminalScreen * screen,GOutputStream * stream,GError * error)2924 terminal_screen_save_contents (TerminalScreen *screen,
2925 GOutputStream *stream,
2926 GError *error)
2927 {
2928 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2929 vte_terminal_write_contents_sync (VTE_TERMINAL (screen->terminal),
2930 stream, VTE_WRITE_DEFAULT, NULL, &error);
2931 }
2932
2933
2934
2935 /**
2936 * terminal_screen_has_foreground_process:
2937 * @screen : A #TerminalScreen.
2938 *
2939 * Return value: %TRUE if there's a foreground process running in @screen.
2940 **/
2941 gboolean
terminal_screen_has_foreground_process(TerminalScreen * screen)2942 terminal_screen_has_foreground_process (TerminalScreen *screen)
2943 {
2944 VtePty *pty;
2945 int fd;
2946 int fgpid;
2947
2948 if (screen == NULL || screen->pid == -1)
2949 return FALSE;
2950
2951 pty = vte_terminal_get_pty (VTE_TERMINAL (screen->terminal));
2952 if (pty == NULL)
2953 return FALSE;
2954
2955 fd = vte_pty_get_fd (pty);
2956 if (fd == -1)
2957 return FALSE;
2958
2959 fgpid = tcgetpgrp (fd);
2960 if (fgpid == -1 || fgpid == screen->pid)
2961 return FALSE;
2962
2963 return TRUE;
2964 }
2965
2966
2967
2968 void
terminal_screen_feed_text(TerminalScreen * screen,const char * text)2969 terminal_screen_feed_text (TerminalScreen *screen,
2970 const char *text)
2971 {
2972 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2973 vte_terminal_feed_child (VTE_TERMINAL (screen->terminal), text, strlen (text));
2974 }
2975
2976
2977
2978 const gchar *
terminal_screen_get_custom_fg_color(TerminalScreen * screen)2979 terminal_screen_get_custom_fg_color (TerminalScreen *screen)
2980 {
2981 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2982 return screen->custom_fg_color;
2983 }
2984
2985
2986
2987 const gchar *
terminal_screen_get_custom_bg_color(TerminalScreen * screen)2988 terminal_screen_get_custom_bg_color (TerminalScreen *screen)
2989 {
2990 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
2991 return screen->custom_bg_color;
2992 }
2993
2994
2995
2996 const gchar *
terminal_screen_get_custom_title_color(TerminalScreen * screen)2997 terminal_screen_get_custom_title_color (TerminalScreen *screen)
2998 {
2999 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
3000 return screen->custom_title_color;
3001 }
3002
3003
3004
3005 void
terminal_screen_set_custom_title_color(TerminalScreen * screen,const gchar * color)3006 terminal_screen_set_custom_title_color (TerminalScreen *screen,
3007 const gchar *color)
3008 {
3009 GdkRGBA label_color;
3010
3011 terminal_return_if_fail (TERMINAL_IS_SCREEN (screen));
3012
3013 g_free (screen->custom_title_color);
3014 screen->custom_title_color = NULL;
3015
3016 if (color == NULL)
3017 gtk_label_set_attributes (GTK_LABEL (screen->tab_label), NULL);
3018 else if (gdk_rgba_parse (&label_color, color))
3019 {
3020 screen->custom_title_color = g_strdup (color);
3021 terminal_screen_set_tab_label_color (screen, &label_color);
3022 }
3023 }
3024