1 /*
2  * Copyright © 2001 Havoc Pennington
3  * Copyright © 2007, 2008, 2010 Christian Persch
4  * Copyright (C) 2012-2021 MATE Developers
5  *
6  * Mate-terminal is free software; you can redistribute it and/or modify
7  * it under the terms of the GNU General Public License as published by
8  * the Free Software Foundation; either version 3 of the License, or
9  * (at your option) any later version.
10  *
11  * Mate-terminal is distributed in the hope that it will be useful,
12  * but WITHOUT ANY WARRANTY; without even the implied warranty of
13  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
14  * GNU General Public License for 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 #include <config.h>
21 
22 #ifdef __FreeBSD__
23 #include <sys/types.h>
24 #include <sys/sysctl.h>
25 #include <sys/param.h>
26 #include <sys/user.h>
27 #ifdef HAVE_KINFO_GETFILE
28 #include <libutil.h>
29 #endif
30 #endif
31 #include <string.h>
32 #include <stdlib.h>
33 #include <unistd.h>
34 #include <sys/wait.h>
35 
36 #include <gio/gio.h>
37 #include <gtk/gtk.h>
38 #include <gdk/gdkkeysyms.h>
39 
40 #include <gdk/gdk.h>
41 #include <gdk/gdkx.h>
42 #include <gdk-pixbuf/gdk-pixbuf.h>
43 #include <cairo.h>
44 
45 #include "terminal-accels.h"
46 #include "terminal-app.h"
47 #include "terminal-debug.h"
48 #include "terminal-intl.h"
49 #include "terminal-marshal.h"
50 #include "terminal-profile.h"
51 #include "terminal-screen-container.h"
52 #include "terminal-util.h"
53 #include "terminal-window.h"
54 #include "terminal-info-bar.h"
55 
56 #include "eggshell.h"
57 
58 #define PCRE2_CODE_UNIT_WIDTH 0
59 #include <pcre2.h>
60 
61 #define URL_MATCH_CURSOR  (GDK_HAND2)
62 #define SKEY_MATCH_CURSOR (GDK_HAND2)
63 
64 typedef struct
65 {
66 	int tag;
67 	TerminalURLFlavour flavor;
68 } TagData;
69 
70 struct _TerminalScreenPrivate
71 {
72 	TerminalProfile *profile; /* may be NULL at times */
73 	guint profile_changed_id;
74 	guint profile_forgotten_id;
75 	char *raw_title, *raw_icon_title;
76 	char *cooked_title, *cooked_icon_title;
77 	char *override_title;
78 	gboolean icon_title_set;
79 	char *initial_working_directory;
80 	char **initial_env;
81 	char **override_command;
82 	int child_pid;
83 	double font_scale;
84 	gboolean user_title; /* title was manually set */
85 	GSList *match_tags;
86 	guint launch_child_source_id;
87 	gulong bg_image_callback_id;
88 	GdkPixbuf *bg_image;
89 };
90 
91 enum
92 {
93     PROFILE_SET,
94     SHOW_POPUP_MENU,
95     MATCH_CLICKED,
96     CLOSE_SCREEN,
97     LAST_SIGNAL
98 };
99 
100 enum
101 {
102     PROP_0,
103     PROP_PROFILE,
104     PROP_ICON_TITLE,
105     PROP_ICON_TITLE_SET,
106     PROP_OVERRIDE_COMMAND,
107     PROP_TITLE,
108     PROP_INITIAL_ENVIRONMENT
109 };
110 
111 enum
112 {
113     TARGET_COLOR,
114     TARGET_BGIMAGE,
115     TARGET_RESET_BG,
116     TARGET_MOZ_URL,
117     TARGET_NETSCAPE_URL,
118     TARGET_TAB
119 };
120 
121 static void terminal_screen_dispose     (GObject             *object);
122 static void terminal_screen_finalize    (GObject             *object);
123 static void terminal_screen_drag_data_received (GtkWidget        *widget,
124         GdkDragContext   *context,
125         gint              x,
126         gint              y,
127         GtkSelectionData *selection_data,
128         guint             info,
129         guint             time);
130 static void terminal_screen_system_font_notify_cb (TerminalApp *app,
131         GParamSpec *pspec,
132         TerminalScreen *screen);
133 static void terminal_screen_change_font (TerminalScreen *screen);
134 static gboolean terminal_screen_popup_menu (GtkWidget *widget);
135 static gboolean terminal_screen_button_press (GtkWidget *widget,
136         GdkEventButton *event);
137 static void terminal_screen_launch_child_on_idle (TerminalScreen *screen);
138 static void terminal_screen_child_exited (VteTerminal *terminal, int status);
139 
140 static void terminal_screen_window_title_changed      (VteTerminal *vte_terminal,
141         TerminalScreen *screen);
142 static void terminal_screen_icon_title_changed        (VteTerminal *vte_terminal,
143         TerminalScreen *screen);
144 
145 static void update_color_scheme                      (TerminalScreen *screen);
146 
147 static gboolean terminal_screen_format_title (TerminalScreen *screen, const char *raw_title, char **old_cooked_title);
148 
149 static void terminal_screen_cook_title      (TerminalScreen *screen);
150 static void terminal_screen_cook_icon_title (TerminalScreen *screen);
151 
152 static char* terminal_screen_check_match       (TerminalScreen            *screen,
153         GdkEvent             *event,
154         int                  *flavor);
155 
156 static guint signals[LAST_SIGNAL] = { 0 };
157 
158 #define USERCHARS "-[:alnum:]"
159 #define USERCHARS_CLASS "[" USERCHARS "]"
160 #define PASSCHARS_CLASS "[-[:alnum:]\\Q,?;.:/!%$^*&~\"#'\\E]"
161 #define HOSTCHARS_CLASS "[-[:alnum:]]"
162 #define HOST HOSTCHARS_CLASS "+(\\." HOSTCHARS_CLASS "+)*"
163 #define PORT "(?:\\:[[:digit:]]{1,5})?"
164 #define PATHCHARS_CLASS "[-[:alnum:]\\Q_$.+!*,:;@&=?/~#%\\E]"
165 #define PATHTERM_CLASS "[^\\Q]'.:}>) \t\r\n,\"\\E]"
166 #define SCHEME "(?:news:|telnet:|nntp:|file:\\/|https?:|ftps?:|sftp:|webcal:)"
167 #define USERPASS USERCHARS_CLASS "+(?:" PASSCHARS_CLASS "+)?"
168 #define URLPATH   "(?:(/"PATHCHARS_CLASS"+(?:[(]"PATHCHARS_CLASS"*[)])*"PATHCHARS_CLASS"*)*"PATHTERM_CLASS")?"
169 
170 typedef struct
171 {
172 	const char *pattern;
173 	TerminalURLFlavour flavor;
174 	guint32 flags;
175 } TerminalRegexPattern;
176 
177 static const TerminalRegexPattern url_regex_patterns[] =
178 {
179 	{ SCHEME "//(?:" USERPASS "\\@)?" HOST PORT URLPATH, FLAVOR_AS_IS, PCRE2_CASELESS },
180 	{ "(?:www|ftp)" HOSTCHARS_CLASS "*\\." HOST PORT URLPATH , FLAVOR_DEFAULT_TO_HTTP, PCRE2_CASELESS  },
181 	{ "(?:callto:|h323:|sip:)" USERCHARS_CLASS "[" USERCHARS ".]*(?:" PORT "/[a-z0-9]+)?\\@" HOST, FLAVOR_VOIP_CALL, PCRE2_CASELESS  },
182 	{ "(?:mailto:)?" USERCHARS_CLASS "[" USERCHARS ".]*\\@" HOSTCHARS_CLASS "+\\." HOST, FLAVOR_EMAIL, PCRE2_CASELESS  },
183 	{ "news:[[:alnum:]\\Q^_{|}~!\"#$%&'()*+,./;:=?`\\E]+", FLAVOR_AS_IS, PCRE2_CASELESS  },
184 };
185 
186 static VteRegex **url_regexes;
187 static TerminalURLFlavour *url_regex_flavors;
188 static guint n_url_regexes;
189 
190 static void terminal_screen_url_match_remove (TerminalScreen *screen);
191 
192 
193 #ifdef ENABLE_SKEY
194 static const TerminalRegexPattern skey_regex_patterns[] =
195 {
196 	{ "s/key [[:digit:]]* [-[:alnum:]]*",         FLAVOR_AS_IS, 0 },
197 	{ "otp-[a-z0-9]* [[:digit:]]* [-[:alnum:]]*", FLAVOR_AS_IS, 0 },
198 };
199 
200 static VteRegex **skey_regexes;
201 static guint n_skey_regexes;
202 
203 static void  terminal_screen_skey_match_remove (TerminalScreen            *screen);
204 #endif /* ENABLE_SKEY */
205 
G_DEFINE_TYPE_WITH_PRIVATE(TerminalScreen,terminal_screen,VTE_TYPE_TERMINAL)206 G_DEFINE_TYPE_WITH_PRIVATE (TerminalScreen, terminal_screen, VTE_TYPE_TERMINAL)
207 
208 static char *
209 cwd_of_pid (int pid)
210 {
211 #ifndef __FreeBSD__
212 	static const char patterns[][18] =
213 	{
214 		"/proc/%d/cwd",         /* Linux */
215 		"/proc/%d/path/cwd",    /* Solaris >= 10 */
216 	};
217 #else
218 #if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
219   struct kinfo_file *freep, *kif;
220 #ifndef HAVE_KINFO_GETFILE
221   size_t len;
222   int name[4];
223 #else
224   int cnt;
225 #endif /* HAVE_KINFO_GETFILE */
226 #endif /* __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104) */
227 #endif /* __FreeBSD__ */
228 	guint i;
229 
230 	if (pid == -1)
231 		return NULL;
232 
233 #ifndef __FreeBSD__
234 	/* Try to get the working directory using various OS-specific mechanisms */
235 	for (i = 0; i < G_N_ELEMENTS (patterns); ++i)
236 	{
237 		char cwd_file[64];
238 		char buf[PATH_MAX + 1];
239 		int len;
240 
241 		g_snprintf (cwd_file, sizeof (cwd_file), patterns[i], pid);
242 		len = readlink (cwd_file, buf, sizeof (buf) - 1);
243 
244 		if (len > 0 && buf[0] == '/')
245 			return g_strndup (buf, len);
246 
247 		/* If that didn't do it, try this hack */
248 		if (len <= 0)
249 		{
250 			char *cwd, *working_dir = NULL;
251 
252 			cwd = g_get_current_dir ();
253 			if (cwd != NULL)
254 			{
255 				/* On Solaris, readlink returns an empty string, but the
256 				 * link can be used as a directory, including as a target
257 				 * of chdir().
258 				 */
259 				if (chdir (cwd_file) == 0)
260 				{
261 					working_dir = g_get_current_dir ();
262 					if (chdir (cwd) < 0)
263 						g_warning ("Could not change working directory.");
264 				}
265 				g_free (cwd);
266 			}
267 
268 			if (working_dir)
269 				return working_dir;
270 		}
271 	}
272 #else
273   int fgpid = pid;
274 #if __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104)
275 #ifndef HAVE_KINFO_GETFILE
276   name[0] = CTL_KERN;
277   name[1] = KERN_PROC;
278   name[2] = KERN_PROC_FILEDESC;
279   name[3] = fgpid;
280 
281   if (sysctl (name, 4, NULL, &len, NULL, 0) < 0)
282     return NULL;
283   freep = kif = g_malloc (len);
284   if (sysctl (name, 4, kif, &len, NULL, 0) < 0)
285     {
286       g_free (freep);
287       return NULL;
288     }
289 #else
290   freep = kinfo_getfile (fgpid, &cnt);
291 #endif /* HAVE_KINFO_GETFILE */
292 
293 #ifndef HAVE_KINFO_GETFILE
294   for (i = 0; i < len / sizeof (*kif); i++, kif++)
295     {
296       if (kif->kf_structsize != sizeof (*kif))
297         continue;
298 #else
299   for (i = 0; i < cnt; i++)
300     {
301       kif = &freep[i];
302 #endif /* HAVE_KINFO_GETFILE */
303       if (kif->kf_fd == KF_FD_TYPE_CWD)
304         {
305           char *working_dir;
306 
307           working_dir = g_strdup (kif->kf_path);
308           g_free (freep);
309           return working_dir;
310         }
311     }
312   g_free (freep);
313 #endif /* __FreeBSD_version > 800018 || (__FreeBSD_version < 800000 && __FreeBSD_version >= 700104) */
314 #endif /* __FreeBSD__ */
315 
316 	return NULL;
317 }
318 
319 static void
320 free_tag_data (TagData *tagdata)
321 {
322 	g_slice_free (TagData, tagdata);
323 }
324 
325 static void
326 terminal_screen_class_enable_menu_bar_accel_notify_cb (TerminalApp *app,
327         GParamSpec *pspec,
328         TerminalScreenClass *klass)
329 {
330 	static gboolean is_enabled = TRUE; /* the binding is enabled by default since GtkWidgetClass installs it */
331 	gboolean enable;
332 	GtkBindingSet *binding_set;
333 
334 	g_object_get (app, TERMINAL_APP_ENABLE_MENU_BAR_ACCEL, &enable, NULL);
335 
336 	/* Only remove the 'skip' entry when we have added it previously! */
337 	if (enable == is_enabled)
338 		return;
339 
340 	is_enabled = enable;
341 
342 	binding_set = gtk_binding_set_by_class (klass);
343 	if (enable)
344 		gtk_binding_entry_remove (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK);
345 	else
346 		gtk_binding_entry_skip (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK);
347 }
348 
349 static TerminalWindow *
350 terminal_screen_get_window (TerminalScreen *screen)
351 {
352 	GtkWidget *widget = GTK_WIDGET (screen);
353 	GtkWidget *toplevel;
354 
355 	toplevel = gtk_widget_get_toplevel (widget);
356 	if (!gtk_widget_is_toplevel (toplevel))
357 		return NULL;
358 
359 	return TERMINAL_WINDOW (toplevel);
360 }
361 
362 static void
363 terminal_screen_realize (GtkWidget *widget)
364 {
365     TerminalScreen *screen = TERMINAL_SCREEN (widget);
366 
367     GTK_WIDGET_CLASS (terminal_screen_parent_class)->realize (widget);
368 
369     terminal_screen_set_font (screen);
370 }
371 
372 static void
373 terminal_screen_style_updated (GtkWidget *widget)
374 {
375     TerminalScreen *screen = TERMINAL_SCREEN (widget);
376 
377     GTK_WIDGET_CLASS (terminal_screen_parent_class)->style_updated (widget);
378 
379     update_color_scheme (screen);
380 
381     if (gtk_widget_get_realized (widget))
382       terminal_screen_change_font (screen);
383 }
384 
385 #ifdef MATE_ENABLE_DEBUG
386 static void
387 size_allocate (GtkWidget *widget,
388                GtkAllocation *allocation)
389 {
390 	_terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
391 	                       "[screen %p] size-alloc   %d : %d at (%d, %d)\n",
392 	                       widget, allocation->width, allocation->height, allocation->x, allocation->y);
393 }
394 #endif
395 
396 static void
397 terminal_screen_init (TerminalScreen *screen)
398 {
399 	const GtkTargetEntry target_table[] =
400 	{
401 		{ "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, TARGET_TAB },
402 		{ "application/x-color", 0, TARGET_COLOR },
403 		{ "property/bgimage",    0, TARGET_BGIMAGE },
404 		{ "x-special/mate-reset-background", 0, TARGET_RESET_BG },
405 		{ "text/x-moz-url",  0, TARGET_MOZ_URL },
406 		{ "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL }
407 	};
408 	TerminalScreenPrivate *priv;
409 	GtkTargetList *target_list;
410 	GtkTargetEntry *targets;
411 	int n_targets;
412 
413 	priv = screen->priv = terminal_screen_get_instance_private (screen);
414 
415 	vte_terminal_set_mouse_autohide (VTE_TERMINAL (screen), TRUE);
416 #if VTE_CHECK_VERSION (0, 52, 0)
417 	vte_terminal_set_bold_is_bright (VTE_TERMINAL (screen), TRUE);
418 #endif
419 
420 	priv->child_pid = -1;
421 
422 	priv->font_scale = PANGO_SCALE_MEDIUM;
423 
424 	/* Setup DND */
425 	target_list = gtk_target_list_new (NULL, 0);
426 	gtk_target_list_add_uri_targets (target_list, 0);
427 	gtk_target_list_add_text_targets (target_list, 0);
428 	gtk_target_list_add_table (target_list, target_table, G_N_ELEMENTS (target_table));
429 
430 	targets = gtk_target_table_new_from_list (target_list, &n_targets);
431 
432 	gtk_drag_dest_set (GTK_WIDGET (screen),
433 	                   GTK_DEST_DEFAULT_MOTION |
434 	                   GTK_DEST_DEFAULT_HIGHLIGHT |
435 	                   GTK_DEST_DEFAULT_DROP,
436 	                   targets, n_targets,
437 	                   GDK_ACTION_COPY | GDK_ACTION_MOVE);
438 
439 	gtk_target_table_free (targets, n_targets);
440 	gtk_target_list_unref (target_list);
441 
442 	priv->override_title = NULL;
443 	priv->user_title = FALSE;
444 
445 	g_signal_connect (screen, "window-title-changed",
446 	                  G_CALLBACK (terminal_screen_window_title_changed),
447 	                  screen);
448 	g_signal_connect (screen, "icon-title-changed",
449 	                  G_CALLBACK (terminal_screen_icon_title_changed),
450 	                  screen);
451 
452 	g_signal_connect (terminal_app_get (), "notify::system-font",
453 	                  G_CALLBACK (terminal_screen_system_font_notify_cb), screen);
454 
455 	priv->bg_image_callback_id = 0;
456 	priv->bg_image = NULL;
457 
458 #ifdef MATE_ENABLE_DEBUG
459 	_TERMINAL_DEBUG_IF (TERMINAL_DEBUG_GEOMETRY)
460 	{
461 		g_signal_connect_after (screen, "size-allocate", G_CALLBACK (size_allocate), NULL);
462 	}
463 #endif
464 }
465 
466 static void
467 terminal_screen_get_property (GObject *object,
468                               guint prop_id,
469                               GValue *value,
470                               GParamSpec *pspec)
471 {
472 	TerminalScreen *screen = TERMINAL_SCREEN (object);
473 
474 	switch (prop_id)
475 	{
476 	case PROP_PROFILE:
477 		g_value_set_object (value, terminal_screen_get_profile (screen));
478 		break;
479 	case PROP_ICON_TITLE:
480 		g_value_set_string (value, terminal_screen_get_icon_title (screen));
481 		break;
482 	case PROP_ICON_TITLE_SET:
483 		g_value_set_boolean (value, terminal_screen_get_icon_title_set (screen));
484 		break;
485 	case PROP_OVERRIDE_COMMAND:
486 		g_value_set_boxed (value, terminal_screen_get_override_command (screen));
487 		break;
488 	case PROP_INITIAL_ENVIRONMENT:
489 		g_value_set_boxed (value, terminal_screen_get_initial_environment (screen));
490 		break;
491 	case PROP_TITLE:
492 		g_value_set_string (value, terminal_screen_get_title (screen));
493 		break;
494 	default:
495 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
496 		break;
497 	}
498 }
499 
500 static void
501 terminal_screen_set_property (GObject *object,
502                               guint prop_id,
503                               const GValue *value,
504                               GParamSpec *pspec)
505 {
506 	TerminalScreen *screen = TERMINAL_SCREEN (object);
507 
508 	switch (prop_id)
509 	{
510 	case PROP_PROFILE:
511 	{
512 		TerminalProfile *profile;
513 
514 		profile = g_value_get_object (value);
515 		g_assert (profile != NULL);
516 		terminal_screen_set_profile (screen, profile);
517 		break;
518 	}
519 	case PROP_OVERRIDE_COMMAND:
520 		terminal_screen_set_override_command (screen, g_value_get_boxed (value));
521 		break;
522 	case PROP_INITIAL_ENVIRONMENT:
523 		terminal_screen_set_initial_environment (screen, g_value_get_boxed (value));
524 		break;
525 	case PROP_ICON_TITLE:
526 	case PROP_ICON_TITLE_SET:
527 	case PROP_TITLE:
528 		/* not writable */
529 	default:
530 		G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
531 		break;
532 	}
533 }
534 
535 static void
536 terminal_screen_class_init (TerminalScreenClass *klass)
537 {
538 	GObjectClass *object_class = G_OBJECT_CLASS (klass);
539 	GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass);
540 	VteTerminalClass *terminal_class = VTE_TERMINAL_CLASS (klass);
541 	TerminalApp *app;
542 	guint i;
543 
544 	object_class->dispose = terminal_screen_dispose;
545 	object_class->finalize = terminal_screen_finalize;
546 	object_class->get_property = terminal_screen_get_property;
547 	object_class->set_property = terminal_screen_set_property;
548 
549 	widget_class->realize = terminal_screen_realize;
550 	widget_class->style_updated = terminal_screen_style_updated;
551 	widget_class->drag_data_received = terminal_screen_drag_data_received;
552 	widget_class->button_press_event = terminal_screen_button_press;
553 	widget_class->popup_menu = terminal_screen_popup_menu;
554 
555 	terminal_class->child_exited = terminal_screen_child_exited;
556 
557 	signals[PROFILE_SET] =
558 	    g_signal_new (I_("profile-set"),
559 	                  G_OBJECT_CLASS_TYPE (object_class),
560 	                  G_SIGNAL_RUN_LAST,
561 	                  G_STRUCT_OFFSET (TerminalScreenClass, profile_set),
562 	                  NULL, NULL,
563 	                  g_cclosure_marshal_VOID__OBJECT,
564 	                  G_TYPE_NONE,
565 	                  1, TERMINAL_TYPE_PROFILE);
566 
567 	signals[SHOW_POPUP_MENU] =
568 	    g_signal_new (I_("show-popup-menu"),
569 	                  G_OBJECT_CLASS_TYPE (object_class),
570 	                  G_SIGNAL_RUN_LAST,
571 	                  G_STRUCT_OFFSET (TerminalScreenClass, show_popup_menu),
572 	                  NULL, NULL,
573 	                  g_cclosure_marshal_VOID__POINTER,
574 	                  G_TYPE_NONE,
575 	                  1,
576 	                  G_TYPE_POINTER);
577 
578 	signals[MATCH_CLICKED] =
579 	    g_signal_new (I_("match-clicked"),
580 	                  G_OBJECT_CLASS_TYPE (object_class),
581 	                  G_SIGNAL_RUN_LAST,
582 	                  G_STRUCT_OFFSET (TerminalScreenClass, match_clicked),
583 	                  g_signal_accumulator_true_handled, NULL,
584 	                  _terminal_marshal_BOOLEAN__STRING_INT_UINT,
585 	                  G_TYPE_BOOLEAN,
586 	                  3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT);
587 
588 	signals[CLOSE_SCREEN] =
589 	    g_signal_new (I_("close-screen"),
590 	                  G_OBJECT_CLASS_TYPE (object_class),
591 	                  G_SIGNAL_RUN_LAST,
592 	                  G_STRUCT_OFFSET (TerminalScreenClass, close_screen),
593 	                  NULL, NULL,
594 	                  g_cclosure_marshal_VOID__VOID,
595 	                  G_TYPE_NONE,
596 	                  0);
597 
598 	g_object_class_install_property
599 	(object_class,
600 	 PROP_PROFILE,
601 	 g_param_spec_string ("profile", NULL, NULL,
602 	                      NULL,
603 	                      G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
604 
605 	g_object_class_install_property
606 	(object_class,
607 	 PROP_ICON_TITLE,
608 	 g_param_spec_string ("icon-title", NULL, NULL,
609 	                      NULL,
610 	                      G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
611 
612 	g_object_class_install_property
613 	(object_class,
614 	 PROP_ICON_TITLE_SET,
615 	 g_param_spec_boolean ("icon-title-set", NULL, NULL,
616 	                       FALSE,
617 	                       G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
618 
619 	g_object_class_install_property
620 	(object_class,
621 	 PROP_OVERRIDE_COMMAND,
622 	 g_param_spec_boxed ("override-command", NULL, NULL,
623 	                     G_TYPE_STRV,
624 	                     G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
625 
626 	g_object_class_install_property
627 	(object_class,
628 	 PROP_TITLE,
629 	 g_param_spec_string ("title", NULL, NULL,
630 	                      NULL,
631 	                      G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
632 
633 	g_object_class_install_property
634 	(object_class,
635 	 PROP_INITIAL_ENVIRONMENT,
636 	 g_param_spec_boxed ("initial-environment", NULL, NULL,
637 	                     G_TYPE_STRV,
638 	                     G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
639 
640 	/* Precompile the regexes */
641 	n_url_regexes = G_N_ELEMENTS (url_regex_patterns);
642 	url_regexes = g_new0 (VteRegex*, n_url_regexes);
643 	url_regex_flavors = g_new0 (TerminalURLFlavour, n_url_regexes);
644 
645 	for (i = 0; i < n_url_regexes; ++i)
646 	{
647 		GError *error = NULL;
648 
649 		url_regexes[i] = vte_regex_new_for_match(url_regex_patterns[i].pattern, -1,
650 				                         url_regex_patterns[i].flags | PCRE2_MULTILINE, &error);
651 		if (error)
652 		{
653 			g_message ("%s", error->message);
654 			g_error_free (error);
655 		}
656 
657 		url_regex_flavors[i] = url_regex_patterns[i].flavor;
658 	}
659 
660 #ifdef ENABLE_SKEY
661 	n_skey_regexes = G_N_ELEMENTS (skey_regex_patterns);
662 	skey_regexes = g_new0 (VteRegex*, n_skey_regexes);
663 
664 	for (i = 0; i < n_skey_regexes; ++i)
665 	{
666 		GError *error = NULL;
667 
668 		skey_regexes[i] = vte_regex_new_for_match(skey_regex_patterns[i].pattern, -1,
669 							  PCRE2_MULTILINE | PCRE2_UTF | PCRE2_NO_UTF_CHECK, &error);
670 		if (error)
671 		{
672 			g_message ("%s", error->message);
673 			g_error_free (error);
674 		}
675 	}
676 #endif /* ENABLE_SKEY */
677 
678 	/* This fixes bug #329827 */
679 	app = terminal_app_get ();
680 	terminal_screen_class_enable_menu_bar_accel_notify_cb (app, NULL, klass);
681 	g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MENU_BAR_ACCEL,
682 	                  G_CALLBACK (terminal_screen_class_enable_menu_bar_accel_notify_cb), klass);
683 }
684 
685 static void
686 terminal_screen_dispose (GObject *object)
687 {
688 	TerminalScreen *screen = TERMINAL_SCREEN (object);
689 	TerminalScreenPrivate *priv = screen->priv;
690 	GtkSettings *settings;
691 
692 	settings = gtk_widget_get_settings (GTK_WIDGET (screen));
693 	g_signal_handlers_disconnect_matched (settings, G_SIGNAL_MATCH_DATA,
694 	                                      0, 0, NULL, NULL,
695 	                                      screen);
696 
697 	if (priv->launch_child_source_id != 0)
698 	{
699 		g_source_remove (priv->launch_child_source_id);
700 		priv->launch_child_source_id = 0;
701 	}
702 
703 	G_OBJECT_CLASS (terminal_screen_parent_class)->dispose (object);
704 }
705 
706 static void
707 terminal_screen_finalize (GObject *object)
708 {
709 	TerminalScreen *screen = TERMINAL_SCREEN (object);
710 	TerminalScreenPrivate *priv = screen->priv;
711 
712 	g_signal_handlers_disconnect_by_func (terminal_app_get (),
713 	                                      G_CALLBACK (terminal_screen_system_font_notify_cb),
714 	                                      screen);
715 
716 	terminal_screen_set_profile (screen, NULL);
717 
718 	g_free (priv->raw_title);
719 	g_free (priv->cooked_title);
720 	g_free (priv->override_title);
721 	g_free (priv->raw_icon_title);
722 	g_free (priv->cooked_icon_title);
723 	g_free (priv->initial_working_directory);
724 	g_strfreev (priv->override_command);
725 	g_strfreev (priv->initial_env);
726 
727 	g_slist_foreach (priv->match_tags, (GFunc) free_tag_data, NULL);
728 	g_slist_free (priv->match_tags);
729 
730 	if (priv->bg_image)
731 		g_object_unref (priv->bg_image);
732 
733 	G_OBJECT_CLASS (terminal_screen_parent_class)->finalize (object);
734 }
735 
736 static gboolean
737 terminal_screen_image_draw_cb (GtkWidget *widget, cairo_t *cr, void *userdata)
738 {
739 	TerminalScreen *screen = TERMINAL_SCREEN (widget);
740 	TerminalScreenPrivate *priv = screen->priv;
741 	GdkPixbuf *bg_image = priv->bg_image;
742 	GdkRectangle target_rect;
743 	GtkAllocation alloc;
744 	cairo_surface_t *child_surface;
745 	cairo_t *child_cr;
746 
747 	if (!bg_image)
748 		return FALSE;
749 
750 	gtk_widget_get_allocation (widget, &alloc);
751 
752 	target_rect.x = 0;
753 	target_rect.y = 0;
754 	target_rect.width = alloc.width;
755 	target_rect.height = alloc.height;
756 
757 	child_surface = cairo_image_surface_create (CAIRO_FORMAT_ARGB32, alloc.width, alloc.height);
758 	child_cr = cairo_create (child_surface);
759 
760 	g_signal_handler_block (screen, priv->bg_image_callback_id);
761 	gtk_widget_draw (widget, child_cr);
762 	g_signal_handler_unblock (screen, priv->bg_image_callback_id);
763 
764 	gdk_cairo_set_source_pixbuf (cr, bg_image, 0, 0);
765 	cairo_pattern_set_extend (cairo_get_source (cr), CAIRO_EXTEND_REPEAT);
766 
767 	gdk_cairo_rectangle (cr, &target_rect);
768 	cairo_fill (cr);
769 
770 	cairo_set_source_surface (cr, child_surface, 0, 0);
771 	cairo_set_operator (cr, CAIRO_OPERATOR_OVER);
772 	cairo_paint (cr);
773 
774 	cairo_destroy (child_cr);
775 	cairo_surface_destroy (child_surface);
776 
777 	return TRUE;
778 }
779 
780 TerminalScreen *
781 terminal_screen_new (TerminalProfile *profile,
782                      char           **override_command,
783                      const char      *title,
784                      const char      *working_dir,
785                      char           **child_env,
786                      double           zoom)
787 {
788 	TerminalScreen *screen;
789 	TerminalScreenPrivate *priv;
790 
791 	g_return_val_if_fail (TERMINAL_IS_PROFILE (profile), NULL);
792 
793 	screen = g_object_new (TERMINAL_TYPE_SCREEN, NULL);
794 	priv = screen->priv;
795 
796 	terminal_screen_set_profile (screen, profile);
797 
798 	if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE))
799 	{
800 		vte_terminal_set_size (VTE_TERMINAL (screen),
801 		                       terminal_profile_get_property_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS),
802 		                       terminal_profile_get_property_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS));
803 	}
804 
805 	if (title)
806 		terminal_screen_set_override_title (screen, title);
807 
808 	priv->initial_working_directory = g_strdup (working_dir);
809 
810 	if (override_command)
811 		terminal_screen_set_override_command (screen, override_command);
812 
813 	if (child_env)
814 		terminal_screen_set_initial_environment (screen, child_env);
815 
816 	terminal_screen_set_font_scale (screen, zoom);
817 	terminal_screen_set_font (screen);
818 
819 	/* Launch the child on idle */
820 	terminal_screen_launch_child_on_idle (screen);
821 
822 	return screen;
823 }
824 
825 const char*
826 terminal_screen_get_raw_title (TerminalScreen *screen)
827 {
828 	TerminalScreenPrivate *priv = screen->priv;
829 
830 	if (priv->raw_title)
831 		return priv->raw_title;
832 
833 	return "";
834 }
835 
836 const char*
837 terminal_screen_get_title (TerminalScreen *screen)
838 {
839 	TerminalScreenPrivate *priv = screen->priv;
840 
841 	if (priv->cooked_title == NULL)
842 		terminal_screen_cook_title (screen);
843 
844 	/* cooked_title may still be NULL */
845 	if (priv->cooked_title != NULL)
846 		return priv->cooked_title;
847 	else
848 		return "";
849 }
850 
851 const char*
852 terminal_screen_get_icon_title (TerminalScreen *screen)
853 {
854 	TerminalScreenPrivate *priv = screen->priv;
855 
856 	if (priv->cooked_icon_title == NULL)
857 		terminal_screen_cook_icon_title (screen);
858 
859 	/* cooked_icon_title may still be NULL */
860 	if (priv->cooked_icon_title != NULL)
861 		return priv->cooked_icon_title;
862 	else
863 		return "";
864 }
865 
866 gboolean
867 terminal_screen_get_icon_title_set (TerminalScreen *screen)
868 {
869 	return screen->priv->icon_title_set;
870 }
871 
872 /* Supported format specifiers:
873  * %S = static title
874  * %D = dynamic title
875  * %A = dynamic title, falling back to static title if empty
876  * %- = separator, if not at start or end of string (excluding whitespace)
877  */
878 static const char *
879 terminal_screen_get_title_format (TerminalScreen *screen)
880 {
881 	TerminalScreenPrivate *priv = screen->priv;
882 	static const char *formats[] =
883 	{
884 		"%A"      /* TERMINAL_TITLE_REPLACE */,
885 		"%D%-%S"  /* TERMINAL_TITLE_BEFORE  */,
886 		"%S%-%D"  /* TERMINAL_TITLE_AFTER   */,
887 		"%S"      /* TERMINAL_TITLE_IGNORE  */
888 	};
889 
890 	return formats[terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_TITLE_MODE)];
891 }
892 
893 /**
894  * terminal_screen_format_title::
895  * @screen:
896  * @raw_title: main ingredient
897  * @titleptr <inout>: pointer of the current title string
898  *
899  * Format title according @format, and stores it in <literal>*titleptr</literal>.
900  * Always ensures that *titleptr will be non-NULL.
901  *
902  * Returns: %TRUE iff the title changed
903  */
904 static gboolean
905 terminal_screen_format_title (TerminalScreen *screen,
906                               const char *raw_title,
907                               char **titleptr)
908 {
909 	TerminalScreenPrivate *priv = screen->priv;
910 	const char *format, *arg;
911 	const char *static_title = NULL;
912 	GString *title;
913 	gboolean add_sep = FALSE;
914 
915 	g_assert (titleptr);
916 
917 	/* use --title argument if one was supplied, otherwise ask the profile */
918 	if (priv->override_title)
919 		static_title = priv->override_title;
920 	else
921 		static_title = terminal_profile_get_property_string (priv->profile, TERMINAL_PROFILE_TITLE);
922 
923 	//title = g_string_sized_new (strlen (static_title) + strlen (raw_title) + 3 + 1);
924 	title = g_string_sized_new (128);
925 
926 	format = terminal_screen_get_title_format (screen);
927 	for (arg = format; *arg; arg += 2)
928 	{
929 		const char *text_to_append = NULL;
930 
931 		g_assert (arg[0] == '%');
932 
933 		switch (arg[1])
934 		{
935 		case 'A':
936 			text_to_append = raw_title ? raw_title : static_title;
937 			break;
938 		case 'D':
939 			text_to_append = raw_title;
940 			break;
941 		case 'S':
942 			text_to_append = static_title;
943 			break;
944 		case '-':
945 			text_to_append = NULL;
946 			add_sep = TRUE;
947 			break;
948 		default:
949 			g_assert_not_reached ();
950 		}
951 
952 		if (!text_to_append || !text_to_append[0])
953 			continue;
954 
955 		if (add_sep && title->len > 0)
956 			g_string_append (title, " - ");
957 
958 		g_string_append (title, text_to_append);
959 		add_sep = FALSE;
960 	}
961 
962 	if (*titleptr == NULL || strcmp (title->str, *titleptr) != 0)
963 	{
964 		g_free (*titleptr);
965 		*titleptr = g_string_free (title, FALSE);
966 		return TRUE;
967 	}
968 
969 	g_string_free (title, TRUE);
970 	return FALSE;
971 }
972 
973 static void
974 terminal_screen_cook_title (TerminalScreen *screen)
975 {
976 	TerminalScreenPrivate *priv = screen->priv;
977 
978 	if (terminal_screen_format_title (screen, priv->raw_title, &priv->cooked_title))
979 		g_object_notify (G_OBJECT (screen), "title");
980 }
981 
982 static void
983 terminal_screen_cook_icon_title (TerminalScreen *screen)
984 {
985 	TerminalScreenPrivate *priv = screen->priv;
986 
987 	if (terminal_screen_format_title (screen, priv->raw_icon_title, &priv->cooked_icon_title))
988 		g_object_notify (G_OBJECT (screen), "icon-title");
989 }
990 
991 static void
992 terminal_screen_profile_notify_cb (TerminalProfile *profile,
993                                    GParamSpec *pspec,
994                                    TerminalScreen *screen)
995 {
996 	TerminalScreenPrivate *priv = screen->priv;
997 	GObject *object = G_OBJECT (screen);
998 	VteTerminal *vte_terminal = VTE_TERMINAL (screen);
999 	const char *prop_name;
1000 	TerminalWindow *window;
1001 
1002 	if (pspec)
1003 		prop_name = pspec->name;
1004 	else
1005 		prop_name = NULL;
1006 
1007 	g_object_freeze_notify (object);
1008 
1009 	if ((window = terminal_screen_get_window (screen)))
1010 	{
1011 		/* We need these in line for the set_size in
1012 		 * update_on_realize
1013 		 */
1014 		terminal_window_update_geometry (window);
1015 
1016 		/* madars.vitolins@gmail.com 24/07/2014 -
1017 		 * update terminal window config
1018 		 * with the flag of copy selection to clipboard or not. */
1019 		terminal_window_update_copy_selection(screen, window);
1020 	}
1021 
1022 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLLBAR_POSITION))
1023 		_terminal_screen_update_scrollbar (screen);
1024 
1025 	if (!prop_name ||
1026 	        prop_name == I_(TERMINAL_PROFILE_TITLE_MODE) ||
1027 	        prop_name == I_(TERMINAL_PROFILE_TITLE))
1028 	{
1029 		terminal_screen_cook_title (screen);
1030 		terminal_screen_cook_icon_title (screen);
1031 	}
1032 
1033 	if (gtk_widget_get_realized (GTK_WIDGET (screen)) &&
1034 	        (!prop_name ||
1035 	         prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT) ||
1036 	         prop_name == I_(TERMINAL_PROFILE_FONT)))
1037 		terminal_screen_change_font (screen);
1038 
1039 	if (!prop_name ||
1040 	        prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS) ||
1041 	        prop_name == I_(TERMINAL_PROFILE_FOREGROUND_COLOR) ||
1042 	        prop_name == I_(TERMINAL_PROFILE_BACKGROUND_COLOR) ||
1043 	        prop_name == I_(TERMINAL_PROFILE_BACKGROUND_TYPE) ||
1044 	        prop_name == I_(TERMINAL_PROFILE_BACKGROUND_DARKNESS) ||
1045 	        prop_name == I_(TERMINAL_PROFILE_BACKGROUND_IMAGE) ||
1046 	        prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
1047 	        prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
1048 	        prop_name == I_(TERMINAL_PROFILE_PALETTE))
1049 		update_color_scheme (screen);
1050 
1051 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SILENT_BELL))
1052 		vte_terminal_set_audible_bell (vte_terminal, !terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SILENT_BELL));
1053 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_WORD_CHARS))
1054 		vte_terminal_set_word_char_exceptions (vte_terminal,
1055 		                                       terminal_profile_get_property_string (profile, TERMINAL_PROFILE_WORD_CHARS));
1056 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE))
1057 		vte_terminal_set_scroll_on_keystroke (vte_terminal,
1058 		                                      terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE));
1059 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_OUTPUT))
1060 		vte_terminal_set_scroll_on_output (vte_terminal,
1061 		                                   terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT));
1062 	if (!prop_name ||
1063 	        prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_LINES) ||
1064 	        prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_UNLIMITED))
1065 	{
1066 		glong lines = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED) ?
1067 		              -1 : terminal_profile_get_property_int (profile, TERMINAL_PROFILE_SCROLLBACK_LINES);
1068 		vte_terminal_set_scrollback_lines (vte_terminal, lines);
1069 	}
1070 
1071 #ifdef ENABLE_SKEY
1072 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_SKEY))
1073 	{
1074 		if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SKEY))
1075 		{
1076 			guint i;
1077 
1078 			for (i = 0; i < n_skey_regexes; ++i)
1079 			{
1080 				TagData *tag_data;
1081 
1082 				tag_data = g_slice_new (TagData);
1083 				tag_data->flavor = FLAVOR_SKEY;
1084 				tag_data->tag = vte_terminal_match_add_regex (vte_terminal, skey_regexes[i], 0);
1085 				vte_terminal_match_set_cursor_type (vte_terminal, tag_data->tag, SKEY_MATCH_CURSOR);
1086 
1087 				priv->match_tags = g_slist_prepend (priv->match_tags, tag_data);
1088 			}
1089 		}
1090 		else
1091 		{
1092 			terminal_screen_skey_match_remove (screen);
1093 		}
1094 	}
1095 #endif /* ENABLE_SKEY */
1096 
1097 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING))
1098 		vte_terminal_set_backspace_binding (vte_terminal,
1099 		                                    terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKSPACE_BINDING));
1100 
1101 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING))
1102 		vte_terminal_set_delete_binding (vte_terminal,
1103 		                                 terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_DELETE_BINDING));
1104 
1105 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ALLOW_BOLD))
1106 		vte_terminal_set_allow_bold (vte_terminal,
1107 		                             terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_ALLOW_BOLD));
1108 
1109 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_BLINK_MODE))
1110 		vte_terminal_set_cursor_blink_mode (vte_terminal,
1111 		                                    terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_CURSOR_BLINK_MODE));
1112 
1113 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_SHAPE))
1114 		vte_terminal_set_cursor_shape (vte_terminal,
1115 		                               terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_CURSOR_SHAPE));
1116 
1117 	if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_URLS))
1118 	{
1119 		if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_URLS))
1120 		{
1121 			guint i;
1122 
1123 			for (i = 0; i < n_url_regexes; ++i)
1124 			{
1125 				TagData *tag_data;
1126 
1127 				tag_data = g_slice_new (TagData);
1128 				tag_data->flavor = url_regex_flavors[i];
1129 				tag_data->tag = vte_terminal_match_add_regex (vte_terminal, url_regexes[i], 0);
1130 				vte_terminal_match_set_cursor_type (vte_terminal, tag_data->tag, URL_MATCH_CURSOR);
1131 
1132 				priv->match_tags = g_slist_prepend (priv->match_tags, tag_data);
1133 			}
1134 		}
1135 		else
1136 		{
1137 			terminal_screen_url_match_remove (screen);
1138 		}
1139 	}
1140 	g_object_thaw_notify (object);
1141 }
1142 
1143 static void
1144 update_color_scheme (TerminalScreen *screen)
1145 {
1146 	TerminalScreenPrivate *priv = screen->priv;
1147 	TerminalProfile *profile = priv->profile;
1148 	GdkRGBA colors[TERMINAL_PALETTE_SIZE];
1149 	const GdkRGBA *fg_rgba, *bg_rgba, *bold_rgba;
1150 	TerminalBackgroundType bg_type;
1151 	const gchar *bg_image_file;
1152 	double bg_alpha = 1.0;
1153 	GdkRGBA fg, bg;
1154 	GdkRGBA *c;
1155 	guint n_colors;
1156 	GtkStyleContext *context;
1157 	GError *error = NULL;
1158 
1159 	context = gtk_widget_get_style_context (GTK_WIDGET (screen));
1160 	gtk_style_context_save (context);
1161 	gtk_style_context_set_state (context, GTK_STATE_FLAG_NORMAL);
1162 	gtk_style_context_get_color (context, GTK_STATE_FLAG_NORMAL, &fg);
1163 
1164 	gtk_style_context_get (context, GTK_STATE_FLAG_NORMAL,
1165 			       GTK_STYLE_PROPERTY_BACKGROUND_COLOR,
1166 			       &c, NULL);
1167 	bg = *c;
1168 	gdk_rgba_free (c);
1169 
1170 	gtk_style_context_restore (context);
1171 
1172 	bold_rgba = NULL;
1173 
1174 	if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS))
1175 	{
1176 		fg_rgba = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
1177 		bg_rgba = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
1178 
1179 		if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG))
1180 			bold_rgba = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BOLD_COLOR);
1181 
1182 		if (fg_rgba)
1183 			fg = *fg_rgba;
1184 		if (bg_rgba)
1185 			bg = *bg_rgba;
1186 	}
1187 
1188 	n_colors = G_N_ELEMENTS (colors);
1189 	terminal_profile_get_palette (priv->profile, colors, &n_colors);
1190 
1191 	bg_type = terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
1192 	bg_image_file = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE);
1193 
1194 	if (bg_type == TERMINAL_BACKGROUND_TRANSPARENT)
1195 		bg_alpha = terminal_profile_get_property_double (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS);
1196 	else if (bg_type == TERMINAL_BACKGROUND_IMAGE)
1197 	  bg_alpha = 0.0;
1198 	bg.alpha = bg_alpha;
1199 
1200 	if (bg_type == TERMINAL_BACKGROUND_IMAGE)
1201 	{
1202 		if (!priv->bg_image_callback_id)
1203 			priv->bg_image_callback_id = g_signal_connect (screen, "draw", G_CALLBACK (terminal_screen_image_draw_cb), NULL);
1204 
1205 		g_clear_object (&priv->bg_image);
1206 		priv->bg_image = gdk_pixbuf_new_from_file (bg_image_file, &error);
1207 
1208 		if (error) {
1209 			g_printerr ("Failed to load background image: %s\n", error->message);
1210 			g_clear_error (&error);
1211 		}
1212 
1213 		gtk_widget_queue_draw (GTK_WIDGET (screen));
1214 	} else {
1215 		if (priv->bg_image_callback_id)
1216 		{
1217 			g_signal_handler_disconnect (screen, priv->bg_image_callback_id);
1218 			priv->bg_image_callback_id = 0;
1219 		}
1220 	}
1221 
1222 	vte_terminal_set_colors (VTE_TERMINAL (screen),
1223 	                         &fg, &bg,
1224 	                         colors, n_colors);
1225 	if (bold_rgba)
1226 		vte_terminal_set_color_bold (VTE_TERMINAL (screen),
1227 		                             bold_rgba);
1228 }
1229 
1230 void
1231 terminal_screen_set_font (TerminalScreen *screen)
1232 {
1233 	TerminalScreenPrivate *priv = screen->priv;
1234 	TerminalProfile *profile;
1235 	PangoFontDescription *desc;
1236 	int size;
1237 
1238 	profile = priv->profile;
1239 
1240 	if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT))
1241 		g_object_get (terminal_app_get (), "system-font", &desc, NULL);
1242 	else
1243 		g_object_get (profile, TERMINAL_PROFILE_FONT, &desc, NULL);
1244 	g_assert (desc);
1245 
1246 	size = pango_font_description_get_size (desc);
1247 	if (pango_font_description_get_size_is_absolute (desc))
1248 		pango_font_description_set_absolute_size (desc, priv->font_scale * size);
1249 	else
1250 		pango_font_description_set_size (desc, (int)(priv->font_scale * size));
1251 
1252 	vte_terminal_set_font (VTE_TERMINAL (screen), desc);
1253 
1254 	pango_font_description_free (desc);
1255 }
1256 
1257 static void
1258 terminal_screen_system_font_notify_cb (TerminalApp *app,
1259                                        GParamSpec *pspec,
1260                                        TerminalScreen *screen)
1261 {
1262 	TerminalScreenPrivate *priv = screen->priv;
1263 
1264 	if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
1265 		return;
1266 
1267 	if (!terminal_profile_get_property_boolean (priv->profile, TERMINAL_PROFILE_USE_SYSTEM_FONT))
1268 		return;
1269 
1270 	terminal_screen_change_font (screen);
1271 }
1272 
1273 static void
1274 terminal_screen_change_font (TerminalScreen *screen)
1275 {
1276 	TerminalWindow *window;
1277 
1278 	terminal_screen_set_font (screen);
1279 
1280 	window = terminal_screen_get_window (screen);
1281 	terminal_window_update_size (window, screen, TRUE);
1282 }
1283 
1284 static void
1285 profile_forgotten_callback (TerminalProfile *profile,
1286                             TerminalScreen  *screen)
1287 {
1288 	TerminalProfile *new_profile;
1289 
1290 	new_profile = terminal_app_get_profile_for_new_term (terminal_app_get ());
1291 	g_assert (new_profile != NULL);
1292 	terminal_screen_set_profile (screen, new_profile);
1293 }
1294 
1295 void
1296 terminal_screen_set_profile (TerminalScreen *screen,
1297                              TerminalProfile *profile)
1298 {
1299 	TerminalScreenPrivate *priv = screen->priv;
1300 	TerminalProfile *old_profile;
1301 
1302 	old_profile = priv->profile;
1303 	if (profile == old_profile)
1304 		return;
1305 
1306 	if (priv->profile_changed_id)
1307 	{
1308 		g_signal_handler_disconnect (G_OBJECT (priv->profile),
1309 		                             priv->profile_changed_id);
1310 		priv->profile_changed_id = 0;
1311 	}
1312 
1313 	if (priv->profile_forgotten_id)
1314 	{
1315 		g_signal_handler_disconnect (G_OBJECT (priv->profile),
1316 		                             priv->profile_forgotten_id);
1317 		priv->profile_forgotten_id = 0;
1318 	}
1319 
1320 	priv->profile = profile;
1321 	if (profile)
1322 	{
1323 		g_object_ref (profile);
1324 		priv->profile_changed_id =
1325 		    g_signal_connect (profile, "notify",
1326 		                      G_CALLBACK (terminal_screen_profile_notify_cb),
1327 		                      screen);
1328 		priv->profile_forgotten_id =
1329 		    g_signal_connect (G_OBJECT (profile),
1330 		                      "forgotten",
1331 		                      G_CALLBACK (profile_forgotten_callback),
1332 		                      screen);
1333 
1334 		terminal_screen_profile_notify_cb (profile, NULL, screen);
1335 
1336 		g_signal_emit (G_OBJECT (screen), signals[PROFILE_SET], 0, old_profile);
1337 	}
1338 
1339 	if (old_profile)
1340 		g_object_unref (old_profile);
1341 
1342 	g_object_notify (G_OBJECT (screen), "profile");
1343 }
1344 
1345 TerminalProfile*
1346 terminal_screen_get_profile (TerminalScreen *screen)
1347 {
1348 	TerminalScreenPrivate *priv = screen->priv;
1349 
1350 	g_assert (priv->profile != NULL);
1351 	return priv->profile;
1352 }
1353 
1354 void
1355 terminal_screen_set_override_command (TerminalScreen *screen,
1356                                       char          **argv)
1357 {
1358 	TerminalScreenPrivate *priv;
1359 
1360 	g_return_if_fail (TERMINAL_IS_SCREEN (screen));
1361 
1362 	priv = screen->priv;
1363 	g_strfreev (priv->override_command);
1364 	priv->override_command = g_strdupv (argv);
1365 }
1366 
1367 const char**
1368 terminal_screen_get_override_command (TerminalScreen *screen)
1369 {
1370 	g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
1371 
1372 	return (const char**) screen->priv->override_command;
1373 }
1374 
1375 void
1376 terminal_screen_set_initial_environment (TerminalScreen *screen,
1377         char          **argv)
1378 {
1379 	TerminalScreenPrivate *priv;
1380 
1381 	g_return_if_fail (TERMINAL_IS_SCREEN (screen));
1382 
1383 	priv = screen->priv;
1384 	g_assert (priv->initial_env == NULL);
1385 	priv->initial_env = g_strdupv (argv);
1386 }
1387 
1388 char**
1389 terminal_screen_get_initial_environment (TerminalScreen *screen)
1390 {
1391 	g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
1392 
1393 	return screen->priv->initial_env;
1394 }
1395 
1396 static gboolean
1397 get_child_command (TerminalScreen *screen,
1398                    const char     *shell_env,
1399                    GSpawnFlags    *spawn_flags_p,
1400                    char         ***argv_p,
1401                    GError        **err)
1402 {
1403 	TerminalScreenPrivate *priv = screen->priv;
1404 	TerminalProfile *profile;
1405 	char **argv;
1406 
1407 	g_assert (spawn_flags_p != NULL && argv_p != NULL);
1408 
1409 	profile = priv->profile;
1410 
1411 	*argv_p = argv = NULL;
1412 
1413 	if (priv->override_command)
1414 	{
1415 		argv = g_strdupv (priv->override_command);
1416 
1417 		*spawn_flags_p |= G_SPAWN_SEARCH_PATH;
1418 	}
1419 	else if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND))
1420 	{
1421 		if (!g_shell_parse_argv (terminal_profile_get_property_string (profile, TERMINAL_PROFILE_CUSTOM_COMMAND),
1422 		                         NULL, &argv,
1423 		                         err))
1424 			return FALSE;
1425 
1426 		*spawn_flags_p |= G_SPAWN_SEARCH_PATH;
1427 	}
1428 	else
1429 	{
1430 		const char *only_name;
1431 		char *shell;
1432 		int argc = 0;
1433 
1434 		shell = egg_shell (shell_env);
1435 
1436 		only_name = strrchr (shell, '/');
1437 		if (only_name != NULL)
1438 			only_name++;
1439 		else
1440 			only_name = shell;
1441 
1442 		argv = g_new (char*, 3);
1443 
1444 		argv[argc++] = shell;
1445 
1446 		if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_LOGIN_SHELL))
1447 			argv[argc++] = g_strconcat ("-", only_name, NULL);
1448 		else
1449 			argv[argc++] = g_strdup (only_name);
1450 
1451 		argv[argc++] = NULL;
1452 
1453 		*spawn_flags_p |= G_SPAWN_FILE_AND_ARGV_ZERO;
1454 	}
1455 
1456 	*argv_p = argv;
1457 
1458 	return TRUE;
1459 }
1460 
1461 static char**
1462 get_child_environment (TerminalScreen *screen,
1463                        char **shell)
1464 {
1465 	TerminalScreenPrivate *priv = screen->priv;
1466 	GtkWidget *term = GTK_WIDGET (screen);
1467 	GtkWidget *window;
1468 	GdkDisplay *display;
1469 	char **env;
1470 	char *e, *v;
1471 	GHashTable *env_table;
1472 	GHashTableIter iter;
1473 	GPtrArray *retval;
1474 	guint i;
1475 	gchar **list_schemas = NULL;
1476 	gboolean schema_exists;
1477 
1478 	window = gtk_widget_get_toplevel (term);
1479 	g_assert (window != NULL);
1480 	g_assert (gtk_widget_is_toplevel (window));
1481 	display = gdk_window_get_display (gtk_widget_get_window (window));
1482 
1483 	env_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
1484 
1485 	/* First take the factory's environment */
1486 	env = g_listenv ();
1487 	for (i = 0; env[i]; ++i)
1488 		g_hash_table_insert (env_table, env[i], g_strdup (g_getenv (env[i])));
1489 	g_free (env); /* the strings themselves are now owned by the hash table */
1490 
1491 	/* and then merge the child environment, if any */
1492 	env = priv->initial_env;
1493 	if (env)
1494 	{
1495 		for (i = 0; env[i]; ++i)
1496 		{
1497 			v = strchr (env[i], '=');
1498 			if (v)
1499 				g_hash_table_replace (env_table, g_strndup (env[i], v - env[i]), g_strdup (v + 1));
1500 			else
1501 				g_hash_table_replace (env_table, g_strdup (env[i]), NULL);
1502 		}
1503 	}
1504 
1505 	g_hash_table_remove (env_table, "COLUMNS");
1506 	g_hash_table_remove (env_table, "LINES");
1507 	g_hash_table_remove (env_table, "MATE_DESKTOP_ICON");
1508 
1509 	g_hash_table_replace (env_table, g_strdup ("TERM"), g_strdup ("xterm-256color")); /* FIXME configurable later? */
1510 
1511 	/* FIXME: moving the tab between windows, or the window between displays will make the next two invalid... */
1512 #ifdef GDK_WINDOWING_X11
1513     if (GDK_IS_X11_DISPLAY (display)) {
1514         g_hash_table_replace (env_table, g_strdup ("WINDOWID"), g_strdup_printf ("%ld", GDK_WINDOW_XID (gtk_widget_get_window (window))));
1515     }
1516 #endif
1517 	g_hash_table_replace (env_table, g_strdup ("DISPLAY"), g_strdup (gdk_display_get_name (display)));
1518 
1519 	g_settings_schema_source_list_schemas (g_settings_schema_source_get_default (), TRUE, &list_schemas, NULL);
1520 
1521 	schema_exists = FALSE;
1522 	for (i = 0; list_schemas[i] != NULL; i++) {
1523 		if (g_strcmp0 (list_schemas[i], CONF_PROXY_SCHEMA) == 0)
1524 		{
1525 			schema_exists = TRUE;
1526 			break;
1527 		}
1528 	}
1529 
1530 	g_strfreev (list_schemas);
1531 
1532 	if (schema_exists == TRUE) {
1533 		terminal_util_add_proxy_env (env_table);
1534 	}
1535 
1536 	retval = g_ptr_array_sized_new (g_hash_table_size (env_table));
1537 	g_hash_table_iter_init (&iter, env_table);
1538 	while (g_hash_table_iter_next (&iter, (gpointer *) &e, (gpointer *) &v))
1539 		g_ptr_array_add (retval, g_strdup_printf ("%s=%s", e, v ? v : ""));
1540 	g_ptr_array_add (retval, NULL);
1541 
1542 	*shell = g_strdup (g_hash_table_lookup (env_table, "SHELL"));
1543 
1544 	g_hash_table_destroy (env_table);
1545 	return (char **) g_ptr_array_free (retval, FALSE);
1546 }
1547 
1548 enum
1549 {
1550     RESPONSE_RELAUNCH,
1551     RESPONSE_EDIT_PROFILE
1552 };
1553 
1554 static void
1555 info_bar_response_cb (GtkWidget *info_bar,
1556                       int response,
1557                       TerminalScreen *screen)
1558 {
1559 	gtk_widget_grab_focus (GTK_WIDGET (screen));
1560 
1561 	switch (response)
1562 	{
1563 	case GTK_RESPONSE_CANCEL:
1564 		gtk_widget_destroy (info_bar);
1565 		g_signal_emit (screen, signals[CLOSE_SCREEN], 0);
1566 		break;
1567 	case RESPONSE_RELAUNCH:
1568 		gtk_widget_destroy (info_bar);
1569 		terminal_screen_launch_child_on_idle (screen);
1570 		break;
1571 	case RESPONSE_EDIT_PROFILE:
1572 		terminal_app_edit_profile (terminal_app_get (),
1573 		                           terminal_screen_get_profile (screen),
1574 		                           GTK_WINDOW (terminal_screen_get_window (screen)),
1575 		                           "custom-command-entry");
1576 		break;
1577 	default:
1578 		gtk_widget_destroy (info_bar);
1579 		break;
1580 	}
1581 }
1582 
1583 static void handle_error_child (TerminalScreen *screen,
1584 				GError         *err)
1585 {
1586 	GtkWidget *info_bar;
1587 
1588 	info_bar = terminal_info_bar_new (GTK_MESSAGE_ERROR,
1589 	                                  _("_Profile Preferences"), RESPONSE_EDIT_PROFILE,
1590 	                                  _("_Relaunch"), RESPONSE_RELAUNCH,
1591 	                                  NULL);
1592 	terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
1593 	                               _("There was an error creating the child process for this terminal"));
1594 	terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
1595 	                               "%s", err->message);
1596 	g_signal_connect (info_bar, "response",
1597 	                  G_CALLBACK (info_bar_response_cb), screen);
1598 
1599 	gtk_box_pack_start (GTK_BOX (terminal_screen_container_get_from_screen (screen)),
1600 	                    info_bar, FALSE, FALSE, 0);
1601 	gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
1602 	gtk_widget_show (info_bar);
1603 }
1604 
1605 static void term_spawn_callback (GtkWidget *terminal,
1606 				 GPid       pid,
1607 				 GError    *error,
1608 				 gpointer   user_data)
1609 {
1610 	TerminalScreen *screen = TERMINAL_SCREEN (terminal);
1611 
1612 	if (error)
1613 	{
1614 		handle_error_child (screen, error);
1615 	}
1616 	else
1617 	{
1618 		TerminalScreenPrivate *priv = screen->priv;
1619 		priv->child_pid = pid;
1620 	}
1621 }
1622 
1623 static gboolean
1624 terminal_screen_launch_child_cb (TerminalScreen *screen)
1625 {
1626 	TerminalScreenPrivate *priv = screen->priv;
1627 	VteTerminal *terminal = VTE_TERMINAL (screen);
1628 	char **env, **argv;
1629 	char *shell = NULL;
1630 	GError *err = NULL;
1631 	const char *working_dir;
1632 	VtePtyFlags pty_flags = VTE_PTY_DEFAULT;
1633 	GSpawnFlags spawn_flags = 0;
1634 
1635 	priv->launch_child_source_id = 0;
1636 
1637 	_terminal_debug_print (TERMINAL_DEBUG_PROCESSES,
1638 	                       "[screen %p] now launching the child process\n",
1639 	                       screen);
1640 
1641 	env = get_child_environment (screen, &shell);
1642 
1643 	if (priv->initial_working_directory)
1644 		working_dir = priv->initial_working_directory;
1645 	else
1646 		working_dir = g_get_home_dir ();
1647 
1648 	if (!get_child_command (screen, shell, &spawn_flags, &argv, &err))
1649 	{
1650 		handle_error_child (screen, err);
1651 
1652 		g_error_free (err);
1653 		g_strfreev (env);
1654 		g_free (shell);
1655 
1656 		return FALSE;
1657 	}
1658 
1659         vte_terminal_spawn_async (terminal,
1660 				  pty_flags,
1661 				  working_dir,
1662 				  argv,
1663 				  env,
1664 				  spawn_flags,
1665 				  NULL,
1666 				  NULL,
1667 				  NULL,
1668 				  -1,
1669 				  NULL,
1670 				  (VteTerminalSpawnAsyncCallback) term_spawn_callback,
1671 				  NULL);
1672 
1673 	g_free (shell);
1674 	g_strfreev (argv);
1675 	g_strfreev (env);
1676 
1677 	return FALSE; /* don't run again */
1678 }
1679 
1680 static void
1681 terminal_screen_launch_child_on_idle (TerminalScreen *screen)
1682 {
1683 	TerminalScreenPrivate *priv = screen->priv;
1684 
1685 	if (priv->launch_child_source_id != 0)
1686 		return;
1687 
1688 	_terminal_debug_print (TERMINAL_DEBUG_PROCESSES,
1689 	                       "[screen %p] scheduling launching the child process on idle\n",
1690 	                       screen);
1691 
1692 	priv->launch_child_source_id = g_idle_add ((GSourceFunc) terminal_screen_launch_child_cb, screen);
1693 }
1694 
1695 static TerminalScreenPopupInfo *
1696 terminal_screen_popup_info_new (TerminalScreen *screen)
1697 {
1698 	TerminalScreenPopupInfo *info;
1699 
1700 	info = g_slice_new0 (TerminalScreenPopupInfo);
1701 	info->ref_count = 1;
1702 	info->screen = g_object_ref (screen);
1703 	info->window = terminal_screen_get_window (screen);
1704 
1705 	return info;
1706 }
1707 
1708 TerminalScreenPopupInfo *
1709 terminal_screen_popup_info_ref (TerminalScreenPopupInfo *info)
1710 {
1711 	g_return_val_if_fail (info != NULL, NULL);
1712 
1713 	info->ref_count++;
1714 	return info;
1715 }
1716 
1717 void
1718 terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info)
1719 {
1720 	g_return_if_fail (info != NULL);
1721 
1722 	if (--info->ref_count > 0)
1723 		return;
1724 
1725 	g_object_unref (info->screen);
1726 	g_free (info->string);
1727 	g_slice_free (TerminalScreenPopupInfo, info);
1728 }
1729 
1730 static gboolean
1731 terminal_screen_popup_menu (GtkWidget *widget)
1732 {
1733 	TerminalScreen *screen = TERMINAL_SCREEN (widget);
1734 	TerminalScreenPopupInfo *info;
1735 
1736 	info = terminal_screen_popup_info_new (screen);
1737 	info->button = 0;
1738 	info->timestamp = gtk_get_current_event_time ();
1739 
1740 	g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info);
1741 	terminal_screen_popup_info_unref (info);
1742 
1743 	return TRUE;
1744 }
1745 
1746 static gboolean
1747 terminal_screen_button_press (GtkWidget      *widget,
1748                               GdkEventButton *event)
1749 {
1750 	TerminalScreen *screen = TERMINAL_SCREEN (widget);
1751 	gboolean (* button_press_event) (GtkWidget*, GdkEventButton*) =
1752 	    GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event;
1753 	char *matched_string;
1754 	int matched_flavor = 0;
1755 	guint state;
1756 
1757 	state = event->state & gtk_accelerator_get_default_mod_mask ();
1758 
1759 	matched_string = terminal_screen_check_match (screen, (GdkEvent*)event, &matched_flavor);
1760 
1761 	if (matched_string != NULL &&
1762 	        (event->button == 1 || event->button == 2) &&
1763 	        (state & GDK_CONTROL_MASK))
1764 	{
1765 		gboolean handled = FALSE;
1766 
1767 #ifdef ENABLE_SKEY
1768 		if (matched_flavor != FLAVOR_SKEY ||
1769 		        terminal_profile_get_property_boolean (screen->priv->profile, TERMINAL_PROFILE_USE_SKEY))
1770 #endif
1771 		{
1772 			g_signal_emit (screen, signals[MATCH_CLICKED], 0,
1773 			               matched_string,
1774 			               matched_flavor,
1775 			               state,
1776 			               &handled);
1777 		}
1778 
1779 		g_free (matched_string);
1780 
1781 		if (handled)
1782 			return TRUE; /* don't do anything else such as select with the click */
1783 	}
1784 
1785 	if (event->button == 3 &&
1786 	        (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == 0)
1787 	{
1788 		TerminalScreenPopupInfo *info;
1789 
1790 		info = terminal_screen_popup_info_new (screen);
1791 		info->button = event->button;
1792 		info->state = state;
1793 		info->timestamp = event->time;
1794 		info->string = matched_string; /* adopted */
1795 		info->flavour = matched_flavor;
1796 
1797 		g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info);
1798 		terminal_screen_popup_info_unref (info);
1799 
1800 		return TRUE;
1801 	}
1802 
1803 	/* default behavior is to let the terminal widget deal with it */
1804 	if (button_press_event)
1805 		return button_press_event (widget, event);
1806 
1807 	return FALSE;
1808 }
1809 
1810 static void
1811 terminal_screen_set_dynamic_title (TerminalScreen *screen,
1812                                    const char     *title,
1813                                    gboolean	  userset)
1814 {
1815 	TerminalScreenPrivate *priv = screen->priv;
1816 
1817 	g_assert (TERMINAL_IS_SCREEN (screen));
1818 
1819 	if ((priv->user_title && !userset) ||
1820 	        (priv->raw_title && title &&
1821 	         strcmp (priv->raw_title, title) == 0))
1822 		return;
1823 
1824 	g_free (priv->raw_title);
1825 	priv->raw_title = g_strdup (title);
1826 	terminal_screen_cook_title (screen);
1827 }
1828 
1829 static void
1830 terminal_screen_set_dynamic_icon_title (TerminalScreen *screen,
1831                                         const char     *icon_title,
1832                                         gboolean       userset)
1833 {
1834 	TerminalScreenPrivate *priv = screen->priv;
1835 	GObject *object = G_OBJECT (screen);
1836 
1837 	g_assert (TERMINAL_IS_SCREEN (screen));
1838 
1839 	if ((priv->user_title && !userset) ||
1840 	        (priv->icon_title_set &&
1841 	         priv->raw_icon_title &&
1842 	         icon_title &&
1843 	         strcmp (priv->raw_icon_title, icon_title) == 0))
1844 		return;
1845 
1846 	g_object_freeze_notify (object);
1847 
1848 	g_free (priv->raw_icon_title);
1849 	priv->raw_icon_title = g_strdup (icon_title);
1850 	priv->icon_title_set = TRUE;
1851 
1852 	g_object_notify (object, "icon-title-set");
1853 	terminal_screen_cook_icon_title (screen);
1854 
1855 	g_object_thaw_notify (object);
1856 }
1857 
1858 void
1859 terminal_screen_set_override_title (TerminalScreen *screen,
1860                                     const char     *title)
1861 {
1862 	TerminalScreenPrivate *priv = screen->priv;
1863 	char *old_title;
1864 
1865 	old_title = priv->override_title;
1866 	priv->override_title = g_strdup (title);
1867 	g_free (old_title);
1868 
1869 	terminal_screen_set_dynamic_title (screen, title, FALSE);
1870 	terminal_screen_set_dynamic_icon_title (screen, title, FALSE);
1871 }
1872 
1873 const char*
1874 terminal_screen_get_dynamic_title (TerminalScreen *screen)
1875 {
1876 	g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
1877 
1878 	return screen->priv->raw_title;
1879 }
1880 
1881 const char*
1882 terminal_screen_get_dynamic_icon_title (TerminalScreen *screen)
1883 {
1884 	g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
1885 
1886 	return screen->priv->raw_icon_title;
1887 }
1888 
1889 /**
1890  * terminal_screen_get_current_dir:
1891  * @screen:
1892  *
1893  * Tries to determine the current working directory of the foreground process
1894  * in @screen's PTY, falling back to the current working directory of the
1895  * primary child.
1896  *
1897  * Returns: a newly allocated string containing the current working directory,
1898  *   or %NULL on failure
1899  */
1900 char*
1901 terminal_screen_get_current_dir (TerminalScreen *screen)
1902 {
1903 	TerminalScreenPrivate *priv = screen->priv;
1904 	char *cwd;
1905 	VtePty *pty;
1906 
1907 	pty = vte_terminal_get_pty (VTE_TERMINAL (screen));
1908 	if (pty != NULL)
1909 	{
1910 #if 0
1911 		/* Get the foreground process ID */
1912 		cwd = cwd_of_pid (tcgetpgrp (priv->pty_fd));
1913 		if (cwd != NULL)
1914 			return cwd;
1915 #endif
1916 
1917 		/* If that didn't work, try falling back to the primary child. See bug #575184. */
1918 		cwd = cwd_of_pid (priv->child_pid);
1919 		if (cwd != NULL)
1920 			return cwd;
1921 	}
1922 
1923 	return NULL;
1924 }
1925 
1926 /**
1927  * terminal_screen_get_current_dir_with_fallback:
1928  * @screen:
1929  *
1930  * Like terminal_screen_get_current_dir(), but falls back to returning
1931  * @screen's initial working directory, with a further fallback to the
1932  * user's home directory.
1933  *
1934  * Returns: a newly allocated string containing the current working directory,
1935  *   or %NULL on failure
1936  */
1937 char*
1938 terminal_screen_get_current_dir_with_fallback (TerminalScreen *screen)
1939 {
1940 	VtePty *pty;
1941 	TerminalScreenPrivate *priv = screen->priv;
1942 
1943 	pty = vte_terminal_get_pty (VTE_TERMINAL (screen));
1944 	if (pty == NULL)
1945 		return g_strdup (priv->initial_working_directory);
1946 
1947 	return terminal_screen_get_current_dir (screen);
1948 }
1949 
1950 void
1951 terminal_screen_set_font_scale (TerminalScreen *screen,
1952                                 double          factor)
1953 {
1954 	TerminalScreenPrivate *priv = screen->priv;
1955 
1956 	g_return_if_fail (TERMINAL_IS_SCREEN (screen));
1957 
1958 	if (factor < TERMINAL_SCALE_MINIMUM)
1959 		factor = TERMINAL_SCALE_MINIMUM;
1960 	if (factor > TERMINAL_SCALE_MAXIMUM)
1961 		factor = TERMINAL_SCALE_MAXIMUM;
1962 
1963 	priv->font_scale = factor;
1964 
1965 	if (gtk_widget_get_realized (GTK_WIDGET (screen)))
1966 	{
1967 		/* Update the font */
1968 		terminal_screen_change_font (screen);
1969 	}
1970 }
1971 
1972 double
1973 terminal_screen_get_font_scale (TerminalScreen *screen)
1974 {
1975 	g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), 1.0);
1976 
1977 	return screen->priv->font_scale;
1978 }
1979 
1980 static void
1981 terminal_screen_window_title_changed (VteTerminal *vte_terminal,
1982                                       TerminalScreen *screen)
1983 {
1984 	terminal_screen_set_dynamic_title (screen,
1985 	                                   vte_terminal_get_window_title (vte_terminal),
1986 	                                   FALSE);
1987 }
1988 
1989 static void
1990 terminal_screen_icon_title_changed (VteTerminal *vte_terminal,
1991                                     TerminalScreen *screen)
1992 {
1993 	terminal_screen_set_dynamic_icon_title (screen,
1994 	                                        vte_terminal_get_icon_title (vte_terminal),
1995 	                                        FALSE);
1996 }
1997 
1998 static void
1999 terminal_screen_child_exited (VteTerminal *terminal, int status)
2000 {
2001 	TerminalScreen *screen = TERMINAL_SCREEN (terminal);
2002 	TerminalScreenPrivate *priv = screen->priv;
2003 	TerminalExitAction action;
2004 
2005 	/* No need to chain up to VteTerminalClass::child_exited since it's NULL */
2006 
2007 	_terminal_debug_print (TERMINAL_DEBUG_PROCESSES,
2008 	                       "[screen %p] child process exited\n",
2009 	                       screen);
2010 
2011 	priv->child_pid = -1;
2012 
2013 	action = terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION);
2014 
2015 	switch (action)
2016 	{
2017 	case TERMINAL_EXIT_CLOSE:
2018 		if ((status != 9) || (priv->override_command != NULL))
2019 			g_signal_emit (screen, signals[CLOSE_SCREEN], 0);
2020 		break;
2021 	case TERMINAL_EXIT_RESTART:
2022 		terminal_screen_launch_child_on_idle (screen);
2023 		break;
2024 	case TERMINAL_EXIT_HOLD:
2025 	{
2026 		if ((status == 9) && (priv->override_command == NULL))
2027 			break;
2028 
2029 		GtkWidget *info_bar;
2030 
2031 		info_bar = terminal_info_bar_new (GTK_MESSAGE_INFO,
2032 		                                  _("_Relaunch"), RESPONSE_RELAUNCH,
2033 		                                  NULL);
2034 		if (WIFEXITED (status))
2035 		{
2036 			terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
2037 			                               _("The child process exited normally with status %d."), WEXITSTATUS (status));
2038 		}
2039 		else if (WIFSIGNALED (status))
2040 		{
2041 			terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
2042 			                               _("The child process was terminated by signal %d."), WTERMSIG (status));
2043 		}
2044 		else
2045 		{
2046 			terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
2047 			                               _("The child process was terminated."));
2048 		}
2049 		g_signal_connect (info_bar, "response",
2050 		                  G_CALLBACK (info_bar_response_cb), screen);
2051 
2052 		gtk_box_pack_start (GTK_BOX (terminal_screen_container_get_from_screen (screen)),
2053 		                    info_bar, FALSE, FALSE, 0);
2054 		gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), RESPONSE_RELAUNCH);
2055 		gtk_widget_show (info_bar);
2056 		break;
2057 	}
2058 
2059 	default:
2060 		break;
2061 	}
2062 }
2063 
2064 void
2065 terminal_screen_set_user_title (TerminalScreen *screen,
2066                                 const char *text)
2067 {
2068 	TerminalScreenPrivate *priv = screen->priv;
2069 
2070 	/* The user set the title to nothing, let's understand that as a
2071 	   request to revert to dynamically setting the title again. */
2072 	if (!text || !text[0])
2073 		priv->user_title = FALSE;
2074 	else
2075 	{
2076 		priv->user_title = TRUE;
2077 		terminal_screen_set_dynamic_title (screen, text, TRUE);
2078 		terminal_screen_set_dynamic_icon_title (screen, text, TRUE);
2079 	}
2080 }
2081 
2082 static void
2083 terminal_screen_drag_data_received (GtkWidget        *widget,
2084                                     GdkDragContext   *context,
2085                                     gint              x,
2086                                     gint              y,
2087                                     GtkSelectionData *selection_data,
2088                                     guint             info,
2089                                     guint             timestamp)
2090 {
2091 	TerminalScreen *screen = TERMINAL_SCREEN (widget);
2092 	TerminalScreenPrivate *priv = screen->priv;
2093 	const guchar *selection_data_data;
2094 	GdkAtom selection_data_target;
2095 	gint selection_data_length, selection_data_format;
2096 
2097 	selection_data_data = gtk_selection_data_get_data (selection_data);
2098 	selection_data_target = gtk_selection_data_get_target (selection_data);
2099 	selection_data_length = gtk_selection_data_get_length (selection_data);
2100 	selection_data_format = gtk_selection_data_get_format (selection_data);
2101 
2102 #if 0
2103 	{
2104 		GList *tmp;
2105 
2106 		g_print ("info: %d\n", info);
2107 		tmp = context->targets;
2108 		while (tmp != NULL)
2109 		{
2110 			GdkAtom atom = GDK_POINTER_TO_ATOM (tmp->data);
2111 
2112 			g_print ("Target: %s\n", gdk_atom_name (atom));
2113 
2114 			tmp = tmp->next;
2115 		}
2116 
2117 		g_print ("Chosen target: %s\n", gdk_atom_name (selection_data->target));
2118 	}
2119 #endif
2120 
2121 	if (gtk_targets_include_uri (&selection_data_target, 1))
2122 	{
2123 		char **uris;
2124 		char *text;
2125 		gsize len;
2126 
2127 		uris = gtk_selection_data_get_uris (selection_data);
2128 		if (!uris)
2129 			return;
2130 
2131 		terminal_util_transform_uris_to_quoted_fuse_paths (uris);
2132 
2133 		text = terminal_util_concat_uris (uris, &len);
2134 		vte_terminal_feed_child (VTE_TERMINAL (screen), text, len);
2135 		g_free (text);
2136 
2137 		g_strfreev (uris);
2138 	}
2139 	else if (gtk_targets_include_text (&selection_data_target, 1))
2140 	{
2141 		char *text;
2142 
2143 		text = (char *) gtk_selection_data_get_text (selection_data);
2144 		if (text && text[0])
2145 			vte_terminal_feed_child (VTE_TERMINAL (screen), text, strlen (text));
2146 		g_free (text);
2147 	}
2148 	else switch (info)
2149 		{
2150 		case TARGET_COLOR:
2151 		{
2152 			guint16 *data = (guint16 *)selection_data_data;
2153 			GdkRGBA color;
2154 
2155 			/* We accept drops with the wrong format, since the KDE color
2156 			 * chooser incorrectly drops application/x-color with format 8.
2157 			 * So just check for the data length.
2158 			 */
2159 			if (selection_data_length != 8)
2160 				return;
2161 
2162 			color.red = (double) data[0] / 65535.;
2163 			color.green = (double) data[1] / 65535.;
2164 			color.blue = (double) data[2] / 65535.;
2165 			color.alpha = 1.;
2166 			/* FIXME: use opacity from data[3] */
2167 
2168 			g_object_set (priv->profile,
2169 			              TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_SOLID,
2170 			              TERMINAL_PROFILE_USE_THEME_COLORS, FALSE,
2171 			              TERMINAL_PROFILE_BACKGROUND_COLOR, &color,
2172 			              NULL);
2173 		}
2174 		break;
2175 
2176 		case TARGET_MOZ_URL:
2177 		{
2178 			char *utf8_data, *newline, *text;
2179 			char *uris[2];
2180 			gsize len;
2181 
2182 			/* MOZ_URL is in UCS-2 but in format 8. BROKEN!
2183 			 *
2184 			 * The data contains the URL, a \n, then the
2185 			 * title of the web page.
2186 			 */
2187 			if (selection_data_format != 8 ||
2188 			        selection_data_length == 0 ||
2189 			        (selection_data_length % 2) != 0)
2190 				return;
2191 
2192 			utf8_data = g_utf16_to_utf8 ((const gunichar2*) selection_data_data,
2193 			                             selection_data_length / 2,
2194 			                             NULL, NULL, NULL);
2195 			if (!utf8_data)
2196 				return;
2197 
2198 			newline = strchr (utf8_data, '\n');
2199 			if (newline)
2200 				*newline = '\0';
2201 
2202 			uris[0] = utf8_data;
2203 			uris[1] = NULL;
2204 			terminal_util_transform_uris_to_quoted_fuse_paths (uris); /* This may replace uris[0] */
2205 
2206 			text = terminal_util_concat_uris (uris, &len);
2207 			vte_terminal_feed_child (VTE_TERMINAL (screen), text, len);
2208 			g_free (text);
2209 			g_free (uris[0]);
2210 		}
2211 		break;
2212 
2213 		case TARGET_NETSCAPE_URL:
2214 		{
2215 			char *utf8_data, *newline, *text;
2216 			char *uris[2];
2217 			gsize len;
2218 
2219 			/* The data contains the URL, a \n, then the
2220 			 * title of the web page.
2221 			 */
2222 			if (selection_data_length < 0 || selection_data_format != 8)
2223 				return;
2224 
2225 			utf8_data = g_strndup ((char *) selection_data_data, selection_data_length);
2226 			newline = strchr (utf8_data, '\n');
2227 			if (newline)
2228 				*newline = '\0';
2229 
2230 			uris[0] = utf8_data;
2231 			uris[1] = NULL;
2232 			terminal_util_transform_uris_to_quoted_fuse_paths (uris); /* This may replace uris[0] */
2233 
2234 			text = terminal_util_concat_uris (uris, &len);
2235 			vte_terminal_feed_child (VTE_TERMINAL (screen), text, len);
2236 			g_free (text);
2237 			g_free (uris[0]);
2238 		}
2239 		break;
2240 
2241 		case TARGET_BGIMAGE:
2242 		{
2243 			char *utf8_data;
2244 			char **uris;
2245 
2246 			if (selection_data_length < 0 || selection_data_format != 8)
2247 				return;
2248 
2249 			utf8_data = g_strndup ((char *) selection_data_data, selection_data_length);
2250 			uris = g_uri_list_extract_uris (utf8_data);
2251 			g_free (utf8_data);
2252 
2253 			/* FIXME: use terminal_util_transform_uris_to_quoted_fuse_paths? */
2254 
2255 			if (uris && uris[0])
2256 			{
2257 				char *filename;
2258 
2259 				filename = g_filename_from_uri (uris[0], NULL, NULL);
2260 				if (filename)
2261 				{
2262 					g_object_set (priv->profile,
2263 					              TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_IMAGE,
2264 					              TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE, filename,
2265 					              NULL);
2266 				}
2267 
2268 				g_free (filename);
2269 			}
2270 
2271 			g_strfreev (uris);
2272 		}
2273 		break;
2274 
2275 		case TARGET_RESET_BG:
2276 			g_object_set (priv->profile,
2277 			              TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_SOLID,
2278 			              NULL);
2279 			break;
2280 
2281 		case TARGET_TAB:
2282 		{
2283 			GtkWidget *container;
2284 			TerminalScreen *moving_screen;
2285 			TerminalWindow *source_window;
2286 			TerminalWindow *dest_window;
2287 			GtkWidget *dest_notebook;
2288 			int page_num;
2289 
2290 			container = *(GtkWidget**) selection_data_data;
2291 			if (!GTK_IS_WIDGET (container))
2292 				return;
2293 
2294 			moving_screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
2295 			g_return_if_fail (TERMINAL_IS_SCREEN (moving_screen));
2296 			if (!TERMINAL_IS_SCREEN (moving_screen))
2297 				return;
2298 
2299 			source_window = terminal_screen_get_window (moving_screen);
2300 			dest_window = terminal_screen_get_window (screen);
2301 			dest_notebook = terminal_window_get_notebook (dest_window);
2302 			page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dest_notebook),
2303 			                                  GTK_WIDGET (screen));
2304 			terminal_window_move_screen (source_window, dest_window, moving_screen, page_num + 1);
2305 
2306 			gtk_drag_finish (context, TRUE, TRUE, timestamp);
2307 		}
2308 		break;
2309 
2310 		default:
2311 			g_assert_not_reached ();
2312 		}
2313 }
2314 
2315 void
2316 _terminal_screen_update_scrollbar (TerminalScreen *screen)
2317 {
2318 	TerminalScreenPrivate *priv = screen->priv;
2319 	TerminalScreenContainer *container;
2320 	GtkPolicyType policy = GTK_POLICY_ALWAYS;
2321 	GtkCornerType corner = GTK_CORNER_TOP_LEFT;
2322 
2323 	container = terminal_screen_container_get_from_screen (screen);
2324 	if (container == NULL)
2325 		return;
2326 
2327 	switch (terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_SCROLLBAR_POSITION))
2328 	{
2329 	case TERMINAL_SCROLLBAR_HIDDEN:
2330 		policy = GTK_POLICY_NEVER;
2331 		break;
2332 	case TERMINAL_SCROLLBAR_RIGHT:
2333 		policy = GTK_POLICY_ALWAYS;
2334 		corner = GTK_CORNER_TOP_LEFT;
2335 		break;
2336 	case TERMINAL_SCROLLBAR_LEFT:
2337 		policy = GTK_POLICY_ALWAYS;
2338 		corner = GTK_CORNER_TOP_RIGHT;
2339 		break;
2340 	default:
2341 		g_assert_not_reached ();
2342 		break;
2343 	}
2344 
2345 	terminal_screen_container_set_placement (container, corner);
2346 	terminal_screen_container_set_policy (container, GTK_POLICY_NEVER, policy);
2347 }
2348 
2349 void
2350 terminal_screen_get_size (TerminalScreen *screen,
2351                           int       *width_chars,
2352                           int       *height_chars)
2353 {
2354 	VteTerminal *terminal = VTE_TERMINAL (screen);
2355 
2356 	*width_chars = vte_terminal_get_column_count (terminal);
2357 	*height_chars = vte_terminal_get_row_count (terminal);
2358 }
2359 
2360 void
2361 terminal_screen_get_cell_size (TerminalScreen *screen,
2362                                int                  *cell_width_pixels,
2363                                int                  *cell_height_pixels)
2364 {
2365 	VteTerminal *terminal = VTE_TERMINAL (screen);
2366 
2367 	*cell_width_pixels = vte_terminal_get_char_width (terminal);
2368 	*cell_height_pixels = vte_terminal_get_char_height (terminal);
2369 }
2370 
2371 #ifdef ENABLE_SKEY
2372 static void
2373 terminal_screen_skey_match_remove (TerminalScreen *screen)
2374 {
2375 	TerminalScreenPrivate *priv = screen->priv;
2376 	GSList *l, *next;
2377 
2378 	l = priv->match_tags;
2379 	while (l != NULL)
2380 	{
2381 		TagData *tag_data = (TagData *) l->data;
2382 
2383 		next = l->next;
2384 		if (tag_data->flavor == FLAVOR_SKEY)
2385 		{
2386 			vte_terminal_match_remove (VTE_TERMINAL (screen), tag_data->tag);
2387 			priv->match_tags = g_slist_delete_link (priv->match_tags, l);
2388 		}
2389 
2390 		l = next;
2391 	}
2392 }
2393 #endif /* ENABLE_SKEY */
2394 
2395 static void
2396 terminal_screen_url_match_remove (TerminalScreen *screen)
2397 {
2398 	TerminalScreenPrivate *priv = screen->priv;
2399 	GSList *l, *next;
2400 
2401 	l = priv->match_tags;
2402 	while (l != NULL)
2403 	{
2404 		TagData *tag_data = (TagData *) l->data;
2405 
2406 		next = l->next;
2407 #ifdef ENABLE_SKEY
2408 		if (tag_data->flavor != FLAVOR_SKEY)
2409 #endif
2410 		{
2411 			vte_terminal_match_remove (VTE_TERMINAL (screen), tag_data->tag);
2412 			priv->match_tags = g_slist_delete_link (priv->match_tags, l);
2413 		}
2414 
2415 		l = next;
2416 	}
2417 }
2418 
2419 static char*
2420 terminal_screen_check_match (TerminalScreen *screen,
2421                              GdkEvent  *event,
2422                              int       *flavor)
2423 {
2424 	TerminalScreenPrivate *priv = screen->priv;
2425 	GSList *tags;
2426 	int tag;
2427 	char *match;
2428 
2429 	match = vte_terminal_match_check_event (VTE_TERMINAL (screen), event, &tag);
2430 	for (tags = priv->match_tags; tags != NULL; tags = tags->next)
2431 	{
2432 		TagData *tag_data = (TagData*) tags->data;
2433 		if (tag_data->tag == tag)
2434 		{
2435 			if (flavor)
2436 				*flavor = tag_data->flavor;
2437 			return match;
2438 		}
2439 	}
2440 
2441 	g_free (match);
2442 	return NULL;
2443 }
2444 
2445 void
2446 terminal_screen_save_config (TerminalScreen *screen,
2447                              GKeyFile *key_file,
2448                              const char *group)
2449 {
2450 	TerminalScreenPrivate *priv = screen->priv;
2451 	VteTerminal *terminal = VTE_TERMINAL (screen);
2452 	TerminalProfile *profile = priv->profile;
2453 	const char *profile_id;
2454 	char *working_directory;
2455 
2456 	profile_id = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME);
2457 	g_key_file_set_string (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_PROFILE_ID, profile_id);
2458 
2459 	if (priv->override_command)
2460 		terminal_util_key_file_set_argv (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_COMMAND,
2461 		                                 -1, priv->override_command);
2462 
2463 	if (priv->override_title)
2464 		g_key_file_set_string (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_TITLE, priv->override_title);
2465 
2466 	/* FIXMEchpe: use the initial_working_directory instead?? */
2467 	working_directory = terminal_screen_get_current_dir (screen);
2468 	if (working_directory)
2469 		terminal_util_key_file_set_string_escape (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_WORKING_DIRECTORY, working_directory);
2470 	g_free (working_directory);
2471 
2472 	g_key_file_set_double (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_ZOOM, priv->font_scale);
2473 
2474 	g_key_file_set_integer (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_WIDTH,
2475 	                        vte_terminal_get_column_count (terminal));
2476 	g_key_file_set_integer (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_HEIGHT,
2477 	                        vte_terminal_get_row_count (terminal));
2478 }
2479 
2480 /**
2481  * terminal_screen_has_foreground_process:
2482  * @screen:
2483  *
2484  * Checks whether there's a foreground process running in
2485  * this terminal.
2486  *
2487  * Returns: %TRUE iff there's a foreground process running in @screen
2488  */
2489 gboolean
2490 terminal_screen_has_foreground_process (TerminalScreen *screen)
2491 {
2492 	TerminalScreenPrivate *priv = screen->priv;
2493 	VtePty *pty;
2494 	int fd;
2495 	int fgpid;
2496 
2497 	pty = vte_terminal_get_pty (VTE_TERMINAL (screen));
2498 	if (pty == NULL)
2499 		return FALSE;
2500 
2501 	fd = vte_pty_get_fd (pty);
2502 	if (fd == -1)
2503 		return FALSE;
2504 
2505 	fgpid = tcgetpgrp (fd);
2506 	if (fgpid == -1 || fgpid == priv->child_pid)
2507 		return FALSE;
2508 
2509 	return TRUE;
2510 
2511 #if 0
2512 	char *cmdline, *basename, *name;
2513 	gsize len;
2514 	char filename[64];
2515 
2516 	g_snprintf (filename, sizeof (filename), "/proc/%d/cmdline", fgpid);
2517 	if (!g_file_get_contents (filename, &cmdline, &len, NULL))
2518 		return TRUE;
2519 
2520 	basename = g_path_get_basename (cmdline);
2521 	g_free (cmdline);
2522 	if (!basename)
2523 		return TRUE;
2524 
2525 	name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
2526 	g_free (basename);
2527 	if (!name)
2528 		return TRUE;
2529 
2530 	if (process_name)
2531 		*process_name = name;
2532 
2533 	return TRUE;
2534 #endif
2535 }
2536