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", &copy_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