From f8a786c8f7878517aa695a69322bc9f2c8b92b6a Mon Sep 17 00:00:00 2001 From: Daniel Baumann Date: Sat, 27 Apr 2024 17:21:32 +0200 Subject: Adding upstream version 3.38.3. Signed-off-by: Daniel Baumann --- src/Makefile.am | 352 ++++ src/Makefile.in | 2446 ++++++++++++++++++++++++ src/eggshell.c | 112 ++ src/eggshell.h | 38 + src/gnome-terminal-search-provider.ini | 20 + src/nautilus.symbols | 3 + src/org.gnome.Terminal.gschema.xml | 724 +++++++ src/org.gnome.Terminal.xml | 43 + src/preferences.ui | 2453 ++++++++++++++++++++++++ src/profile-editor.c | 1444 ++++++++++++++ src/profile-editor.h | 37 + src/search-popover.ui | 251 +++ src/server.c | 191 ++ src/terminal-accels.c | 614 ++++++ src/terminal-accels.h | 37 + src/terminal-app.c | 1278 +++++++++++++ src/terminal-app.h | 117 ++ src/terminal-client-utils.c | 252 +++ src/terminal-client-utils.h | 54 + src/terminal-debug.c | 48 + src/terminal-debug.h | 76 + src/terminal-defines.h | 48 + src/terminal-enums.h | 69 + src/terminal-gdbus.c | 566 ++++++ src/terminal-gdbus.h | 90 + src/terminal-headerbar.c | 170 ++ src/terminal-headerbar.h | 40 + src/terminal-headerbar.ui | 111 ++ src/terminal-headermenu.ui | 119 ++ src/terminal-i18n.c | 31 + src/terminal-i18n.h | 29 + src/terminal-icon-button.c | 50 + src/terminal-icon-button.h | 33 + src/terminal-info-bar.c | 119 ++ src/terminal-info-bar.h | 61 + src/terminal-intl.h | 29 + src/terminal-libgsystem.h | 258 +++ src/terminal-marshal.list | 1 + src/terminal-mdi-container.c | 208 ++ src/terminal-mdi-container.h | 104 + src/terminal-menu-button.c | 147 ++ src/terminal-menu-button.h | 57 + src/terminal-menubar.ui.in | 248 +++ src/terminal-nautilus.c | 770 ++++++++ src/terminal-notebook-menu.ui | 49 + src/terminal-notebook.c | 593 ++++++ src/terminal-notebook.h | 62 + src/terminal-options.c | 1696 +++++++++++++++++ src/terminal-options.h | 193 ++ src/terminal-pcre2.h | 25 + src/terminal-prefs.c | 922 +++++++++ src/terminal-prefs.h | 55 + src/terminal-profiles-list.c | 267 +++ src/terminal-profiles-list.h | 53 + src/terminal-regex.c | 374 ++++ src/terminal-regex.h | 162 ++ src/terminal-schemas.h | 101 + src/terminal-screen-container.c | 391 ++++ src/terminal-screen-container.h | 64 + src/terminal-screen.c | 2324 +++++++++++++++++++++++ src/terminal-screen.h | 164 ++ src/terminal-search-popover.c | 580 ++++++ src/terminal-search-popover.h | 49 + src/terminal-search-provider.c | 379 ++++ src/terminal-search-provider.h | 51 + src/terminal-settings-list.c | 938 +++++++++ src/terminal-settings-list.h | 89 + src/terminal-tab-label.c | 391 ++++ src/terminal-tab-label.h | 66 + src/terminal-type-builtins.c.template | 45 + src/terminal-type-builtins.h.template | 25 + src/terminal-util.c | 1580 ++++++++++++++++ src/terminal-util.h | 117 ++ src/terminal-version.h | 34 + src/terminal-version.h.in | 34 + src/terminal-window.c | 3259 ++++++++++++++++++++++++++++++++ src/terminal-window.h | 97 + src/terminal-window.ui | 17 + src/terminal.about | 5 + src/terminal.c | 601 ++++++ src/terminal.common.css | 22 + src/terminal.gresource.xml | 31 + 82 files changed, 29853 insertions(+) create mode 100644 src/Makefile.am create mode 100644 src/Makefile.in create mode 100644 src/eggshell.c create mode 100644 src/eggshell.h create mode 100644 src/gnome-terminal-search-provider.ini create mode 100644 src/nautilus.symbols create mode 100644 src/org.gnome.Terminal.gschema.xml create mode 100644 src/org.gnome.Terminal.xml create mode 100644 src/preferences.ui create mode 100644 src/profile-editor.c create mode 100644 src/profile-editor.h create mode 100644 src/search-popover.ui create mode 100644 src/server.c create mode 100644 src/terminal-accels.c create mode 100644 src/terminal-accels.h create mode 100644 src/terminal-app.c create mode 100644 src/terminal-app.h create mode 100644 src/terminal-client-utils.c create mode 100644 src/terminal-client-utils.h create mode 100644 src/terminal-debug.c create mode 100644 src/terminal-debug.h create mode 100644 src/terminal-defines.h create mode 100644 src/terminal-enums.h create mode 100644 src/terminal-gdbus.c create mode 100644 src/terminal-gdbus.h create mode 100644 src/terminal-headerbar.c create mode 100644 src/terminal-headerbar.h create mode 100644 src/terminal-headerbar.ui create mode 100644 src/terminal-headermenu.ui create mode 100644 src/terminal-i18n.c create mode 100644 src/terminal-i18n.h create mode 100644 src/terminal-icon-button.c create mode 100644 src/terminal-icon-button.h create mode 100644 src/terminal-info-bar.c create mode 100644 src/terminal-info-bar.h create mode 100644 src/terminal-intl.h create mode 100644 src/terminal-libgsystem.h create mode 100644 src/terminal-marshal.list create mode 100644 src/terminal-mdi-container.c create mode 100644 src/terminal-mdi-container.h create mode 100644 src/terminal-menu-button.c create mode 100644 src/terminal-menu-button.h create mode 100644 src/terminal-menubar.ui.in create mode 100644 src/terminal-nautilus.c create mode 100644 src/terminal-notebook-menu.ui create mode 100644 src/terminal-notebook.c create mode 100644 src/terminal-notebook.h create mode 100644 src/terminal-options.c create mode 100644 src/terminal-options.h create mode 100644 src/terminal-pcre2.h create mode 100644 src/terminal-prefs.c create mode 100644 src/terminal-prefs.h create mode 100644 src/terminal-profiles-list.c create mode 100644 src/terminal-profiles-list.h create mode 100644 src/terminal-regex.c create mode 100644 src/terminal-regex.h create mode 100644 src/terminal-schemas.h create mode 100644 src/terminal-screen-container.c create mode 100644 src/terminal-screen-container.h create mode 100644 src/terminal-screen.c create mode 100644 src/terminal-screen.h create mode 100644 src/terminal-search-popover.c create mode 100644 src/terminal-search-popover.h create mode 100644 src/terminal-search-provider.c create mode 100644 src/terminal-search-provider.h create mode 100644 src/terminal-settings-list.c create mode 100644 src/terminal-settings-list.h create mode 100644 src/terminal-tab-label.c create mode 100644 src/terminal-tab-label.h create mode 100644 src/terminal-type-builtins.c.template create mode 100644 src/terminal-type-builtins.h.template create mode 100644 src/terminal-util.c create mode 100644 src/terminal-util.h create mode 100644 src/terminal-version.h create mode 100644 src/terminal-version.h.in create mode 100644 src/terminal-window.c create mode 100644 src/terminal-window.h create mode 100644 src/terminal-window.ui create mode 100644 src/terminal.about create mode 100644 src/terminal.c create mode 100644 src/terminal.common.css create mode 100644 src/terminal.gresource.xml (limited to 'src') diff --git a/src/Makefile.am b/src/Makefile.am new file mode 100644 index 0000000..2ea3d93 --- /dev/null +++ b/src/Makefile.am @@ -0,0 +1,352 @@ +NULL = + +BUILT_SOURCES = + +bin_PROGRAMS = gnome-terminal +libexec_PROGRAMS = gnome-terminal-server +noinst_PROGRAMS = + +check_PROGRAMS = terminal-regex + +if WITH_NAUTILUS_EXTENSION +nautilusextension_LTLIBRARIES = libterminal-nautilus.la +endif # WITH_NAUTILUS_EXTENSION + +# Terminal server + +dbusservice_DATA = org.gnome.Terminal.service + +# It is correct for this to be in ${prefix}/lib, even on systems where that +# does not match ${libdir}. This is what systemd uses on such platforms. +systemduserdir = $(prefix)/lib/systemd/user +nodist_systemduser_DATA = gnome-terminal-server.service + +gnome_terminal_server_built = \ + terminal-marshal.c \ + terminal-marshal.h \ + terminal-type-builtins.c \ + terminal-type-builtins.h \ + terminal-gdbus-generated.c \ + terminal-gdbus-generated.h \ + terminal-resources.c \ + terminal-resources.h \ + terminal-menubar-with-mnemonics.ui \ + terminal-menubar-without-mnemonics.ui \ + $(NULL) +BUILT_SOURCES += $(gnome_terminal_server_built) + +gnome_terminal_server_SOURCES = \ + eggshell.c \ + eggshell.h \ + profile-editor.c \ + profile-editor.h \ + server.c \ + terminal-accels.c \ + terminal-accels.h \ + terminal-app.c \ + terminal-app.h \ + terminal-debug.c \ + terminal-debug.h \ + terminal-defines.h \ + terminal-enums.h \ + terminal-gdbus.c \ + terminal-gdbus.h \ + terminal-headerbar.c \ + terminal-headerbar.h \ + terminal-icon-button.h \ + terminal-icon-button.c \ + terminal-info-bar.c \ + terminal-info-bar.h \ + terminal-intl.h \ + terminal-i18n.c \ + terminal-i18n.h \ + terminal-libgsystem.h \ + terminal-mdi-container.c \ + terminal-mdi-container.h \ + terminal-menu-button.h \ + terminal-menu-button.c \ + terminal-notebook.c \ + terminal-notebook.h \ + terminal-pcre2.h \ + terminal-prefs.c \ + terminal-prefs.h \ + terminal-profiles-list.c \ + terminal-profiles-list.h \ + terminal-regex.h \ + terminal-schemas.h \ + terminal-settings-list.c \ + terminal-settings-list.h \ + terminal-screen.c \ + terminal-screen.h \ + terminal-screen-container.c \ + terminal-screen-container.h \ + terminal-search-popover.c \ + terminal-search-popover.h \ + terminal-tab-label.c \ + terminal-tab-label.h \ + terminal-util.c \ + terminal-util.h \ + terminal-version.h \ + terminal-window.c \ + terminal-window.h \ + $(NULL) + +nodist_gnome_terminal_server_SOURCES = $(gnome_terminal_server_built) + +gnome_terminal_server_CPPFLAGS = \ + -DTERMINAL_COMPILATION \ + -DVTE_DISABLE_DEPRECATION_WARNINGS \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + $(AM_CPPFLAGS) + +gnome_terminal_server_CFLAGS = \ + $(TERM_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +gnome_terminal_server_LDFLAGS = \ + $(AM_LDFLAGS) + +gnome_terminal_server_LDADD = \ + $(TERM_LIBS) \ + $(PTHREAD_LIBS) \ + $(NULL) + +TYPES_H_FILES = \ + terminal-enums.h \ + $(NULL) + +terminal-type-builtins.h: stamp-terminal-type-builtins.h + @true + +stamp-terminal-type-builtins.h: terminal-type-builtins.h.template $(TYPES_H_FILES) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-ttbh \ + && (cmp -s xgen-ttbh terminal-type-builtins.h || cp xgen-ttbh terminal-type-builtins.h ) \ + && rm -f xgen-ttbh \ + && echo timestamp > $(@F) + +terminal-type-builtins.c: terminal-type-builtins.c.template $(TYPES_H_FILES) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-ttbc \ + && (cmp -s xgen-ttbc terminal-type-builtins.c || cp xgen-ttbc terminal-type-builtins.c ) \ + && rm -f xgen-ttbc + +terminal-marshal.h: $(srcdir)/terminal-marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \ + --header \ + --internal > terminal-marshal.h.tmp \ + && mv terminal-marshal.h.tmp terminal-marshal.h ) \ + || ( rm -f terminal-marshal.h.tmp && exit 1 ) + +terminal-marshal.c: $(srcdir)/terminal-marshal.list + $(AM_V_GEN) ( echo '#include "terminal-marshal.h"' > terminal-marshal.c.tmp && \ + $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \ + --body \ + --internal >> terminal-marshal.c.tmp \ + && mv terminal-marshal.c.tmp terminal-marshal.c ) \ + || ( rm -f terminal-marshal.c.tmp && exit 1 ) + +org.gnome.Terminal.service: Makefile + $(AM_V_GEN) ( echo "[D-BUS Service]"; \ + echo "Name=org.gnome.Terminal"; \ + echo "SystemdService=gnome-terminal-server.service"; \ + echo "Exec=${libexecdir}/gnome-terminal-server") > $@ + +gnome-terminal-server.service: Makefile + $(AM_V_GEN) ( echo "[Unit]"; \ + echo "Description=GNOME Terminal Server"; \ + echo "PartOf=graphical-session.target"; \ + echo "[Service]"; \ + echo "Slice=app-org.gnome.Terminal.slice"; \ + echo "Type=dbus"; \ + echo "BusName=org.gnome.Terminal"; \ + echo "ExecStart=${libexecdir}/gnome-terminal-server"; \ + echo "TimeoutStopSec=5s"; \ + echo "KillMode=process") > $@ + +terminal-gdbus-generated.c terminal-gdbus-generated.h: org.gnome.Terminal.xml Makefile + $(AM_V_GEN) $(GDBUS_CODEGEN) \ + --interface-prefix=org.gnome.Terminal \ + --c-namespace=Terminal \ + --c-generate-object-manager \ + --generate-c-code terminal-gdbus-generated \ + $< + +terminal-menubar-with-mnemonics.ui: terminal-menubar.ui.in + $(AM_V_GEN)$(SED) -e 's|||g' -e 's|||g' -e 's|||g' $< > $@ + +terminal-menubar-without-mnemonics.ui: terminal-menubar.ui.in + $(AM_V_GEN)$(SED) -e 's|||g' -e 's|||g' -e 's|||g' $< > $@ + +terminal-resources.h terminal-resources.c: terminal.gresource.xml Makefile $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir) --sourcedir $(builddir) $(srcdir)/terminal.gresource.xml) + $(AM_V_GEN) XMLLINT=$(XMLLINT) $(GLIB_COMPILE_RESOURCES) --target $@ --sourcedir $(builddir) --sourcedir $(srcdir) --generate --c-name terminal $< + +# Checks + +TESTS = \ + terminal-regex \ + $(NULL) + +# Check programmes + +terminal_regex_CPPFLAGS = \ + $(AM_CPPFLAGS) +terminal_regex_SOURCES = \ + terminal-regex.c \ + terminal-regex.h \ + $(NULL) +terminal_regex_CFLAGS = \ + -DTERMINAL_REGEX_MAIN \ + $(TERM_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) +terminal_regex_LDFLAGS = \ + $(AM_LDFLAGS) +terminal_regex_LDADD = \ + $(TERM_LIBS) + +# Legacy terminal client + +gnome_terminal_SOURCES = \ + terminal.c \ + terminal-client-utils.c \ + terminal-client-utils.h \ + terminal-debug.c \ + terminal-debug.h \ + terminal-defines.h \ + terminal-i18n.c \ + terminal-i18n.h \ + terminal-libgsystem.h \ + terminal-options.c \ + terminal-options.h \ + terminal-profiles-list.c \ + terminal-profiles-list.h \ + terminal-schemas.h \ + terminal-settings-list.c \ + terminal-settings-list.h \ + $(NULL) + +nodist_gnome_terminal_SOURCES = \ + terminal-gdbus-generated.c \ + terminal-gdbus-generated.h \ + terminal-type-builtins.c \ + terminal-type-builtins.h \ + $(NULL) + +gnome_terminal_CPPFLAGS = \ + -DTERMINAL_COMPILATION \ + -DTERMINAL_CLIENT \ + -DTERM_DATADIR="\"$(datadir)\"" \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + -DTERM_PKGDATADIR="\"$(pkgdatadir)\"" \ + $(AM_CPPFLAGS) + +gnome_terminal_CFLAGS = \ + $(TERM_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +gnome_terminal_LDFLAGS = \ + $(AM_LDFLAGS) + +gnome_terminal_LDADD = \ + $(TERM_LIBS) + +# Nautilus extension + +libterminal_nautilus_la_SOURCES = \ + terminal-client-utils.c \ + terminal-client-utils.h \ + terminal-defines.h \ + terminal-i18n.c \ + terminal-i18n.h \ + terminal-libgsystem.h \ + terminal-nautilus.c \ + $(NULL) + +nodist_libterminal_nautilus_la_SOURCES = \ + terminal-gdbus-generated.c \ + terminal-gdbus-generated.h \ + terminal-type-builtins.c \ + terminal-type-builtins.h \ + $(NULL) + +libterminal_nautilus_la_CPPFLAGS = \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + $(AM_CPPFLAGS) + +libterminal_nautilus_la_CFLAGS = \ + $(NAUTILUS_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +libterminal_nautilus_la_LDFLAGS = \ + -module -avoid-version \ + -export-symbols $(srcdir)/nautilus.symbols \ + $(AM_LDFLAGS) + +libterminal_nautilus_la_LIBADD = \ + $(NAUTILUS_LIBS) + +# GNOME Shell search provider + +if ENABLE_SEARCH_PROVIDER + +searchproviderdir = $(datadir)/gnome-shell/search-providers +dist_searchprovider_DATA = gnome-terminal-search-provider.ini + +gnome_terminal_server_built += \ + terminal-search-provider-gdbus-generated.c \ + terminal-search-provider-gdbus-generated.h \ + $(NULL) + +gnome_terminal_server_SOURCES += \ + terminal-search-provider.c \ + terminal-search-provider.h \ + $(NULL) + +terminal-search-provider-gdbus-generated.c terminal-search-provider-gdbus-generated.h: $(dbusinterfacedir)/org.gnome.ShellSearchProvider2.xml Makefile + $(AM_V_GEN) $(GDBUS_CODEGEN) \ + --interface-prefix=org.gnome.Shell \ + --c-namespace=Terminal \ + --generate-c-code terminal-search-provider-gdbus-generated \ + $< + +endif # ENABLE_SEARCH_PROVIDER + +gsettings_SCHEMAS = \ + org.gnome.Terminal.gschema.xml \ + $(NULL) + +CLEANFILES = \ + stamp-terminal-type-builtins.h \ + gnome-terminal.schemas \ + stamp-terminal-type-builtins.h \ + org.gnome.Terminal.service \ + gnome-terminal-server.service \ + $(BUILT_SOURCES) + +EXTRA_DIST = \ + terminal.about \ + terminal-headerbar.ui \ + terminal-headermenu.ui \ + terminal-menubar.ui.in \ + terminal-notebook-menu.ui \ + terminal-window.ui \ + terminal.gresource.xml \ + terminal-marshal.list \ + terminal-type-builtins.c.template \ + terminal-type-builtins.h.template \ + org.gnome.Terminal.xml \ + nautilus.symbols \ + search-popover.ui \ + preferences.ui \ + terminal.common.css \ + $(about_DATA) \ + $(builder_DATA) \ + $(gsettings_SCHEMAS) \ + $(NULL) + +@GSETTINGS_RULES@ + +-include $(top_srcdir)/git.mk diff --git a/src/Makefile.in b/src/Makefile.in new file mode 100644 index 0000000..d38c7d2 --- /dev/null +++ b/src/Makefile.in @@ -0,0 +1,2446 @@ +# Makefile.in generated by automake 1.16.2 from Makefile.am. +# @configure_input@ + +# Copyright (C) 1994-2020 Free Software Foundation, Inc. + +# This Makefile.in is free software; the Free Software Foundation +# gives unlimited permission to copy and/or distribute it, +# with or without modifications, as long as this notice is preserved. + +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY, to the extent permitted by law; without +# even the implied warranty of MERCHANTABILITY or FITNESS FOR A +# PARTICULAR PURPOSE. + +@SET_MAKE@ + + + +VPATH = @srcdir@ +am__is_gnu_make = { \ + if test -z '$(MAKELEVEL)'; then \ + false; \ + elif test -n '$(MAKE_HOST)'; then \ + true; \ + elif test -n '$(MAKE_VERSION)' && test -n '$(CURDIR)'; then \ + true; \ + else \ + false; \ + fi; \ +} +am__make_running_with_option = \ + case $${target_option-} in \ + ?) ;; \ + *) echo "am__make_running_with_option: internal error: invalid" \ + "target option '$${target_option-}' specified" >&2; \ + exit 1;; \ + esac; \ + has_opt=no; \ + sane_makeflags=$$MAKEFLAGS; \ + if $(am__is_gnu_make); then \ + sane_makeflags=$$MFLAGS; \ + else \ + case $$MAKEFLAGS in \ + *\\[\ \ ]*) \ + bs=\\; \ + sane_makeflags=`printf '%s\n' "$$MAKEFLAGS" \ + | sed "s/$$bs$$bs[$$bs $$bs ]*//g"`;; \ + esac; \ + fi; \ + skip_next=no; \ + strip_trailopt () \ + { \ + flg=`printf '%s\n' "$$flg" | sed "s/$$1.*$$//"`; \ + }; \ + for flg in $$sane_makeflags; do \ + test $$skip_next = yes && { skip_next=no; continue; }; \ + case $$flg in \ + *=*|--*) continue;; \ + -*I) strip_trailopt 'I'; skip_next=yes;; \ + -*I?*) strip_trailopt 'I';; \ + -*O) strip_trailopt 'O'; skip_next=yes;; \ + -*O?*) strip_trailopt 'O';; \ + -*l) strip_trailopt 'l'; skip_next=yes;; \ + -*l?*) strip_trailopt 'l';; \ + -[dEDm]) skip_next=yes;; \ + -[JT]) skip_next=yes;; \ + esac; \ + case $$flg in \ + *$$target_option*) has_opt=yes; break;; \ + esac; \ + done; \ + test $$has_opt = yes +am__make_dryrun = (target_option=n; $(am__make_running_with_option)) +am__make_keepgoing = (target_option=k; $(am__make_running_with_option)) +pkgdatadir = $(datadir)/@PACKAGE@ +pkgincludedir = $(includedir)/@PACKAGE@ +pkglibdir = $(libdir)/@PACKAGE@ +pkglibexecdir = $(libexecdir)/@PACKAGE@ +am__cd = CDPATH="$${ZSH_VERSION+.}$(PATH_SEPARATOR)" && cd +install_sh_DATA = $(install_sh) -c -m 644 +install_sh_PROGRAM = $(install_sh) -c +install_sh_SCRIPT = $(install_sh) -c +INSTALL_HEADER = $(INSTALL_DATA) +transform = $(program_transform_name) +NORMAL_INSTALL = : +PRE_INSTALL = : +POST_INSTALL = : +NORMAL_UNINSTALL = : +PRE_UNINSTALL = : +POST_UNINSTALL = : +build_triplet = @build@ +host_triplet = @host@ +bin_PROGRAMS = gnome-terminal$(EXEEXT) +libexec_PROGRAMS = gnome-terminal-server$(EXEEXT) +noinst_PROGRAMS = +check_PROGRAMS = terminal-regex$(EXEEXT) +TESTS = terminal-regex$(EXEEXT) $(am__EXEEXT_1) +@ENABLE_SEARCH_PROVIDER_TRUE@am__append_1 = \ +@ENABLE_SEARCH_PROVIDER_TRUE@ terminal-search-provider-gdbus-generated.c \ +@ENABLE_SEARCH_PROVIDER_TRUE@ terminal-search-provider-gdbus-generated.h \ +@ENABLE_SEARCH_PROVIDER_TRUE@ $(NULL) + +@ENABLE_SEARCH_PROVIDER_TRUE@am__append_2 = \ +@ENABLE_SEARCH_PROVIDER_TRUE@ terminal-search-provider.c \ +@ENABLE_SEARCH_PROVIDER_TRUE@ terminal-search-provider.h \ +@ENABLE_SEARCH_PROVIDER_TRUE@ $(NULL) + +subdir = src +ACLOCAL_M4 = $(top_srcdir)/aclocal.m4 +am__aclocal_m4_deps = $(top_srcdir)/m4/ax_pthread.m4 \ + $(top_srcdir)/m4/gettext.m4 $(top_srcdir)/m4/iconv.m4 \ + $(top_srcdir)/m4/intlmacosx.m4 $(top_srcdir)/m4/lib-ld.m4 \ + $(top_srcdir)/m4/lib-link.m4 $(top_srcdir)/m4/lib-prefix.m4 \ + $(top_srcdir)/m4/libtool.m4 $(top_srcdir)/m4/ltoptions.m4 \ + $(top_srcdir)/m4/ltsugar.m4 $(top_srcdir)/m4/ltversion.m4 \ + $(top_srcdir)/m4/lt~obsolete.m4 $(top_srcdir)/m4/nls.m4 \ + $(top_srcdir)/m4/po.m4 $(top_srcdir)/m4/progtest.m4 \ + $(top_srcdir)/acinclude.m4 $(top_srcdir)/configure.ac +am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \ + $(ACLOCAL_M4) +DIST_COMMON = $(srcdir)/Makefile.am \ + $(am__dist_searchprovider_DATA_DIST) $(am__DIST_COMMON) +mkinstalldirs = $(install_sh) -d +CONFIG_HEADER = $(top_builddir)/config.h +CONFIG_CLEAN_FILES = terminal-version.h +CONFIG_CLEAN_VPATH_FILES = +am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" \ + "$(DESTDIR)$(nautilusextensiondir)" \ + "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(searchproviderdir)" \ + "$(DESTDIR)$(systemduserdir)" +PROGRAMS = $(bin_PROGRAMS) $(libexec_PROGRAMS) $(noinst_PROGRAMS) +am__vpath_adj_setup = srcdirstrip=`echo "$(srcdir)" | sed 's|.|.|g'`; +am__vpath_adj = case $$p in \ + $(srcdir)/*) f=`echo "$$p" | sed "s|^$$srcdirstrip/||"`;; \ + *) f=$$p;; \ + esac; +am__strip_dir = f=`echo $$p | sed -e 's|^.*/||'`; +am__install_max = 40 +am__nobase_strip_setup = \ + srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*|]/\\\\&/g'` +am__nobase_strip = \ + for p in $$list; do echo "$$p"; done | sed -e "s|$$srcdirstrip/||" +am__nobase_list = $(am__nobase_strip_setup); \ + for p in $$list; do echo "$$p $$p"; done | \ + sed "s| $$srcdirstrip/| |;"' / .*\//!s/ .*/ ./; s,\( .*\)/[^/]*$$,\1,' | \ + $(AWK) 'BEGIN { files["."] = "" } { files[$$2] = files[$$2] " " $$1; \ + if (++n[$$2] == $(am__install_max)) \ + { print $$2, files[$$2]; n[$$2] = 0; files[$$2] = "" } } \ + END { for (dir in files) print dir, files[dir] }' +am__base_list = \ + sed '$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;$$!N;s/\n/ /g' | \ + sed '$$!N;$$!N;$$!N;$$!N;s/\n/ /g' +am__uninstall_files_from_dir = { \ + test -z "$$files" \ + || { test ! -d "$$dir" && test ! -f "$$dir" && test ! -r "$$dir"; } \ + || { echo " ( cd '$$dir' && rm -f" $$files ")"; \ + $(am__cd) "$$dir" && rm -f $$files; }; \ + } +LTLIBRARIES = $(nautilusextension_LTLIBRARIES) +am__DEPENDENCIES_1 = +libterminal_nautilus_la_DEPENDENCIES = $(am__DEPENDENCIES_1) +am__objects_1 = +am_libterminal_nautilus_la_OBJECTS = \ + libterminal_nautilus_la-terminal-client-utils.lo \ + libterminal_nautilus_la-terminal-i18n.lo \ + libterminal_nautilus_la-terminal-nautilus.lo $(am__objects_1) +nodist_libterminal_nautilus_la_OBJECTS = \ + libterminal_nautilus_la-terminal-gdbus-generated.lo \ + libterminal_nautilus_la-terminal-type-builtins.lo \ + $(am__objects_1) +libterminal_nautilus_la_OBJECTS = \ + $(am_libterminal_nautilus_la_OBJECTS) \ + $(nodist_libterminal_nautilus_la_OBJECTS) +AM_V_lt = $(am__v_lt_@AM_V@) +am__v_lt_ = $(am__v_lt_@AM_DEFAULT_V@) +am__v_lt_0 = --silent +am__v_lt_1 = +libterminal_nautilus_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) \ + $(libterminal_nautilus_la_LDFLAGS) $(LDFLAGS) -o $@ +@WITH_NAUTILUS_EXTENSION_TRUE@am_libterminal_nautilus_la_rpath = \ +@WITH_NAUTILUS_EXTENSION_TRUE@ -rpath $(nautilusextensiondir) +am_gnome_terminal_OBJECTS = gnome_terminal-terminal.$(OBJEXT) \ + gnome_terminal-terminal-client-utils.$(OBJEXT) \ + gnome_terminal-terminal-debug.$(OBJEXT) \ + gnome_terminal-terminal-i18n.$(OBJEXT) \ + gnome_terminal-terminal-options.$(OBJEXT) \ + gnome_terminal-terminal-profiles-list.$(OBJEXT) \ + gnome_terminal-terminal-settings-list.$(OBJEXT) \ + $(am__objects_1) +nodist_gnome_terminal_OBJECTS = \ + gnome_terminal-terminal-gdbus-generated.$(OBJEXT) \ + gnome_terminal-terminal-type-builtins.$(OBJEXT) \ + $(am__objects_1) +gnome_terminal_OBJECTS = $(am_gnome_terminal_OBJECTS) \ + $(nodist_gnome_terminal_OBJECTS) +gnome_terminal_DEPENDENCIES = $(am__DEPENDENCIES_1) +gnome_terminal_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(gnome_terminal_CFLAGS) $(CFLAGS) $(gnome_terminal_LDFLAGS) \ + $(LDFLAGS) -o $@ +am__gnome_terminal_server_SOURCES_DIST = eggshell.c eggshell.h \ + profile-editor.c profile-editor.h server.c terminal-accels.c \ + terminal-accels.h terminal-app.c terminal-app.h \ + terminal-debug.c terminal-debug.h terminal-defines.h \ + terminal-enums.h terminal-gdbus.c terminal-gdbus.h \ + terminal-headerbar.c terminal-headerbar.h \ + terminal-icon-button.h terminal-icon-button.c \ + terminal-info-bar.c terminal-info-bar.h terminal-intl.h \ + terminal-i18n.c terminal-i18n.h terminal-libgsystem.h \ + terminal-mdi-container.c terminal-mdi-container.h \ + terminal-menu-button.h terminal-menu-button.c \ + terminal-notebook.c terminal-notebook.h terminal-pcre2.h \ + terminal-prefs.c terminal-prefs.h terminal-profiles-list.c \ + terminal-profiles-list.h terminal-regex.h terminal-schemas.h \ + terminal-settings-list.c terminal-settings-list.h \ + terminal-screen.c terminal-screen.h \ + terminal-screen-container.c terminal-screen-container.h \ + terminal-search-popover.c terminal-search-popover.h \ + terminal-tab-label.c terminal-tab-label.h terminal-util.c \ + terminal-util.h terminal-version.h terminal-window.c \ + terminal-window.h terminal-search-provider.c \ + terminal-search-provider.h +@ENABLE_SEARCH_PROVIDER_TRUE@am__objects_2 = gnome_terminal_server-terminal-search-provider.$(OBJEXT) \ +@ENABLE_SEARCH_PROVIDER_TRUE@ $(am__objects_1) +am_gnome_terminal_server_OBJECTS = \ + gnome_terminal_server-eggshell.$(OBJEXT) \ + gnome_terminal_server-profile-editor.$(OBJEXT) \ + gnome_terminal_server-server.$(OBJEXT) \ + gnome_terminal_server-terminal-accels.$(OBJEXT) \ + gnome_terminal_server-terminal-app.$(OBJEXT) \ + gnome_terminal_server-terminal-debug.$(OBJEXT) \ + gnome_terminal_server-terminal-gdbus.$(OBJEXT) \ + gnome_terminal_server-terminal-headerbar.$(OBJEXT) \ + gnome_terminal_server-terminal-icon-button.$(OBJEXT) \ + gnome_terminal_server-terminal-info-bar.$(OBJEXT) \ + gnome_terminal_server-terminal-i18n.$(OBJEXT) \ + gnome_terminal_server-terminal-mdi-container.$(OBJEXT) \ + gnome_terminal_server-terminal-menu-button.$(OBJEXT) \ + gnome_terminal_server-terminal-notebook.$(OBJEXT) \ + gnome_terminal_server-terminal-prefs.$(OBJEXT) \ + gnome_terminal_server-terminal-profiles-list.$(OBJEXT) \ + gnome_terminal_server-terminal-settings-list.$(OBJEXT) \ + gnome_terminal_server-terminal-screen.$(OBJEXT) \ + gnome_terminal_server-terminal-screen-container.$(OBJEXT) \ + gnome_terminal_server-terminal-search-popover.$(OBJEXT) \ + gnome_terminal_server-terminal-tab-label.$(OBJEXT) \ + gnome_terminal_server-terminal-util.$(OBJEXT) \ + gnome_terminal_server-terminal-window.$(OBJEXT) \ + $(am__objects_1) $(am__objects_2) +@ENABLE_SEARCH_PROVIDER_TRUE@am__objects_3 = gnome_terminal_server-terminal-search-provider-gdbus-generated.$(OBJEXT) \ +@ENABLE_SEARCH_PROVIDER_TRUE@ $(am__objects_1) +am__objects_4 = gnome_terminal_server-terminal-marshal.$(OBJEXT) \ + gnome_terminal_server-terminal-type-builtins.$(OBJEXT) \ + gnome_terminal_server-terminal-gdbus-generated.$(OBJEXT) \ + gnome_terminal_server-terminal-resources.$(OBJEXT) \ + $(am__objects_1) $(am__objects_3) +nodist_gnome_terminal_server_OBJECTS = $(am__objects_4) +gnome_terminal_server_OBJECTS = $(am_gnome_terminal_server_OBJECTS) \ + $(nodist_gnome_terminal_server_OBJECTS) +gnome_terminal_server_DEPENDENCIES = $(am__DEPENDENCIES_1) \ + $(am__DEPENDENCIES_1) $(am__DEPENDENCIES_1) +gnome_terminal_server_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(gnome_terminal_server_CFLAGS) $(CFLAGS) \ + $(gnome_terminal_server_LDFLAGS) $(LDFLAGS) -o $@ +am_terminal_regex_OBJECTS = terminal_regex-terminal-regex.$(OBJEXT) \ + $(am__objects_1) +terminal_regex_OBJECTS = $(am_terminal_regex_OBJECTS) +terminal_regex_DEPENDENCIES = $(am__DEPENDENCIES_1) +terminal_regex_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC \ + $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=link $(CCLD) \ + $(terminal_regex_CFLAGS) $(CFLAGS) $(terminal_regex_LDFLAGS) \ + $(LDFLAGS) -o $@ +AM_V_P = $(am__v_P_@AM_V@) +am__v_P_ = $(am__v_P_@AM_DEFAULT_V@) +am__v_P_0 = false +am__v_P_1 = : +AM_V_GEN = $(am__v_GEN_@AM_V@) +am__v_GEN_ = $(am__v_GEN_@AM_DEFAULT_V@) +am__v_GEN_0 = @echo " GEN " $@; +am__v_GEN_1 = +AM_V_at = $(am__v_at_@AM_V@) +am__v_at_ = $(am__v_at_@AM_DEFAULT_V@) +am__v_at_0 = @ +am__v_at_1 = +DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir) +depcomp = $(SHELL) $(top_srcdir)/depcomp +am__maybe_remake_depfiles = depfiles +am__depfiles_remade = \ + ./$(DEPDIR)/gnome_terminal-terminal-client-utils.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-debug.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-i18n.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-options.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-profiles-list.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-settings-list.Po \ + ./$(DEPDIR)/gnome_terminal-terminal-type-builtins.Po \ + ./$(DEPDIR)/gnome_terminal-terminal.Po \ + ./$(DEPDIR)/gnome_terminal_server-eggshell.Po \ + ./$(DEPDIR)/gnome_terminal_server-profile-editor.Po \ + ./$(DEPDIR)/gnome_terminal_server-server.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-accels.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-app.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-debug.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-i18n.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-marshal.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-notebook.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-prefs.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-resources.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-screen.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-util.Po \ + ./$(DEPDIR)/gnome_terminal_server-terminal-window.Po \ + ./$(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Plo \ + ./$(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Plo \ + ./$(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Plo \ + ./$(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Plo \ + ./$(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Plo \ + ./$(DEPDIR)/terminal_regex-terminal-regex.Po +am__mv = mv -f +COMPILE = $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) \ + $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) +LTCOMPILE = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) \ + $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) \ + $(AM_CFLAGS) $(CFLAGS) +AM_V_CC = $(am__v_CC_@AM_V@) +am__v_CC_ = $(am__v_CC_@AM_DEFAULT_V@) +am__v_CC_0 = @echo " CC " $@; +am__v_CC_1 = +CCLD = $(CC) +LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \ + $(LIBTOOLFLAGS) --mode=link $(CCLD) $(AM_CFLAGS) $(CFLAGS) \ + $(AM_LDFLAGS) $(LDFLAGS) -o $@ +AM_V_CCLD = $(am__v_CCLD_@AM_V@) +am__v_CCLD_ = $(am__v_CCLD_@AM_DEFAULT_V@) +am__v_CCLD_0 = @echo " CCLD " $@; +am__v_CCLD_1 = +SOURCES = $(libterminal_nautilus_la_SOURCES) \ + $(nodist_libterminal_nautilus_la_SOURCES) \ + $(gnome_terminal_SOURCES) $(nodist_gnome_terminal_SOURCES) \ + $(gnome_terminal_server_SOURCES) \ + $(nodist_gnome_terminal_server_SOURCES) \ + $(terminal_regex_SOURCES) +DIST_SOURCES = $(libterminal_nautilus_la_SOURCES) \ + $(gnome_terminal_SOURCES) \ + $(am__gnome_terminal_server_SOURCES_DIST) \ + $(terminal_regex_SOURCES) +am__can_run_installinfo = \ + case $$AM_UPDATE_INFO_DIR in \ + n|no|NO) false;; \ + *) (install-info --version) >/dev/null 2>&1;; \ + esac +am__dist_searchprovider_DATA_DIST = \ + gnome-terminal-search-provider.ini +DATA = $(dbusservice_DATA) $(dist_searchprovider_DATA) \ + $(nodist_systemduser_DATA) +am__tagged_files = $(HEADERS) $(SOURCES) $(TAGS_FILES) $(LISP) +# Read a list of newline-separated strings from the standard input, +# and print each of them once, without duplicates. Input order is +# *not* preserved. +am__uniquify_input = $(AWK) '\ + BEGIN { nonempty = 0; } \ + { items[$$0] = 1; nonempty = 1; } \ + END { if (nonempty) { for (i in items) print i; }; } \ +' +# Make sure the list of sources is unique. This is necessary because, +# e.g., the same source file might be shared among _SOURCES variables +# for different programs/libraries. +am__define_uniq_tagged_files = \ + list='$(am__tagged_files)'; \ + unique=`for i in $$list; do \ + if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \ + done | $(am__uniquify_input)` +ETAGS = etags +CTAGS = ctags +am__tty_colors_dummy = \ + mgn= red= grn= lgn= blu= brg= std=; \ + am__color_tests=no +am__tty_colors = { \ + $(am__tty_colors_dummy); \ + if test "X$(AM_COLOR_TESTS)" = Xno; then \ + am__color_tests=no; \ + elif test "X$(AM_COLOR_TESTS)" = Xalways; then \ + am__color_tests=yes; \ + elif test "X$$TERM" != Xdumb && { test -t 1; } 2>/dev/null; then \ + am__color_tests=yes; \ + fi; \ + if test $$am__color_tests = yes; then \ + red=''; \ + grn=''; \ + lgn=''; \ + blu=''; \ + mgn=''; \ + brg=''; \ + std=''; \ + fi; \ +} +am__recheck_rx = ^[ ]*:recheck:[ ]* +am__global_test_result_rx = ^[ ]*:global-test-result:[ ]* +am__copy_in_global_log_rx = ^[ ]*:copy-in-global-log:[ ]* +# A command that, given a newline-separated list of test names on the +# standard input, print the name of the tests that are to be re-run +# upon "make recheck". +am__list_recheck_tests = $(AWK) '{ \ + recheck = 1; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + { \ + if ((getline line2 < ($$0 ".log")) < 0) \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[nN][Oo]/) \ + { \ + recheck = 0; \ + break; \ + } \ + else if (line ~ /$(am__recheck_rx)[yY][eE][sS]/) \ + { \ + break; \ + } \ + }; \ + if (recheck) \ + print $$0; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# A command that, given a newline-separated list of test names on the +# standard input, create the global log from their .trs and .log files. +am__create_global_log = $(AWK) ' \ +function fatal(msg) \ +{ \ + print "fatal: making $@: " msg | "cat >&2"; \ + exit 1; \ +} \ +function rst_section(header) \ +{ \ + print header; \ + len = length(header); \ + for (i = 1; i <= len; i = i + 1) \ + printf "="; \ + printf "\n\n"; \ +} \ +{ \ + copy_in_global_log = 1; \ + global_test_result = "RUN"; \ + while ((rc = (getline line < ($$0 ".trs"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".trs"); \ + if (line ~ /$(am__global_test_result_rx)/) \ + { \ + sub("$(am__global_test_result_rx)", "", line); \ + sub("[ ]*$$", "", line); \ + global_test_result = line; \ + } \ + else if (line ~ /$(am__copy_in_global_log_rx)[nN][oO]/) \ + copy_in_global_log = 0; \ + }; \ + if (copy_in_global_log) \ + { \ + rst_section(global_test_result ": " $$0); \ + while ((rc = (getline line < ($$0 ".log"))) != 0) \ + { \ + if (rc < 0) \ + fatal("failed to read from " $$0 ".log"); \ + print line; \ + }; \ + printf "\n"; \ + }; \ + close ($$0 ".trs"); \ + close ($$0 ".log"); \ +}' +# Restructured Text title. +am__rst_title = { sed 's/.*/ & /;h;s/./=/g;p;x;s/ *$$//;p;g' && echo; } +# Solaris 10 'make', and several other traditional 'make' implementations, +# pass "-e" to $(SHELL), and POSIX 2008 even requires this. Work around it +# by disabling -e (using the XSI extension "set +e") if it's set. +am__sh_e_setup = case $$- in *e*) set +e;; esac +# Default flags passed to test drivers. +am__common_driver_flags = \ + --color-tests "$$am__color_tests" \ + --enable-hard-errors "$$am__enable_hard_errors" \ + --expect-failure "$$am__expect_failure" +# To be inserted before the command running the test. Creates the +# directory for the log if needed. Stores in $dir the directory +# containing $f, in $tst the test, in $log the log. Executes the +# developer- defined test setup AM_TESTS_ENVIRONMENT (if any), and +# passes TESTS_ENVIRONMENT. Set up options for the wrapper that +# will run the test scripts (or their associated LOG_COMPILER, if +# thy have one). +am__check_pre = \ +$(am__sh_e_setup); \ +$(am__vpath_adj_setup) $(am__vpath_adj) \ +$(am__tty_colors); \ +srcdir=$(srcdir); export srcdir; \ +case "$@" in \ + */*) am__odir=`echo "./$@" | sed 's|/[^/]*$$||'`;; \ + *) am__odir=.;; \ +esac; \ +test "x$$am__odir" = x"." || test -d "$$am__odir" \ + || $(MKDIR_P) "$$am__odir" || exit $$?; \ +if test -f "./$$f"; then dir=./; \ +elif test -f "$$f"; then dir=; \ +else dir="$(srcdir)/"; fi; \ +tst=$$dir$$f; log='$@'; \ +if test -n '$(DISABLE_HARD_ERRORS)'; then \ + am__enable_hard_errors=no; \ +else \ + am__enable_hard_errors=yes; \ +fi; \ +case " $(XFAIL_TESTS) " in \ + *[\ \ ]$$f[\ \ ]* | *[\ \ ]$$dir$$f[\ \ ]*) \ + am__expect_failure=yes;; \ + *) \ + am__expect_failure=no;; \ +esac; \ +$(AM_TESTS_ENVIRONMENT) $(TESTS_ENVIRONMENT) +# A shell command to get the names of the tests scripts with any registered +# extension removed (i.e., equivalently, the names of the test logs, with +# the '.log' extension removed). The result is saved in the shell variable +# '$bases'. This honors runtime overriding of TESTS and TEST_LOGS. Sadly, +# we cannot use something simpler, involving e.g., "$(TEST_LOGS:.log=)", +# since that might cause problem with VPATH rewrites for suffix-less tests. +# See also 'test-harness-vpath-rewrite.sh' and 'test-trs-basic.sh'. +am__set_TESTS_bases = \ + bases='$(TEST_LOGS)'; \ + bases=`for i in $$bases; do echo $$i; done | sed 's/\.log$$//'`; \ + bases=`echo $$bases` +RECHECK_LOGS = $(TEST_LOGS) +AM_RECURSIVE_TARGETS = check recheck +am__EXEEXT_1 = +TEST_SUITE_LOG = test-suite.log +TEST_EXTENSIONS = @EXEEXT@ .test +LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +LOG_COMPILE = $(LOG_COMPILER) $(AM_LOG_FLAGS) $(LOG_FLAGS) +am__set_b = \ + case '$@' in \ + */*) \ + case '$*' in \ + */*) b='$*';; \ + *) b=`echo '$@' | sed 's/\.log$$//'`; \ + esac;; \ + *) \ + b='$*';; \ + esac +am__test_logs1 = $(TESTS:=.log) +am__test_logs2 = $(am__test_logs1:@EXEEXT@.log=.log) +TEST_LOGS = $(am__test_logs2:.test.log=.log) +TEST_LOG_DRIVER = $(SHELL) $(top_srcdir)/test-driver +TEST_LOG_COMPILE = $(TEST_LOG_COMPILER) $(AM_TEST_LOG_FLAGS) \ + $(TEST_LOG_FLAGS) +am__DIST_COMMON = $(srcdir)/Makefile.in \ + $(srcdir)/terminal-version.h.in $(top_srcdir)/depcomp \ + $(top_srcdir)/test-driver +DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST) +ACLOCAL = @ACLOCAL@ +AMTAR = @AMTAR@ +AM_CFLAGS = @AM_CFLAGS@ +AM_CPPFLAGS = @AM_CPPFLAGS@ +AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@ +AM_LDFLAGS = @AM_LDFLAGS@ +AR = @AR@ +AUTOCONF = @AUTOCONF@ +AUTOHEADER = @AUTOHEADER@ +AUTOMAKE = @AUTOMAKE@ +AWK = @AWK@ +CC = @CC@ +CCDEPMODE = @CCDEPMODE@ +CFLAGS = @CFLAGS@ +CPP = @CPP@ +CPPFLAGS = @CPPFLAGS@ +CYGPATH_W = @CYGPATH_W@ +DEFS = @DEFS@ +DEPDIR = @DEPDIR@ +DESKTOP_FILE_VALIDATE = @DESKTOP_FILE_VALIDATE@ +DLLTOOL = @DLLTOOL@ +DSYMUTIL = @DSYMUTIL@ +DUMPBIN = @DUMPBIN@ +ECHO_C = @ECHO_C@ +ECHO_N = @ECHO_N@ +ECHO_T = @ECHO_T@ +EGREP = @EGREP@ +EXEEXT = @EXEEXT@ +FGREP = @FGREP@ +GDBUS_CODEGEN = @GDBUS_CODEGEN@ +GETTEXT_MACRO_VERSION = @GETTEXT_MACRO_VERSION@ +GETTEXT_PACKAGE = @GETTEXT_PACKAGE@ +GLIB_COMPILE_RESOURCES = @GLIB_COMPILE_RESOURCES@ +GLIB_COMPILE_SCHEMAS = @GLIB_COMPILE_SCHEMAS@ +GLIB_GENMARSHAL = @GLIB_GENMARSHAL@ +GLIB_MKENUMS = @GLIB_MKENUMS@ +GMSGFMT = @GMSGFMT@ +GMSGFMT_015 = @GMSGFMT_015@ +GREP = @GREP@ +GSETTINGS_DISABLE_SCHEMAS_COMPILE = @GSETTINGS_DISABLE_SCHEMAS_COMPILE@ +GTK_API_VERSION = @GTK_API_VERSION@ +HELP_DIR = @HELP_DIR@ +INSTALL = @INSTALL@ +INSTALL_DATA = @INSTALL_DATA@ +INSTALL_PROGRAM = @INSTALL_PROGRAM@ +INSTALL_SCRIPT = @INSTALL_SCRIPT@ +INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@ +INTLLIBS = @INTLLIBS@ +INTL_MACOSX_LIBS = @INTL_MACOSX_LIBS@ +ITSTOOL = @ITSTOOL@ +LD = @LD@ +LDFLAGS = @LDFLAGS@ +LIBICONV = @LIBICONV@ +LIBINTL = @LIBINTL@ +LIBOBJS = @LIBOBJS@ +LIBS = @LIBS@ +LIBTOOL = @LIBTOOL@ +LIPO = @LIPO@ +LN_S = @LN_S@ +LTLIBICONV = @LTLIBICONV@ +LTLIBINTL = @LTLIBINTL@ +LTLIBOBJS = @LTLIBOBJS@ +LT_SYS_LIBRARY_PATH = @LT_SYS_LIBRARY_PATH@ +MAINT = @MAINT@ +MAKEINFO = @MAKEINFO@ +MANIFEST_TOOL = @MANIFEST_TOOL@ +MKDIR_P = @MKDIR_P@ +MSGFMT = @MSGFMT@ +MSGFMT_015 = @MSGFMT_015@ +MSGMERGE = @MSGMERGE@ +NAUTILUS_CFLAGS = @NAUTILUS_CFLAGS@ +NAUTILUS_LIBS = @NAUTILUS_LIBS@ +NM = @NM@ +NMEDIT = @NMEDIT@ +OBJDUMP = @OBJDUMP@ +OBJEXT = @OBJEXT@ +OTOOL = @OTOOL@ +OTOOL64 = @OTOOL64@ +PACKAGE = @PACKAGE@ +PACKAGE_BUGREPORT = @PACKAGE_BUGREPORT@ +PACKAGE_NAME = @PACKAGE_NAME@ +PACKAGE_STRING = @PACKAGE_STRING@ +PACKAGE_TARNAME = @PACKAGE_TARNAME@ +PACKAGE_URL = @PACKAGE_URL@ +PACKAGE_VERSION = @PACKAGE_VERSION@ +PATH_SEPARATOR = @PATH_SEPARATOR@ +PKG_CONFIG = @PKG_CONFIG@ +PKG_CONFIG_LIBDIR = @PKG_CONFIG_LIBDIR@ +PKG_CONFIG_PATH = @PKG_CONFIG_PATH@ +POSUB = @POSUB@ +PTHREAD_CC = @PTHREAD_CC@ +PTHREAD_CFLAGS = @PTHREAD_CFLAGS@ +PTHREAD_LIBS = @PTHREAD_LIBS@ +RANLIB = @RANLIB@ +SED = @SED@ +SET_MAKE = @SET_MAKE@ +SHELL = @SHELL@ +STRIP = @STRIP@ +TERMINAL_API_VERSION = @TERMINAL_API_VERSION@ +TERMINAL_MAJOR_VERSION = @TERMINAL_MAJOR_VERSION@ +TERMINAL_MICRO_VERSION = @TERMINAL_MICRO_VERSION@ +TERMINAL_MINOR_VERSION = @TERMINAL_MINOR_VERSION@ +TERM_CFLAGS = @TERM_CFLAGS@ +TERM_LIBS = @TERM_LIBS@ +USE_NLS = @USE_NLS@ +VERSION = @VERSION@ +WARN_CFLAGS = @WARN_CFLAGS@ +XGETTEXT = @XGETTEXT@ +XGETTEXT_015 = @XGETTEXT_015@ +XGETTEXT_EXTRA_OPTIONS = @XGETTEXT_EXTRA_OPTIONS@ +XMLLINT = @XMLLINT@ +XSLTPROC = @XSLTPROC@ +YELP_LC_DIST = @YELP_LC_DIST@ +YELP_LC_MEDIA_LINKS = @YELP_LC_MEDIA_LINKS@ +abs_builddir = @abs_builddir@ +abs_srcdir = @abs_srcdir@ +abs_top_builddir = @abs_top_builddir@ +abs_top_srcdir = @abs_top_srcdir@ +ac_ct_AR = @ac_ct_AR@ +ac_ct_CC = @ac_ct_CC@ +ac_ct_DUMPBIN = @ac_ct_DUMPBIN@ +am__include = @am__include@ +am__leading_dot = @am__leading_dot@ +am__quote = @am__quote@ +am__tar = @am__tar@ +am__untar = @am__untar@ +ax_pthread_config = @ax_pthread_config@ +bindir = @bindir@ +build = @build@ +build_alias = @build_alias@ +build_cpu = @build_cpu@ +build_os = @build_os@ +build_vendor = @build_vendor@ +builddir = @builddir@ +datadir = @datadir@ +datarootdir = @datarootdir@ +dbusinterfacedir = @dbusinterfacedir@ +dbusservicedir = @dbusservicedir@ +docdir = @docdir@ +dvidir = @dvidir@ +exec_prefix = @exec_prefix@ +gsettingsschemadir = @gsettingsschemadir@ +host = @host@ +host_alias = @host_alias@ +host_cpu = @host_cpu@ +host_os = @host_os@ +host_vendor = @host_vendor@ +htmldir = @htmldir@ +includedir = @includedir@ +infodir = @infodir@ +install_sh = @install_sh@ +libdir = @libdir@ +libexecdir = @libexecdir@ +localedir = @localedir@ +localstatedir = @localstatedir@ +mandir = @mandir@ +mkdir_p = @mkdir_p@ +nautilusextensiondir = @nautilusextensiondir@ +oldincludedir = @oldincludedir@ +pdfdir = @pdfdir@ +prefix = @prefix@ +program_transform_name = @program_transform_name@ +psdir = @psdir@ +sbindir = @sbindir@ +sharedstatedir = @sharedstatedir@ +srcdir = @srcdir@ +sysconfdir = @sysconfdir@ +target_alias = @target_alias@ +top_build_prefix = @top_build_prefix@ +top_builddir = @top_builddir@ +top_srcdir = @top_srcdir@ +NULL = +BUILT_SOURCES = $(gnome_terminal_server_built) +@WITH_NAUTILUS_EXTENSION_TRUE@nautilusextension_LTLIBRARIES = libterminal-nautilus.la + +# Terminal server +dbusservice_DATA = org.gnome.Terminal.service + +# It is correct for this to be in ${prefix}/lib, even on systems where that +# does not match ${libdir}. This is what systemd uses on such platforms. +systemduserdir = $(prefix)/lib/systemd/user +nodist_systemduser_DATA = gnome-terminal-server.service +gnome_terminal_server_built = terminal-marshal.c terminal-marshal.h \ + terminal-type-builtins.c terminal-type-builtins.h \ + terminal-gdbus-generated.c terminal-gdbus-generated.h \ + terminal-resources.c terminal-resources.h \ + terminal-menubar-with-mnemonics.ui \ + terminal-menubar-without-mnemonics.ui $(NULL) $(am__append_1) +gnome_terminal_server_SOURCES = eggshell.c eggshell.h profile-editor.c \ + profile-editor.h server.c terminal-accels.c terminal-accels.h \ + terminal-app.c terminal-app.h terminal-debug.c \ + terminal-debug.h terminal-defines.h terminal-enums.h \ + terminal-gdbus.c terminal-gdbus.h terminal-headerbar.c \ + terminal-headerbar.h terminal-icon-button.h \ + terminal-icon-button.c terminal-info-bar.c terminal-info-bar.h \ + terminal-intl.h terminal-i18n.c terminal-i18n.h \ + terminal-libgsystem.h terminal-mdi-container.c \ + terminal-mdi-container.h terminal-menu-button.h \ + terminal-menu-button.c terminal-notebook.c terminal-notebook.h \ + terminal-pcre2.h terminal-prefs.c terminal-prefs.h \ + terminal-profiles-list.c terminal-profiles-list.h \ + terminal-regex.h terminal-schemas.h terminal-settings-list.c \ + terminal-settings-list.h terminal-screen.c terminal-screen.h \ + terminal-screen-container.c terminal-screen-container.h \ + terminal-search-popover.c terminal-search-popover.h \ + terminal-tab-label.c terminal-tab-label.h terminal-util.c \ + terminal-util.h terminal-version.h terminal-window.c \ + terminal-window.h $(NULL) $(am__append_2) +nodist_gnome_terminal_server_SOURCES = $(gnome_terminal_server_built) +gnome_terminal_server_CPPFLAGS = \ + -DTERMINAL_COMPILATION \ + -DVTE_DISABLE_DEPRECATION_WARNINGS \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + $(AM_CPPFLAGS) + +gnome_terminal_server_CFLAGS = \ + $(TERM_CFLAGS) \ + $(PTHREAD_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +gnome_terminal_server_LDFLAGS = \ + $(AM_LDFLAGS) + +gnome_terminal_server_LDADD = \ + $(TERM_LIBS) \ + $(PTHREAD_LIBS) \ + $(NULL) + +TYPES_H_FILES = \ + terminal-enums.h \ + $(NULL) + + +# Check programmes +terminal_regex_CPPFLAGS = \ + $(AM_CPPFLAGS) + +terminal_regex_SOURCES = \ + terminal-regex.c \ + terminal-regex.h \ + $(NULL) + +terminal_regex_CFLAGS = \ + -DTERMINAL_REGEX_MAIN \ + $(TERM_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +terminal_regex_LDFLAGS = \ + $(AM_LDFLAGS) + +terminal_regex_LDADD = \ + $(TERM_LIBS) + + +# Legacy terminal client +gnome_terminal_SOURCES = \ + terminal.c \ + terminal-client-utils.c \ + terminal-client-utils.h \ + terminal-debug.c \ + terminal-debug.h \ + terminal-defines.h \ + terminal-i18n.c \ + terminal-i18n.h \ + terminal-libgsystem.h \ + terminal-options.c \ + terminal-options.h \ + terminal-profiles-list.c \ + terminal-profiles-list.h \ + terminal-schemas.h \ + terminal-settings-list.c \ + terminal-settings-list.h \ + $(NULL) + +nodist_gnome_terminal_SOURCES = \ + terminal-gdbus-generated.c \ + terminal-gdbus-generated.h \ + terminal-type-builtins.c \ + terminal-type-builtins.h \ + $(NULL) + +gnome_terminal_CPPFLAGS = \ + -DTERMINAL_COMPILATION \ + -DTERMINAL_CLIENT \ + -DTERM_DATADIR="\"$(datadir)\"" \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + -DTERM_PKGDATADIR="\"$(pkgdatadir)\"" \ + $(AM_CPPFLAGS) + +gnome_terminal_CFLAGS = \ + $(TERM_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +gnome_terminal_LDFLAGS = \ + $(AM_LDFLAGS) + +gnome_terminal_LDADD = \ + $(TERM_LIBS) + + +# Nautilus extension +libterminal_nautilus_la_SOURCES = \ + terminal-client-utils.c \ + terminal-client-utils.h \ + terminal-defines.h \ + terminal-i18n.c \ + terminal-i18n.h \ + terminal-libgsystem.h \ + terminal-nautilus.c \ + $(NULL) + +nodist_libterminal_nautilus_la_SOURCES = \ + terminal-gdbus-generated.c \ + terminal-gdbus-generated.h \ + terminal-type-builtins.c \ + terminal-type-builtins.h \ + $(NULL) + +libterminal_nautilus_la_CPPFLAGS = \ + -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \ + $(AM_CPPFLAGS) + +libterminal_nautilus_la_CFLAGS = \ + $(NAUTILUS_CFLAGS) \ + $(WARN_CFLAGS) \ + $(AM_CFLAGS) + +libterminal_nautilus_la_LDFLAGS = \ + -module -avoid-version \ + -export-symbols $(srcdir)/nautilus.symbols \ + $(AM_LDFLAGS) + +libterminal_nautilus_la_LIBADD = \ + $(NAUTILUS_LIBS) + + +# GNOME Shell search provider +@ENABLE_SEARCH_PROVIDER_TRUE@searchproviderdir = $(datadir)/gnome-shell/search-providers +@ENABLE_SEARCH_PROVIDER_TRUE@dist_searchprovider_DATA = gnome-terminal-search-provider.ini +gsettings_SCHEMAS = \ + org.gnome.Terminal.gschema.xml \ + $(NULL) + +CLEANFILES = \ + stamp-terminal-type-builtins.h \ + gnome-terminal.schemas \ + stamp-terminal-type-builtins.h \ + org.gnome.Terminal.service \ + gnome-terminal-server.service \ + $(BUILT_SOURCES) + +EXTRA_DIST = \ + terminal.about \ + terminal-headerbar.ui \ + terminal-headermenu.ui \ + terminal-menubar.ui.in \ + terminal-notebook-menu.ui \ + terminal-window.ui \ + terminal.gresource.xml \ + terminal-marshal.list \ + terminal-type-builtins.c.template \ + terminal-type-builtins.h.template \ + org.gnome.Terminal.xml \ + nautilus.symbols \ + search-popover.ui \ + preferences.ui \ + terminal.common.css \ + $(about_DATA) \ + $(builder_DATA) \ + $(gsettings_SCHEMAS) \ + $(NULL) + +all: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) all-am + +.SUFFIXES: +.SUFFIXES: .c .lo .log .o .obj .test .test$(EXEEXT) .trs +$(srcdir)/Makefile.in: @MAINTAINER_MODE_TRUE@ $(srcdir)/Makefile.am $(am__configure_deps) + @for dep in $?; do \ + case '$(am__configure_deps)' in \ + *$$dep*) \ + ( cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh ) \ + && { if test -f $@; then exit 0; else break; fi; }; \ + exit 1;; \ + esac; \ + done; \ + echo ' cd $(top_srcdir) && $(AUTOMAKE) --foreign src/Makefile'; \ + $(am__cd) $(top_srcdir) && \ + $(AUTOMAKE) --foreign src/Makefile +Makefile: $(srcdir)/Makefile.in $(top_builddir)/config.status + @case '$?' in \ + *config.status*) \ + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh;; \ + *) \ + echo ' cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles)'; \ + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__maybe_remake_depfiles);; \ + esac; + +$(top_builddir)/config.status: $(top_srcdir)/configure $(CONFIG_STATUS_DEPENDENCIES) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh + +$(top_srcdir)/configure: @MAINTAINER_MODE_TRUE@ $(am__configure_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(ACLOCAL_M4): @MAINTAINER_MODE_TRUE@ $(am__aclocal_m4_deps) + cd $(top_builddir) && $(MAKE) $(AM_MAKEFLAGS) am--refresh +$(am__aclocal_m4_deps): +terminal-version.h: $(top_builddir)/config.status $(srcdir)/terminal-version.h.in + cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ +install-binPROGRAMS: $(bin_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(bindir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(bindir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(bindir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(bindir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-binPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(bindir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(bindir)" && rm -f $$files + +clean-binPROGRAMS: + @list='$(bin_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-checkPROGRAMS: + @list='$(check_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list +install-libexecPROGRAMS: $(libexec_PROGRAMS) + @$(NORMAL_INSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(libexecdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(libexecdir)" || exit 1; \ + fi; \ + for p in $$list; do echo "$$p $$p"; done | \ + sed 's/$(EXEEXT)$$//' | \ + while read p p1; do if test -f $$p \ + || test -f $$p1 \ + ; then echo "$$p"; echo "$$p"; else :; fi; \ + done | \ + sed -e 'p;s,.*/,,;n;h' \ + -e 's|.*|.|' \ + -e 'p;x;s,.*/,,;s/$(EXEEXT)$$//;$(transform);s/$$/$(EXEEXT)/' | \ + sed 'N;N;N;s,\n, ,g' | \ + $(AWK) 'BEGIN { files["."] = ""; dirs["."] = 1 } \ + { d=$$3; if (dirs[d] != 1) { print "d", d; dirs[d] = 1 } \ + if ($$2 == $$4) files[d] = files[d] " " $$1; \ + else { print "f", $$3 "/" $$4, $$1; } } \ + END { for (d in files) print "f", d, files[d] }' | \ + while read type dir files; do \ + if test "$$dir" = .; then dir=; else dir=/$$dir; fi; \ + test -z "$$files" || { \ + echo " $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files '$(DESTDIR)$(libexecdir)$$dir'"; \ + $(INSTALL_PROGRAM_ENV) $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL_PROGRAM) $$files "$(DESTDIR)$(libexecdir)$$dir" || exit $$?; \ + } \ + ; done + +uninstall-libexecPROGRAMS: + @$(NORMAL_UNINSTALL) + @list='$(libexec_PROGRAMS)'; test -n "$(libexecdir)" || list=; \ + files=`for p in $$list; do echo "$$p"; done | \ + sed -e 'h;s,^.*/,,;s/$(EXEEXT)$$//;$(transform)' \ + -e 's/$$/$(EXEEXT)/' \ + `; \ + test -n "$$list" || exit 0; \ + echo " ( cd '$(DESTDIR)$(libexecdir)' && rm -f" $$files ")"; \ + cd "$(DESTDIR)$(libexecdir)" && rm -f $$files + +clean-libexecPROGRAMS: + @list='$(libexec_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +clean-noinstPROGRAMS: + @list='$(noinst_PROGRAMS)'; test -n "$$list" || exit 0; \ + echo " rm -f" $$list; \ + rm -f $$list || exit $$?; \ + test -n "$(EXEEXT)" || exit 0; \ + list=`for p in $$list; do echo "$$p"; done | sed 's/$(EXEEXT)$$//'`; \ + echo " rm -f" $$list; \ + rm -f $$list + +install-nautilusextensionLTLIBRARIES: $(nautilusextension_LTLIBRARIES) + @$(NORMAL_INSTALL) + @list='$(nautilusextension_LTLIBRARIES)'; test -n "$(nautilusextensiondir)" || list=; \ + list2=; for p in $$list; do \ + if test -f $$p; then \ + list2="$$list2 $$p"; \ + else :; fi; \ + done; \ + test -z "$$list2" || { \ + echo " $(MKDIR_P) '$(DESTDIR)$(nautilusextensiondir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(nautilusextensiondir)" || exit 1; \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 '$(DESTDIR)$(nautilusextensiondir)'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=install $(INSTALL) $(INSTALL_STRIP_FLAG) $$list2 "$(DESTDIR)$(nautilusextensiondir)"; \ + } + +uninstall-nautilusextensionLTLIBRARIES: + @$(NORMAL_UNINSTALL) + @list='$(nautilusextension_LTLIBRARIES)'; test -n "$(nautilusextensiondir)" || list=; \ + for p in $$list; do \ + $(am__strip_dir) \ + echo " $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f '$(DESTDIR)$(nautilusextensiondir)/$$f'"; \ + $(LIBTOOL) $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=uninstall rm -f "$(DESTDIR)$(nautilusextensiondir)/$$f"; \ + done + +clean-nautilusextensionLTLIBRARIES: + -test -z "$(nautilusextension_LTLIBRARIES)" || rm -f $(nautilusextension_LTLIBRARIES) + @list='$(nautilusextension_LTLIBRARIES)'; \ + locs=`for p in $$list; do echo $$p; done | \ + sed 's|^[^/]*$$|.|; s|/[^/]*$$||; s|$$|/so_locations|' | \ + sort -u`; \ + test -z "$$locs" || { \ + echo rm -f $${locs}; \ + rm -f $${locs}; \ + } + +libterminal-nautilus.la: $(libterminal_nautilus_la_OBJECTS) $(libterminal_nautilus_la_DEPENDENCIES) $(EXTRA_libterminal_nautilus_la_DEPENDENCIES) + $(AM_V_CCLD)$(libterminal_nautilus_la_LINK) $(am_libterminal_nautilus_la_rpath) $(libterminal_nautilus_la_OBJECTS) $(libterminal_nautilus_la_LIBADD) $(LIBS) + +gnome-terminal$(EXEEXT): $(gnome_terminal_OBJECTS) $(gnome_terminal_DEPENDENCIES) $(EXTRA_gnome_terminal_DEPENDENCIES) + @rm -f gnome-terminal$(EXEEXT) + $(AM_V_CCLD)$(gnome_terminal_LINK) $(gnome_terminal_OBJECTS) $(gnome_terminal_LDADD) $(LIBS) + +gnome-terminal-server$(EXEEXT): $(gnome_terminal_server_OBJECTS) $(gnome_terminal_server_DEPENDENCIES) $(EXTRA_gnome_terminal_server_DEPENDENCIES) + @rm -f gnome-terminal-server$(EXEEXT) + $(AM_V_CCLD)$(gnome_terminal_server_LINK) $(gnome_terminal_server_OBJECTS) $(gnome_terminal_server_LDADD) $(LIBS) + +terminal-regex$(EXEEXT): $(terminal_regex_OBJECTS) $(terminal_regex_DEPENDENCIES) $(EXTRA_terminal_regex_DEPENDENCIES) + @rm -f terminal-regex$(EXEEXT) + $(AM_V_CCLD)$(terminal_regex_LINK) $(terminal_regex_OBJECTS) $(terminal_regex_LDADD) $(LIBS) + +mostlyclean-compile: + -rm -f *.$(OBJEXT) + +distclean-compile: + -rm -f *.tab.c + +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-client-utils.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-debug.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-i18n.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-options.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-profiles-list.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-settings-list.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal-type-builtins.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal-terminal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-eggshell.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-profile-editor.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-server.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-accels.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-app.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-debug.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-i18n.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-marshal.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-notebook.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-prefs.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-resources.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-screen.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-util.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/gnome_terminal_server-terminal-window.Po@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Plo@am__quote@ # am--include-marker +@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/terminal_regex-terminal-regex.Po@am__quote@ # am--include-marker + +$(am__depfiles_remade): + @$(MKDIR_P) $(@D) + @echo '# dummy' >$@-t && $(am__mv) $@-t $@ + +am--depfiles: $(am__depfiles_remade) + +.c.o: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ $< + +.c.obj: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(COMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ `$(CYGPATH_W) '$<'` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(COMPILE) -c -o $@ `$(CYGPATH_W) '$<'` + +.c.lo: +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LTCOMPILE) -MT $@ -MD -MP -MF $(DEPDIR)/$*.Tpo -c -o $@ $< +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/$*.Tpo $(DEPDIR)/$*.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LTCOMPILE) -c -o $@ $< + +libterminal_nautilus_la-terminal-client-utils.lo: terminal-client-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -MT libterminal_nautilus_la-terminal-client-utils.lo -MD -MP -MF $(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Tpo -c -o libterminal_nautilus_la-terminal-client-utils.lo `test -f 'terminal-client-utils.c' || echo '$(srcdir)/'`terminal-client-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Tpo $(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-client-utils.c' object='libterminal_nautilus_la-terminal-client-utils.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -c -o libterminal_nautilus_la-terminal-client-utils.lo `test -f 'terminal-client-utils.c' || echo '$(srcdir)/'`terminal-client-utils.c + +libterminal_nautilus_la-terminal-i18n.lo: terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -MT libterminal_nautilus_la-terminal-i18n.lo -MD -MP -MF $(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Tpo -c -o libterminal_nautilus_la-terminal-i18n.lo `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Tpo $(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-i18n.c' object='libterminal_nautilus_la-terminal-i18n.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -c -o libterminal_nautilus_la-terminal-i18n.lo `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c + +libterminal_nautilus_la-terminal-nautilus.lo: terminal-nautilus.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -MT libterminal_nautilus_la-terminal-nautilus.lo -MD -MP -MF $(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Tpo -c -o libterminal_nautilus_la-terminal-nautilus.lo `test -f 'terminal-nautilus.c' || echo '$(srcdir)/'`terminal-nautilus.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Tpo $(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-nautilus.c' object='libterminal_nautilus_la-terminal-nautilus.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -c -o libterminal_nautilus_la-terminal-nautilus.lo `test -f 'terminal-nautilus.c' || echo '$(srcdir)/'`terminal-nautilus.c + +libterminal_nautilus_la-terminal-gdbus-generated.lo: terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -MT libterminal_nautilus_la-terminal-gdbus-generated.lo -MD -MP -MF $(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Tpo -c -o libterminal_nautilus_la-terminal-gdbus-generated.lo `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Tpo $(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus-generated.c' object='libterminal_nautilus_la-terminal-gdbus-generated.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -c -o libterminal_nautilus_la-terminal-gdbus-generated.lo `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c + +libterminal_nautilus_la-terminal-type-builtins.lo: terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -MT libterminal_nautilus_la-terminal-type-builtins.lo -MD -MP -MF $(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Tpo -c -o libterminal_nautilus_la-terminal-type-builtins.lo `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Tpo $(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Plo +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-type-builtins.c' object='libterminal_nautilus_la-terminal-type-builtins.lo' libtool=yes @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libterminal_nautilus_la_CPPFLAGS) $(CPPFLAGS) $(libterminal_nautilus_la_CFLAGS) $(CFLAGS) -c -o libterminal_nautilus_la-terminal-type-builtins.lo `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c + +gnome_terminal-terminal.o: terminal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal.Tpo -c -o gnome_terminal-terminal.o `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal.Tpo $(DEPDIR)/gnome_terminal-terminal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal.c' object='gnome_terminal-terminal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal.o `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c + +gnome_terminal-terminal.obj: terminal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal.Tpo -c -o gnome_terminal-terminal.obj `if test -f 'terminal.c'; then $(CYGPATH_W) 'terminal.c'; else $(CYGPATH_W) '$(srcdir)/terminal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal.Tpo $(DEPDIR)/gnome_terminal-terminal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal.c' object='gnome_terminal-terminal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal.obj `if test -f 'terminal.c'; then $(CYGPATH_W) 'terminal.c'; else $(CYGPATH_W) '$(srcdir)/terminal.c'; fi` + +gnome_terminal-terminal-client-utils.o: terminal-client-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-client-utils.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-client-utils.Tpo -c -o gnome_terminal-terminal-client-utils.o `test -f 'terminal-client-utils.c' || echo '$(srcdir)/'`terminal-client-utils.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-client-utils.Tpo $(DEPDIR)/gnome_terminal-terminal-client-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-client-utils.c' object='gnome_terminal-terminal-client-utils.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-client-utils.o `test -f 'terminal-client-utils.c' || echo '$(srcdir)/'`terminal-client-utils.c + +gnome_terminal-terminal-client-utils.obj: terminal-client-utils.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-client-utils.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-client-utils.Tpo -c -o gnome_terminal-terminal-client-utils.obj `if test -f 'terminal-client-utils.c'; then $(CYGPATH_W) 'terminal-client-utils.c'; else $(CYGPATH_W) '$(srcdir)/terminal-client-utils.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-client-utils.Tpo $(DEPDIR)/gnome_terminal-terminal-client-utils.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-client-utils.c' object='gnome_terminal-terminal-client-utils.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-client-utils.obj `if test -f 'terminal-client-utils.c'; then $(CYGPATH_W) 'terminal-client-utils.c'; else $(CYGPATH_W) '$(srcdir)/terminal-client-utils.c'; fi` + +gnome_terminal-terminal-debug.o: terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-debug.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-debug.Tpo -c -o gnome_terminal-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-debug.Tpo $(DEPDIR)/gnome_terminal-terminal-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-debug.c' object='gnome_terminal-terminal-debug.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c + +gnome_terminal-terminal-debug.obj: terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-debug.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-debug.Tpo -c -o gnome_terminal-terminal-debug.obj `if test -f 'terminal-debug.c'; then $(CYGPATH_W) 'terminal-debug.c'; else $(CYGPATH_W) '$(srcdir)/terminal-debug.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-debug.Tpo $(DEPDIR)/gnome_terminal-terminal-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-debug.c' object='gnome_terminal-terminal-debug.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-debug.obj `if test -f 'terminal-debug.c'; then $(CYGPATH_W) 'terminal-debug.c'; else $(CYGPATH_W) '$(srcdir)/terminal-debug.c'; fi` + +gnome_terminal-terminal-i18n.o: terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-i18n.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-i18n.Tpo -c -o gnome_terminal-terminal-i18n.o `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-i18n.Tpo $(DEPDIR)/gnome_terminal-terminal-i18n.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-i18n.c' object='gnome_terminal-terminal-i18n.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-i18n.o `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c + +gnome_terminal-terminal-i18n.obj: terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-i18n.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-i18n.Tpo -c -o gnome_terminal-terminal-i18n.obj `if test -f 'terminal-i18n.c'; then $(CYGPATH_W) 'terminal-i18n.c'; else $(CYGPATH_W) '$(srcdir)/terminal-i18n.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-i18n.Tpo $(DEPDIR)/gnome_terminal-terminal-i18n.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-i18n.c' object='gnome_terminal-terminal-i18n.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-i18n.obj `if test -f 'terminal-i18n.c'; then $(CYGPATH_W) 'terminal-i18n.c'; else $(CYGPATH_W) '$(srcdir)/terminal-i18n.c'; fi` + +gnome_terminal-terminal-options.o: terminal-options.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-options.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-options.Tpo -c -o gnome_terminal-terminal-options.o `test -f 'terminal-options.c' || echo '$(srcdir)/'`terminal-options.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-options.Tpo $(DEPDIR)/gnome_terminal-terminal-options.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-options.c' object='gnome_terminal-terminal-options.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-options.o `test -f 'terminal-options.c' || echo '$(srcdir)/'`terminal-options.c + +gnome_terminal-terminal-options.obj: terminal-options.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-options.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-options.Tpo -c -o gnome_terminal-terminal-options.obj `if test -f 'terminal-options.c'; then $(CYGPATH_W) 'terminal-options.c'; else $(CYGPATH_W) '$(srcdir)/terminal-options.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-options.Tpo $(DEPDIR)/gnome_terminal-terminal-options.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-options.c' object='gnome_terminal-terminal-options.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-options.obj `if test -f 'terminal-options.c'; then $(CYGPATH_W) 'terminal-options.c'; else $(CYGPATH_W) '$(srcdir)/terminal-options.c'; fi` + +gnome_terminal-terminal-profiles-list.o: terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-profiles-list.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-profiles-list.Tpo -c -o gnome_terminal-terminal-profiles-list.o `test -f 'terminal-profiles-list.c' || echo '$(srcdir)/'`terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-profiles-list.Tpo $(DEPDIR)/gnome_terminal-terminal-profiles-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-profiles-list.c' object='gnome_terminal-terminal-profiles-list.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-profiles-list.o `test -f 'terminal-profiles-list.c' || echo '$(srcdir)/'`terminal-profiles-list.c + +gnome_terminal-terminal-profiles-list.obj: terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-profiles-list.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-profiles-list.Tpo -c -o gnome_terminal-terminal-profiles-list.obj `if test -f 'terminal-profiles-list.c'; then $(CYGPATH_W) 'terminal-profiles-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profiles-list.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-profiles-list.Tpo $(DEPDIR)/gnome_terminal-terminal-profiles-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-profiles-list.c' object='gnome_terminal-terminal-profiles-list.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-profiles-list.obj `if test -f 'terminal-profiles-list.c'; then $(CYGPATH_W) 'terminal-profiles-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profiles-list.c'; fi` + +gnome_terminal-terminal-settings-list.o: terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-settings-list.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-settings-list.Tpo -c -o gnome_terminal-terminal-settings-list.o `test -f 'terminal-settings-list.c' || echo '$(srcdir)/'`terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-settings-list.Tpo $(DEPDIR)/gnome_terminal-terminal-settings-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-settings-list.c' object='gnome_terminal-terminal-settings-list.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-settings-list.o `test -f 'terminal-settings-list.c' || echo '$(srcdir)/'`terminal-settings-list.c + +gnome_terminal-terminal-settings-list.obj: terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-settings-list.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-settings-list.Tpo -c -o gnome_terminal-terminal-settings-list.obj `if test -f 'terminal-settings-list.c'; then $(CYGPATH_W) 'terminal-settings-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-settings-list.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-settings-list.Tpo $(DEPDIR)/gnome_terminal-terminal-settings-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-settings-list.c' object='gnome_terminal-terminal-settings-list.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-settings-list.obj `if test -f 'terminal-settings-list.c'; then $(CYGPATH_W) 'terminal-settings-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-settings-list.c'; fi` + +gnome_terminal-terminal-gdbus-generated.o: terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-gdbus-generated.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Tpo -c -o gnome_terminal-terminal-gdbus-generated.o `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus-generated.c' object='gnome_terminal-terminal-gdbus-generated.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-gdbus-generated.o `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c + +gnome_terminal-terminal-gdbus-generated.obj: terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-gdbus-generated.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Tpo -c -o gnome_terminal-terminal-gdbus-generated.obj `if test -f 'terminal-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus-generated.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus-generated.c' object='gnome_terminal-terminal-gdbus-generated.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-gdbus-generated.obj `if test -f 'terminal-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus-generated.c'; fi` + +gnome_terminal-terminal-type-builtins.o: terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-type-builtins.o -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-type-builtins.Tpo -c -o gnome_terminal-terminal-type-builtins.o `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-type-builtins.Tpo $(DEPDIR)/gnome_terminal-terminal-type-builtins.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-type-builtins.c' object='gnome_terminal-terminal-type-builtins.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-type-builtins.o `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c + +gnome_terminal-terminal-type-builtins.obj: terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -MT gnome_terminal-terminal-type-builtins.obj -MD -MP -MF $(DEPDIR)/gnome_terminal-terminal-type-builtins.Tpo -c -o gnome_terminal-terminal-type-builtins.obj `if test -f 'terminal-type-builtins.c'; then $(CYGPATH_W) 'terminal-type-builtins.c'; else $(CYGPATH_W) '$(srcdir)/terminal-type-builtins.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal-terminal-type-builtins.Tpo $(DEPDIR)/gnome_terminal-terminal-type-builtins.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-type-builtins.c' object='gnome_terminal-terminal-type-builtins.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_CFLAGS) $(CFLAGS) -c -o gnome_terminal-terminal-type-builtins.obj `if test -f 'terminal-type-builtins.c'; then $(CYGPATH_W) 'terminal-type-builtins.c'; else $(CYGPATH_W) '$(srcdir)/terminal-type-builtins.c'; fi` + +gnome_terminal_server-eggshell.o: eggshell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-eggshell.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-eggshell.Tpo -c -o gnome_terminal_server-eggshell.o `test -f 'eggshell.c' || echo '$(srcdir)/'`eggshell.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-eggshell.Tpo $(DEPDIR)/gnome_terminal_server-eggshell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eggshell.c' object='gnome_terminal_server-eggshell.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-eggshell.o `test -f 'eggshell.c' || echo '$(srcdir)/'`eggshell.c + +gnome_terminal_server-eggshell.obj: eggshell.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-eggshell.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-eggshell.Tpo -c -o gnome_terminal_server-eggshell.obj `if test -f 'eggshell.c'; then $(CYGPATH_W) 'eggshell.c'; else $(CYGPATH_W) '$(srcdir)/eggshell.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-eggshell.Tpo $(DEPDIR)/gnome_terminal_server-eggshell.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='eggshell.c' object='gnome_terminal_server-eggshell.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-eggshell.obj `if test -f 'eggshell.c'; then $(CYGPATH_W) 'eggshell.c'; else $(CYGPATH_W) '$(srcdir)/eggshell.c'; fi` + +gnome_terminal_server-profile-editor.o: profile-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-profile-editor.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-profile-editor.Tpo -c -o gnome_terminal_server-profile-editor.o `test -f 'profile-editor.c' || echo '$(srcdir)/'`profile-editor.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-profile-editor.Tpo $(DEPDIR)/gnome_terminal_server-profile-editor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile-editor.c' object='gnome_terminal_server-profile-editor.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-profile-editor.o `test -f 'profile-editor.c' || echo '$(srcdir)/'`profile-editor.c + +gnome_terminal_server-profile-editor.obj: profile-editor.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-profile-editor.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-profile-editor.Tpo -c -o gnome_terminal_server-profile-editor.obj `if test -f 'profile-editor.c'; then $(CYGPATH_W) 'profile-editor.c'; else $(CYGPATH_W) '$(srcdir)/profile-editor.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-profile-editor.Tpo $(DEPDIR)/gnome_terminal_server-profile-editor.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='profile-editor.c' object='gnome_terminal_server-profile-editor.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-profile-editor.obj `if test -f 'profile-editor.c'; then $(CYGPATH_W) 'profile-editor.c'; else $(CYGPATH_W) '$(srcdir)/profile-editor.c'; fi` + +gnome_terminal_server-server.o: server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-server.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-server.Tpo -c -o gnome_terminal_server-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-server.Tpo $(DEPDIR)/gnome_terminal_server-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='gnome_terminal_server-server.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-server.o `test -f 'server.c' || echo '$(srcdir)/'`server.c + +gnome_terminal_server-server.obj: server.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-server.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-server.Tpo -c -o gnome_terminal_server-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-server.Tpo $(DEPDIR)/gnome_terminal_server-server.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='server.c' object='gnome_terminal_server-server.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-server.obj `if test -f 'server.c'; then $(CYGPATH_W) 'server.c'; else $(CYGPATH_W) '$(srcdir)/server.c'; fi` + +gnome_terminal_server-terminal-accels.o: terminal-accels.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-accels.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-accels.Tpo -c -o gnome_terminal_server-terminal-accels.o `test -f 'terminal-accels.c' || echo '$(srcdir)/'`terminal-accels.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-accels.Tpo $(DEPDIR)/gnome_terminal_server-terminal-accels.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-accels.c' object='gnome_terminal_server-terminal-accels.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-accels.o `test -f 'terminal-accels.c' || echo '$(srcdir)/'`terminal-accels.c + +gnome_terminal_server-terminal-accels.obj: terminal-accels.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-accels.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-accels.Tpo -c -o gnome_terminal_server-terminal-accels.obj `if test -f 'terminal-accels.c'; then $(CYGPATH_W) 'terminal-accels.c'; else $(CYGPATH_W) '$(srcdir)/terminal-accels.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-accels.Tpo $(DEPDIR)/gnome_terminal_server-terminal-accels.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-accels.c' object='gnome_terminal_server-terminal-accels.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-accels.obj `if test -f 'terminal-accels.c'; then $(CYGPATH_W) 'terminal-accels.c'; else $(CYGPATH_W) '$(srcdir)/terminal-accels.c'; fi` + +gnome_terminal_server-terminal-app.o: terminal-app.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-app.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-app.Tpo -c -o gnome_terminal_server-terminal-app.o `test -f 'terminal-app.c' || echo '$(srcdir)/'`terminal-app.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-app.Tpo $(DEPDIR)/gnome_terminal_server-terminal-app.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-app.c' object='gnome_terminal_server-terminal-app.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-app.o `test -f 'terminal-app.c' || echo '$(srcdir)/'`terminal-app.c + +gnome_terminal_server-terminal-app.obj: terminal-app.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-app.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-app.Tpo -c -o gnome_terminal_server-terminal-app.obj `if test -f 'terminal-app.c'; then $(CYGPATH_W) 'terminal-app.c'; else $(CYGPATH_W) '$(srcdir)/terminal-app.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-app.Tpo $(DEPDIR)/gnome_terminal_server-terminal-app.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-app.c' object='gnome_terminal_server-terminal-app.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-app.obj `if test -f 'terminal-app.c'; then $(CYGPATH_W) 'terminal-app.c'; else $(CYGPATH_W) '$(srcdir)/terminal-app.c'; fi` + +gnome_terminal_server-terminal-debug.o: terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-debug.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-debug.Tpo -c -o gnome_terminal_server-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-debug.Tpo $(DEPDIR)/gnome_terminal_server-terminal-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-debug.c' object='gnome_terminal_server-terminal-debug.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c + +gnome_terminal_server-terminal-debug.obj: terminal-debug.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-debug.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-debug.Tpo -c -o gnome_terminal_server-terminal-debug.obj `if test -f 'terminal-debug.c'; then $(CYGPATH_W) 'terminal-debug.c'; else $(CYGPATH_W) '$(srcdir)/terminal-debug.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-debug.Tpo $(DEPDIR)/gnome_terminal_server-terminal-debug.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-debug.c' object='gnome_terminal_server-terminal-debug.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-debug.obj `if test -f 'terminal-debug.c'; then $(CYGPATH_W) 'terminal-debug.c'; else $(CYGPATH_W) '$(srcdir)/terminal-debug.c'; fi` + +gnome_terminal_server-terminal-gdbus.o: terminal-gdbus.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-gdbus.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Tpo -c -o gnome_terminal_server-terminal-gdbus.o `test -f 'terminal-gdbus.c' || echo '$(srcdir)/'`terminal-gdbus.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Tpo $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus.c' object='gnome_terminal_server-terminal-gdbus.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-gdbus.o `test -f 'terminal-gdbus.c' || echo '$(srcdir)/'`terminal-gdbus.c + +gnome_terminal_server-terminal-gdbus.obj: terminal-gdbus.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-gdbus.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Tpo -c -o gnome_terminal_server-terminal-gdbus.obj `if test -f 'terminal-gdbus.c'; then $(CYGPATH_W) 'terminal-gdbus.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Tpo $(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus.c' object='gnome_terminal_server-terminal-gdbus.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-gdbus.obj `if test -f 'terminal-gdbus.c'; then $(CYGPATH_W) 'terminal-gdbus.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus.c'; fi` + +gnome_terminal_server-terminal-headerbar.o: terminal-headerbar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-headerbar.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Tpo -c -o gnome_terminal_server-terminal-headerbar.o `test -f 'terminal-headerbar.c' || echo '$(srcdir)/'`terminal-headerbar.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Tpo $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-headerbar.c' object='gnome_terminal_server-terminal-headerbar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-headerbar.o `test -f 'terminal-headerbar.c' || echo '$(srcdir)/'`terminal-headerbar.c + +gnome_terminal_server-terminal-headerbar.obj: terminal-headerbar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-headerbar.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Tpo -c -o gnome_terminal_server-terminal-headerbar.obj `if test -f 'terminal-headerbar.c'; then $(CYGPATH_W) 'terminal-headerbar.c'; else $(CYGPATH_W) '$(srcdir)/terminal-headerbar.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Tpo $(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-headerbar.c' object='gnome_terminal_server-terminal-headerbar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-headerbar.obj `if test -f 'terminal-headerbar.c'; then $(CYGPATH_W) 'terminal-headerbar.c'; else $(CYGPATH_W) '$(srcdir)/terminal-headerbar.c'; fi` + +gnome_terminal_server-terminal-icon-button.o: terminal-icon-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-icon-button.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Tpo -c -o gnome_terminal_server-terminal-icon-button.o `test -f 'terminal-icon-button.c' || echo '$(srcdir)/'`terminal-icon-button.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Tpo $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-icon-button.c' object='gnome_terminal_server-terminal-icon-button.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-icon-button.o `test -f 'terminal-icon-button.c' || echo '$(srcdir)/'`terminal-icon-button.c + +gnome_terminal_server-terminal-icon-button.obj: terminal-icon-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-icon-button.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Tpo -c -o gnome_terminal_server-terminal-icon-button.obj `if test -f 'terminal-icon-button.c'; then $(CYGPATH_W) 'terminal-icon-button.c'; else $(CYGPATH_W) '$(srcdir)/terminal-icon-button.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Tpo $(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-icon-button.c' object='gnome_terminal_server-terminal-icon-button.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-icon-button.obj `if test -f 'terminal-icon-button.c'; then $(CYGPATH_W) 'terminal-icon-button.c'; else $(CYGPATH_W) '$(srcdir)/terminal-icon-button.c'; fi` + +gnome_terminal_server-terminal-info-bar.o: terminal-info-bar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-info-bar.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Tpo -c -o gnome_terminal_server-terminal-info-bar.o `test -f 'terminal-info-bar.c' || echo '$(srcdir)/'`terminal-info-bar.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Tpo $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-info-bar.c' object='gnome_terminal_server-terminal-info-bar.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-info-bar.o `test -f 'terminal-info-bar.c' || echo '$(srcdir)/'`terminal-info-bar.c + +gnome_terminal_server-terminal-info-bar.obj: terminal-info-bar.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-info-bar.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Tpo -c -o gnome_terminal_server-terminal-info-bar.obj `if test -f 'terminal-info-bar.c'; then $(CYGPATH_W) 'terminal-info-bar.c'; else $(CYGPATH_W) '$(srcdir)/terminal-info-bar.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Tpo $(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-info-bar.c' object='gnome_terminal_server-terminal-info-bar.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-info-bar.obj `if test -f 'terminal-info-bar.c'; then $(CYGPATH_W) 'terminal-info-bar.c'; else $(CYGPATH_W) '$(srcdir)/terminal-info-bar.c'; fi` + +gnome_terminal_server-terminal-i18n.o: terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-i18n.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-i18n.Tpo -c -o gnome_terminal_server-terminal-i18n.o `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-i18n.Tpo $(DEPDIR)/gnome_terminal_server-terminal-i18n.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-i18n.c' object='gnome_terminal_server-terminal-i18n.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-i18n.o `test -f 'terminal-i18n.c' || echo '$(srcdir)/'`terminal-i18n.c + +gnome_terminal_server-terminal-i18n.obj: terminal-i18n.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-i18n.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-i18n.Tpo -c -o gnome_terminal_server-terminal-i18n.obj `if test -f 'terminal-i18n.c'; then $(CYGPATH_W) 'terminal-i18n.c'; else $(CYGPATH_W) '$(srcdir)/terminal-i18n.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-i18n.Tpo $(DEPDIR)/gnome_terminal_server-terminal-i18n.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-i18n.c' object='gnome_terminal_server-terminal-i18n.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-i18n.obj `if test -f 'terminal-i18n.c'; then $(CYGPATH_W) 'terminal-i18n.c'; else $(CYGPATH_W) '$(srcdir)/terminal-i18n.c'; fi` + +gnome_terminal_server-terminal-mdi-container.o: terminal-mdi-container.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-mdi-container.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Tpo -c -o gnome_terminal_server-terminal-mdi-container.o `test -f 'terminal-mdi-container.c' || echo '$(srcdir)/'`terminal-mdi-container.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Tpo $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-mdi-container.c' object='gnome_terminal_server-terminal-mdi-container.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-mdi-container.o `test -f 'terminal-mdi-container.c' || echo '$(srcdir)/'`terminal-mdi-container.c + +gnome_terminal_server-terminal-mdi-container.obj: terminal-mdi-container.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-mdi-container.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Tpo -c -o gnome_terminal_server-terminal-mdi-container.obj `if test -f 'terminal-mdi-container.c'; then $(CYGPATH_W) 'terminal-mdi-container.c'; else $(CYGPATH_W) '$(srcdir)/terminal-mdi-container.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Tpo $(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-mdi-container.c' object='gnome_terminal_server-terminal-mdi-container.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-mdi-container.obj `if test -f 'terminal-mdi-container.c'; then $(CYGPATH_W) 'terminal-mdi-container.c'; else $(CYGPATH_W) '$(srcdir)/terminal-mdi-container.c'; fi` + +gnome_terminal_server-terminal-menu-button.o: terminal-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-menu-button.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Tpo -c -o gnome_terminal_server-terminal-menu-button.o `test -f 'terminal-menu-button.c' || echo '$(srcdir)/'`terminal-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Tpo $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-menu-button.c' object='gnome_terminal_server-terminal-menu-button.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-menu-button.o `test -f 'terminal-menu-button.c' || echo '$(srcdir)/'`terminal-menu-button.c + +gnome_terminal_server-terminal-menu-button.obj: terminal-menu-button.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-menu-button.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Tpo -c -o gnome_terminal_server-terminal-menu-button.obj `if test -f 'terminal-menu-button.c'; then $(CYGPATH_W) 'terminal-menu-button.c'; else $(CYGPATH_W) '$(srcdir)/terminal-menu-button.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Tpo $(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-menu-button.c' object='gnome_terminal_server-terminal-menu-button.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-menu-button.obj `if test -f 'terminal-menu-button.c'; then $(CYGPATH_W) 'terminal-menu-button.c'; else $(CYGPATH_W) '$(srcdir)/terminal-menu-button.c'; fi` + +gnome_terminal_server-terminal-notebook.o: terminal-notebook.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-notebook.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-notebook.Tpo -c -o gnome_terminal_server-terminal-notebook.o `test -f 'terminal-notebook.c' || echo '$(srcdir)/'`terminal-notebook.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-notebook.Tpo $(DEPDIR)/gnome_terminal_server-terminal-notebook.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-notebook.c' object='gnome_terminal_server-terminal-notebook.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-notebook.o `test -f 'terminal-notebook.c' || echo '$(srcdir)/'`terminal-notebook.c + +gnome_terminal_server-terminal-notebook.obj: terminal-notebook.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-notebook.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-notebook.Tpo -c -o gnome_terminal_server-terminal-notebook.obj `if test -f 'terminal-notebook.c'; then $(CYGPATH_W) 'terminal-notebook.c'; else $(CYGPATH_W) '$(srcdir)/terminal-notebook.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-notebook.Tpo $(DEPDIR)/gnome_terminal_server-terminal-notebook.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-notebook.c' object='gnome_terminal_server-terminal-notebook.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-notebook.obj `if test -f 'terminal-notebook.c'; then $(CYGPATH_W) 'terminal-notebook.c'; else $(CYGPATH_W) '$(srcdir)/terminal-notebook.c'; fi` + +gnome_terminal_server-terminal-prefs.o: terminal-prefs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-prefs.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-prefs.Tpo -c -o gnome_terminal_server-terminal-prefs.o `test -f 'terminal-prefs.c' || echo '$(srcdir)/'`terminal-prefs.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-prefs.Tpo $(DEPDIR)/gnome_terminal_server-terminal-prefs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-prefs.c' object='gnome_terminal_server-terminal-prefs.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-prefs.o `test -f 'terminal-prefs.c' || echo '$(srcdir)/'`terminal-prefs.c + +gnome_terminal_server-terminal-prefs.obj: terminal-prefs.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-prefs.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-prefs.Tpo -c -o gnome_terminal_server-terminal-prefs.obj `if test -f 'terminal-prefs.c'; then $(CYGPATH_W) 'terminal-prefs.c'; else $(CYGPATH_W) '$(srcdir)/terminal-prefs.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-prefs.Tpo $(DEPDIR)/gnome_terminal_server-terminal-prefs.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-prefs.c' object='gnome_terminal_server-terminal-prefs.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-prefs.obj `if test -f 'terminal-prefs.c'; then $(CYGPATH_W) 'terminal-prefs.c'; else $(CYGPATH_W) '$(srcdir)/terminal-prefs.c'; fi` + +gnome_terminal_server-terminal-profiles-list.o: terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-profiles-list.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Tpo -c -o gnome_terminal_server-terminal-profiles-list.o `test -f 'terminal-profiles-list.c' || echo '$(srcdir)/'`terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Tpo $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-profiles-list.c' object='gnome_terminal_server-terminal-profiles-list.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-profiles-list.o `test -f 'terminal-profiles-list.c' || echo '$(srcdir)/'`terminal-profiles-list.c + +gnome_terminal_server-terminal-profiles-list.obj: terminal-profiles-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-profiles-list.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Tpo -c -o gnome_terminal_server-terminal-profiles-list.obj `if test -f 'terminal-profiles-list.c'; then $(CYGPATH_W) 'terminal-profiles-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profiles-list.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Tpo $(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-profiles-list.c' object='gnome_terminal_server-terminal-profiles-list.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-profiles-list.obj `if test -f 'terminal-profiles-list.c'; then $(CYGPATH_W) 'terminal-profiles-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profiles-list.c'; fi` + +gnome_terminal_server-terminal-settings-list.o: terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-settings-list.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Tpo -c -o gnome_terminal_server-terminal-settings-list.o `test -f 'terminal-settings-list.c' || echo '$(srcdir)/'`terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Tpo $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-settings-list.c' object='gnome_terminal_server-terminal-settings-list.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-settings-list.o `test -f 'terminal-settings-list.c' || echo '$(srcdir)/'`terminal-settings-list.c + +gnome_terminal_server-terminal-settings-list.obj: terminal-settings-list.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-settings-list.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Tpo -c -o gnome_terminal_server-terminal-settings-list.obj `if test -f 'terminal-settings-list.c'; then $(CYGPATH_W) 'terminal-settings-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-settings-list.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Tpo $(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-settings-list.c' object='gnome_terminal_server-terminal-settings-list.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-settings-list.obj `if test -f 'terminal-settings-list.c'; then $(CYGPATH_W) 'terminal-settings-list.c'; else $(CYGPATH_W) '$(srcdir)/terminal-settings-list.c'; fi` + +gnome_terminal_server-terminal-screen.o: terminal-screen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-screen.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-screen.Tpo -c -o gnome_terminal_server-terminal-screen.o `test -f 'terminal-screen.c' || echo '$(srcdir)/'`terminal-screen.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-screen.Tpo $(DEPDIR)/gnome_terminal_server-terminal-screen.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-screen.c' object='gnome_terminal_server-terminal-screen.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-screen.o `test -f 'terminal-screen.c' || echo '$(srcdir)/'`terminal-screen.c + +gnome_terminal_server-terminal-screen.obj: terminal-screen.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-screen.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-screen.Tpo -c -o gnome_terminal_server-terminal-screen.obj `if test -f 'terminal-screen.c'; then $(CYGPATH_W) 'terminal-screen.c'; else $(CYGPATH_W) '$(srcdir)/terminal-screen.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-screen.Tpo $(DEPDIR)/gnome_terminal_server-terminal-screen.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-screen.c' object='gnome_terminal_server-terminal-screen.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-screen.obj `if test -f 'terminal-screen.c'; then $(CYGPATH_W) 'terminal-screen.c'; else $(CYGPATH_W) '$(srcdir)/terminal-screen.c'; fi` + +gnome_terminal_server-terminal-screen-container.o: terminal-screen-container.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-screen-container.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Tpo -c -o gnome_terminal_server-terminal-screen-container.o `test -f 'terminal-screen-container.c' || echo '$(srcdir)/'`terminal-screen-container.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Tpo $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-screen-container.c' object='gnome_terminal_server-terminal-screen-container.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-screen-container.o `test -f 'terminal-screen-container.c' || echo '$(srcdir)/'`terminal-screen-container.c + +gnome_terminal_server-terminal-screen-container.obj: terminal-screen-container.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-screen-container.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Tpo -c -o gnome_terminal_server-terminal-screen-container.obj `if test -f 'terminal-screen-container.c'; then $(CYGPATH_W) 'terminal-screen-container.c'; else $(CYGPATH_W) '$(srcdir)/terminal-screen-container.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Tpo $(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-screen-container.c' object='gnome_terminal_server-terminal-screen-container.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-screen-container.obj `if test -f 'terminal-screen-container.c'; then $(CYGPATH_W) 'terminal-screen-container.c'; else $(CYGPATH_W) '$(srcdir)/terminal-screen-container.c'; fi` + +gnome_terminal_server-terminal-search-popover.o: terminal-search-popover.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-popover.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Tpo -c -o gnome_terminal_server-terminal-search-popover.o `test -f 'terminal-search-popover.c' || echo '$(srcdir)/'`terminal-search-popover.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-popover.c' object='gnome_terminal_server-terminal-search-popover.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-popover.o `test -f 'terminal-search-popover.c' || echo '$(srcdir)/'`terminal-search-popover.c + +gnome_terminal_server-terminal-search-popover.obj: terminal-search-popover.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-popover.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Tpo -c -o gnome_terminal_server-terminal-search-popover.obj `if test -f 'terminal-search-popover.c'; then $(CYGPATH_W) 'terminal-search-popover.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-popover.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-popover.c' object='gnome_terminal_server-terminal-search-popover.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-popover.obj `if test -f 'terminal-search-popover.c'; then $(CYGPATH_W) 'terminal-search-popover.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-popover.c'; fi` + +gnome_terminal_server-terminal-tab-label.o: terminal-tab-label.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-tab-label.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Tpo -c -o gnome_terminal_server-terminal-tab-label.o `test -f 'terminal-tab-label.c' || echo '$(srcdir)/'`terminal-tab-label.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Tpo $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-tab-label.c' object='gnome_terminal_server-terminal-tab-label.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-tab-label.o `test -f 'terminal-tab-label.c' || echo '$(srcdir)/'`terminal-tab-label.c + +gnome_terminal_server-terminal-tab-label.obj: terminal-tab-label.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-tab-label.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Tpo -c -o gnome_terminal_server-terminal-tab-label.obj `if test -f 'terminal-tab-label.c'; then $(CYGPATH_W) 'terminal-tab-label.c'; else $(CYGPATH_W) '$(srcdir)/terminal-tab-label.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Tpo $(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-tab-label.c' object='gnome_terminal_server-terminal-tab-label.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-tab-label.obj `if test -f 'terminal-tab-label.c'; then $(CYGPATH_W) 'terminal-tab-label.c'; else $(CYGPATH_W) '$(srcdir)/terminal-tab-label.c'; fi` + +gnome_terminal_server-terminal-util.o: terminal-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-util.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-util.Tpo -c -o gnome_terminal_server-terminal-util.o `test -f 'terminal-util.c' || echo '$(srcdir)/'`terminal-util.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-util.Tpo $(DEPDIR)/gnome_terminal_server-terminal-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-util.c' object='gnome_terminal_server-terminal-util.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-util.o `test -f 'terminal-util.c' || echo '$(srcdir)/'`terminal-util.c + +gnome_terminal_server-terminal-util.obj: terminal-util.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-util.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-util.Tpo -c -o gnome_terminal_server-terminal-util.obj `if test -f 'terminal-util.c'; then $(CYGPATH_W) 'terminal-util.c'; else $(CYGPATH_W) '$(srcdir)/terminal-util.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-util.Tpo $(DEPDIR)/gnome_terminal_server-terminal-util.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-util.c' object='gnome_terminal_server-terminal-util.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-util.obj `if test -f 'terminal-util.c'; then $(CYGPATH_W) 'terminal-util.c'; else $(CYGPATH_W) '$(srcdir)/terminal-util.c'; fi` + +gnome_terminal_server-terminal-window.o: terminal-window.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-window.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-window.Tpo -c -o gnome_terminal_server-terminal-window.o `test -f 'terminal-window.c' || echo '$(srcdir)/'`terminal-window.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-window.Tpo $(DEPDIR)/gnome_terminal_server-terminal-window.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-window.c' object='gnome_terminal_server-terminal-window.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-window.o `test -f 'terminal-window.c' || echo '$(srcdir)/'`terminal-window.c + +gnome_terminal_server-terminal-window.obj: terminal-window.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-window.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-window.Tpo -c -o gnome_terminal_server-terminal-window.obj `if test -f 'terminal-window.c'; then $(CYGPATH_W) 'terminal-window.c'; else $(CYGPATH_W) '$(srcdir)/terminal-window.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-window.Tpo $(DEPDIR)/gnome_terminal_server-terminal-window.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-window.c' object='gnome_terminal_server-terminal-window.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-window.obj `if test -f 'terminal-window.c'; then $(CYGPATH_W) 'terminal-window.c'; else $(CYGPATH_W) '$(srcdir)/terminal-window.c'; fi` + +gnome_terminal_server-terminal-search-provider.o: terminal-search-provider.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-provider.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Tpo -c -o gnome_terminal_server-terminal-search-provider.o `test -f 'terminal-search-provider.c' || echo '$(srcdir)/'`terminal-search-provider.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-provider.c' object='gnome_terminal_server-terminal-search-provider.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-provider.o `test -f 'terminal-search-provider.c' || echo '$(srcdir)/'`terminal-search-provider.c + +gnome_terminal_server-terminal-search-provider.obj: terminal-search-provider.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-provider.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Tpo -c -o gnome_terminal_server-terminal-search-provider.obj `if test -f 'terminal-search-provider.c'; then $(CYGPATH_W) 'terminal-search-provider.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-provider.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-provider.c' object='gnome_terminal_server-terminal-search-provider.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-provider.obj `if test -f 'terminal-search-provider.c'; then $(CYGPATH_W) 'terminal-search-provider.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-provider.c'; fi` + +gnome_terminal_server-terminal-marshal.o: terminal-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-marshal.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-marshal.Tpo -c -o gnome_terminal_server-terminal-marshal.o `test -f 'terminal-marshal.c' || echo '$(srcdir)/'`terminal-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-marshal.Tpo $(DEPDIR)/gnome_terminal_server-terminal-marshal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-marshal.c' object='gnome_terminal_server-terminal-marshal.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-marshal.o `test -f 'terminal-marshal.c' || echo '$(srcdir)/'`terminal-marshal.c + +gnome_terminal_server-terminal-marshal.obj: terminal-marshal.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-marshal.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-marshal.Tpo -c -o gnome_terminal_server-terminal-marshal.obj `if test -f 'terminal-marshal.c'; then $(CYGPATH_W) 'terminal-marshal.c'; else $(CYGPATH_W) '$(srcdir)/terminal-marshal.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-marshal.Tpo $(DEPDIR)/gnome_terminal_server-terminal-marshal.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-marshal.c' object='gnome_terminal_server-terminal-marshal.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-marshal.obj `if test -f 'terminal-marshal.c'; then $(CYGPATH_W) 'terminal-marshal.c'; else $(CYGPATH_W) '$(srcdir)/terminal-marshal.c'; fi` + +gnome_terminal_server-terminal-type-builtins.o: terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-type-builtins.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Tpo -c -o gnome_terminal_server-terminal-type-builtins.o `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Tpo $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-type-builtins.c' object='gnome_terminal_server-terminal-type-builtins.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-type-builtins.o `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c + +gnome_terminal_server-terminal-type-builtins.obj: terminal-type-builtins.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-type-builtins.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Tpo -c -o gnome_terminal_server-terminal-type-builtins.obj `if test -f 'terminal-type-builtins.c'; then $(CYGPATH_W) 'terminal-type-builtins.c'; else $(CYGPATH_W) '$(srcdir)/terminal-type-builtins.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Tpo $(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-type-builtins.c' object='gnome_terminal_server-terminal-type-builtins.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-type-builtins.obj `if test -f 'terminal-type-builtins.c'; then $(CYGPATH_W) 'terminal-type-builtins.c'; else $(CYGPATH_W) '$(srcdir)/terminal-type-builtins.c'; fi` + +gnome_terminal_server-terminal-gdbus-generated.o: terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-gdbus-generated.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Tpo -c -o gnome_terminal_server-terminal-gdbus-generated.o `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus-generated.c' object='gnome_terminal_server-terminal-gdbus-generated.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-gdbus-generated.o `test -f 'terminal-gdbus-generated.c' || echo '$(srcdir)/'`terminal-gdbus-generated.c + +gnome_terminal_server-terminal-gdbus-generated.obj: terminal-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-gdbus-generated.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Tpo -c -o gnome_terminal_server-terminal-gdbus-generated.obj `if test -f 'terminal-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus-generated.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-gdbus-generated.c' object='gnome_terminal_server-terminal-gdbus-generated.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-gdbus-generated.obj `if test -f 'terminal-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-gdbus-generated.c'; fi` + +gnome_terminal_server-terminal-resources.o: terminal-resources.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-resources.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-resources.Tpo -c -o gnome_terminal_server-terminal-resources.o `test -f 'terminal-resources.c' || echo '$(srcdir)/'`terminal-resources.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-resources.Tpo $(DEPDIR)/gnome_terminal_server-terminal-resources.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-resources.c' object='gnome_terminal_server-terminal-resources.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-resources.o `test -f 'terminal-resources.c' || echo '$(srcdir)/'`terminal-resources.c + +gnome_terminal_server-terminal-resources.obj: terminal-resources.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-resources.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-resources.Tpo -c -o gnome_terminal_server-terminal-resources.obj `if test -f 'terminal-resources.c'; then $(CYGPATH_W) 'terminal-resources.c'; else $(CYGPATH_W) '$(srcdir)/terminal-resources.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-resources.Tpo $(DEPDIR)/gnome_terminal_server-terminal-resources.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-resources.c' object='gnome_terminal_server-terminal-resources.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-resources.obj `if test -f 'terminal-resources.c'; then $(CYGPATH_W) 'terminal-resources.c'; else $(CYGPATH_W) '$(srcdir)/terminal-resources.c'; fi` + +gnome_terminal_server-terminal-search-provider-gdbus-generated.o: terminal-search-provider-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-provider-gdbus-generated.o -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Tpo -c -o gnome_terminal_server-terminal-search-provider-gdbus-generated.o `test -f 'terminal-search-provider-gdbus-generated.c' || echo '$(srcdir)/'`terminal-search-provider-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-provider-gdbus-generated.c' object='gnome_terminal_server-terminal-search-provider-gdbus-generated.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-provider-gdbus-generated.o `test -f 'terminal-search-provider-gdbus-generated.c' || echo '$(srcdir)/'`terminal-search-provider-gdbus-generated.c + +gnome_terminal_server-terminal-search-provider-gdbus-generated.obj: terminal-search-provider-gdbus-generated.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -MT gnome_terminal_server-terminal-search-provider-gdbus-generated.obj -MD -MP -MF $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Tpo -c -o gnome_terminal_server-terminal-search-provider-gdbus-generated.obj `if test -f 'terminal-search-provider-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-search-provider-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-provider-gdbus-generated.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Tpo $(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-search-provider-gdbus-generated.c' object='gnome_terminal_server-terminal-search-provider-gdbus-generated.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(gnome_terminal_server_CPPFLAGS) $(CPPFLAGS) $(gnome_terminal_server_CFLAGS) $(CFLAGS) -c -o gnome_terminal_server-terminal-search-provider-gdbus-generated.obj `if test -f 'terminal-search-provider-gdbus-generated.c'; then $(CYGPATH_W) 'terminal-search-provider-gdbus-generated.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-provider-gdbus-generated.c'; fi` + +terminal_regex-terminal-regex.o: terminal-regex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(terminal_regex_CPPFLAGS) $(CPPFLAGS) $(terminal_regex_CFLAGS) $(CFLAGS) -MT terminal_regex-terminal-regex.o -MD -MP -MF $(DEPDIR)/terminal_regex-terminal-regex.Tpo -c -o terminal_regex-terminal-regex.o `test -f 'terminal-regex.c' || echo '$(srcdir)/'`terminal-regex.c +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/terminal_regex-terminal-regex.Tpo $(DEPDIR)/terminal_regex-terminal-regex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-regex.c' object='terminal_regex-terminal-regex.o' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(terminal_regex_CPPFLAGS) $(CPPFLAGS) $(terminal_regex_CFLAGS) $(CFLAGS) -c -o terminal_regex-terminal-regex.o `test -f 'terminal-regex.c' || echo '$(srcdir)/'`terminal-regex.c + +terminal_regex-terminal-regex.obj: terminal-regex.c +@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(terminal_regex_CPPFLAGS) $(CPPFLAGS) $(terminal_regex_CFLAGS) $(CFLAGS) -MT terminal_regex-terminal-regex.obj -MD -MP -MF $(DEPDIR)/terminal_regex-terminal-regex.Tpo -c -o terminal_regex-terminal-regex.obj `if test -f 'terminal-regex.c'; then $(CYGPATH_W) 'terminal-regex.c'; else $(CYGPATH_W) '$(srcdir)/terminal-regex.c'; fi` +@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/terminal_regex-terminal-regex.Tpo $(DEPDIR)/terminal_regex-terminal-regex.Po +@AMDEP_TRUE@@am__fastdepCC_FALSE@ $(AM_V_CC)source='terminal-regex.c' object='terminal_regex-terminal-regex.obj' libtool=no @AMDEPBACKSLASH@ +@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@ +@am__fastdepCC_FALSE@ $(AM_V_CC@am__nodep@)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(terminal_regex_CPPFLAGS) $(CPPFLAGS) $(terminal_regex_CFLAGS) $(CFLAGS) -c -o terminal_regex-terminal-regex.obj `if test -f 'terminal-regex.c'; then $(CYGPATH_W) 'terminal-regex.c'; else $(CYGPATH_W) '$(srcdir)/terminal-regex.c'; fi` + +mostlyclean-libtool: + -rm -f *.lo + +clean-libtool: + -rm -rf .libs _libs +install-dbusserviceDATA: $(dbusservice_DATA) + @$(NORMAL_INSTALL) + @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(dbusservicedir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(dbusservicedir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(dbusservicedir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(dbusservicedir)" || exit $$?; \ + done + +uninstall-dbusserviceDATA: + @$(NORMAL_UNINSTALL) + @list='$(dbusservice_DATA)'; test -n "$(dbusservicedir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(dbusservicedir)'; $(am__uninstall_files_from_dir) +install-dist_searchproviderDATA: $(dist_searchprovider_DATA) + @$(NORMAL_INSTALL) + @list='$(dist_searchprovider_DATA)'; test -n "$(searchproviderdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(searchproviderdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(searchproviderdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(searchproviderdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(searchproviderdir)" || exit $$?; \ + done + +uninstall-dist_searchproviderDATA: + @$(NORMAL_UNINSTALL) + @list='$(dist_searchprovider_DATA)'; test -n "$(searchproviderdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(searchproviderdir)'; $(am__uninstall_files_from_dir) +install-nodist_systemduserDATA: $(nodist_systemduser_DATA) + @$(NORMAL_INSTALL) + @list='$(nodist_systemduser_DATA)'; test -n "$(systemduserdir)" || list=; \ + if test -n "$$list"; then \ + echo " $(MKDIR_P) '$(DESTDIR)$(systemduserdir)'"; \ + $(MKDIR_P) "$(DESTDIR)$(systemduserdir)" || exit 1; \ + fi; \ + for p in $$list; do \ + if test -f "$$p"; then d=; else d="$(srcdir)/"; fi; \ + echo "$$d$$p"; \ + done | $(am__base_list) | \ + while read files; do \ + echo " $(INSTALL_DATA) $$files '$(DESTDIR)$(systemduserdir)'"; \ + $(INSTALL_DATA) $$files "$(DESTDIR)$(systemduserdir)" || exit $$?; \ + done + +uninstall-nodist_systemduserDATA: + @$(NORMAL_UNINSTALL) + @list='$(nodist_systemduser_DATA)'; test -n "$(systemduserdir)" || list=; \ + files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \ + dir='$(DESTDIR)$(systemduserdir)'; $(am__uninstall_files_from_dir) + +ID: $(am__tagged_files) + $(am__define_uniq_tagged_files); mkid -fID $$unique +tags: tags-am +TAGS: tags + +tags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + set x; \ + here=`pwd`; \ + $(am__define_uniq_tagged_files); \ + shift; \ + if test -z "$(ETAGS_ARGS)$$*$$unique"; then :; else \ + test -n "$$unique" || unique=$$empty_fix; \ + if test $$# -gt 0; then \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + "$$@" $$unique; \ + else \ + $(ETAGS) $(ETAGSFLAGS) $(AM_ETAGSFLAGS) $(ETAGS_ARGS) \ + $$unique; \ + fi; \ + fi +ctags: ctags-am + +CTAGS: ctags +ctags-am: $(TAGS_DEPENDENCIES) $(am__tagged_files) + $(am__define_uniq_tagged_files); \ + test -z "$(CTAGS_ARGS)$$unique" \ + || $(CTAGS) $(CTAGSFLAGS) $(AM_CTAGSFLAGS) $(CTAGS_ARGS) \ + $$unique + +GTAGS: + here=`$(am__cd) $(top_builddir) && pwd` \ + && $(am__cd) $(top_srcdir) \ + && gtags -i $(GTAGS_ARGS) "$$here" +cscopelist: cscopelist-am + +cscopelist-am: $(am__tagged_files) + list='$(am__tagged_files)'; \ + case "$(srcdir)" in \ + [\\/]* | ?:[\\/]*) sdir="$(srcdir)" ;; \ + *) sdir=$(subdir)/$(srcdir) ;; \ + esac; \ + for i in $$list; do \ + if test -f "$$i"; then \ + echo "$(subdir)/$$i"; \ + else \ + echo "$$sdir/$$i"; \ + fi; \ + done >> $(top_builddir)/cscope.files + +distclean-tags: + -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags + +# Recover from deleted '.trs' file; this should ensure that +# "rm -f foo.log; make foo.trs" re-run 'foo.test', and re-create +# both 'foo.log' and 'foo.trs'. Break the recipe in two subshells +# to avoid problems with "make -n". +.log.trs: + rm -f $< $@ + $(MAKE) $(AM_MAKEFLAGS) $< + +# Leading 'am--fnord' is there to ensure the list of targets does not +# expand to empty, as could happen e.g. with make check TESTS=''. +am--fnord $(TEST_LOGS) $(TEST_LOGS:.log=.trs): $(am__force_recheck) +am--force-recheck: + @: + +$(TEST_SUITE_LOG): $(TEST_LOGS) + @$(am__set_TESTS_bases); \ + am__f_ok () { test -f "$$1" && test -r "$$1"; }; \ + redo_bases=`for i in $$bases; do \ + am__f_ok $$i.trs && am__f_ok $$i.log || echo $$i; \ + done`; \ + if test -n "$$redo_bases"; then \ + redo_logs=`for i in $$redo_bases; do echo $$i.log; done`; \ + redo_results=`for i in $$redo_bases; do echo $$i.trs; done`; \ + if $(am__make_dryrun); then :; else \ + rm -f $$redo_logs && rm -f $$redo_results || exit 1; \ + fi; \ + fi; \ + if test -n "$$am__remaking_logs"; then \ + echo "fatal: making $(TEST_SUITE_LOG): possible infinite" \ + "recursion detected" >&2; \ + elif test -n "$$redo_logs"; then \ + am__remaking_logs=yes $(MAKE) $(AM_MAKEFLAGS) $$redo_logs; \ + fi; \ + if $(am__make_dryrun); then :; else \ + st=0; \ + errmsg="fatal: making $(TEST_SUITE_LOG): failed to create"; \ + for i in $$redo_bases; do \ + test -f $$i.trs && test -r $$i.trs \ + || { echo "$$errmsg $$i.trs" >&2; st=1; }; \ + test -f $$i.log && test -r $$i.log \ + || { echo "$$errmsg $$i.log" >&2; st=1; }; \ + done; \ + test $$st -eq 0 || exit 1; \ + fi + @$(am__sh_e_setup); $(am__tty_colors); $(am__set_TESTS_bases); \ + ws='[ ]'; \ + results=`for b in $$bases; do echo $$b.trs; done`; \ + test -n "$$results" || results=/dev/null; \ + all=` grep "^$$ws*:test-result:" $$results | wc -l`; \ + pass=` grep "^$$ws*:test-result:$$ws*PASS" $$results | wc -l`; \ + fail=` grep "^$$ws*:test-result:$$ws*FAIL" $$results | wc -l`; \ + skip=` grep "^$$ws*:test-result:$$ws*SKIP" $$results | wc -l`; \ + xfail=`grep "^$$ws*:test-result:$$ws*XFAIL" $$results | wc -l`; \ + xpass=`grep "^$$ws*:test-result:$$ws*XPASS" $$results | wc -l`; \ + error=`grep "^$$ws*:test-result:$$ws*ERROR" $$results | wc -l`; \ + if test `expr $$fail + $$xpass + $$error` -eq 0; then \ + success=true; \ + else \ + success=false; \ + fi; \ + br='==================='; br=$$br$$br$$br$$br; \ + result_count () \ + { \ + if test x"$$1" = x"--maybe-color"; then \ + maybe_colorize=yes; \ + elif test x"$$1" = x"--no-color"; then \ + maybe_colorize=no; \ + else \ + echo "$@: invalid 'result_count' usage" >&2; exit 4; \ + fi; \ + shift; \ + desc=$$1 count=$$2; \ + if test $$maybe_colorize = yes && test $$count -gt 0; then \ + color_start=$$3 color_end=$$std; \ + else \ + color_start= color_end=; \ + fi; \ + echo "$${color_start}# $$desc $$count$${color_end}"; \ + }; \ + create_testsuite_report () \ + { \ + result_count $$1 "TOTAL:" $$all "$$brg"; \ + result_count $$1 "PASS: " $$pass "$$grn"; \ + result_count $$1 "SKIP: " $$skip "$$blu"; \ + result_count $$1 "XFAIL:" $$xfail "$$lgn"; \ + result_count $$1 "FAIL: " $$fail "$$red"; \ + result_count $$1 "XPASS:" $$xpass "$$red"; \ + result_count $$1 "ERROR:" $$error "$$mgn"; \ + }; \ + { \ + echo "$(PACKAGE_STRING): $(subdir)/$(TEST_SUITE_LOG)" | \ + $(am__rst_title); \ + create_testsuite_report --no-color; \ + echo; \ + echo ".. contents:: :depth: 2"; \ + echo; \ + for b in $$bases; do echo $$b; done \ + | $(am__create_global_log); \ + } >$(TEST_SUITE_LOG).tmp || exit 1; \ + mv $(TEST_SUITE_LOG).tmp $(TEST_SUITE_LOG); \ + if $$success; then \ + col="$$grn"; \ + else \ + col="$$red"; \ + test x"$$VERBOSE" = x || cat $(TEST_SUITE_LOG); \ + fi; \ + echo "$${col}$$br$${std}"; \ + echo "$${col}Testsuite summary for $(PACKAGE_STRING)$${std}"; \ + echo "$${col}$$br$${std}"; \ + create_testsuite_report --maybe-color; \ + echo "$$col$$br$$std"; \ + if $$success; then :; else \ + echo "$${col}See $(subdir)/$(TEST_SUITE_LOG)$${std}"; \ + if test -n "$(PACKAGE_BUGREPORT)"; then \ + echo "$${col}Please report to $(PACKAGE_BUGREPORT)$${std}"; \ + fi; \ + echo "$$col$$br$$std"; \ + fi; \ + $$success || exit 1 + +check-TESTS: $(check_PROGRAMS) + @list='$(RECHECK_LOGS)'; test -z "$$list" || rm -f $$list + @list='$(RECHECK_LOGS:.log=.trs)'; test -z "$$list" || rm -f $$list + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + trs_list=`for i in $$bases; do echo $$i.trs; done`; \ + log_list=`echo $$log_list`; trs_list=`echo $$trs_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) TEST_LOGS="$$log_list"; \ + exit $$?; +recheck: all $(check_PROGRAMS) + @test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + @set +e; $(am__set_TESTS_bases); \ + bases=`for i in $$bases; do echo $$i; done \ + | $(am__list_recheck_tests)` || exit 1; \ + log_list=`for i in $$bases; do echo $$i.log; done`; \ + log_list=`echo $$log_list`; \ + $(MAKE) $(AM_MAKEFLAGS) $(TEST_SUITE_LOG) \ + am__force_recheck=am--force-recheck \ + TEST_LOGS="$$log_list"; \ + exit $$? +terminal-regex.log: terminal-regex$(EXEEXT) + @p='terminal-regex$(EXEEXT)'; \ + b='terminal-regex'; \ + $(am__check_pre) $(LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_LOG_DRIVER_FLAGS) $(LOG_DRIVER_FLAGS) -- $(LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +.test.log: + @p='$<'; \ + $(am__set_b); \ + $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ + --log-file $$b.log --trs-file $$b.trs \ + $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ + "$$tst" $(AM_TESTS_FD_REDIRECT) +@am__EXEEXT_TRUE@.test$(EXEEXT).log: +@am__EXEEXT_TRUE@ @p='$<'; \ +@am__EXEEXT_TRUE@ $(am__set_b); \ +@am__EXEEXT_TRUE@ $(am__check_pre) $(TEST_LOG_DRIVER) --test-name "$$f" \ +@am__EXEEXT_TRUE@ --log-file $$b.log --trs-file $$b.trs \ +@am__EXEEXT_TRUE@ $(am__common_driver_flags) $(AM_TEST_LOG_DRIVER_FLAGS) $(TEST_LOG_DRIVER_FLAGS) -- $(TEST_LOG_COMPILE) \ +@am__EXEEXT_TRUE@ "$$tst" $(AM_TESTS_FD_REDIRECT) + +distdir: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) distdir-am + +distdir-am: $(DISTFILES) + @srcdirstrip=`echo "$(srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + topsrcdirstrip=`echo "$(top_srcdir)" | sed 's/[].[^$$\\*]/\\\\&/g'`; \ + list='$(DISTFILES)'; \ + dist_files=`for file in $$list; do echo $$file; done | \ + sed -e "s|^$$srcdirstrip/||;t" \ + -e "s|^$$topsrcdirstrip/|$(top_builddir)/|;t"`; \ + case $$dist_files in \ + */*) $(MKDIR_P) `echo "$$dist_files" | \ + sed '/\//!d;s|^|$(distdir)/|;s,/[^/]*$$,,' | \ + sort -u` ;; \ + esac; \ + for file in $$dist_files; do \ + if test -f $$file || test -d $$file; then d=.; else d=$(srcdir); fi; \ + if test -d $$d/$$file; then \ + dir=`echo "/$$file" | sed -e 's,/[^/]*$$,,'`; \ + if test -d "$(distdir)/$$file"; then \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + if test -d $(srcdir)/$$file && test $$d != $(srcdir); then \ + cp -fpR $(srcdir)/$$file "$(distdir)$$dir" || exit 1; \ + find "$(distdir)/$$file" -type d ! -perm -700 -exec chmod u+rwx {} \;; \ + fi; \ + cp -fpR $$d/$$file "$(distdir)$$dir" || exit 1; \ + else \ + test -f "$(distdir)/$$file" \ + || cp -p $$d/$$file "$(distdir)/$$file" \ + || exit 1; \ + fi; \ + done +check-am: all-am + $(MAKE) $(AM_MAKEFLAGS) $(check_PROGRAMS) + $(MAKE) $(AM_MAKEFLAGS) check-TESTS +check: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) check-am +all-am: Makefile $(PROGRAMS) $(LTLIBRARIES) $(DATA) +installdirs: + for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(libexecdir)" "$(DESTDIR)$(nautilusextensiondir)" "$(DESTDIR)$(dbusservicedir)" "$(DESTDIR)$(searchproviderdir)" "$(DESTDIR)$(systemduserdir)"; do \ + test -z "$$dir" || $(MKDIR_P) "$$dir"; \ + done +install: $(BUILT_SOURCES) + $(MAKE) $(AM_MAKEFLAGS) install-am +install-exec: install-exec-am +install-data: install-data-am +uninstall: uninstall-am + +install-am: all-am + @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am + +installcheck: installcheck-am +install-strip: + if test -z '$(STRIP)'; then \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + install; \ + else \ + $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \ + install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \ + "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'" install; \ + fi +mostlyclean-generic: + -test -z "$(TEST_LOGS)" || rm -f $(TEST_LOGS) + -test -z "$(TEST_LOGS:.log=.trs)" || rm -f $(TEST_LOGS:.log=.trs) + -test -z "$(TEST_SUITE_LOG)" || rm -f $(TEST_SUITE_LOG) + +clean-generic: + -test -z "$(CLEANFILES)" || rm -f $(CLEANFILES) + +distclean-generic: + -test -z "$(CONFIG_CLEAN_FILES)" || rm -f $(CONFIG_CLEAN_FILES) + -test . = "$(srcdir)" || test -z "$(CONFIG_CLEAN_VPATH_FILES)" || rm -f $(CONFIG_CLEAN_VPATH_FILES) + +maintainer-clean-generic: + @echo "This command is intended for maintainers to use" + @echo "it deletes files that may require special tools to rebuild." + -test -z "$(BUILT_SOURCES)" || rm -f $(BUILT_SOURCES) +clean: clean-am + +clean-am: clean-binPROGRAMS clean-checkPROGRAMS clean-generic \ + clean-libexecPROGRAMS clean-libtool \ + clean-nautilusextensionLTLIBRARIES clean-noinstPROGRAMS \ + mostlyclean-am + +distclean: distclean-am + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-client-utils.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-debug.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-i18n.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-options.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-profiles-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-settings-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-type-builtins.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-eggshell.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-profile-editor.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-server.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-accels.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-app.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-debug.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-i18n.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-marshal.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-notebook.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-prefs.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-resources.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-screen.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-util.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-window.Po + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Plo + -rm -f ./$(DEPDIR)/terminal_regex-terminal-regex.Po + -rm -f Makefile +distclean-am: clean-am distclean-compile distclean-generic \ + distclean-tags + +dvi: dvi-am + +dvi-am: + +html: html-am + +html-am: + +info: info-am + +info-am: + +install-data-am: install-dbusserviceDATA \ + install-dist_searchproviderDATA \ + install-nautilusextensionLTLIBRARIES \ + install-nodist_systemduserDATA + +install-dvi: install-dvi-am + +install-dvi-am: + +install-exec-am: install-binPROGRAMS install-libexecPROGRAMS + +install-html: install-html-am + +install-html-am: + +install-info: install-info-am + +install-info-am: + +install-man: + +install-pdf: install-pdf-am + +install-pdf-am: + +install-ps: install-ps-am + +install-ps-am: + +installcheck-am: + +maintainer-clean: maintainer-clean-am + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-client-utils.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-debug.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-i18n.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-options.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-profiles-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-settings-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal-type-builtins.Po + -rm -f ./$(DEPDIR)/gnome_terminal-terminal.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-eggshell.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-profile-editor.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-server.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-accels.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-app.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-debug.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-gdbus.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-headerbar.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-i18n.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-icon-button.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-info-bar.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-marshal.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-mdi-container.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-menu-button.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-notebook.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-prefs.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-profiles-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-resources.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-screen-container.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-screen.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-popover.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider-gdbus-generated.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-search-provider.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-settings-list.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-tab-label.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-type-builtins.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-util.Po + -rm -f ./$(DEPDIR)/gnome_terminal_server-terminal-window.Po + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-client-utils.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-gdbus-generated.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-i18n.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-nautilus.Plo + -rm -f ./$(DEPDIR)/libterminal_nautilus_la-terminal-type-builtins.Plo + -rm -f ./$(DEPDIR)/terminal_regex-terminal-regex.Po + -rm -f Makefile +maintainer-clean-am: distclean-am maintainer-clean-generic + +mostlyclean: mostlyclean-am + +mostlyclean-am: mostlyclean-compile mostlyclean-generic \ + mostlyclean-libtool + +pdf: pdf-am + +pdf-am: + +ps: ps-am + +ps-am: + +uninstall-am: uninstall-binPROGRAMS uninstall-dbusserviceDATA \ + uninstall-dist_searchproviderDATA uninstall-libexecPROGRAMS \ + uninstall-nautilusextensionLTLIBRARIES \ + uninstall-nodist_systemduserDATA + +.MAKE: all check check-am install install-am install-strip + +.PHONY: CTAGS GTAGS TAGS all all-am am--depfiles check check-TESTS \ + check-am clean clean-binPROGRAMS clean-checkPROGRAMS \ + clean-generic clean-libexecPROGRAMS clean-libtool \ + clean-nautilusextensionLTLIBRARIES clean-noinstPROGRAMS \ + cscopelist-am ctags ctags-am distclean distclean-compile \ + distclean-generic distclean-libtool distclean-tags distdir dvi \ + dvi-am html html-am info info-am install install-am \ + install-binPROGRAMS install-data install-data-am \ + install-dbusserviceDATA install-dist_searchproviderDATA \ + install-dvi install-dvi-am install-exec install-exec-am \ + install-html install-html-am install-info install-info-am \ + install-libexecPROGRAMS install-man \ + install-nautilusextensionLTLIBRARIES \ + install-nodist_systemduserDATA install-pdf install-pdf-am \ + install-ps install-ps-am install-strip installcheck \ + installcheck-am installdirs maintainer-clean \ + maintainer-clean-generic mostlyclean mostlyclean-compile \ + mostlyclean-generic mostlyclean-libtool pdf pdf-am ps ps-am \ + recheck tags tags-am uninstall uninstall-am \ + uninstall-binPROGRAMS uninstall-dbusserviceDATA \ + uninstall-dist_searchproviderDATA uninstall-libexecPROGRAMS \ + uninstall-nautilusextensionLTLIBRARIES \ + uninstall-nodist_systemduserDATA + +.PRECIOUS: Makefile + + +terminal-type-builtins.h: stamp-terminal-type-builtins.h + @true + +stamp-terminal-type-builtins.h: terminal-type-builtins.h.template $(TYPES_H_FILES) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-ttbh \ + && (cmp -s xgen-ttbh terminal-type-builtins.h || cp xgen-ttbh terminal-type-builtins.h ) \ + && rm -f xgen-ttbh \ + && echo timestamp > $(@F) + +terminal-type-builtins.c: terminal-type-builtins.c.template $(TYPES_H_FILES) + $(AM_V_GEN) $(GLIB_MKENUMS) --template $< $(filter-out $<,$^) > xgen-ttbc \ + && (cmp -s xgen-ttbc terminal-type-builtins.c || cp xgen-ttbc terminal-type-builtins.c ) \ + && rm -f xgen-ttbc + +terminal-marshal.h: $(srcdir)/terminal-marshal.list + $(AM_V_GEN) ( $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \ + --header \ + --internal > terminal-marshal.h.tmp \ + && mv terminal-marshal.h.tmp terminal-marshal.h ) \ + || ( rm -f terminal-marshal.h.tmp && exit 1 ) + +terminal-marshal.c: $(srcdir)/terminal-marshal.list + $(AM_V_GEN) ( echo '#include "terminal-marshal.h"' > terminal-marshal.c.tmp && \ + $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \ + --body \ + --internal >> terminal-marshal.c.tmp \ + && mv terminal-marshal.c.tmp terminal-marshal.c ) \ + || ( rm -f terminal-marshal.c.tmp && exit 1 ) + +org.gnome.Terminal.service: Makefile + $(AM_V_GEN) ( echo "[D-BUS Service]"; \ + echo "Name=org.gnome.Terminal"; \ + echo "SystemdService=gnome-terminal-server.service"; \ + echo "Exec=${libexecdir}/gnome-terminal-server") > $@ + +gnome-terminal-server.service: Makefile + $(AM_V_GEN) ( echo "[Unit]"; \ + echo "Description=GNOME Terminal Server"; \ + echo "PartOf=graphical-session.target"; \ + echo "[Service]"; \ + echo "Slice=app-org.gnome.Terminal.slice"; \ + echo "Type=dbus"; \ + echo "BusName=org.gnome.Terminal"; \ + echo "ExecStart=${libexecdir}/gnome-terminal-server"; \ + echo "TimeoutStopSec=5s"; \ + echo "KillMode=process") > $@ + +terminal-gdbus-generated.c terminal-gdbus-generated.h: org.gnome.Terminal.xml Makefile + $(AM_V_GEN) $(GDBUS_CODEGEN) \ + --interface-prefix=org.gnome.Terminal \ + --c-namespace=Terminal \ + --c-generate-object-manager \ + --generate-c-code terminal-gdbus-generated \ + $< + +terminal-menubar-with-mnemonics.ui: terminal-menubar.ui.in + $(AM_V_GEN)$(SED) -e 's|||g' -e 's|||g' -e 's|||g' $< > $@ + +terminal-menubar-without-mnemonics.ui: terminal-menubar.ui.in + $(AM_V_GEN)$(SED) -e 's|||g' -e 's|||g' -e 's|||g' $< > $@ + +terminal-resources.h terminal-resources.c: terminal.gresource.xml Makefile $(shell $(GLIB_COMPILE_RESOURCES) --generate-dependencies --sourcedir $(srcdir) --sourcedir $(builddir) $(srcdir)/terminal.gresource.xml) + $(AM_V_GEN) XMLLINT=$(XMLLINT) $(GLIB_COMPILE_RESOURCES) --target $@ --sourcedir $(builddir) --sourcedir $(srcdir) --generate --c-name terminal $< + +@ENABLE_SEARCH_PROVIDER_TRUE@terminal-search-provider-gdbus-generated.c terminal-search-provider-gdbus-generated.h: $(dbusinterfacedir)/org.gnome.ShellSearchProvider2.xml Makefile +@ENABLE_SEARCH_PROVIDER_TRUE@ $(AM_V_GEN) $(GDBUS_CODEGEN) \ +@ENABLE_SEARCH_PROVIDER_TRUE@ --interface-prefix=org.gnome.Shell \ +@ENABLE_SEARCH_PROVIDER_TRUE@ --c-namespace=Terminal \ +@ENABLE_SEARCH_PROVIDER_TRUE@ --generate-c-code terminal-search-provider-gdbus-generated \ +@ENABLE_SEARCH_PROVIDER_TRUE@ $< + +@GSETTINGS_RULES@ + +-include $(top_srcdir)/git.mk + +# Tell versions [3.59,3.63) of GNU make to not export all variables. +# Otherwise a system limit (for SysV at least) may be exceeded. +.NOEXPORT: diff --git a/src/eggshell.c b/src/eggshell.c new file mode 100644 index 0000000..ed4f3b5 --- /dev/null +++ b/src/eggshell.c @@ -0,0 +1,112 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * Copyright (C) 1999, 2000 Red Hat, Inc. + * All rights reserved. + * + * This file is part of the Gnome Library. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* + @NOTATION@ + */ + +/* + * + * Gnome utility routines. + * (C) 1997, 1998, 1999 the Free Software Foundation. + * + * Author: Miguel de Icaza, + */ + +#include + +#include "eggshell.h" + +#include +#include +#include +#include +#ifndef G_OS_WIN32 +#include +#endif + +#include + +/** + * egg_shell: + * @shell: the value of the SHELL env variable + * + * Retrieves the user's preferred shell. + * + * Returns: A newly allocated string that is the path to the shell. + */ +char * +egg_shell (const char *shell) +{ +#ifndef G_OS_WIN32 + struct passwd *pw; + int i; + static const char shells [][14] = { + /* Note that on some systems shells can also + * be installed in /usr/bin */ + "/bin/bash", "/usr/bin/bash", + "/bin/zsh", "/usr/bin/zsh", + "/bin/tcsh", "/usr/bin/tcsh", + "/bin/ksh", "/usr/bin/ksh", + "/bin/csh", "/bin/sh" + }; + + if (geteuid () == getuid () && + getegid () == getgid ()) { + /* only in non-setuid */ + if (shell != NULL) { + if (access (shell, X_OK) == 0) { + return g_strdup (shell); + } + } + } + pw = getpwuid(getuid()); + if (pw && pw->pw_shell) { + if (access (pw->pw_shell, X_OK) == 0) { + return g_strdup (pw->pw_shell); + } + } + + for (i = 0; i != G_N_ELEMENTS (shells); i++) { + if (access (shells [i], X_OK) == 0) { + return g_strdup (shells[i]); + } + } + + /* If /bin/sh doesn't exist, your system is truly broken. */ + g_assert_not_reached (); + + /* Placate compiler. */ + return NULL; +#else + /* g_find_program_in_path() always looks also in the Windows + * and System32 directories, so it should always find either cmd.exe + * or command.com. + */ + char *retval = g_find_program_in_path ("cmd.exe"); + + if (retval == NULL) + retval = g_find_program_in_path ("command.com"); + + g_assert (retval != NULL); + + return retval; +#endif +} diff --git a/src/eggshell.h b/src/eggshell.h new file mode 100644 index 0000000..2312777 --- /dev/null +++ b/src/eggshell.h @@ -0,0 +1,38 @@ +/* + * Copyright (C) 1997, 1998, 1999, 2000 Free Software Foundation + * Copyright (C) 1999, 2000 Red Hat, Inc. + * All rights reserved. + * + * This file is part of the Gnome Library. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ +/* + @NOTATION@ + */ + +#ifndef __EGG_USER_SHELL_H__ +#define __EGG_USER_SHELL_H__ + +#include +#include + +G_BEGIN_DECLS + +/* Find the name of the user's shell. */ +char *egg_shell (const char *shell); + +G_END_DECLS + +#endif diff --git a/src/gnome-terminal-search-provider.ini b/src/gnome-terminal-search-provider.ini new file mode 100644 index 0000000..1b9f81c --- /dev/null +++ b/src/gnome-terminal-search-provider.ini @@ -0,0 +1,20 @@ +# Copyright © 2013 Red Hat, Inc. +# +# This program is free software: you can redistribute it and/or modify +# it under the terms of the GNU General Public License as published by +# the Free Software Foundation, either version 3 of the License, or +# (at your option) any later version. +# +# This program is distributed in the hope that it will be useful, +# but WITHOUT ANY WARRANTY; without even the implied warranty of +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +# GNU General Public License for more details. +# +# You should have received a copy of the GNU General Public License +# along with this program. If not, see . + +[Shell Search Provider] +DesktopId=org.gnome.Terminal.desktop +BusName=org.gnome.Terminal +ObjectPath=/org/gnome/Terminal/SearchProvider +Version=2 diff --git a/src/nautilus.symbols b/src/nautilus.symbols new file mode 100644 index 0000000..7f58bf8 --- /dev/null +++ b/src/nautilus.symbols @@ -0,0 +1,3 @@ +nautilus_module_initialize +nautilus_module_shutdown +nautilus_module_list_types diff --git a/src/org.gnome.Terminal.gschema.xml b/src/org.gnome.Terminal.gschema.xml new file mode 100644 index 0000000..be00aa2 --- /dev/null +++ b/src/org.gnome.Terminal.gschema.xml @@ -0,0 +1,724 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + + [] + + + '' + + + + + + + ['b1dcc9dd-5262-4d8d-a863-c897e6d979b9'] + 'b1dcc9dd-5262-4d8d-a863-c897e6d979b9' + + + + + + + + 'Unnamed' + Human-readable name of the profile + Human-readable name of the profile. + + + '#171421' + Default color of text in the terminal + Default color of text in the terminal, as a color specification (can be HTML-style hex digits, or a color name such as “red”). + + + '#ffffff' + Default color of terminal background + Default color of terminal background, as a color specification (can be HTML-style hex digits, or a color name such as “red”). + + + '#000000' + Default color of bold text in the terminal + Default color of bold text in the terminal, as a color specification (can be HTML-style hex digits, or a color name such as “red”). This is ignored if bold-color-same-as-fg is true. + + + true + Whether bold text should use the same color as normal text + If true, boldface text will be rendered using the same color as normal text. + + + + 1.0 + Scale factor for the cell height to increase line spacing. (Does not increase the font’s height.) + + + + 1.0 + Scale factor for the cell width to increase letter spacing. (Does not increase the font’s width.) + + + false + Whether to use custom cursor colors + If true, use the cursor colors from the profile. + + + '#000000' + Cursor background color + Custom color of the background of the terminal’s cursor, as a color specification (can be HTML-style hex digits, or a color name such as “red”). This is ignored if cursor-colors-set is false. + + + '#ffffff' + Cursor foreground colour + Custom color for the foreground of the text character at the terminal’s cursor position, as a color specification (can be HTML-style hex digits, or a color name such as “red”). This is ignored if cursor-colors-set is false. + + + false + Whether to use custom highlight colors + If true, use the highlight colors from the profile. + + + '#000000' + Highlight background color + Custom color of the background of the terminal’s highlight, as a color specification (can be HTML-style hex digits, or a color name such as “red”). This is ignored if highlight-colors-set is false. + + + '#ffffff' + Highlight foreground colour + Custom color for the foreground of the text character at the terminal’s highlight position, as a color specification (can be HTML-style hex digits, or a color name such as “red”). This is ignored if highlight-colors-set is false. + + + true + Whether to perform bidirectional text rendering + If true, perform bidirectional text rendering (“BiDi”). + + + true + Whether to perform Arabic shaping + If true, shape Arabic text. + + + false + Whether to enable SIXEL images + If true, SIXEL sequences are parsed and images are rendered. + + + false + Whether bold is also bright + If true, setting bold on the first 8 colors also switches to their bright variants. + + + true + Whether to ring the terminal bell + + + nothing + List of ASCII punctuation characters that are not to be treated as part of a word when doing word-wise selection + + + + 80 + Default number of columns + Number of columns in newly created terminal windows. Has no effect if use_custom_default_size is not enabled. + + + + 24 + Default number of rows + Number of rows in newly created terminal windows. Has no effect if use_custom_default_size is not enabled. + + + 'always' + When to show the scrollbar + + + 10000 + Number of lines to keep in scrollback + Number of scrollback lines to keep around. You can scroll back in the terminal by this number of lines; lines that don’t fit in the scrollback are discarded. If scrollback_unlimited is true, this value is ignored. + + + false + Whether an unlimited number of lines should be kept in scrollback + If true, scrollback lines will never be discarded. The scrollback history is stored on disk temporarily, so this may cause the system to run out of disk space if there is a lot of output to the terminal. + + + true + Whether to scroll to the bottom when a key is pressed + If true, pressing a key jumps the scrollbar to the bottom. + + + false + Whether to scroll to the bottom when there’s new output + If true, whenever there’s new output the terminal will scroll to the bottom. + + + 'close' + What to do with the terminal when the child command exits + Possible values are “close” to close the terminal, “restart” to restart the command, and “hold” to keep the terminal open with no command running inside. + + + false + Whether to launch the command in the terminal as a login shell + If true, the command inside the terminal will be launched as a login shell (argv[0] will have a hyphen in front of it). + + + 'safe' + Whether to preserve the working directory when opening a new terminal + + Controls when opening a new terminal from a previous one carries over the working directory of the opening terminal to the new one. + + + + false + Whether to run a custom command instead of the shell + If true, the value of the custom_command setting will be used in place of running a shell. + + + 'system' + Whether to blink the cursor + The possible values are “system” to use the global cursor blinking settings, or “on” or “off” to set the mode explicitly. + + + 'block' + The cursor appearance + + + 'always' + Possible values are “always” or “never” allow blinking text, or only when the terminal is “focused” or “unfocused”. + + + '' + Custom command to use instead of the shell + Run this command in place of the shell, if use_custom_command is true. + + + ['#171421', + '#c01c28', + '#26a269', + '#a2734c', + '#12488b', + '#a347ba', + '#2aa1b3', + '#d0cfcc', + '#5e5c64', + '#f66151', + '#33da7a', + '#e9ad0c', + '#2a7bde', + '#c061cb', + '#33c7de', + '#ffffff'] + Palette for terminal applications + + + 'Monospace 12' + A Pango font name and size + + + 'ascii-delete' + The code sequence the Backspace key generates + + + 'delete-sequence' + The code sequence the Delete key generates + + + true + Whether to use the colors from the theme for the terminal widget + + + true + Whether to use the system monospace font + + + true + Whether to rewrap the terminal contents on window resize + + + 'UTF-8' + Which encoding to use + + + 'narrow' + Whether ambiguous-width characters are narrow or wide when using UTF-8 encoding + + + + + + + + '<Ctrl><Shift>t' + Keyboard shortcut to open a new tab + + + '<Ctrl><Shift>n' + Keyboard shortcut to open a new window + + + 'disabled' + Keyboard shortcut to save the current tab contents to file + + + 'disabled' + Keyboard shortcut to export the current tab contents to file in various formats + + + 'disabled' + Keyboard shortcut to print the current tab contents to printer or file + + + '<Ctrl><Shift>w' + Keyboard shortcut to close a tab + + + '<Ctrl><Shift>q' + Keyboard shortcut to close a window + + + '<Ctrl><Shift>c' + Keyboard shortcut to copy text + + + 'disabled' + Keyboard shortcut to copy text as HTML + + + '<Ctrl><Shift>v' + Keyboard shortcut to paste text + + + 'disabled' + Keyboard shortcut to select all text + + + 'disabled' + Keyboard shortcut to open the Preferences dialog + + + 'F11' + Keyboard shortcut to toggle full screen mode + + + 'disabled' + Keyboard shortcut to toggle the visibility of the menubar + + + 'disabled' + Keyboard shortcut to toggle the read-only state + + + 'disabled' + Keyboard shortcut to reset the terminal + + + 'disabled' + Keyboard shortcut to reset and clear the terminal + + + '<Control><Shift>F' + Keyboard shortcut to open the search dialog + + + '<Control><Shift>G' + Keyboard shortcut to find the next occurrence of the search term + + + '<Control><Shift>H' + Keyboard shortcut to find the previous occurrence of the search term + + + '<Control><Shift>J' + Keyboard shortcut to clear the find highlighting + + + '<Control>Page_Up' + Keyboard shortcut to switch to the previous tab + + + '<Control>Page_Down' + Keyboard shortcut to switch to the next tab + + + '<Ctrl><Shift>Page_Up' + Keyboard shortcut to move the current tab to the left + + + '<Ctrl><Shift>Page_Down' + Keyboard shortcut to move the current tab to the right + + + 'disabled' + Keyboard shortcut to detach current tab + + + '<Alt>1' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>2' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>3' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>4' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>5' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>6' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>7' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>8' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>9' + Keyboard shortcut to switch to the numbered tab + + + '<Alt>0' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the numbered tab + + + 'disabled' + Keyboard shortcut to switch to the last tab + + + 'disabled' + Keyboard shortcut to launch help + + + '<Ctrl>plus' + Keyboard shortcut to make font larger + + + '<Ctrl>minus' + Keyboard shortcut to make font smaller + + + '<Ctrl>0' + Keyboard shortcut to make font normal-size + + + 'disabled' + Keyboard shortcut to show the primary menu + + + + + + + + + false + Whether the menubar has access keys + + Whether to have Alt+letter access keys for the menubar. + They may interfere with some applications run inside the terminal + so it’s possible to turn them off. + + + + + true + Whether shortcuts are enabled + + Whether shortcuts are enabled. + They may interfere with some applications run inside the terminal + so it’s possible to turn them off. + + + + + true + Whether the standard GTK shortcut for menubar access is enabled + + Normally you can access the menubar with F10. This can also + be customized via gtkrc (gtk-menu-bar-accel = + "whatever"). This option allows the standard menubar + accelerator to be disabled. + + + + + true + Whether the shell integration is enabled + + + + true + Whether to ask for confirmation before closing a terminal + + + + true + Whether to show the menubar in new windows + + + + 'window' + Whether to open new terminals as windows or tabs + + + + 'automatic' + When to show the tabs bar + + + + 'top' + The position of the tab bar + + + + 'system' + Which theme variant to use + + + + 'last' + Whether new tabs should open next to the current one or at the last position + + + + + + nothing + + + + true + + + + + + + + 3 + + + + + diff --git a/src/org.gnome.Terminal.xml b/src/org.gnome.Terminal.xml new file mode 100644 index 0000000..a6ada0e --- /dev/null +++ b/src/org.gnome.Terminal.xml @@ -0,0 +1,43 @@ + + + + + + + + + + + + + + + + + + + + + + + + + + + diff --git a/src/preferences.ui b/src/preferences.ui new file mode 100644 index 0000000..d1aca7b --- /dev/null +++ b/src/preferences.ui @@ -0,0 +1,2453 @@ + + + + + + + + + + + + + + Window + window + + + Tab + tab + + + + + + + + + + + + + Last + last + + + Next + next + + + + + + + + + + + + + Default + system + + + Light + light + + + Dark + dark + + + + + 16 + 511 + 80 + 1 + 10 + + + 4 + 511 + 24 + 1 + 10 + + + 0 + 2147483647 + 10000 + 1000 + 10000 + + + 1.0 + 2.0 + 1.0 + 0.05 + 0.25 + + + 1.0 + 2.0 + 1.0 + 0.05 + 0.25 + + + + + + + + + + + Narrow + narrow + + + Wide + wide + + + + + + + + + + + Block + + + I-Beam + + + Underline + + + + + + + + + + + Default + + + Enabled + + + Disabled + + + + + + + + + + + Never + + + When focused + + + When unfocused + + + Always + + + + + + + + + + + Replace initial title + + + Append initial title + + + Prepend initial title + + + Keep initial title + + + + + + + + + + + Exit the terminal + + + Restart the command + + + Hold the terminal open + + + + + + + + + + + GNOME + + + Tango + + + Linux console + + + XTerm + + + Rxvt + + + Solarized + + + Custom + + + + + + + + + + + Automatic + + + Control-H + + + ASCII DEL + + + Escape sequence + + + TTY Erase + + + + + + + + + + + + + Never + never + + + Shell only + safe + + + Always + always + + + + + False + False + gnome-terminal-preferences + False + + + True + False + 12 + vertical + 12 + + + True + False + + + True + + + True + True + never + + + True + False + + + True + + + + + + + + + + + True + + + True + False + + + True + False + + + True + False + 12 + vertical + 6 + + + _Show menubar by default in new terminals + True + True + False + True + 0 + True + + + False + True + 0 + + + + + _Enable mnemonics (such as Alt+F to open the File menu) + False + True + True + False + True + 0 + True + + + False + True + 1 + + + + + Enable the _menu accelerator key (F10 by default) + False + True + True + False + True + 0 + True + + + False + True + 2 + + + + + True + False + 6 + 12 + + + True + False + Theme _variant: + True + theme-variant-combobox + 0 + + + 0 + 0 + + + + + True + False + theme-variant-liststore + 1 + + + + 0 + + + + + 0 + 1 + + + + + True + False + Open _new terminals in: + True + new-terminal-mode-combobox + 0 + + + 1 + 0 + + + + + True + False + new-terminal-mode-liststore + 1 + + + + 0 + + + + + 1 + 1 + + + + + True + False + New tab _position: + True + new-tab-position-combobox + 0 + + + 2 + 0 + + + + + True + False + new-tab-position-liststore + 1 + + + + 0 + + + + + 2 + 1 + + + + + False + True + 3 + + + + + + + + + general-prefs + + + + + True + False + + + True + False + + + True + False + 12 + 12 + 6 + + + _Enable shortcuts + False + True + True + False + True + 0 + True + + + 0 + 0 + + + + + True + True + never + in + True + True + + + True + True + True + + + + + + + + 1 + 0 + + + + + + + + + shortcut-prefs + + + + + True + False + + + True + True + + + True + False + 12 + 12 + 6 + + + True + False + Text Appearance + 0 + + + + + + 0 + 0 + 4 + + + + + True + False + 12 + Initial terminal si_ze: + True + default-size-columns-spinbutton + 0 + + + 1 + 0 + + + + + True + False + 6 + + + True + True + adjustment1 + True + GTK_INPUT_HINT_NO_EMOJI + + + False + True + 0 + + + + + True + False + columns + + + False + False + 1 + + + + + 1 + 1 + + + + + True + False + 6 + + + True + True + adjustment2 + True + GTK_INPUT_HINT_NO_EMOJI + + + False + True + 0 + + + + + True + False + rows + + + False + False + 1 + + + + + 1 + 2 + + + + + True + False + end + + + Rese_t + True + True + True + True + False + + + False + True + 0 + + + + + 1 + 3 + + + + + Custom _font: + True + True + 12 + False + True + 0 + True + + + 2 + 0 + + + + + True + True + False + False + Sans 12 + Choose A Terminal Font + + + 2 + 1 + 3 + + + + + True + False + 12 + Cell spaci_ng: + True + cell-width-scale-spinbutton + 0 + + + 3 + 0 + + + + + True + False + 6 + + + True + True + adjustment5 + 2 + True + GTK_INPUT_HINT_NO_EMOJI + + + False + True + 0 + + + + + True + False + + + False + False + 1 + + + + + 3 + 1 + + + + + True + False + 6 + + + True + True + adjustment6 + 2 + True + GTK_INPUT_HINT_NO_EMOJI + + + False + True + 0 + + + + + True + False + + + False + False + 1 + + + + + 3 + 2 + + + + + True + False + end + + + Rese_t + True + True + True + True + False + + + False + True + 0 + + + + + 3 + 3 + + + + + True + False + 12 + Allow b_linking text: + True + text-blink-mode-combobox + 0 + + + 4 + 0 + + + + + True + False + model5 + False + + + + 0 + + + + + 4 + 1 + 3 + + + + + True + False + 12 + Cursor + 0 + + + + + + 5 + 0 + 4 + + + + + True + False + 12 + Cursor _shape: + True + cursor-shape-combobox + 0 + + + 6 + 0 + + + + + True + False + model1 + False + + + + 0 + + + + + 6 + 1 + 3 + + + + + True + False + 12 + Cursor blin_king: + True + cursor-blink-mode-combobox + 0 + + + 7 + 0 + + + + + True + False + model7 + False + + + + 0 + + + + + 7 + 1 + 3 + + + + + True + False + 12 + Sound + 0 + + + + + + 8 + 0 + 4 + + + + + Terminal _bell + True + True + 12 + False + True + 0.5 + True + + + 9 + 0 + 4 + + + + + True + False + 6 + end + True + + + True + False + Profile ID: + 0 + + + False + True + end + 1 + + + + + True + False + True + 0 + + + False + True + end + 0 + + + + + 100 + 0 + 4 + + + + + 0 + + + + + True + False + Text + True + center + + + False + + + + + True + False + 12 + 18 + + + True + False + 6 + + + True + False + Text and Background Color + 0 + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + + + _Use colors from system theme + True + True + False + True + 0.5 + True + + + False + False + 0 + + + + + True + False + vertical + 6 + + + True + False + 12 + + + True + False + Built-in sche_mes: + True + center + color-scheme-combobox + 0 + + + False + False + 0 + + + + + True + False + False + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + 6 + 12 + + + True + False + Text + 0 + + + 0 + 1 + + + + + True + False + Background + 0 + + + 0 + 2 + + + + + True + False + start + _Default color: + True + center + foreground-colorpicker + 0 + + + 1 + 0 + + + + + True + True + False + start + Choose Terminal Text Color + True + + + 1 + 1 + + + + + True + True + False + start + Choose Terminal Background Color + True + + + 1 + 2 + + + + + Bo_ld color: + True + True + False + start + True + 0 + True + + + 2 + 0 + + + + + True + True + False + start + Choose Terminal Bold Text Color + True + + + 2 + 1 + + + + + _Underline color: + True + False + start + True + 0 + True + + + 3 + 0 + + + + + True + False + start + Choose Terminal Underlined Text Color + + + 3 + 1 + + + + + Cu_rsor color: + True + True + False + start + True + 0 + True + + + 4 + 0 + + + + + True + True + True + start + Choose Terminal Cursor Foreground Color + True + + + 4 + 1 + + + + + True + True + True + start + Choose Terminal Cursor Background Color + True + + + 4 + 2 + + + + + _Highlight color: + True + True + False + start + True + True + + + 5 + 0 + + + + + True + True + True + start + Choose Terminal Highlight Foreground Color + True + + + 5 + 1 + + + + + True + True + True + start + Choose Terminal Highlight Background Color + True + + + 5 + 2 + + + + + False + True + 1 + + + + + False + True + 1 + + + + + + + False + True + 1 + + + + + False + True + 0 + + + + + True + False + 6 + + + True + False + Palette + 0 + + + + + + False + False + 0 + + + + + True + False + 12 + + + True + False + 6 + + + True + False + 12 + 6 + + + True + False + Built-in _schemes: + True + center + palette-combobox + 0 + + + 0 + 0 + + + + + True + False + model4 + False + + + + 0 + + + + + 0 + 1 + + + + + True + False + Color p_alette: + True + center + palette-colorpicker-0 + 0 + 0 + + + 1 + 0 + + + + + True + False + 6 + 6 + + + True + True + False + dummy + True + + + 0 + 0 + + + + + True + True + False + dummy + True + + + 0 + 1 + + + + + True + True + False + dummy + True + + + 0 + 2 + + + + + True + True + False + dummy + True + + + 0 + 3 + + + + + True + True + False + dummy + True + + + 0 + 4 + + + + + True + True + False + dummy + True + + + 0 + 5 + + + + + True + True + False + dummy + True + + + 0 + 6 + + + + + True + True + False + dummy + True + + + 0 + 7 + + + + + True + True + False + dummy + True + + + 1 + 0 + + + + + True + True + False + dummy + True + + + 1 + 1 + + + + + True + True + False + dummy + True + + + 1 + 2 + + + + + True + True + False + dummy + True + + + 1 + 3 + + + + + True + True + False + dummy + True + + + 1 + 4 + + + + + True + True + False + dummy + True + + + 1 + 5 + + + + + True + True + False + dummy + True + + + 1 + 6 + + + + + True + True + False + dummy + True + + + 1 + 7 + + + + + 1 + 1 + + + + + False + False + 0 + + + + + Show _bold text in bright colors + True + True + False + True + 0.5 + True + + + False + False + 1 + + + + + + + False + True + 1 + + + + + False + True + 1 + + + + + 1 + + + + + True + False + Colors + True + center + + + 1 + False + + + + + True + False + 12 + 12 + 6 + + + _Show scrollbar + True + True + False + True + 0.5 + True + True + + + 0 + 0 + 2 + + + + + Scroll on _output + True + True + False + True + 0.5 + True + True + + + 1 + 0 + 2 + + + + + Scroll on _keystroke + True + True + False + True + 0.5 + True + True + + + 2 + 0 + 2 + + + + + _Limit scrollback to: + True + True + False + True + 0.5 + True + False + + + 3 + 0 + + + + + True + False + 6 + True + + + True + True + adjustment4 + True + GTK_INPUT_HINT_NO_EMOJI + + + False + True + 0 + + + + + True + False + lines + center + scrollback-lines-spinbutton + 0 + + + False + False + 1 + + + + + 3 + 1 + + + + + 2 + + + + + True + False + Scrolling + True + + + 2 + False + + + + + True + False + 12 + 12 + 6 + + + _Run command as a login shell + True + True + False + True + True + + + 0 + 0 + 2 + + + + + Ru_n a custom command instead of my shell + True + True + False + True + True + + + 1 + 0 + 2 + + + + + True + False + Custom co_mmand: + True + custom-command-entry + 0 + + + 2 + 0 + + + + + True + True + True + GTK_INPUT_HINT_NO_EMOJI + + + 2 + 1 + + + + + True + False + _Preserve working directory: + True + center + preserve-working-directory-combobox + 0 + + + 3 + 0 + + + + + True + False + preserve-working-directory-model + False + start + + + + 0 + + + + + 3 + 1 + + + + + True + False + When command _exits: + True + exit-action-combobox + 0 + + + 4 + 0 + + + + + True + False + model3 + False + start + + + + 0 + + + + + 4 + 1 + + + + + 3 + + + + + True + False + Command + True + center + + + 3 + False + + + + + True + False + 12 + 12 + 6 + + + True + False + _Backspace key generates: + True + center + backspace-binding-combobox + 0 + + + 0 + 0 + + + + + True + False + model6 + False + + + + 0 + + + + + 0 + 1 + + + + + True + False + _Delete key generates: + True + center + delete-binding-combobox + 0 + + + 1 + 0 + + + + + True + False + model6 + False + + + + 0 + + + + + 1 + 1 + + + + + True + False + _Encoding: + True + encoding-combobox + 0 + + + 2 + 0 + + + + + True + False + False + 0 + + + + 1 + + + + + 2 + 1 + + + + + True + False + Ambiguous-_width characters: + True + center + cjk-ambiguous-width-combobox + 0 + + + 3 + 0 + + + + + True + False + cjk-ambiguous-width-model + False + 1 + + + + 0 + + + + + 3 + 1 + + + + + Enable _SIXEL images + True + True + False + True + 0 + True + + + 4 + 0 + 2 + + + + + _Reset Compatibility Options to Defaults + True + True + False + True + False + start + + + 5 + 0 + 2 + + + + + 4 + + + + + True + False + Compatibility + True + center + + + 4 + False + + + + + + + profile-prefs + + + + + + + + + True + False + 12 + start + + + gtk-help + True + True + True + True + False + + + False + True + 0 + + + + + gtk-close + True + True + True + True + False + + + True + True + end + 1 + True + + + + + False + True + end + 1 + + + + + + + + + True + 6 + vertical + + + True + win.clone + Clone… + + + + + True + win.rename + Rename… + + + + + True + win.delete + Delete… + + + + + True + horizontal + + + + + True + win.set-as-default + Set as default + + + + + + + False + + + True + False + vertical + 12 + 6 + + + True + False + 0 + 6 + + + + + + False + True + 0 + + + + + True + False + 0 + + + False + True + 1 + + + + + True + True + True + + + False + True + 2 + + + + + True + False + start + 6 + 6 + + + Cancel + True + True + True + + + False + False + end + 0 + True + + + + + True + True + True + True + False + + + False + False + end + 1 + True + + + + + False + True + 3 + + + + + + diff --git a/src/profile-editor.c b/src/profile-editor.c new file mode 100644 index 0000000..4098f90 --- /dev/null +++ b/src/profile-editor.c @@ -0,0 +1,1444 @@ +/* + * Copyright © 2002 Havoc Pennington + * Copyright © 2002 Mathias Hasselmann + * Copyright © 2008, 2011, 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include + +#include +#include +#include + +#include "terminal-app.h" +#include "terminal-enums.h" +#include "profile-editor.h" +#include "terminal-prefs.h" +#include "terminal-schemas.h" +#include "terminal-type-builtins.h" +#include "terminal-util.h" +#include "terminal-profiles-list.h" +#include "terminal-libgsystem.h" + + +/* Wrapper around g_signal_connect that maintains a list of the + * handlers installed, and can disconnect them all. */ +typedef struct { + gpointer instance; + gulong handler_id; +} ProfilePrefsSignal; + +static void +profile_prefs_register_signal_handler (gpointer instance, + gulong handler_id) +{ + ProfilePrefsSignal sig; + sig.instance = instance; + sig.handler_id = handler_id; + g_array_append_val (the_pref_data->profile_signals, sig); +} + +static gulong +profile_prefs_signal_connect (gpointer instance, + const gchar *detailed_signal, + GCallback c_handler, + gpointer data) +{ + gulong handler_id = g_signal_connect(instance, detailed_signal, c_handler, data); + profile_prefs_register_signal_handler (instance, handler_id); + return handler_id; +} + +static void +profile_prefs_signal_handlers_disconnect_all (void) +{ + for (guint i = 0; i < the_pref_data->profile_signals->len; i++) { + ProfilePrefsSignal *sig = &g_array_index (the_pref_data->profile_signals, ProfilePrefsSignal, i); + g_signal_handler_disconnect (sig->instance, sig->handler_id); + } + g_array_set_size (the_pref_data->profile_signals, 0); +} + + +/* Wrappers around g_settings_bind and friends that maintain a list of the + * bindings installed, and can unbind them all. */ +typedef struct { + gpointer object; + char *property; +} ProfilePrefsBinding; + +static void +profile_prefs_register_settings_binding (gpointer object, + const char *property) +{ + ProfilePrefsBinding bind; + bind.object = object; + bind.property = g_strdup (property); + g_array_append_val (the_pref_data->profile_bindings, bind); +} + +static void +profile_prefs_settings_bind (GSettings *settings, + const gchar *key, + gpointer object, + const gchar *property, + GSettingsBindFlags flags) +{ + profile_prefs_register_settings_binding (object, property); + g_settings_bind (settings, key, object, property, flags); +} + +static void +profile_prefs_settings_bind_with_mapping (GSettings *settings, + const gchar *key, + gpointer object, + const gchar *property, + GSettingsBindFlags flags, + GSettingsBindGetMapping get_mapping, + GSettingsBindSetMapping set_mapping, + gpointer user_data, + GDestroyNotify destroy) +{ + profile_prefs_register_settings_binding (object, property); + g_settings_bind_with_mapping (settings, key, object, property, flags, get_mapping, set_mapping, user_data, destroy); +} + +static void +profile_prefs_settings_bind_writable (GSettings *settings, + const gchar *key, + gpointer object, + const gchar *property, + gboolean inverted) +{ + profile_prefs_register_settings_binding (object, property); + g_settings_bind_writable (settings, key, object, property, inverted); +} + +static void +profile_prefs_settings_unbind_all (void) +{ + for (guint i = 0; i < the_pref_data->profile_bindings->len; i++) { + ProfilePrefsBinding *bind = &g_array_index (the_pref_data->profile_bindings, ProfilePrefsBinding, i); + g_settings_unbind (bind->object, bind->property); + g_free (bind->property); + } + g_array_set_size (the_pref_data->profile_bindings, 0); +} + + +typedef struct _TerminalColorScheme TerminalColorScheme; + +struct _TerminalColorScheme +{ + const char *name; + const GdkRGBA foreground; + const GdkRGBA background; +}; + +#define COLOR(r, g, b) { .red = (r) / 255.0, .green = (g) / 255.0, .blue = (b) / 255.0, .alpha = 1.0 } + +static const TerminalColorScheme color_schemes[] = { + { N_("Black on light yellow"), + COLOR (0x00, 0x00, 0x00), + COLOR (0xff, 0xff, 0xdd) + }, + { N_("Black on white"), + COLOR (0x00, 0x00, 0x00), + COLOR (0xff, 0xff, 0xff) + }, + { N_("Gray on black"), + COLOR (0xaa, 0xaa, 0xaa), + COLOR (0x00, 0x00, 0x00) + }, + { N_("Green on black"), + COLOR (0x00, 0xff, 0x00), + COLOR (0x00, 0x00, 0x00) + }, + { N_("White on black"), + COLOR (0xff, 0xff, 0xff), + COLOR (0x00, 0x00, 0x00) + }, + /* Translators: "GNOME" is the name of a colour scheme, "light" can be translated */ + { N_("GNOME light"), + COLOR (0x17, 0x14, 0x21), /* Palette entry 0 */ + COLOR (0xff, 0xff, 0xff) /* Palette entry 15 */ + }, + /* Translators: "GNOME" is the name of a colour scheme, "dark" can be translated */ + { N_("GNOME dark"), + COLOR (0xd0, 0xcf, 0xcc), /* Palette entry 7 */ + COLOR (0x17, 0x14, 0x21) /* Palette entry 0 */ + }, + /* Translators: "Tango" is the name of a colour scheme, "light" can be translated */ + { N_("Tango light"), + COLOR (0x2e, 0x34, 0x36), + COLOR (0xee, 0xee, 0xec) + }, + /* Translators: "Tango" is the name of a colour scheme, "dark" can be translated */ + { N_("Tango dark"), + COLOR (0xd3, 0xd7, 0xcf), + COLOR (0x2e, 0x34, 0x36) + }, + /* Translators: "Solarized" is the name of a colour scheme, "light" can be translated */ + { N_("Solarized light"), + COLOR (0x65, 0x7b, 0x83), /* 11: base00 */ + COLOR (0xfd, 0xf6, 0xe3) /* 15: base3 */ + }, + /* Translators: "Solarized" is the name of a colour scheme, "dark" can be translated */ + { N_("Solarized dark"), + COLOR (0x83, 0x94, 0x96), /* 12: base0 */ + COLOR (0x00, 0x2b, 0x36) /* 8: base03 */ + }, +}; + +#define TERMINAL_PALETTE_SIZE (16) + +enum +{ + TERMINAL_PALETTE_GNOME = 0, + TERMINAL_PALETTE_TANGO = 1, + TERMINAL_PALETTE_LINUX = 2, + TERMINAL_PALETTE_XTERM = 3, + TERMINAL_PALETTE_RXVT = 4, + TERMINAL_PALETTE_SOLARIZED = 5, + TERMINAL_PALETTE_N_BUILTINS +}; + +static const GdkRGBA terminal_palettes[TERMINAL_PALETTE_N_BUILTINS][TERMINAL_PALETTE_SIZE] = +{ + /* Based on GNOME 3.32 palette: https://developer.gnome.org/hig/stable/icon-design.html.en#palette */ + { + COLOR (0x17, 0x14, 0x21), /* Blend of Dark 4 and Black */ + COLOR (0xc0, 0x1c, 0x28), /* Red 4 */ + COLOR (0x26, 0xa2, 0x69), /* Green 5 */ + COLOR (0xa2, 0x73, 0x4c), /* Blend of Brown 2 and Brown 3 */ + COLOR (0x12, 0x48, 0x8b), /* Blend of Blue 5 and Dark 4 */ + COLOR (0xa3, 0x47, 0xba), /* Purple 3 */ + COLOR (0x2a, 0xa1, 0xb3), /* Linear addition Blue 5 + Green 5, darkened slightly */ + COLOR (0xd0, 0xcf, 0xcc), /* Blend of Light 3 and Light 4 */ + COLOR (0x5e, 0x5c, 0x64), /* Dark 2 */ + COLOR (0xf6, 0x61, 0x51), /* Red 1 */ + COLOR (0x33, 0xd1, 0x7a), /* Green 3 */ + COLOR (0xe9, 0xad, 0x0c), /* Blend of Yellow 4 and Yellow 5 */ + COLOR (0x2a, 0x7b, 0xde), /* Blend of Blue 3 and Blue 4 */ + COLOR (0xc0, 0x61, 0xcb), /* Purple 2 */ + COLOR (0x33, 0xc7, 0xde), /* Linear addition Blue 4 + Green 4, darkened slightly */ + COLOR (0xff, 0xff, 0xff) /* Light 1 */ + }, + + /* Tango palette */ + { + COLOR (0x2e, 0x34, 0x36), + COLOR (0xcc, 0x00, 0x00), + COLOR (0x4e, 0x9a, 0x06), + COLOR (0xc4, 0xa0, 0x00), + COLOR (0x34, 0x65, 0xa4), + COLOR (0x75, 0x50, 0x7b), + COLOR (0x06, 0x98, 0x9a), + COLOR (0xd3, 0xd7, 0xcf), + COLOR (0x55, 0x57, 0x53), + COLOR (0xef, 0x29, 0x29), + COLOR (0x8a, 0xe2, 0x34), + COLOR (0xfc, 0xe9, 0x4f), + COLOR (0x72, 0x9f, 0xcf), + COLOR (0xad, 0x7f, 0xa8), + COLOR (0x34, 0xe2, 0xe2), + COLOR (0xee, 0xee, 0xec) + }, + + /* Linux palette */ + { + COLOR (0x00, 0x00, 0x00), + COLOR (0xaa, 0x00, 0x00), + COLOR (0x00, 0xaa, 0x00), + COLOR (0xaa, 0x55, 0x00), + COLOR (0x00, 0x00, 0xaa), + COLOR (0xaa, 0x00, 0xaa), + COLOR (0x00, 0xaa, 0xaa), + COLOR (0xaa, 0xaa, 0xaa), + COLOR (0x55, 0x55, 0x55), + COLOR (0xff, 0x55, 0x55), + COLOR (0x55, 0xff, 0x55), + COLOR (0xff, 0xff, 0x55), + COLOR (0x55, 0x55, 0xff), + COLOR (0xff, 0x55, 0xff), + COLOR (0x55, 0xff, 0xff), + COLOR (0xff, 0xff, 0xff) + }, + + /* XTerm palette */ + { + COLOR (0x00, 0x00, 0x00), + COLOR (0xcd, 0x00, 0x00), + COLOR (0x00, 0xcd, 0x00), + COLOR (0xcd, 0xcd, 0x00), + COLOR (0x00, 0x00, 0xee), + COLOR (0xcd, 0x00, 0xcd), + COLOR (0x00, 0xcd, 0xcd), + COLOR (0xe5, 0xe5, 0xe5), + COLOR (0x7f, 0x7f, 0x7f), + COLOR (0xff, 0x00, 0x00), + COLOR (0x00, 0xff, 0x00), + COLOR (0xff, 0xff, 0x00), + COLOR (0x5c, 0x5c, 0xff), + COLOR (0xff, 0x00, 0xff), + COLOR (0x00, 0xff, 0xff), + COLOR (0xff, 0xff, 0xff) + }, + + /* RXVT palette */ + { + COLOR (0x00, 0x00, 0x00), + COLOR (0xcd, 0x00, 0x00), + COLOR (0x00, 0xcd, 0x00), + COLOR (0xcd, 0xcd, 0x00), + COLOR (0x00, 0x00, 0xcd), + COLOR (0xcd, 0x00, 0xcd), + COLOR (0x00, 0xcd, 0xcd), + COLOR (0xfa, 0xeb, 0xd7), + COLOR (0x40, 0x40, 0x40), + COLOR (0xff, 0x00, 0x00), + COLOR (0x00, 0xff, 0x00), + COLOR (0xff, 0xff, 0x00), + COLOR (0x00, 0x00, 0xff), + COLOR (0xff, 0x00, 0xff), + COLOR (0x00, 0xff, 0xff), + COLOR (0xff, 0xff, 0xff) + }, + + /* Solarized palette (1.0.0beta2): http://ethanschoonover.com/solarized */ + { + COLOR (0x07, 0x36, 0x42), /* 0: base02 */ + COLOR (0xdc, 0x32, 0x2f), /* 1: red */ + COLOR (0x85, 0x99, 0x00), /* 2: green */ + COLOR (0xb5, 0x89, 0x00), /* 3: yellow */ + COLOR (0x26, 0x8b, 0xd2), /* 4: blue */ + COLOR (0xd3, 0x36, 0x82), /* 5: magenta */ + COLOR (0x2a, 0xa1, 0x98), /* 6: cyan */ + COLOR (0xee, 0xe8, 0xd5), /* 7: base2 */ + COLOR (0x00, 0x2b, 0x36), /* 8: base03 */ + COLOR (0xcb, 0x4b, 0x16), /* 9: orange */ + COLOR (0x58, 0x6e, 0x75), /* 10: base01 */ + COLOR (0x65, 0x7b, 0x83), /* 11: base00 */ + COLOR (0x83, 0x94, 0x96), /* 12: base0 */ + COLOR (0x6c, 0x71, 0xc4), /* 13: violet */ + COLOR (0x93, 0xa1, 0xa1), /* 14: base1 */ + COLOR (0xfd, 0xf6, 0xe3) /* 15: base3 */ + }, +}; + +#undef COLOR + +static void profile_colors_notify_scheme_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo); + +static void profile_palette_notify_scheme_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo); + +static void profile_palette_notify_colorpickers_cb (GSettings *profile, + const char *key, + gpointer user_data); + +static void profile_notify_encoding_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo); + +enum { + ENCODINGS_COL_ID, + ENCODINGS_COL_TEXT +}; + +/* gdk_rgba_equal is too strict! */ +static gboolean +rgba_equal (const GdkRGBA *a, + const GdkRGBA *b) +{ + gdouble dr, dg, db; + + dr = a->red - b->red; + dg = a->green - b->green; + db = a->blue - b->blue; + + return (dr * dr + dg * dg + db * db) < 1e-4; +} + +static gboolean +palette_cmp (const GdkRGBA *ca, + const GdkRGBA *cb) +{ + guint i; + + for (i = 0; i < TERMINAL_PALETTE_SIZE; ++i) + if (!rgba_equal (&ca[i], &cb[i])) + return FALSE; + + return TRUE; +} + +static gboolean +palette_is_builtin (const GdkRGBA *colors, + gsize n_colors, + guint *n) +{ + guint i; + + if (n_colors != TERMINAL_PALETTE_SIZE) + return FALSE; + + for (i = 0; i < TERMINAL_PALETTE_N_BUILTINS; ++i) + { + if (palette_cmp (colors, terminal_palettes[i])) + { + *n = i; + return TRUE; + } + } + + return FALSE; +} + +static void +modify_palette_entry (GSettings *profile, + guint i, + const GdkRGBA *color) +{ + gs_free GdkRGBA *colors; + gsize n_colors; + + /* FIXMEchpe: this can be optimised, don't really need to parse the colours! */ + + colors = terminal_g_settings_get_rgba_palette (profile, TERMINAL_PROFILE_PALETTE_KEY, &n_colors); + + if (i < n_colors) + { + colors[i] = *color; + terminal_g_settings_set_rgba_palette (profile, TERMINAL_PROFILE_PALETTE_KEY, + colors, n_colors); + } +} + +static void +color_scheme_combo_changed_cb (GtkWidget *combo, + GParamSpec *pspec, + GSettings *profile) +{ + guint i; + + i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); + + if (i < G_N_ELEMENTS (color_schemes)) + { + g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo); + terminal_g_settings_set_rgba (profile, TERMINAL_PROFILE_FOREGROUND_COLOR_KEY, &color_schemes[i].foreground); + terminal_g_settings_set_rgba (profile, TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, &color_schemes[i].background); + g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo); + } + else + { + /* "custom" selected, no change */ + } +} + +static void +profile_colors_notify_scheme_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo) +{ + GdkRGBA fg, bg; + guint i; + + terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_FOREGROUND_COLOR_KEY, &fg); + terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, &bg); + + for (i = 0; i < G_N_ELEMENTS (color_schemes); ++i) + { + if (rgba_equal (&fg, &color_schemes[i].foreground) && + rgba_equal (&bg, &color_schemes[i].background)) + break; + } + /* If we didn't find a match, then we get the last combo box item which is "custom" */ + + g_signal_handlers_block_by_func (combo, G_CALLBACK (color_scheme_combo_changed_cb), profile); + gtk_combo_box_set_active (GTK_COMBO_BOX (combo), i); + g_signal_handlers_unblock_by_func (combo, G_CALLBACK (color_scheme_combo_changed_cb), profile); +} + +static void +palette_scheme_combo_changed_cb (GtkComboBox *combo, + GParamSpec *pspec, + GSettings *profile) +{ + int i; + + i = gtk_combo_box_get_active (GTK_COMBO_BOX (combo)); + + g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo); + if (i < TERMINAL_PALETTE_N_BUILTINS) + terminal_g_settings_set_rgba_palette (profile, TERMINAL_PROFILE_PALETTE_KEY, + terminal_palettes[i], TERMINAL_PALETTE_SIZE); + else + { + /* "custom" selected, no change */ + } + g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_colors_notify_scheme_combo_cb), combo); +} + +static void +profile_palette_notify_scheme_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo) +{ + gs_free GdkRGBA *colors; + gsize n_colors; + guint i; + + colors = terminal_g_settings_get_rgba_palette (profile, TERMINAL_PROFILE_PALETTE_KEY, &n_colors); + if (!palette_is_builtin (colors, n_colors, &i)) + /* If we didn't find a match, then we want the last combo + * box item which is "custom" + */ + i = TERMINAL_PALETTE_N_BUILTINS; + + g_signal_handlers_block_by_func (combo, G_CALLBACK (palette_scheme_combo_changed_cb), profile); + gtk_combo_box_set_active (combo, i); + g_signal_handlers_unblock_by_func (combo, G_CALLBACK (palette_scheme_combo_changed_cb), profile); +} + +static void +palette_color_notify_cb (GtkColorButton *button, + GParamSpec *pspec, + GSettings *profile) +{ + GdkRGBA color; + guint i; + + gtk_color_chooser_get_rgba (GTK_COLOR_CHOOSER (button), &color); + i = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button), "palette-entry-index")); + + g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), NULL); + modify_palette_entry (profile, i, &color); + g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), NULL); +} + +static void +profile_palette_notify_colorpickers_cb (GSettings *profile, + const char *key, + gpointer user_data) +{ + GtkWidget *w; + GtkBuilder *builder = the_pref_data->builder; + gs_free GdkRGBA *colors; + gsize n_colors, i; + + g_assert (strcmp (key, TERMINAL_PROFILE_PALETTE_KEY) == 0); + + colors = terminal_g_settings_get_rgba_palette (profile, TERMINAL_PROFILE_PALETTE_KEY, &n_colors); + + n_colors = MIN (n_colors, TERMINAL_PALETTE_SIZE); + for (i = 0; i < n_colors; i++) + { + char name[32]; + + g_snprintf (name, sizeof (name), "palette-colorpicker-%" G_GSIZE_FORMAT, i); + w = (GtkWidget *) gtk_builder_get_object (builder, name); + + g_signal_handlers_block_by_func (w, G_CALLBACK (palette_color_notify_cb), profile); + gtk_color_chooser_set_rgba (GTK_COLOR_CHOOSER (w), &colors[i]); + g_signal_handlers_unblock_by_func (w, G_CALLBACK (palette_color_notify_cb), profile); + } +} + +static void +custom_command_entry_changed_cb (GtkEntry *entry) +{ + const char *command; + gs_free_error GError *error = NULL; + + command = gtk_entry_get_text (entry); + + if (command[0] == '\0' || + g_shell_parse_argv (command, NULL, NULL, &error)) + { + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, NULL); + } + else + { + gs_free char *tooltip; + + gtk_entry_set_icon_from_icon_name (entry, GTK_ENTRY_ICON_SECONDARY, "dialog-warning"); + + tooltip = g_strdup_printf (_("Error parsing command: %s"), error->message); + gtk_entry_set_icon_tooltip_text (entry, GTK_ENTRY_ICON_SECONDARY, tooltip); + } +} + +static void +default_size_reset_cb (GtkWidget *button, + GSettings *profile) +{ + g_settings_reset (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY); +} + +static void +cell_scale_reset_cb (GtkWidget *button, + GSettings *profile) +{ + g_settings_reset (profile, TERMINAL_PROFILE_CELL_HEIGHT_SCALE_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_CELL_WIDTH_SCALE_KEY); +} + +static void +reset_compat_defaults_cb (GtkWidget *button, + GSettings *profile) +{ + g_settings_reset (profile, TERMINAL_PROFILE_DELETE_BINDING_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_BACKSPACE_BINDING_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_ENCODING_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY); + g_settings_reset (profile, TERMINAL_PROFILE_ENABLE_SIXEL_KEY); +} + +static gboolean +tree_model_id_to_iter_recurse (GtkTreeModel *model, + int id_column, + const char *active_id, + GtkTreeIter *iter, + GtkTreeIter *result_iter) +{ + do { + /* Descend the tree */ + GtkTreeIter child_iter; + if (gtk_tree_model_iter_children(model, &child_iter, iter) && + tree_model_id_to_iter_recurse (model, id_column, active_id, &child_iter, result_iter)) + return TRUE; + + gs_free char *id = NULL; + gtk_tree_model_get (model, iter, id_column, &id, -1); + if (g_strcmp0 (id, active_id) == 0) { + *result_iter = *iter; + return TRUE; + } + } while (gtk_tree_model_iter_next (model, iter)); + + return FALSE; +} + +static gboolean +tree_model_id_to_iter (GtkTreeModel *model, + int id_column, + const char *active_id, + GtkTreeIter *iter) +{ + GtkTreeIter first_iter; + + return gtk_tree_model_get_iter_first(model, &first_iter) && + tree_model_id_to_iter_recurse(model, id_column, active_id, &first_iter, iter); +} + +static void +profile_encoding_combo_changed_cb (GtkComboBox *combo, + GSettings *profile) +{ + GtkTreeIter iter; + + if (!gtk_combo_box_get_active_iter(combo, &iter)) + return; + + gs_free char *encoding = NULL; + gtk_tree_model_get(gtk_combo_box_get_model(combo), + &iter, + ENCODINGS_COL_ID, &encoding, + -1); + if (encoding == NULL) + return; + + g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_notify_encoding_combo_cb), combo); + g_settings_set_string(profile, TERMINAL_PROFILE_ENCODING_KEY, encoding); + g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_notify_encoding_combo_cb), combo); +} + +static void +profile_notify_encoding_combo_cb (GSettings *profile, + const char *key, + GtkComboBox *combo) +{ + gs_free char *encoding = NULL; + g_settings_get(profile, key, "s", &encoding); + + g_signal_handlers_block_by_func (combo, G_CALLBACK (profile_encoding_combo_changed_cb), profile); + + GtkTreeIter iter; + if (tree_model_id_to_iter(gtk_combo_box_get_model(combo), + ENCODINGS_COL_ID, + encoding, + &iter)) { + gtk_combo_box_set_active_iter(combo, &iter); + } else { + gtk_combo_box_set_active(combo, -1); + } + + g_signal_handlers_unblock_by_func (combo, G_CALLBACK (profile_encoding_combo_changed_cb), profile); +} + +/* + * initialize widgets + */ + +static void +init_color_scheme_menu (GtkWidget *widget) +{ + GtkCellRenderer *renderer; + GtkTreeIter iter; + gs_unref_object GtkListStore *store; + guint i; + + store = gtk_list_store_new (1, G_TYPE_STRING); + for (i = 0; i < G_N_ELEMENTS (color_schemes); ++i) + gtk_list_store_insert_with_values (store, &iter, -1, + 0, _(color_schemes[i].name), + -1); + gtk_list_store_insert_with_values (store, &iter, -1, + 0, _("Custom"), + -1); + + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store)); + + renderer = gtk_cell_renderer_text_new (); + gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (widget), renderer, TRUE); + gtk_cell_layout_set_attributes (GTK_CELL_LAYOUT (widget), renderer, "text", 0, NULL); +} + +typedef enum { + GROUP_UTF8, + GROUP_CJKV, + GROUP_OBSOLETE, + LAST_GROUP +} EncodingGroup; + +typedef struct { + const char *charset; + const char *name; + EncodingGroup group; +} EncodingEntry; + +/* These MUST be sorted by charset so that bsearch can work! */ +static const EncodingEntry encodings[] = { + { "ARMSCII-8", N_("Armenian"), GROUP_OBSOLETE }, + { "BIG5", N_("Chinese Traditional"), GROUP_CJKV }, + { "BIG5-HKSCS", N_("Chinese Traditional"), GROUP_CJKV }, + { "CP866", N_("Cyrillic/Russian"), GROUP_OBSOLETE }, + { "EUC-JP", N_("Japanese"), GROUP_CJKV }, + { "EUC-KR", N_("Korean"), GROUP_CJKV }, + { "EUC-TW", N_("Chinese Traditional"), GROUP_CJKV }, + { "GB18030", N_("Chinese Simplified"), GROUP_CJKV }, + { "GB2312", N_("Chinese Simplified"), GROUP_CJKV }, + { "GBK", N_("Chinese Simplified"), GROUP_CJKV }, + { "GEORGIAN-PS", N_("Georgian"), GROUP_OBSOLETE }, + { "IBM850", N_("Western"), GROUP_OBSOLETE }, + { "IBM852", N_("Central European"), GROUP_OBSOLETE }, + { "IBM855", N_("Cyrillic"), GROUP_OBSOLETE }, + { "IBM857", N_("Turkish"), GROUP_OBSOLETE }, + { "IBM862", N_("Hebrew"), GROUP_OBSOLETE }, + { "IBM864", N_("Arabic"), GROUP_OBSOLETE }, + { "ISO-2022-JP", N_("Japanese"), GROUP_CJKV }, + { "ISO-2022-KR", N_("Korean"), GROUP_CJKV }, + { "ISO-8859-1", N_("Western"), GROUP_OBSOLETE }, + { "ISO-8859-10", N_("Nordic"), GROUP_OBSOLETE }, + { "ISO-8859-13", N_("Baltic"), GROUP_OBSOLETE }, + { "ISO-8859-14", N_("Celtic"), GROUP_OBSOLETE }, + { "ISO-8859-15", N_("Western"), GROUP_OBSOLETE }, + { "ISO-8859-16", N_("Romanian"), GROUP_OBSOLETE }, + { "ISO-8859-2", N_("Central European"), GROUP_OBSOLETE }, + { "ISO-8859-3", N_("South European"), GROUP_OBSOLETE }, + { "ISO-8859-4", N_("Baltic"), GROUP_OBSOLETE }, + { "ISO-8859-5", N_("Cyrillic"), GROUP_OBSOLETE }, + { "ISO-8859-6", N_("Arabic"), GROUP_OBSOLETE }, + { "ISO-8859-7", N_("Greek"), GROUP_OBSOLETE }, + { "ISO-8859-8", N_("Hebrew Visual"), GROUP_OBSOLETE }, + { "ISO-8859-8-I", N_("Hebrew"), GROUP_OBSOLETE }, + { "ISO-8859-9", N_("Turkish"), GROUP_OBSOLETE }, + { "ISO-IR-111", N_("Cyrillic"), GROUP_OBSOLETE }, + { "KOI8-R", N_("Cyrillic"), GROUP_OBSOLETE }, + { "KOI8-U", N_("Cyrillic/Ukrainian"), GROUP_OBSOLETE }, + { "MAC-CYRILLIC", N_("Cyrillic"), GROUP_OBSOLETE }, + { "MAC_ARABIC", N_("Arabic"), GROUP_OBSOLETE }, + { "MAC_CE", N_("Central European"), GROUP_OBSOLETE }, + { "MAC_CROATIAN", N_("Croatian"), GROUP_OBSOLETE }, + { "MAC_GREEK", N_("Greek"), GROUP_OBSOLETE }, + { "MAC_HEBREW", N_("Hebrew"), GROUP_OBSOLETE }, + { "MAC_ROMAN", N_("Western"), GROUP_OBSOLETE }, + { "MAC_ROMANIAN", N_("Romanian"), GROUP_OBSOLETE }, + { "MAC_TURKISH", N_("Turkish"), GROUP_OBSOLETE }, + { "MAC_UKRAINIAN", N_("Cyrillic/Ukrainian"), GROUP_OBSOLETE }, + { "SHIFT_JIS", N_("Japanese"), GROUP_CJKV }, + { "TIS-620", N_("Thai"), GROUP_OBSOLETE }, + { "UHC", N_("Korean"), GROUP_CJKV }, + { "UTF-8", N_("Unicode"), GROUP_UTF8 }, + { "WINDOWS-1250", N_("Central European"), GROUP_OBSOLETE }, + { "WINDOWS-1251", N_("Cyrillic"), GROUP_OBSOLETE }, + { "WINDOWS-1252", N_("Western"), GROUP_OBSOLETE }, + { "WINDOWS-1253", N_("Greek"), GROUP_OBSOLETE }, + { "WINDOWS-1254", N_("Turkish"), GROUP_OBSOLETE }, + { "WINDOWS-1255", N_("Hebrew"), GROUP_OBSOLETE}, + { "WINDOWS-1256", N_("Arabic"), GROUP_OBSOLETE }, + { "WINDOWS-1257", N_("Baltic"), GROUP_OBSOLETE }, + { "WINDOWS-1258", N_("Vietnamese"), GROUP_OBSOLETE }, +}; + +static const struct { + EncodingGroup group; + const char *name; +} encodings_group_names[] = { + { GROUP_UTF8, N_("Unicode") }, + { GROUP_CJKV, N_("Legacy CJK Encodings") }, + { GROUP_OBSOLETE, N_("Obsolete Encodings") }, +}; + +#define EM_DASH "—" + +static void +append_encodings_for_group (GtkTreeStore *store, + EncodingGroup group, + gboolean submenu) +{ + GtkTreeIter parent_iter; + + if (submenu) { + gtk_tree_store_insert_with_values (store, + &parent_iter, + NULL, + -1, + ENCODINGS_COL_ID, NULL, + ENCODINGS_COL_TEXT, _(encodings_group_names[group].name), + -1); + } + + for (guint i = 0; i < G_N_ELEMENTS (encodings); i++) { + if (encodings[i].group != group) + continue; + + gs_free char *name = g_strdup_printf ("%s " EM_DASH " %s", + _(encodings[i].name), encodings[i].charset); + + GtkTreeIter iter; + gtk_tree_store_insert_with_values (store, + &iter, + submenu ? &parent_iter : NULL, + -1, + ENCODINGS_COL_ID, encodings[i].charset, + ENCODINGS_COL_TEXT, name, + -1); + } +} + +static GtkTreeStore * +encodings_tree_store_new (void) +{ + GtkTreeStore *store = gtk_tree_store_new (2, G_TYPE_STRING, G_TYPE_STRING); + + append_encodings_for_group(store, GROUP_UTF8, FALSE); /* UTF-8 in main menu */ + append_encodings_for_group(store, GROUP_CJKV, TRUE); + append_encodings_for_group(store, GROUP_OBSOLETE, TRUE); + + return store; +} + +static void +init_encodings_combo (GtkWidget *widget) +{ + gs_unref_object GtkTreeStore *store = encodings_tree_store_new (); + gtk_combo_box_set_model (GTK_COMBO_BOX (widget), GTK_TREE_MODEL (store)); +} + +static gboolean +s_to_rgba (GValue *value, + GVariant *variant, + gpointer user_data) +{ + const char *s; + GdkRGBA color; + + g_variant_get (variant, "&s", &s); + if (!gdk_rgba_parse (&color, s)) + return FALSE; + + color.alpha = 1.0; + g_value_set_boxed (value, &color); + return TRUE; +} + +static GVariant * +rgba_to_s (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + GdkRGBA *color; + gs_free char *s = NULL; + + color = g_value_get_boxed (value); + if (color == NULL) + return NULL; + + s = gdk_rgba_to_string (color); + return g_variant_new_string (s); +} + +static gboolean +string_to_enum (GValue *value, + GVariant *variant, + gpointer user_data) +{ + GType (* get_type) (void) = user_data; + GEnumClass *klass; + GEnumValue *eval = NULL; + const char *s; + guint i; + + g_variant_get (variant, "&s", &s); + + klass = g_type_class_ref (get_type ()); + for (i = 0; i < klass->n_values; ++i) { + if (strcmp (klass->values[i].value_nick, s) != 0) + continue; + + eval = &klass->values[i]; + break; + } + + if (eval) + g_value_set_int (value, eval->value); + + g_type_class_unref (klass); + + return eval != NULL; +} + +static GVariant * +enum_to_string (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + GType (* get_type) (void) = user_data; + GEnumClass *klass; + GEnumValue *eval = NULL; + int val; + guint i; + GVariant *variant = NULL; + + val = g_value_get_int (value); + + klass = g_type_class_ref (get_type ()); + for (i = 0; i < klass->n_values; ++i) { + if (klass->values[i].value != val) + continue; + + eval = &klass->values[i]; + break; + } + + if (eval) + variant = g_variant_new_string (eval->value_nick); + + g_type_class_unref (klass); + + return variant; +} + +static gboolean +scrollbar_policy_to_bool (GValue *value, + GVariant *variant, + gpointer user_data) +{ + const char *str; + + g_variant_get (variant, "&s", &str); + g_value_set_boolean (value, g_str_equal (str, "always")); + + return TRUE; +} + +static GVariant * +bool_to_scrollbar_policy (const GValue *value, + const GVariantType *expected_type, + gpointer user_data) +{ + return g_variant_new_string (g_value_get_boolean (value) ? "always" : "never"); +} + +static gboolean +monospace_filter (const PangoFontFamily *family, + const PangoFontFace *face, + gpointer data) +{ + return pango_font_family_is_monospace ((PangoFontFamily *) family); +} + +/* Called once per Preferences window, to initialize stuff that doesn't depend on the profile being edited */ +void +profile_prefs_init (void) +{ + GtkWidget *w; + GtkBuilder *builder = the_pref_data->builder; + char *text; + + the_pref_data->profile_signals = g_array_new (FALSE, FALSE, sizeof (ProfilePrefsSignal)); + the_pref_data->profile_bindings = g_array_new (FALSE, FALSE, sizeof (ProfilePrefsBinding)); + + w = (GtkWidget *) gtk_builder_get_object (builder, "color-scheme-combobox"); + init_color_scheme_menu (w); + + w = (GtkWidget *) gtk_builder_get_object (builder, "encoding-combobox"); + init_encodings_combo (w); + + /* Translators: Appears as: [numeric entry] × width */ + text = g_strdup_printf ("× %s", _("width")); + gtk_label_set_text ((GtkLabel *) gtk_builder_get_object (builder, "cell-width-scale-label"), + text); + g_free (text); + /* Translators: Appears as: [numeric entry] × height */ + text = g_strdup_printf ("× %s", _("height")); + gtk_label_set_text ((GtkLabel *) gtk_builder_get_object (builder, "cell-height-scale-label"), + text); + g_free (text); +} + +/* Called each time the user switches away from a profile, so it's no longer being edited */ +void +profile_prefs_unload (void) +{ + profile_prefs_signal_handlers_disconnect_all (); + profile_prefs_settings_unbind_all (); +} + +/* Called each time the user selects a new profile to edit */ +void +profile_prefs_load (const char *uuid, GSettings *profile) +{ + GtkWidget *w; + GtkBuilder *builder = the_pref_data->builder; + guint i; + + profile_prefs_unload (); + + gtk_label_set_text (GTK_LABEL (gtk_builder_get_object (builder, "profile-uuid")), + uuid); + + profile_prefs_signal_connect (gtk_builder_get_object (builder, "default-size-reset-button"), + "clicked", + G_CALLBACK (default_size_reset_cb), + profile); + profile_prefs_signal_connect (gtk_builder_get_object (builder, "cell-scale-reset-button"), + "clicked", + G_CALLBACK (cell_scale_reset_cb), + profile); + + /* Hook up the palette colorpickers and combo box */ + + for (i = 0; i < TERMINAL_PALETTE_SIZE; ++i) + { + char name[32]; + char *text; + + g_snprintf (name, sizeof (name), "palette-colorpicker-%u", i); + w = (GtkWidget *) gtk_builder_get_object (builder, name); + + g_object_set_data (G_OBJECT (w), "palette-entry-index", GUINT_TO_POINTER (i)); + + text = g_strdup_printf (_("Choose Palette Color %u"), i); + gtk_color_button_set_title (GTK_COLOR_BUTTON (w), text); + g_free (text); + + text = g_strdup_printf (_("Palette entry %u"), i); + gtk_widget_set_tooltip_text (w, text); + g_free (text); + + profile_prefs_signal_connect (w, "notify::rgba", + G_CALLBACK (palette_color_notify_cb), + profile); + } + + profile_palette_notify_colorpickers_cb (profile, TERMINAL_PROFILE_PALETTE_KEY, NULL); + profile_prefs_signal_connect (profile, "changed::" TERMINAL_PROFILE_PALETTE_KEY, + G_CALLBACK (profile_palette_notify_colorpickers_cb), + NULL); + + w = (GtkWidget *) gtk_builder_get_object (builder, "palette-combobox"); + profile_prefs_signal_connect (w, "notify::active", + G_CALLBACK (palette_scheme_combo_changed_cb), + profile); + + profile_palette_notify_scheme_combo_cb (profile, TERMINAL_PROFILE_PALETTE_KEY, GTK_COMBO_BOX (w)); + profile_prefs_signal_connect (profile, "changed::" TERMINAL_PROFILE_PALETTE_KEY, + G_CALLBACK (profile_palette_notify_scheme_combo_cb), + w); + + /* Hook up the color scheme pickers and combo box */ + w = (GtkWidget *) gtk_builder_get_object (builder, "color-scheme-combobox"); + profile_prefs_signal_connect (w, "notify::active", + G_CALLBACK (color_scheme_combo_changed_cb), + profile); + + profile_colors_notify_scheme_combo_cb (profile, NULL, GTK_COMBO_BOX (w)); + profile_prefs_signal_connect (profile, "changed::" TERMINAL_PROFILE_FOREGROUND_COLOR_KEY, + G_CALLBACK (profile_colors_notify_scheme_combo_cb), + w); + profile_prefs_signal_connect (profile, "changed::" TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, + G_CALLBACK (profile_colors_notify_scheme_combo_cb), + w); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "custom-command-entry")); + custom_command_entry_changed_cb (GTK_ENTRY (w)); + profile_prefs_signal_connect (w, "changed", + G_CALLBACK (custom_command_entry_changed_cb), NULL); + + profile_prefs_signal_connect (gtk_builder_get_object (builder, "reset-compat-defaults-button"), + "clicked", + G_CALLBACK (reset_compat_defaults_cb), + profile); + + profile_prefs_settings_bind_with_mapping (profile, + TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, + gtk_builder_get_object (builder, + "background-colorpicker"), + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + profile_prefs_settings_bind_with_mapping (profile, + TERMINAL_PROFILE_BACKSPACE_BINDING_KEY, + gtk_builder_get_object (builder, + "backspace-binding-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + vte_erase_binding_get_type, NULL); + profile_prefs_settings_bind (profile, + TERMINAL_PROFILE_BOLD_IS_BRIGHT_KEY, + gtk_builder_get_object (builder, "bold-is-bright-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY, + gtk_builder_get_object (builder, + "bold-color-checkbutton"), + "active", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_INVERT_BOOLEAN | + G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "bold-colorpicker")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY, + w, + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_INVERT_BOOLEAN | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_BOLD_COLOR_KEY, + w, + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "cell-height-scale-spinbutton")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CELL_HEIGHT_SCALE_KEY, + gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)), + "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "cell-width-scale-spinbutton")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CELL_WIDTH_SCALE_KEY, + gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)), + "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY, + gtk_builder_get_object (builder, + "cursor-colors-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "cursor-foreground-colorpicker")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY, + w, + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_CURSOR_FOREGROUND_COLOR_KEY, + w, + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "cursor-background-colorpicker")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY, + w, + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_CURSOR_BACKGROUND_COLOR_KEY, + w, + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY, + gtk_builder_get_object (builder, + "highlight-colors-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "highlight-foreground-colorpicker")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY, + w, + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_HIGHLIGHT_FOREGROUND_COLOR_KEY, + w, + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "highlight-background-colorpicker")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY, + w, + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_HIGHLIGHT_BACKGROUND_COLOR_KEY, + w, + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | G_SETTINGS_BIND_NO_SENSITIVITY, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_CURSOR_SHAPE_KEY, + gtk_builder_get_object (builder, + "cursor-shape-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + vte_cursor_shape_get_type, NULL); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_CURSOR_BLINK_MODE_KEY, + gtk_builder_get_object (builder, + "cursor-blink-mode-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + vte_cursor_blink_mode_get_type, NULL); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_TEXT_BLINK_MODE_KEY, + gtk_builder_get_object (builder, + "text-blink-mode-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + vte_text_blink_mode_get_type, NULL); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CUSTOM_COMMAND_KEY, + gtk_builder_get_object (builder, + "custom-command-entry"), + "text", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "default-size-columns-spinbutton")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY, + gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)), + "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "default-size-rows-spinbutton")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY, + gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)), + "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_DELETE_BINDING_KEY, + gtk_builder_get_object (builder, + "delete-binding-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + vte_erase_binding_get_type, NULL); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_EXIT_ACTION_KEY, + gtk_builder_get_object (builder, + "exit-action-combobox"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + terminal_exit_action_get_type, NULL); + w = (GtkWidget*) gtk_builder_get_object (builder, "font-selector"); + gtk_font_chooser_set_filter_func (GTK_FONT_CHOOSER (w), monospace_filter, NULL, NULL); +#if GTK_CHECK_VERSION (3, 24, 0) + gtk_font_chooser_set_level (GTK_FONT_CHOOSER (w), GTK_FONT_CHOOSER_LEVEL_FAMILY | + GTK_FONT_CHOOSER_LEVEL_SIZE); +#endif + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_FONT_KEY, + w, + "font-name", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind_with_mapping (profile, + TERMINAL_PROFILE_FOREGROUND_COLOR_KEY, + gtk_builder_get_object (builder, + "foreground-colorpicker"), + "rgba", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) s_to_rgba, + (GSettingsBindSetMapping) rgba_to_s, + NULL, NULL); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_LOGIN_SHELL_KEY, + gtk_builder_get_object (builder, + "login-shell-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = GTK_WIDGET (gtk_builder_get_object (builder, "scrollback-lines-spinbutton")); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_SCROLLBACK_LINES_KEY, + gtk_spin_button_get_adjustment (GTK_SPIN_BUTTON (w)), + "value", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY, + gtk_builder_get_object (builder, + "scrollback-limited-checkbutton"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | + G_SETTINGS_BIND_INVERT_BOOLEAN); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY, + gtk_builder_get_object (builder, + "scrollback-box"), + "sensitive", + G_SETTINGS_BIND_GET | + G_SETTINGS_BIND_INVERT_BOOLEAN | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_with_mapping (profile, + TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY, + gtk_builder_get_object (builder, + "scrollbar-checkbutton"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) scrollbar_policy_to_bool, + (GSettingsBindSetMapping) bool_to_scrollbar_policy, + NULL, NULL); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY, + gtk_builder_get_object (builder, + "scroll-on-keystroke-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY, + gtk_builder_get_object (builder, + "scroll-on-output-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY, + gtk_builder_get_object (builder, + "custom-font-checkbutton"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET | + G_SETTINGS_BIND_INVERT_BOOLEAN); + + w = (GtkWidget *) gtk_builder_get_object (builder, "preserve-working-directory-combobox"); + profile_prefs_settings_bind_with_mapping (profile, TERMINAL_PROFILE_PRESERVE_WORKING_DIRECTORY_KEY, w, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET, + (GSettingsBindGetMapping) string_to_enum, + (GSettingsBindSetMapping) enum_to_string, + terminal_preserve_working_directory_get_type, NULL); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY, + gtk_builder_get_object (builder, + "use-custom-command-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_USE_THEME_COLORS_KEY, + gtk_builder_get_object (builder, + "use-theme-colors-checkbutton"), + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_AUDIBLE_BELL_KEY, + gtk_builder_get_object (builder, "bell-checkbutton"), + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + profile_prefs_settings_bind (profile, + TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY, + gtk_builder_get_object (builder, "custom-command-entry-label"), + "sensitive", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind (profile, + TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY, + gtk_builder_get_object (builder, "custom-command-entry"), + "sensitive", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind (profile, + TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY, + gtk_builder_get_object (builder, "font-selector"), + "sensitive", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind (profile, + TERMINAL_PROFILE_USE_THEME_COLORS_KEY, + gtk_builder_get_object (builder, "colors-box"), + "sensitive", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_INVERT_BOOLEAN | + G_SETTINGS_BIND_NO_SENSITIVITY); + profile_prefs_settings_bind_writable (profile, + TERMINAL_PROFILE_PALETTE_KEY, + gtk_builder_get_object (builder, "palette-box"), + "sensitive", + FALSE); + + /* Compatibility options */ + w = (GtkWidget *) gtk_builder_get_object (builder, "encoding-combobox"); + profile_prefs_signal_connect (w, "changed", + G_CALLBACK (profile_encoding_combo_changed_cb), + profile); + + profile_notify_encoding_combo_cb (profile, TERMINAL_PROFILE_ENCODING_KEY, GTK_COMBO_BOX (w)); + profile_prefs_signal_connect (profile, "changed::" TERMINAL_PROFILE_ENCODING_KEY, + G_CALLBACK (profile_notify_encoding_combo_cb), + w); + + w = (GtkWidget *) gtk_builder_get_object (builder, "cjk-ambiguous-width-combobox"); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY, + w, + "active-id", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + w = (GtkWidget *) gtk_builder_get_object (builder, "enable-sixel-checkbutton"); + profile_prefs_settings_bind (profile, TERMINAL_PROFILE_ENABLE_SIXEL_KEY, w, + "active", G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + gtk_widget_set_visible (w, (vte_get_feature_flags() & VTE_FEATURE_FLAG_SIXEL) != 0); +} + +/* Called once per Preferences window, to destroy stuff that doesn't depend on the profile being edited */ +void +profile_prefs_destroy (void) +{ + profile_prefs_unload (); + + g_array_free (the_pref_data->profile_signals, TRUE); + g_array_free (the_pref_data->profile_bindings, TRUE); +} diff --git a/src/profile-editor.h b/src/profile-editor.h new file mode 100644 index 0000000..e83d393 --- /dev/null +++ b/src/profile-editor.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2002 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_PROFILE_EDITOR_H +#define TERMINAL_PROFILE_EDITOR_H + +#include +#include + +G_BEGIN_DECLS + +void profile_prefs_init (void); + +void profile_prefs_destroy (void); + +void profile_prefs_unload (void); + +void profile_prefs_load (const char *uuid, + GSettings *profile); + +G_END_DECLS + +#endif /* TERMINAL_PROFILE_EDITOR_H */ diff --git a/src/search-popover.ui b/src/search-popover.ui new file mode 100644 index 0000000..4bea44d --- /dev/null +++ b/src/search-popover.ui @@ -0,0 +1,251 @@ + + + + + + diff --git a/src/server.c b/src/server.c new file mode 100644 index 0000000..87a6cd9 --- /dev/null +++ b/src/server.c @@ -0,0 +1,191 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008, 2010, 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-gdbus.h" +#include "terminal-i18n.h" +#include "terminal-defines.h" +#include "terminal-libgsystem.h" + +static char *app_id = NULL; + +#define INACTIVITY_TIMEOUT (100 /* ms */) + +static gboolean +option_app_id_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + if (!g_application_id_is_valid (value) || + !g_dbus_is_name (value)) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "\"%s\" is not a valid application ID", value); + return FALSE; + } + + g_free (app_id); + app_id = g_strdup (value); + + return TRUE; +} + +static const GOptionEntry options[] = { + { "app-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, option_app_id_cb, "Application ID", "ID" }, + { NULL } +}; + +/* We use up to 8 FDs per terminal, so let's bump the limit way up. + * However we need to restore the original limit for the child processes. + */ + +static struct rlimit sv_rlimit_nofile; + +static void +atfork_child_restore_rlimit_nofile (void) +{ + if (setrlimit (RLIMIT_NOFILE, &sv_rlimit_nofile) < 0) + _exit (127); +} + +static gboolean +increase_rlimit_nofile (void) +{ + struct rlimit l; + + if (getrlimit (RLIMIT_NOFILE, &sv_rlimit_nofile) < 0) + return FALSE; + + if (pthread_atfork (NULL, NULL, atfork_child_restore_rlimit_nofile) != 0) + return FALSE; + + l.rlim_cur = l.rlim_max = sv_rlimit_nofile.rlim_max; + if (setrlimit (RLIMIT_NOFILE, &l) < 0) + return FALSE; + + return TRUE; +} + +static int +init_server (int argc, + char *argv[], + GApplication **application) +{ + if (G_UNLIKELY ((getuid () != geteuid () || + getgid () != getegid ()) && + geteuid () == 0 && + getegid () == 0)) { + g_printerr ("Wrong euid/egid, exiting.\n"); + return _EXIT_FAILURE_WRONG_ID; + } + + if (setlocale (LC_ALL, "") == NULL) { + g_printerr ("Locale not supported.\n"); + return _EXIT_FAILURE_UNSUPPORTED_LOCALE; + } + + terminal_i18n_init (TRUE); + const char *charset; + if (!g_get_charset (&charset)) { + g_printerr ("Non UTF-8 locale (%s) is not supported!\n", charset); + return _EXIT_FAILURE_NO_UTF8; + } + + /* Sanitise environment */ + g_unsetenv ("DBUS_STARTER_BUS_TYPE"); + + /* Not interested in silly debug spew polluting the journal, bug #749195 */ + if (g_getenv ("G_ENABLE_DIAGNOSTIC") == NULL) + g_setenv ("G_ENABLE_DIAGNOSTIC", "0", TRUE); + + _terminal_debug_init (); + + /* Change directory to $HOME so we don't prevent unmounting, e.g. if the + * factory is started by nautilus-open-terminal. See bug #565328. + * On failure back to /. + */ + const char *home_dir = g_get_home_dir (); + if (home_dir == NULL || chdir (home_dir) < 0) +#pragma GCC diagnostic push +#pragma GCC diagnostic ignored "-Wunused-result" + chdir ("/"); +#pragma GCC diagnostic pop + + g_set_prgname ("gnome-terminal-server"); + g_set_application_name (_("Terminal")); + + GError *error = NULL; + if (!gtk_init_with_args (&argc, &argv, NULL, options, NULL, &error)) { + if (error != NULL) { + g_printerr ("Failed to parse arguments: %s\n", error->message); + g_error_free (error); + } + return _EXIT_FAILURE_GTK_INIT; + } + + if (!increase_rlimit_nofile ()) { + g_printerr ("Failed to increase RLIMIT_NOFILE: %m\n"); + } + + /* Now we can create the app */ + GApplication *app = terminal_app_new (app_id); + g_free (app_id); + app_id = NULL; + + /* We stay around a bit after the last window closed */ + g_application_set_inactivity_timeout (app, INACTIVITY_TIMEOUT); + + *application = app; + return 0; +} + +int +main (int argc, + char *argv[]) +{ + gs_unref_object GApplication *app = NULL; + int r = init_server (argc, argv, &app); + if (r != 0) + return r; + + /* Note that this flushes the D-Bus connection just before quitting, + * thus ensuring that all pending signal emissions (e.g. child-exited) + * are delivered. + */ + return g_application_run (app, 0, NULL); +} diff --git a/src/terminal-accels.c b/src/terminal-accels.c new file mode 100644 index 0000000..333c6d1 --- /dev/null +++ b/src/terminal-accels.c @@ -0,0 +1,614 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington, Red Hat Inc. + * Copyright © 2008, 2011, 2012, 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include +#include +#include + +#include "terminal-accels.h" +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-schemas.h" +#include "terminal-intl.h" +#include "terminal-util.h" +#include "terminal-libgsystem.h" + +/* NOTES + * + * There are two sources of keybindings changes, from GSettings and from + * the accel map (happens with in-place menu editing). + * + * When a keybinding gsettings key changes, we propagate that into the + * accel map. + * When the accel map changes, we queue a sync to GSettings. + * + * To avoid infinite loops, we short-circuit in both directions + * if the value is unchanged from last known. + * + * In the keybinding editor, when editing or clearing an accel, we write + * the change directly to GSettings and rely on the callback to + * actually apply the change to the accel map. + */ + +#define KEY_CLOSE_TAB "close-tab" +#define KEY_CLOSE_WINDOW "close-window" +#define KEY_COPY "copy" +#define KEY_COPY_HTML "copy-html" +#define KEY_DETACH_TAB "detach-tab" +#define KEY_EXPORT "export" +#define KEY_FIND "find" +#define KEY_FIND_CLEAR "find-clear" +#define KEY_FIND_PREV "find-previous" +#define KEY_FIND_NEXT "find-next" +#define KEY_FULL_SCREEN "full-screen" +#define KEY_HEADER_MENU "header-menu" +#define KEY_HELP "help" +#define KEY_MOVE_TAB_LEFT "move-tab-left" +#define KEY_MOVE_TAB_RIGHT "move-tab-right" +#define KEY_NEW_TAB "new-tab" +#define KEY_NEW_WINDOW "new-window" +#define KEY_NEXT_TAB "next-tab" +#define KEY_PASTE "paste" +#define KEY_PREFERENCES "preferences" +#define KEY_PREV_TAB "prev-tab" +#define KEY_PRINT "print" +#define KEY_READ_ONLY "read-only" +#define KEY_RESET_AND_CLEAR "reset-and-clear" +#define KEY_RESET "reset" +#define KEY_SAVE_CONTENTS "save-contents" +#define KEY_SELECT_ALL "select-all" +#define KEY_TOGGLE_MENUBAR "toggle-menubar" +#define KEY_ZOOM_IN "zoom-in" +#define KEY_ZOOM_NORMAL "zoom-normal" +#define KEY_ZOOM_OUT "zoom-out" +#define KEY_SWITCH_TAB_PREFIX "switch-to-tab-" + +#if 1 +/* +* We don't want to enable content saving until vte supports it async. +* So we disable this code for stable versions. +*/ +#include "terminal-version.h" + +#if (TERMINAL_MINOR_VERSION & 1) != 0 +#define ENABLE_SAVE +#else +#undef ENABLE_SAVE +#endif +#endif + +typedef struct +{ + const char *user_visible_name; + const char *settings_key; + const char *action_name; + const GVariantType *action_parameter_type; + const char *action_parameter; + GVariant *parameter; + const char *shadow_action_name; +} KeyEntry; + +typedef struct +{ + KeyEntry *key_entry; + guint n_elements; + const char *user_visible_name; + gboolean headerbar_only; +} KeyEntryList; + +#define ENTRY_FULL(name, key, action, type, parameter, shadow_name) \ + { name, key, "win." action, (const GVariantType *) type, parameter, NULL, shadow_name } +#define ENTRY(name, key, action, type, parameter) \ + ENTRY_FULL (name, key, action, type, parameter, "win.shadow") +#define ENTRY_MDI(name, key, action, type, parameter) \ + ENTRY_FULL (name, key, action, type, parameter, "win.shadow-mdi") + +static KeyEntry file_entries[] = { + ENTRY (N_("New Tab"), KEY_NEW_TAB, "new-terminal", "(ss)", "('tab','current')" ), + ENTRY (N_("New Window"), KEY_NEW_WINDOW, "new-terminal", "(ss)", "('window','current')"), +#ifdef ENABLE_SAVE + ENTRY (N_("Save Contents"), KEY_SAVE_CONTENTS, "save-contents", NULL, NULL ), +#endif +#ifdef ENABLE_EXPORT + ENTRY (N_("Export"), KEY_EXPORT, "export", NULL, NULL ), +#endif +#ifdef ENABLE_PRINT + ENTRY (N_("Print"), KEY_PRINT, "print", NULL, NULL ), +#endif + ENTRY (N_("Close Tab"), KEY_CLOSE_TAB, "close", "s", "'tab'" ), + ENTRY (N_("Close Window"), KEY_CLOSE_WINDOW, "close", "s", "'window'" ), +}; + +static KeyEntry edit_entries[] = { + ENTRY (N_("Copy"), KEY_COPY, "copy", "s", "'text'" ), + ENTRY (N_("Copy as HTML"), KEY_COPY_HTML, "copy", "s", "'html'" ), + ENTRY (N_("Paste"), KEY_PASTE, "paste-text", NULL, NULL ), + ENTRY (N_("Select All"), KEY_SELECT_ALL, "select-all", NULL, NULL ), + ENTRY (N_("Preferences"), KEY_PREFERENCES, "edit-preferences", NULL, NULL ), +}; + +static KeyEntry search_entries[] = { + ENTRY (N_("Find"), KEY_FIND, "find", NULL, NULL), + ENTRY (N_("Find Next"), KEY_FIND_NEXT, "find-forward", NULL, NULL), + ENTRY (N_("Find Previous"), KEY_FIND_PREV, "find-backward", NULL, NULL), + ENTRY (N_("Clear Highlight"), KEY_FIND_CLEAR, "find-clear", NULL, NULL) +}; + +static KeyEntry view_entries[] = { + ENTRY (N_("Hide and Show Menubar"), KEY_TOGGLE_MENUBAR, "menubar-visible", NULL, NULL), + ENTRY (N_("Full Screen"), KEY_FULL_SCREEN, "fullscreen", NULL, NULL), + ENTRY (N_("Zoom In"), KEY_ZOOM_IN, "zoom-in", NULL, NULL), + ENTRY (N_("Zoom Out"), KEY_ZOOM_OUT, "zoom-out", NULL, NULL), + ENTRY (N_("Normal Size"), KEY_ZOOM_NORMAL, "zoom-normal", NULL, NULL) +}; + +static KeyEntry terminal_entries[] = { + ENTRY (N_("Read-Only"), KEY_READ_ONLY, "read-only", NULL, NULL ), + ENTRY (N_("Reset"), KEY_RESET, "reset", "b", "false"), + ENTRY (N_("Reset and Clear"), KEY_RESET_AND_CLEAR, "reset", "b", "true" ), +}; + +static KeyEntry tabs_entries[] = { + ENTRY_MDI (N_("Switch to Previous Tab"), KEY_PREV_TAB, "tab-switch-left", NULL, NULL), + ENTRY_MDI (N_("Switch to Next Tab"), KEY_NEXT_TAB, "tab-switch-right", NULL, NULL), + ENTRY_MDI (N_("Move Tab to the Left"), KEY_MOVE_TAB_LEFT, "tab-move-left", NULL, NULL), + ENTRY_MDI (N_("Move Tab to the Right"), KEY_MOVE_TAB_RIGHT, "tab-move-right", NULL, NULL), + ENTRY_MDI (N_("Detach Tab"), KEY_DETACH_TAB, "tab-detach", NULL, NULL), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "1", "active-tab", "i", "0"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "2", "active-tab", "i", "1"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "3", "active-tab", "i", "2"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "4", "active-tab", "i", "3"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "5", "active-tab", "i", "4"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "6", "active-tab", "i", "5"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "7", "active-tab", "i", "6"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "8", "active-tab", "i", "7"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "9", "active-tab", "i", "8"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "10", "active-tab", "i", "9"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "11", "active-tab", "i", "10"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "12", "active-tab", "i", "11"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "13", "active-tab", "i", "12"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "14", "active-tab", "i", "13"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "15", "active-tab", "i", "14"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "16", "active-tab", "i", "15"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "17", "active-tab", "i", "16"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "18", "active-tab", "i", "17"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "19", "active-tab", "i", "18"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "20", "active-tab", "i", "19"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "21", "active-tab", "i", "20"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "22", "active-tab", "i", "21"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "23", "active-tab", "i", "22"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "24", "active-tab", "i", "23"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "25", "active-tab", "i", "24"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "26", "active-tab", "i", "25"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "27", "active-tab", "i", "26"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "28", "active-tab", "i", "27"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "29", "active-tab", "i", "28"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "30", "active-tab", "i", "29"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "31", "active-tab", "i", "30"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "32", "active-tab", "i", "31"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "33", "active-tab", "i", "32"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "34", "active-tab", "i", "33"), + ENTRY_MDI (NULL, KEY_SWITCH_TAB_PREFIX "35", "active-tab", "i", "34"), + ENTRY_MDI (N_("Switch to Last Tab"), KEY_SWITCH_TAB_PREFIX "last", "active-tab", "i", "-1"), +}; + +static KeyEntry help_entries[] = { + ENTRY (N_("Contents"), KEY_HELP, "help", NULL, NULL) +}; + +static KeyEntry global_entries[] = { + ENTRY (N_("Show Primary Menu"), KEY_HEADER_MENU, "header-menu", NULL, NULL), +}; + +#undef ENTRY_FULL +#undef ENTRY +#undef ENTRY_MDI + +static KeyEntryList all_entries[] = +{ + { file_entries, G_N_ELEMENTS (file_entries), N_("File"), FALSE }, + { edit_entries, G_N_ELEMENTS (edit_entries), N_("Edit"), FALSE }, + { view_entries, G_N_ELEMENTS (view_entries), N_("View"), FALSE }, + { search_entries, G_N_ELEMENTS (search_entries), N_("Search"), FALSE }, + { terminal_entries, G_N_ELEMENTS (terminal_entries), N_("Terminal"), FALSE }, + { tabs_entries, G_N_ELEMENTS (tabs_entries), N_("Tabs"), FALSE }, + { help_entries, G_N_ELEMENTS (help_entries), N_("Help"), FALSE }, + { global_entries, G_N_ELEMENTS (global_entries), N_("Global"), TRUE }, +}; + +enum +{ + ACTION_COLUMN, + KEYVAL_COLUMN, + N_COLUMNS +}; + +static GHashTable *settings_key_to_entry; +static GSettings *keybinding_settings = NULL; + +GS_DEFINE_CLEANUP_FUNCTION(GtkTreePath*, _terminal_local_free_tree_path, gtk_tree_path_free) +#define terminal_free_tree_path __attribute__((__cleanup__(_terminal_local_free_tree_path))) + +static char* +binding_name (guint keyval, + GdkModifierType mask) +{ + if (keyval != 0) + return gtk_accelerator_name (keyval, mask); + + return g_strdup ("disabled"); +} + +static void +key_changed_cb (GSettings *settings, + const char *settings_key, + gpointer user_data) +{ + GtkApplication *application = user_data; + const gchar *accels[2] = { NULL, NULL }; + + _terminal_debug_print (TERMINAL_DEBUG_ACCELS, + "key %s changed\n", + settings_key); + + KeyEntry *key_entry = g_hash_table_lookup (settings_key_to_entry, settings_key); + if (!key_entry) + { + /* shouldn't really happen, but let's be safe */ + _terminal_debug_print (TERMINAL_DEBUG_ACCELS, + " WARNING: KeyEntry for changed key not found, bailing out\n"); + return; + } + + gs_free char *value = g_settings_get_string (settings, settings_key); + + gs_free char *detailed = g_action_print_detailed_name (key_entry->action_name, + key_entry->parameter); + gs_unref_variant GVariant *shadow_parameter = g_variant_new_string (detailed); + gs_free char *shadow_detailed = g_action_print_detailed_name (key_entry->shadow_action_name, + shadow_parameter); + + /* We want to always consume the action's accelerators, even if the corresponding + * action is insensitive, so the corresponding shortcut key escape code isn't sent + * to the terminal. See bug #453193, bug #138609, and bug #559728. + * Since GtkApplication's accelerators don't use GtkAccelGroup, we have no way + * to intercept/chain on its activation. The only way to do this that I found + * was to install an extra action with the same accelerator that shadows + * the real action and gets activated when the shadowed action is disabled. + */ + + if (g_str_equal (value, "disabled")) { + accels[0] = NULL; + } else { + accels[0] = value; + } + + gtk_application_set_accels_for_action (application, + detailed, + accels); + gtk_application_set_accels_for_action (application, + shadow_detailed, + accels); +} + +static void +add_accel_entries (GApplication*application, + KeyEntry *entries, + guint n_entries) +{ + guint j; + + for (j = 0; j < n_entries; ++j) { + KeyEntry *key_entry = &entries[j]; + if (key_entry->action_parameter) { + GError *err = NULL; + key_entry->parameter = g_variant_parse (key_entry->action_parameter_type, + key_entry->action_parameter, + NULL, NULL, &err); + g_assert_no_error (err); + + g_assert (key_entry->parameter != NULL); + } + + g_hash_table_insert (settings_key_to_entry, + (gpointer) key_entry->settings_key, + key_entry); + + key_changed_cb (keybinding_settings, key_entry->settings_key, application); + } +} + +void +terminal_accels_init (GApplication *application, + GSettings *settings, + gboolean use_headerbar) +{ + guint i, j; + + keybinding_settings = g_object_ref (settings); + + settings_key_to_entry = g_hash_table_new (g_str_hash, g_str_equal); + + /* Initialise names of tab_switch_entries */ + j = 1; + for (i = 0; i < G_N_ELEMENTS (tabs_entries); i++) + { + gs_free char *name = NULL; + + if (tabs_entries[i].user_visible_name != NULL) + continue; + + name = g_strdup_printf (_("Switch to Tab %u"), j++); + tabs_entries[i].user_visible_name = g_intern_string (name); + } + + for (i = 0; i < G_N_ELEMENTS (all_entries); ++i) { + if (!use_headerbar && all_entries[i].headerbar_only) + continue; + + add_accel_entries (application, all_entries[i].key_entry, all_entries[i].n_elements); + } + + g_signal_connect (keybinding_settings, "changed", G_CALLBACK (key_changed_cb), application); +} + +void +terminal_accels_shutdown (void) +{ + guint i, j; + + for (i = 0; i < G_N_ELEMENTS (all_entries); ++i) { + for (j = 0; j < all_entries[i].n_elements; ++j) { + KeyEntry *key_entry; + + key_entry = &(all_entries[i].key_entry[j]); + if (key_entry->parameter) + g_variant_unref (key_entry->parameter); + } + } + + g_signal_handlers_disconnect_by_func (keybinding_settings, + G_CALLBACK (key_changed_cb), + g_application_get_default ()); + + g_clear_pointer (&settings_key_to_entry, (GDestroyNotify) g_hash_table_unref); + g_clear_object (&keybinding_settings); +} + +static gboolean +foreach_row_cb (GtkTreeModel *model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer data) +{ + const char *key = data; + KeyEntry *key_entry; + + gtk_tree_model_get (model, iter, + KEYVAL_COLUMN, &key_entry, + -1); + + if (key_entry == NULL || + !g_str_equal (key_entry->settings_key, key)) + return FALSE; + + gtk_tree_model_row_changed (model, path, iter); + return TRUE; +} + +static void +treeview_key_changed_cb (GSettings *settings, + const char *key, + GtkTreeView *tree_view) +{ + gtk_tree_model_foreach (gtk_tree_view_get_model (tree_view), foreach_row_cb, (gpointer) key); +} + +static void +accel_set_func (GtkTreeViewColumn *tree_column, + GtkCellRenderer *cell, + GtkTreeModel *model, + GtkTreeIter *iter, + gpointer data) +{ + KeyEntry *ke; + + gtk_tree_model_get (model, iter, + KEYVAL_COLUMN, &ke, + -1); + + if (ke == NULL) { + /* This is a title row */ + g_object_set (cell, + "visible", FALSE, + NULL); + } else { + gs_free char *value; + guint key; + GdkModifierType mods; + gboolean writable; + GtkWidget *button = data; + + value = g_settings_get_string (keybinding_settings, ke->settings_key); + gtk_accelerator_parse (value, &key, &mods); + + writable = g_settings_is_writable (keybinding_settings, ke->settings_key) && + gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (button)); + + g_object_set (cell, + "visible", TRUE, + "sensitive", writable, + "editable", writable, + "accel-key", key, + "accel-mods", mods, + NULL); + } +} + +static void +accel_update (GtkTreeView *view, + GtkCellRendererAccel *cell, + gchar *path_string, + guint keyval, + GdkModifierType mask) +{ + GtkTreeModel *model; + terminal_free_tree_path GtkTreePath *path = NULL; + GtkTreeIter iter; + KeyEntry *ke; + gs_free char *str = NULL; + + model = gtk_tree_view_get_model (view); + + path = gtk_tree_path_new_from_string (path_string); + if (!path) + return; + + if (!gtk_tree_model_get_iter (model, &iter, path)) + return; + + gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1); + + /* sanity check */ + if (ke == NULL) + return; + + str = binding_name (keyval, mask); + g_settings_set_string (keybinding_settings, ke->settings_key, str); +} + +static void +accel_edited_callback (GtkCellRendererAccel *cell, + gchar *path_string, + guint keyval, + GdkModifierType mask, + guint hardware_keycode, + GtkTreeView *view) +{ + accel_update (view, cell, path_string, keyval, mask); +} + +static void +accel_cleared_callback (GtkCellRendererAccel *cell, + gchar *path_string, + GtkTreeView *view) +{ + accel_update (view, cell, path_string, 0, 0); +} + +static void +treeview_destroy_cb (GtkWidget *tree_view, + gpointer user_data) +{ + g_signal_handlers_disconnect_by_func (keybinding_settings, + G_CALLBACK (treeview_key_changed_cb), + tree_view); +} + +#ifdef ENABLE_DEBUG +static void +row_changed (GtkTreeModel *tree_model, + GtkTreePath *path, + GtkTreeIter *iter, + gpointer user_data) +{ + _terminal_debug_print (TERMINAL_DEBUG_ACCELS, + "ROW-CHANGED [%s]\n", gtk_tree_path_to_string (path) /* leak */); +} +#endif + +void +terminal_accels_fill_treeview (GtkWidget *tree_view, + GtkWidget *disable_shortcuts_button) +{ + GtkTreeViewColumn *column; + GtkCellRenderer *cell_renderer; + gs_unref_object GtkTreeStore *tree = NULL; + guint i; + + /* Column 1 */ + cell_renderer = gtk_cell_renderer_text_new (); + column = gtk_tree_view_column_new_with_attributes (_("_Action"), + cell_renderer, + "text", ACTION_COLUMN, + NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); + + /* Column 2 */ + cell_renderer = gtk_cell_renderer_accel_new (); + g_object_set (cell_renderer, + "editable", TRUE, + "accel-mode", GTK_CELL_RENDERER_ACCEL_MODE_GTK, + NULL); + + g_signal_connect (cell_renderer, "accel-edited", + G_CALLBACK (accel_edited_callback), tree_view); + g_signal_connect (cell_renderer, "accel-cleared", + G_CALLBACK (accel_cleared_callback), tree_view); + + column = gtk_tree_view_column_new (); + gtk_tree_view_column_set_title (column, _("Shortcut _Key")); + gtk_tree_view_column_pack_start (column, cell_renderer, TRUE); + gtk_tree_view_column_set_cell_data_func (column, cell_renderer, accel_set_func, + disable_shortcuts_button, NULL); + gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column); + + /* Add the data */ + + tree = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER); + +#ifdef ENABLE_DEBUG + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS) + g_signal_connect (tree, "row-changed", G_CALLBACK (row_changed), NULL); +#endif + + for (i = 0; i < G_N_ELEMENTS (all_entries); ++i) + { + GtkTreeIter parent_iter; + guint j; + + gtk_tree_store_insert_with_values (tree, &parent_iter, NULL, -1, + ACTION_COLUMN, _(all_entries[i].user_visible_name), + KEYVAL_COLUMN, NULL, + -1); + + for (j = 0; j < all_entries[i].n_elements; ++j) + { + KeyEntry *key_entry = &(all_entries[i].key_entry[j]); + GtkTreeIter iter; + + gtk_tree_store_insert_with_values (tree, &iter, &parent_iter, -1, + ACTION_COLUMN, _(key_entry->user_visible_name), + KEYVAL_COLUMN, key_entry, + -1); + } + } + + gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (tree)); + + gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view)); + + g_signal_connect (keybinding_settings, "changed", + G_CALLBACK (treeview_key_changed_cb), tree_view); + g_signal_connect (tree_view, "destroy", + G_CALLBACK (treeview_destroy_cb), tree); +} diff --git a/src/terminal-accels.h b/src/terminal-accels.h new file mode 100644 index 0000000..8c860a3 --- /dev/null +++ b/src/terminal-accels.h @@ -0,0 +1,37 @@ +/* + * Copyright © 2001 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_ACCELS_H +#define TERMINAL_ACCELS_H + +#include +#include + +G_BEGIN_DECLS + +void terminal_accels_init (GApplication *application, + GSettings *settings, + gboolean use_headerbar); + +void terminal_accels_shutdown (void); + +void terminal_accels_fill_treeview (GtkWidget *treeview, + GtkWidget *disable_shortcuts_button); + +G_END_DECLS + +#endif /* TERMINAL_ACCELS_H */ diff --git a/src/terminal-app.c b/src/terminal-app.c new file mode 100644 index 0000000..ff91e15 --- /dev/null +++ b/src/terminal-app.c @@ -0,0 +1,1278 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008, 2010, 2011, 2015, 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include + +#define G_SETTINGS_ENABLE_BACKEND +#include + +#include "terminal-intl.h" +#include "terminal-debug.h" +#include "terminal-app.h" +#include "terminal-accels.h" +#include "terminal-screen.h" +#include "terminal-screen-container.h" +#include "terminal-window.h" +#include "terminal-profiles-list.h" +#include "terminal-util.h" +#include "profile-editor.h" +#include "terminal-schemas.h" +#include "terminal-gdbus.h" +#include "terminal-defines.h" +#include "terminal-prefs.h" +#include "terminal-libgsystem.h" + +#ifdef ENABLE_SEARCH_PROVIDER +#include "terminal-search-provider.h" +#endif /* ENABLE_SEARCH_PROVIDER */ + +#include +#include +#include +#include +#include + +#define DESKTOP_INTERFACE_SETTINGS_SCHEMA "org.gnome.desktop.interface" + +#define SYSTEM_PROXY_SETTINGS_SCHEMA "org.gnome.system.proxy" + +#define GTK_SETTING_PREFER_DARK_THEME "gtk-application-prefer-dark-theme" + +#define GTK_DEBUG_SETTING_SCHEMA "org.gtk.Settings.Debug" +#define GTK_DEBUG_ENABLE_INSPECTOR_KEY "enable-inspector-keybinding" +#define GTK_DEBUG_ENABLE_INSPECTOR_TYPE G_VARIANT_TYPE_BOOLEAN + +#ifdef DISUNIFY_NEW_TERMINAL_SECTION +#error Use a gsettings override instead +#endif + +/* + * Session state is stored entirely in the RestartCommand command line. + * + * The number one rule: all stored information is EITHER per-session, + * per-profile, or set from a command line option. THERE CAN BE NO + * OVERLAP. The UI and implementation totally break if you overlap + * these categories. See gnome-terminal 1.x for why. + */ + +struct _TerminalAppClass { + GtkApplicationClass parent_class; + + void (* clipboard_targets_changed) (TerminalApp *app, + GtkClipboard *clipboard); +}; + +struct _TerminalApp +{ + GtkApplication parent_instance; + + GDBusObjectManagerServer *object_manager; + + TerminalSettingsList *profiles_list; + + GHashTable *screen_map; + + GSettings *global_settings; + GSettings *desktop_interface_settings; + GSettings *system_proxy_settings; + GSettings *gtk_debug_settings; + +#ifdef ENABLE_SEARCH_PROVIDER + TerminalSearchProvider *search_provider; +#endif /* ENABLE_SEARCH_PROVIDER */ + + GMenuModel *menubar; + GMenu *menubar_new_terminal_section; + GMenu *menubar_set_profile_section; + + GMenuModel *profilemenu; + GMenuModel *headermenu; + GMenu *headermenu_set_profile_section; + + GMenu *set_profile_menu; + + GtkClipboard *clipboard; + GdkAtom *clipboard_targets; + int n_clipboard_targets; + + gboolean unified_menu; + gboolean use_headerbar; +}; + +enum +{ + CLIPBOARD_TARGETS_CHANGED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +/* Debugging helper */ + +static void +terminal_app_init_debug (void) +{ +#ifdef ENABLE_DEBUG + const char *env = g_getenv ("GTK_TEXT_DIR"); + if (env != NULL) { + if (g_str_equal (env, "help")) { + g_printerr ("Usage: GTK_TEXT_DIR=ltr|rtl\n"); + } else { + GtkTextDirection dir; + if (g_str_equal (env, "rtl")) + dir = GTK_TEXT_DIR_RTL; + else + dir = GTK_TEXT_DIR_LTR; + + gtk_widget_set_default_direction (dir); + } + } + + env = g_getenv ("GTK_SETTINGS"); + if (env == NULL) + return; + + GObject *settings = G_OBJECT (gtk_settings_get_default ()); + GObjectClass *settings_class = G_OBJECT_GET_CLASS (settings); + + if (g_str_equal (env, "help")) { + g_printerr ("Usage: GTK_SETTINGS=setting[,setting…] where 'setting' is one of these:\n"); + + guint n_props; + GParamSpec **props = g_object_class_list_properties (settings_class, &n_props); + for (guint i = 0; i < n_props; i++) { + if (G_PARAM_SPEC_VALUE_TYPE (props[i]) != G_TYPE_BOOLEAN) + continue; + + GValue value = { 0, }; + g_value_init (&value, G_TYPE_BOOLEAN); + g_object_get_property (settings, props[i]->name, &value); + g_printerr (" %s (%s)\n", props[i]->name, g_value_get_boolean (&value) ? "true" : "false"); + g_value_unset (&value); + } + g_printerr (" Use 'setting' to set to true, " + "'~setting' to set to false, " + "and '!setting' to invert.\n"); + } else { + gs_strfreev char **tokens = g_strsplit (env, ",", -1); + for (guint i = 0; tokens[i] != NULL; i++) { + const char *prop = tokens[i]; + char c = prop[0]; + if (c == '~' || c == '!') + prop++; + + GParamSpec *pspec = g_object_class_find_property (settings_class, prop); + if (pspec == NULL) { + g_printerr ("Setting \"%s\" does not exist.\n", prop); + } else if (G_PARAM_SPEC_VALUE_TYPE (pspec) != G_TYPE_BOOLEAN) { + g_printerr ("Setting \"%s\" is not boolean.\n", prop); + } else { + GValue value = { 0, }; + g_value_init (&value, G_TYPE_BOOLEAN); + if (c == '!') { + g_object_get_property (settings, pspec->name, &value); + g_value_set_boolean (&value, !g_value_get_boolean (&value)); + } else if (c == '~') { + g_value_set_boolean (&value, FALSE); + } else { + g_value_set_boolean (&value, TRUE); + } + g_object_set_property (settings, pspec->name, &value); + g_value_unset (&value); + } + } + } +#endif +} + +/* Helper functions */ + +static gboolean +strv_contains_gnome (char **strv) +{ + if (strv == NULL) + return FALSE; + + for (int i = 0; strv[i] != NULL; i++) { + if (g_ascii_strcasecmp (strv[i], "gnome") == 0 || + g_ascii_strcasecmp (strv[i], "gnome-classic") == 0) + return TRUE; + } + + return FALSE; +} + +/* + * terminal_app_should_use_headerbar: + * + * Determines if the app should use headerbars. This is determined + * * If the pref is set, the pref value is used + * * Otherwise, if XDG_CURRENT_DESKTOP contains GNOME or GNOME-Classic, + * headerbar is used + * * Otherwise, headerbar is not used. + */ +static gboolean +terminal_app_should_use_headerbar (TerminalApp *app) +{ + gboolean set, use; + g_settings_get (app->global_settings, TERMINAL_SETTING_HEADERBAR_KEY, "mb", &set, &use); + if (set) + return use; + + const char *desktop = g_getenv ("XDG_CURRENT_DESKTOP"); + if (desktop == NULL) + return FALSE; + + char **desktops = g_strsplit (desktop, G_SEARCHPATH_SEPARATOR_S, -1); + use = strv_contains_gnome (desktops); + g_strfreev (desktops); + + return use; +} + +static gboolean +load_css_from_resource (GApplication *application, + GtkCssProvider *provider, + gboolean theme) +{ + const char *base_path; + gs_free char *uri; + gs_unref_object GFile *file; + gs_free_error GError *error = NULL; + + base_path = g_application_get_resource_base_path (application); + + if (theme) { + gs_free char *str, *theme_name; + + g_object_get (gtk_settings_get_default (), "gtk-theme-name", &str, NULL); + theme_name = g_ascii_strdown (str, -1); + uri = g_strdup_printf ("resource://%s/css/%s/terminal.css", base_path, theme_name); + } else { + uri = g_strdup_printf ("resource://%s/css/terminal.css", base_path); + } + + file = g_file_new_for_uri (uri); + if (!g_file_query_exists (file, NULL /* cancellable */)) + return FALSE; + + if (!gtk_css_provider_load_from_file (provider, file, &error)) + g_assert_no_error (error); + + return TRUE; +} + +static void +add_css_provider (GApplication *application, + gboolean theme) +{ + gs_unref_object GtkCssProvider *provider; + + provider = gtk_css_provider_new (); + if (!load_css_from_resource (application, provider, theme)) + return; + + gtk_style_context_add_provider_for_screen (gdk_screen_get_default (), + GTK_STYLE_PROVIDER (provider), + GTK_STYLE_PROVIDER_PRIORITY_APPLICATION); +} + +static void +app_load_css (GApplication *application) +{ + add_css_provider (application, FALSE); + add_css_provider (application, TRUE); +} + +char * +terminal_app_new_profile (TerminalApp *app, + GSettings *base_profile, + const char *name) +{ + char *uuid; + + if (base_profile) { + gs_free char *base_uuid; + + base_uuid = terminal_settings_list_dup_uuid_from_child (app->profiles_list, base_profile); + uuid = terminal_settings_list_clone_child (app->profiles_list, base_uuid, name); + } else { + uuid = terminal_settings_list_add_child (app->profiles_list, name); + } + + return uuid; +} + +void +terminal_app_remove_profile (TerminalApp *app, + GSettings *profile) +{ + g_return_if_fail (TERMINAL_IS_APP (app)); + g_return_if_fail (G_IS_SETTINGS (profile)); + + gs_unref_object GSettings *default_profile = terminal_settings_list_ref_default_child (app->profiles_list); + if (default_profile == profile) + return; + + /* First, we need to switch any screen using this profile to the default profile */ + gs_free_list GList *screens = g_hash_table_get_values (app->screen_map); + for (GList *l = screens; l != NULL; l = l->next) { + TerminalScreen *screen = TERMINAL_SCREEN (l->data); + if (terminal_screen_get_profile (screen) != profile) + continue; + + terminal_screen_set_profile (screen, default_profile); + } + + /* Now we can safely remove the profile */ + gs_free char *uuid = terminal_settings_list_dup_uuid_from_child (app->profiles_list, profile); + terminal_settings_list_remove_child (app->profiles_list, uuid); +} + +static void +terminal_app_theme_variant_changed_cb (GSettings *settings, + const char *key, + GtkSettings *gtk_settings) +{ + TerminalThemeVariant theme; + + theme = g_settings_get_enum (settings, key); + if (theme == TERMINAL_THEME_VARIANT_SYSTEM) + gtk_settings_reset_property (gtk_settings, GTK_SETTING_PREFER_DARK_THEME); + else + g_object_set (gtk_settings, + GTK_SETTING_PREFER_DARK_THEME, + theme == TERMINAL_THEME_VARIANT_DARK, + NULL); +} + +/* Submenus for New Terminal per profile, and to change profiles */ + +static void terminal_app_update_profile_menus (TerminalApp *app); + +typedef struct { + char *uuid; + char *label; +} ProfileData; + +static void +profile_data_clear (ProfileData *data) +{ + g_free (data->uuid); + g_free (data->label); +} + +typedef struct { + GArray *array; + TerminalApp *app; +} ProfilesForeachData; + +static void +foreach_profile_cb (TerminalSettingsList *list, + const char *uuid, + GSettings *profile, + ProfilesForeachData *user_data) +{ + ProfileData data; + data.uuid = g_strdup (uuid); + data.label = g_settings_get_string (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + + g_array_append_val (user_data->array, data); + + /* only connect if we haven't seen this profile before */ + if (g_signal_handler_find (profile, G_SIGNAL_MATCH_FUNC | G_SIGNAL_MATCH_DATA, + 0, 0, NULL, terminal_app_update_profile_menus, user_data->app) == 0) + g_signal_connect_swapped (profile, "changed::" TERMINAL_PROFILE_VISIBLE_NAME_KEY, + G_CALLBACK (terminal_app_update_profile_menus), user_data->app); +} + +static int +compare_profile_label_cb (gconstpointer ap, + gconstpointer bp) +{ + const ProfileData *a = ap; + const ProfileData *b = bp; + + return g_utf8_collate (a->label, b->label); +} + +static void +menu_append_numbered (GMenu *menu, + const char *label, + int num, + const char *action_name, + GVariant *target /* floating, consumed */) +{ + gs_free_gstring GString *str; + gs_unref_object GMenuItem *item; + const char *p; + + /* Who'd use more that 4 underscores in a profile name... */ + str = g_string_sized_new (strlen (label) + 4 + 1 + 8); + + if (num < 10) + g_string_append_printf (str, "_%Id. ", num); + else if (num < 36) + g_string_append_printf (str, "_%c. ", (char)('A' + num - 10)); + + /* Append the label with underscores elided */ + for (p = label; *p; p++) { + if (*p == '_') + g_string_append (str, "__"); + else + g_string_append_c (str, *p); + } + + item = g_menu_item_new (str->str, NULL); + g_menu_item_set_action_and_target_value (item, action_name, target); + g_menu_append_item (menu, item); +} + +static void +append_new_terminal_item (GMenu *section, + const char *label, + const char *target, + ProfileData *data, + guint n_profiles) +{ + gs_unref_object GMenuItem *item = g_menu_item_new (label, NULL); + + if (n_profiles > 1) { + gs_unref_object GMenu *submenu = g_menu_new (); + + for (guint i = 0; i < n_profiles; i++) { + menu_append_numbered (submenu, data[i].label, i + 1, + "win.new-terminal", + g_variant_new ("(ss)", target, data[i].uuid)); + } + + g_menu_item_set_link (item, G_MENU_LINK_SUBMENU, G_MENU_MODEL (submenu)); + } else { + g_menu_item_set_action_and_target (item, "win.new-terminal", + "(ss)", target, "current"); + } + g_menu_append_item (section, item); +} + +static void +fill_header_new_terminal_menu (GMenuModel *menu, + ProfileData *data, + guint n_profiles) +{ + gs_unref_object GMenu *section = NULL; + + if (n_profiles <= 1) + return; + + section = g_menu_new (); + + for (guint i = 0; i < n_profiles; i++) { + menu_append_numbered (section, data[i].label, i + 1, + "win.new-terminal", + g_variant_new ("(ss)", "default", data[i].uuid)); + } + + g_menu_append_section (G_MENU (menu), _("New Terminal"), G_MENU_MODEL (section)); +} + +static void +fill_new_terminal_section (TerminalApp *app, + GMenu *section, + ProfileData *profiles, + guint n_profiles) +{ + if (terminal_app_get_menu_unified (app)) { + append_new_terminal_item (section, _("New _Terminal"), "default", profiles, n_profiles); + } else { + append_new_terminal_item (section, _("New _Tab"), "tab", profiles, n_profiles); + append_new_terminal_item (section, _("New _Window"), "window", profiles, n_profiles); + } +} + +static GMenu * +set_profile_submenu_new (ProfileData *data, + guint n_profiles) +{ + /* No submenu if there's only one profile */ + if (n_profiles <= 1) + return NULL; + + GMenu *menu = g_menu_new (); + for (guint i = 0; i < n_profiles; i++) { + menu_append_numbered (menu, data[i].label, i + 1, + "win.profile", + g_variant_new_string (data[i].uuid)); + } + + return menu; +} + +static void +terminal_app_update_profile_menus (TerminalApp *app) +{ + g_clear_object (&app->set_profile_menu); + + /* Get profiles list and sort by label */ + gs_unref_array GArray *array = g_array_sized_new (FALSE, TRUE, sizeof (ProfileData), + terminal_settings_list_get_n_children (app->profiles_list)); + g_array_set_clear_func (array, (GDestroyNotify) profile_data_clear); + + ProfilesForeachData data = { array, app }; + terminal_settings_list_foreach_child (app->profiles_list, + (TerminalSettingsListForeachFunc) foreach_profile_cb, + &data); + g_array_sort (array, compare_profile_label_cb); + + ProfileData *profiles = (ProfileData*) array->data; + guint n_profiles = array->len; + + app->set_profile_menu = set_profile_submenu_new (profiles, n_profiles); + + if (app->menubar != NULL) { + g_menu_remove_all (G_MENU (app->menubar_new_terminal_section)); + fill_new_terminal_section (app, app->menubar_new_terminal_section, profiles, n_profiles); + + g_menu_remove_all (G_MENU (app->menubar_set_profile_section)); + if (app->set_profile_menu != NULL) { + g_menu_append_submenu (app->menubar_set_profile_section, _("Change _Profile"), + G_MENU_MODEL (app->set_profile_menu)); + } + } + + if (app->profilemenu != NULL) { + g_menu_remove_all (G_MENU (app->profilemenu)); + fill_header_new_terminal_menu (app->profilemenu, profiles, n_profiles); + } + + if (app->headermenu != NULL) { + g_menu_remove_all (G_MENU (app->headermenu_set_profile_section)); + if (app->set_profile_menu != NULL) { + g_menu_append_submenu (app->headermenu_set_profile_section, _("_Profile"), + G_MENU_MODEL (app->set_profile_menu)); + } + } +} + +static GMenuModel * +terminal_app_create_menubar (TerminalApp *app, + gboolean shell_shows_menubar) +{ + /* If the menubar is shown by the shell, omit mnemonics for the submenus. This is because Alt+F etc. + * are more important to be usable in the terminal, the menu cannot be replaced runtime (to toggle + * between mnemonic and non-mnemonic versions), gtk-enable-mnemonics or gtk_window_set_mnemonic_modifier() + * don't effect the menubar either, so there wouldn't be a way to disable Alt+F for File etc. otherwise. + * Furthermore, the menu would even grab mnemonics from the File and Preferences windows. + * In Unity, Alt+F10 opens the menubar, this should be good enough for keyboard navigation. + * If the menubar is shown by the app, toggling mnemonics is handled in terminal-window.c using + * gtk_window_set_mnemonic_modifier(). + * See bug 792978 for details. */ + terminal_util_load_objects_resource (shell_shows_menubar ? "/org/gnome/terminal/ui/menubar-without-mnemonics.ui" + : "/org/gnome/terminal/ui/menubar-with-mnemonics.ui", + "menubar", &app->menubar, + "new-terminal-section", &app->menubar_new_terminal_section, + "set-profile-section", &app->menubar_set_profile_section, + NULL); + + /* Install profile sections */ + terminal_app_update_profile_menus (app); + + return app->menubar; +} + +static void +terminal_app_create_headermenu (TerminalApp *app) +{ + terminal_util_load_objects_resource ("/org/gnome/terminal/ui/headerbar-menu.ui", + "headermenu", &app->headermenu, + "set-profile-section", &app->headermenu_set_profile_section, + NULL); + + /* Install profile sections */ + terminal_app_update_profile_menus (app); +} + +static void +terminal_app_create_profilemenu (TerminalApp *app) +{ + app->profilemenu = G_MENU_MODEL (g_menu_new ()); + + /* Install profile sections */ + terminal_app_update_profile_menus (app); +} + +/* Clipboard */ + +static void +free_clipboard_targets (TerminalApp *app) +{ + g_free (app->clipboard_targets); + app->clipboard_targets = NULL; + app->n_clipboard_targets = 0; +} + +static void +update_clipboard_targets (TerminalApp *app, + GdkAtom *targets, + int n_targets) +{ + free_clipboard_targets (app); + + /* Sometimes we receive targets == NULL but n_targets == -1 */ + if (targets != NULL && n_targets < 255) { + app->clipboard_targets = g_memdup (targets, sizeof (targets[0]) * n_targets); + app->n_clipboard_targets = n_targets; + } +} + +static void +clipboard_targets_received_cb (GtkClipboard *clipboard, + GdkAtom *targets, + int n_targets, + TerminalApp *app) +{ + update_clipboard_targets (app, targets, n_targets); + + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_CLIPBOARD) { + g_printerr ("Clipboard has %d targets:", app->n_clipboard_targets); + + int i; + for (i = 0; i < app->n_clipboard_targets; i++) { + gs_free char *atom_name = gdk_atom_name (app->clipboard_targets[i]); + g_printerr (" %s", atom_name); + } + g_printerr ("\n"); + } + + g_signal_emit (app, signals[CLIPBOARD_TARGETS_CHANGED], 0, clipboard); +} + +static void +clipboard_owner_change_cb (GtkClipboard *clipboard, + GdkEvent *event G_GNUC_UNUSED, + TerminalApp *app) +{ + _terminal_debug_print (TERMINAL_DEBUG_CLIPBOARD, + "Clipboard owner changed\n"); + + clipboard_targets_received_cb (clipboard, NULL, 0, app); /* clear */ + + /* We can do this without holding a reference to @app since + * the app lives as long as the process. + */ + gtk_clipboard_request_targets (clipboard, + (GtkClipboardTargetsReceivedFunc) clipboard_targets_received_cb, + app); +} + +/* Callbacks from former app menu. + * The preferences one is still used with the "--preferences" cmdline option. */ + +static void +app_menu_preferences_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalApp *app = user_data; + + terminal_app_edit_preferences (app, NULL, NULL); +} + +static void +app_menu_help_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + terminal_util_show_help (NULL); +} + +static void +app_menu_about_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + terminal_util_show_about (); +} + +static void +app_menu_quit_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + GtkApplication *application = user_data; + GtkWindow *window; + + window = gtk_application_get_active_window (application); + if (TERMINAL_IS_WINDOW (window)) + terminal_window_request_close (TERMINAL_WINDOW (window)); + else /* a dialogue */ + gtk_widget_destroy (GTK_WIDGET (window)); +} + +/* Class implementation */ + +G_DEFINE_TYPE (TerminalApp, terminal_app, GTK_TYPE_APPLICATION) + +/* GApplicationClass impl */ + +static void +terminal_app_activate (GApplication *application) +{ + /* No-op required because GApplication is stupid */ +} + +static void +terminal_app_startup (GApplication *application) +{ + TerminalApp *app = TERMINAL_APP (application); + const GActionEntry action_entries[] = { + { "preferences", app_menu_preferences_cb, NULL, NULL, NULL }, + { "help", app_menu_help_cb, NULL, NULL, NULL }, + { "about", app_menu_about_cb, NULL, NULL, NULL }, + { "quit", app_menu_quit_cb, NULL, NULL, NULL } + }; + + g_application_set_resource_base_path (application, TERMINAL_RESOURCES_PATH_PREFIX); + + G_APPLICATION_CLASS (terminal_app_parent_class)->startup (application); + + /* Need to set the WM class (bug #685742) */ + gdk_set_program_class("Gnome-terminal"); + + g_action_map_add_action_entries (G_ACTION_MAP (application), + action_entries, G_N_ELEMENTS (action_entries), + application); + + app_load_css (application); + + /* Figure out whether the shell shows the menubar */ + gboolean shell_shows_menubar; + g_object_get (gtk_settings_get_default (), + "gtk-shell-shows-menubar", &shell_shows_menubar, + NULL); + + /* Create menubar */ + terminal_app_create_menubar (app, shell_shows_menubar); + + /* Keep dynamic menus updated */ + g_signal_connect_swapped (app->profiles_list, "children-changed", + G_CALLBACK (terminal_app_update_profile_menus), app); + + /* Show/hide the menubar as appropriate: If the shell wants to show the menubar, make it available. */ + if (shell_shows_menubar) + gtk_application_set_menubar (GTK_APPLICATION (app), + terminal_app_get_menubar (app)); + + _terminal_debug_print (TERMINAL_DEBUG_SERVER, "Startup complete\n"); +} + +/* GObjectClass impl */ + +static void +terminal_app_init (TerminalApp *app) +{ + terminal_app_init_debug (); + + gtk_window_set_default_icon_name (GNOME_TERMINAL_ICON_NAME); + + /* Desktop proxy settings */ + app->system_proxy_settings = g_settings_new (SYSTEM_PROXY_SETTINGS_SCHEMA); + + /* Desktop Interface settings */ + app->desktop_interface_settings = g_settings_new (DESKTOP_INTERFACE_SETTINGS_SCHEMA); + + /* Terminal global settings */ + app->global_settings = g_settings_new (TERMINAL_SETTING_SCHEMA); + + /* Gtk debug settings */ + app->gtk_debug_settings = terminal_g_settings_new (GTK_DEBUG_SETTING_SCHEMA, + GTK_DEBUG_ENABLE_INSPECTOR_KEY, + GTK_DEBUG_ENABLE_INSPECTOR_TYPE); + + /* These are internal settings that exists only for distributions + * to override, so we cache them on startup and don't react to changes. + */ + app->unified_menu = g_settings_get_boolean (app->global_settings, TERMINAL_SETTING_UNIFIED_MENU_KEY); + app->use_headerbar = terminal_app_should_use_headerbar (app); + + GtkSettings *gtk_settings = gtk_settings_get_default (); + terminal_app_theme_variant_changed_cb (app->global_settings, + TERMINAL_SETTING_THEME_VARIANT_KEY, gtk_settings); + g_signal_connect (app->global_settings, + "changed::" TERMINAL_SETTING_THEME_VARIANT_KEY, + G_CALLBACK (terminal_app_theme_variant_changed_cb), + gtk_settings); + + /* Clipboard targets */ + GdkDisplay *display = gdk_display_get_default (); + app->clipboard = gtk_clipboard_get_for_display (display, GDK_SELECTION_CLIPBOARD); + clipboard_owner_change_cb (app->clipboard, NULL, app); + g_signal_connect (app->clipboard, "owner-change", + G_CALLBACK (clipboard_owner_change_cb), app); + + if (!gdk_display_supports_selection_notification (display)) + g_printerr ("Display does not support owner-change; copy/paste will be broken!\n"); + + /* Get the profiles */ + app->profiles_list = terminal_profiles_list_new (); + + app->screen_map = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, NULL); + + gs_unref_object GSettings *settings = g_settings_get_child (app->global_settings, "keybindings"); + terminal_accels_init (G_APPLICATION (app), settings, app->use_headerbar); +} + +static void +terminal_app_finalize (GObject *object) +{ + TerminalApp *app = TERMINAL_APP (object); + + g_signal_handlers_disconnect_by_func (app->clipboard, + G_CALLBACK (clipboard_owner_change_cb), + app); + free_clipboard_targets (app); + + g_signal_handlers_disconnect_by_func (app->profiles_list, + G_CALLBACK (terminal_app_update_profile_menus), + app); + g_hash_table_destroy (app->screen_map); + + g_object_unref (app->global_settings); + g_object_unref (app->desktop_interface_settings); + g_object_unref (app->system_proxy_settings); + g_clear_object (&app->gtk_debug_settings); + + g_clear_object (&app->menubar); + g_clear_object (&app->menubar_new_terminal_section); + g_clear_object (&app->menubar_set_profile_section); + g_clear_object (&app->profilemenu); + g_clear_object (&app->headermenu); + g_clear_object (&app->headermenu_set_profile_section); + g_clear_object (&app->set_profile_menu); + + terminal_accels_shutdown (); + + G_OBJECT_CLASS (terminal_app_parent_class)->finalize (object); +} + +static gboolean +terminal_app_dbus_register (GApplication *application, + GDBusConnection *connection, + const gchar *object_path, + GError **error) +{ + TerminalApp *app = TERMINAL_APP (application); + gs_unref_object TerminalObjectSkeleton *object = NULL; + gs_unref_object TerminalFactory *factory = NULL; + + if (!G_APPLICATION_CLASS (terminal_app_parent_class)->dbus_register (application, + connection, + object_path, + error)) + return FALSE; + +#ifdef ENABLE_SEARCH_PROVIDER + if (g_settings_get_boolean (app->global_settings, TERMINAL_SETTING_SHELL_INTEGRATION_KEY)) { + gs_unref_object TerminalSearchProvider *search_provider; + + search_provider = terminal_search_provider_new (); + + if (!terminal_search_provider_dbus_register (search_provider, + connection, + TERMINAL_SEARCH_PROVIDER_PATH, + error)) + return FALSE; + + gs_transfer_out_value (&app->search_provider, &search_provider); + } +#endif /* ENABLE_SEARCH_PROVIDER */ + + object = terminal_object_skeleton_new (TERMINAL_FACTORY_OBJECT_PATH); + factory = terminal_factory_impl_new (); + terminal_object_skeleton_set_factory (object, factory); + + app->object_manager = g_dbus_object_manager_server_new (TERMINAL_OBJECT_PATH_PREFIX); + g_dbus_object_manager_server_export (app->object_manager, G_DBUS_OBJECT_SKELETON (object)); + + /* And export the object */ + g_dbus_object_manager_server_set_connection (app->object_manager, connection); + return TRUE; +} + +static void +terminal_app_dbus_unregister (GApplication *application, + GDBusConnection *connection, + const gchar *object_path) +{ + TerminalApp *app = TERMINAL_APP (application); + + if (app->object_manager) { + g_dbus_object_manager_server_unexport (app->object_manager, TERMINAL_FACTORY_OBJECT_PATH); + g_object_unref (app->object_manager); + app->object_manager = NULL; + } + +#ifdef ENABLE_SEARCH_PROVIDER + if (app->search_provider) { + terminal_search_provider_dbus_unregister (app->search_provider, connection, TERMINAL_SEARCH_PROVIDER_PATH); + g_object_unref (app->search_provider); + app->search_provider = NULL; + } +#endif /* ENABLE_SEARCH_PROVIDER */ + + G_APPLICATION_CLASS (terminal_app_parent_class)->dbus_unregister (application, + connection, + object_path); +} + +static void +terminal_app_class_init (TerminalAppClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GApplicationClass *g_application_class = G_APPLICATION_CLASS (klass); + + object_class->finalize = terminal_app_finalize; + + g_application_class->activate = terminal_app_activate; + g_application_class->startup = terminal_app_startup; + g_application_class->dbus_register = terminal_app_dbus_register; + g_application_class->dbus_unregister = terminal_app_dbus_unregister; + + signals[CLIPBOARD_TARGETS_CHANGED] = + g_signal_new (I_("clipboard-targets-changed"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalAppClass, clipboard_targets_changed), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, 1, G_TYPE_OBJECT); +} + +/* Public API */ + +GApplication * +terminal_app_new (const char *app_id) +{ + const GApplicationFlags flags = G_APPLICATION_IS_SERVICE; + + return g_object_new (TERMINAL_TYPE_APP, + "application-id", app_id ? app_id : TERMINAL_APPLICATION_ID, + "flags", flags, + NULL); +} + +TerminalScreen * +terminal_app_get_screen_by_uuid (TerminalApp *app, + const char *uuid) +{ + g_return_val_if_fail (TERMINAL_IS_APP (app), NULL); + + return g_hash_table_lookup (app->screen_map, uuid); +} + +char * +terminal_app_dup_screen_object_path (TerminalApp *app, + TerminalScreen *screen) +{ + char *object_path = g_strdup_printf (TERMINAL_RECEIVER_OBJECT_PATH_FORMAT, + terminal_screen_get_uuid (screen)); + object_path = g_strdelimit (object_path, "-", '_'); + g_assert (g_variant_is_object_path (object_path)); + return object_path; +} + +/** + * terminal_app_get_receiver_impl_by_object_path: + * @app: + * @object_path: + * + * Returns: (transfer full): the #TerminalReceiverImpl for @object_path, or %NULL + */ +static TerminalReceiverImpl * +terminal_app_get_receiver_impl_by_object_path (TerminalApp *app, + const char *object_path) +{ + gs_unref_object GDBusObject *skeleton = + g_dbus_object_manager_get_object (G_DBUS_OBJECT_MANAGER (app->object_manager), + object_path); + if (skeleton == NULL || !TERMINAL_IS_OBJECT_SKELETON (skeleton)) + return NULL; + + TerminalReceiverImpl *impl = NULL; + g_object_get (skeleton, "receiver", &impl, NULL); + if (impl == NULL) + return NULL; + + g_assert (TERMINAL_IS_RECEIVER_IMPL (impl)); + return impl; +} + +/** + * terminal_app_get_screen_by_object_path: + * @app: + * @object_path: + * + * Returns: (transfer full): the #TerminalScreen for @object_path, or %NULL + */ +TerminalScreen * +terminal_app_get_screen_by_object_path (TerminalApp *app, + const char *object_path) +{ + gs_unref_object TerminalReceiverImpl *impl = + terminal_app_get_receiver_impl_by_object_path (app, object_path); + if (impl == NULL) + return NULL; + + return terminal_receiver_impl_get_screen (impl); +} + +void +terminal_app_register_screen (TerminalApp *app, + TerminalScreen *screen) +{ + const char *uuid = terminal_screen_get_uuid (screen); + g_hash_table_insert (app->screen_map, g_strdup (uuid), screen); + + gs_free char *object_path = terminal_app_dup_screen_object_path (app, screen); + TerminalObjectSkeleton *skeleton = terminal_object_skeleton_new (object_path); + + TerminalReceiverImpl *impl = terminal_receiver_impl_new (screen); + terminal_object_skeleton_set_receiver (skeleton, TERMINAL_RECEIVER (impl)); + g_object_unref (impl); + + g_dbus_object_manager_server_export (app->object_manager, + G_DBUS_OBJECT_SKELETON (skeleton)); +} + +void +terminal_app_unregister_screen (TerminalApp *app, + TerminalScreen *screen) +{ + const char *uuid = terminal_screen_get_uuid (screen); + gboolean found = g_hash_table_remove (app->screen_map, uuid); + g_warn_if_fail (found); + if (!found) + return; /* repeat unregistering */ + + gs_free char *object_path = terminal_app_dup_screen_object_path (app, screen); + gs_unref_object TerminalReceiverImpl *impl = + terminal_app_get_receiver_impl_by_object_path (app, object_path); + g_warn_if_fail (impl != NULL); + + if (impl != NULL) + terminal_receiver_impl_unset_screen (impl); + + g_dbus_object_manager_server_unexport (app->object_manager, object_path); +} + +GdkAtom * +terminal_app_get_clipboard_targets (TerminalApp *app, + GtkClipboard *clipboard, + int *n_targets) +{ + g_return_val_if_fail (TERMINAL_IS_APP (app), NULL); + g_return_val_if_fail (n_targets != NULL, NULL); + + if (clipboard != app->clipboard) { + *n_targets = 0; + return NULL; + } + + *n_targets = app->n_clipboard_targets; + return app->clipboard_targets; +} + +void +terminal_app_edit_preferences (TerminalApp *app, + GSettings *profile, + const char *widget_name) +{ + terminal_prefs_show_preferences (profile, widget_name); +} + +/** + * terminal_app_get_profiles_list: + * + * Returns: (transfer none): returns the singleton profiles list #TerminalSettingsList + */ +TerminalSettingsList * +terminal_app_get_profiles_list (TerminalApp *app) +{ + return app->profiles_list; +} + +/** + * terminal_app_get_menubar: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the main window menu bar as a #GMenuModel + */ +GMenuModel * +terminal_app_get_menubar (TerminalApp *app) +{ + return app->menubar; +} + +/** + * terminal_app_get_headermenu: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the main window headerbar menu bar as a #GMenuModel + */ +GMenuModel * +terminal_app_get_headermenu (TerminalApp *app) +{ + if (app->headermenu == NULL) + terminal_app_create_headermenu (app); + + return app->headermenu; +} + +/** + * terminal_app_get_profilemenu: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the main window headerbar profile menu as a #GMenuModel + */ +GMenuModel * +terminal_app_get_profilemenu (TerminalApp *app) +{ + if (app->profilemenu == NULL) + terminal_app_create_profilemenu (app); + + return app->profilemenu; +} + +/** + * terminal_app_get_profile_section: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the main window's menubar's profiles section as a #GMenuModel + */ +GMenuModel * +terminal_app_get_profile_section (TerminalApp *app) +{ + return G_MENU_MODEL (app->set_profile_menu); +} + +/** + * terminal_app_get_global_settings: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the cached #GSettings object for the org.gnome.Terminal.Preferences schema + */ +GSettings * +terminal_app_get_global_settings (TerminalApp *app) +{ + return app->global_settings; +} + +/** + * terminal_app_get_desktop_interface_settings: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the cached #GSettings object for the org.gnome.interface schema + */ +GSettings * +terminal_app_get_desktop_interface_settings (TerminalApp *app) +{ + return app->desktop_interface_settings; +} + +/** + * terminal_app_get_proxy_settings: + * @app: a #TerminalApp + * + * Returns: (tranfer none): the cached #GSettings object for the org.gnome.system.proxy schema + */ +GSettings * +terminal_app_get_proxy_settings (TerminalApp *app) +{ + return app->system_proxy_settings; +} + +GSettings * +terminal_app_get_gtk_debug_settings (TerminalApp *app) +{ + return app->gtk_debug_settings; +} + +/** + * terminal_app_get_system_font: + * @app: + * + * Creates a #PangoFontDescription for the system monospace font. + * + * Returns: (transfer full): a new #PangoFontDescription + */ +PangoFontDescription * +terminal_app_get_system_font (TerminalApp *app) +{ + gs_free char *font = NULL; + + g_return_val_if_fail (TERMINAL_IS_APP (app), NULL); + + font = g_settings_get_string (app->desktop_interface_settings, MONOSPACE_FONT_KEY_NAME); + + return pango_font_description_from_string (font); +} + +/** + * FIXME + */ +GDBusObjectManagerServer * +terminal_app_get_object_manager (TerminalApp *app) +{ + g_warn_if_fail (app->object_manager != NULL); + return app->object_manager; +} + +gboolean +terminal_app_get_menu_unified (TerminalApp *app) +{ + g_return_val_if_fail (TERMINAL_IS_APP (app), TRUE); + + return app->unified_menu; +} + +gboolean +terminal_app_get_use_headerbar (TerminalApp *app) +{ + g_return_val_if_fail (TERMINAL_IS_APP (app), FALSE); + + return app->use_headerbar; +} + +gboolean +terminal_app_get_dialog_use_headerbar (TerminalApp *app) +{ + g_return_val_if_fail (TERMINAL_IS_APP (app), FALSE); + + gboolean dialog_use_header; + g_object_get (gtk_settings_get_default (), + "gtk-dialogs-use-header", &dialog_use_header, + NULL); + + return dialog_use_header && app->use_headerbar; +} diff --git a/src/terminal-app.h b/src/terminal-app.h new file mode 100644 index 0000000..a36361e --- /dev/null +++ b/src/terminal-app.h @@ -0,0 +1,117 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2008 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_APP_H +#define TERMINAL_APP_H + +#include + +#include "terminal-screen.h" +#include "terminal-profiles-list.h" + +G_BEGIN_DECLS + +#define GNOME_TERMINAL_ICON_NAME "org.gnome.Terminal" + +#define TERMINAL_RESOURCES_PATH_PREFIX "/org/gnome/terminal" + +#define MONOSPACE_FONT_KEY_NAME "monospace-font-name" + +/* TerminalApp */ + +#define TERMINAL_TYPE_APP (terminal_app_get_type ()) +#define TERMINAL_APP(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_APP, TerminalApp)) +#define TERMINAL_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_APP, TerminalAppClass)) +#define TERMINAL_IS_APP(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_APP)) +#define TERMINAL_IS_APP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_APP)) +#define TERMINAL_APP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_APP, TerminalAppClass)) + +typedef struct _TerminalAppClass TerminalAppClass; +typedef struct _TerminalApp TerminalApp; + +GType terminal_app_get_type (void); + +GApplication *terminal_app_new (const char *app_id); + +#define terminal_app_get (TerminalApp *) g_application_get_default + +GDBusObjectManagerServer *terminal_app_get_object_manager (TerminalApp *app); + +GdkAtom *terminal_app_get_clipboard_targets (TerminalApp *app, + GtkClipboard *clipboard, + int *n_targets); + +void terminal_app_edit_preferences (TerminalApp *app, + GSettings *profile, + const char *widget_name); + +char *terminal_app_new_profile (TerminalApp *app, + GSettings *default_base_profile, + const char *name); + +void terminal_app_remove_profile (TerminalApp *app, + GSettings *profile); + +char *terminal_app_dup_screen_object_path (TerminalApp *app, + TerminalScreen *screen); + +TerminalScreen *terminal_app_get_screen_by_uuid (TerminalApp *app, + const char *uuid); + +TerminalScreen *terminal_app_get_screen_by_object_path (TerminalApp *app, + const char *object_path); + +void terminal_app_register_screen (TerminalApp *app, + TerminalScreen *screen); + +void terminal_app_unregister_screen (TerminalApp *app, + TerminalScreen *screen); + +TerminalSettingsList *terminal_app_get_profiles_list (TerminalApp *app); + +/* Menus */ + +GMenuModel *terminal_app_get_menubar (TerminalApp *app); + +GMenuModel *terminal_app_get_headermenu (TerminalApp *app); + +GMenuModel *terminal_app_get_profilemenu (TerminalApp *app); + +GMenuModel *terminal_app_get_profile_section (TerminalApp *app); + +gboolean terminal_app_get_menu_unified (TerminalApp *app); + +gboolean terminal_app_get_use_headerbar (TerminalApp *app); + +gboolean terminal_app_get_dialog_use_headerbar (TerminalApp *app); + +/* GSettings */ + +GSettings *terminal_app_get_global_settings (TerminalApp *app); + +GSettings *terminal_app_get_desktop_interface_settings (TerminalApp *app); + +GSettings *terminal_app_get_proxy_settings (TerminalApp *app); + +GSettings *terminal_app_get_gtk_debug_settings (TerminalApp *app); + +PangoFontDescription *terminal_app_get_system_font (TerminalApp *app); + +G_END_DECLS + +#endif /* !TERMINAL_APP_H */ diff --git a/src/terminal-client-utils.c b/src/terminal-client-utils.c new file mode 100644 index 0000000..e929281 --- /dev/null +++ b/src/terminal-client-utils.c @@ -0,0 +1,252 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2011, 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-client-utils.h" +#include "terminal-defines.h" +#include "terminal-libgsystem.h" + +#include + +#include + +#include +#if defined(TERMINAL_COMPILATION) && defined(GDK_WINDOWING_X11) +#include +#endif + +/** + * terminal_client_append_create_instance_options: + * @builder: a #GVariantBuilder of #GVariantType "a{sv}" + * @display: (array element-type=guint8): + * @startup_id: (array element-type=guint8): + * @geometry: + * @role: + * @profile: + * @title: + * @maximise_window: + * @fullscreen_window: + * + * Appends common options to @builder. + */ +void +terminal_client_append_create_instance_options (GVariantBuilder *builder, + const char *display_name, + const char *startup_id, + const char *geometry, + const char *role, + const char *profile, + const char *encoding, + const char *title, + gboolean active, + gboolean maximise_window, + gboolean fullscreen_window) +{ + /* Bytestring options */ + if (display_name != NULL) + g_variant_builder_add (builder, "{sv}", + "display", g_variant_new_bytestring (display_name)); + if (startup_id) + g_variant_builder_add (builder, "{sv}", + "desktop-startup-id", g_variant_new_bytestring (startup_id)); + + /* String options */ + if (profile) + g_variant_builder_add (builder, "{sv}", + "profile", g_variant_new_string (profile)); + if (encoding) + g_variant_builder_add (builder, "{sv}", + "encoding", g_variant_new_string (encoding)); + if (title) + g_variant_builder_add (builder, "{sv}", + "title", g_variant_new_string (title)); + if (geometry) + g_variant_builder_add (builder, "{sv}", + "geometry", g_variant_new_string (geometry)); + if (role) + g_variant_builder_add (builder, "{sv}", + "role", g_variant_new_string (role)); + + /* Boolean options */ + if (active) + g_variant_builder_add (builder, "{sv}", + "active", g_variant_new_boolean (active)); + + if (maximise_window) + g_variant_builder_add (builder, "{sv}", + "maximize-window", g_variant_new_boolean (TRUE)); + if (fullscreen_window) + g_variant_builder_add (builder, "{sv}", + "fullscreen-window", g_variant_new_boolean (TRUE)); +} + +/** + * terminal_client_append_exec_options: + * @builder: a #GVariantBuilder of #GVariantType "a{sv}" + * @pass_environment: whether to pass the current environment + * @working_directory: (allow-none): the cwd, or %NULL + * @fd_array: (array lenght=fd_array_len): + * @fd_array_len: + * @shell: + * + * Appends the environment and the working directory to @builder. + */ +void +terminal_client_append_exec_options (GVariantBuilder *builder, + gboolean pass_environment, + const char *working_directory, + PassFdElement *fd_array, + gsize fd_array_len, + gboolean shell) +{ + if (pass_environment) { + gs_strfreev char **envv; + + envv = g_get_environ (); + envv = g_environ_unsetenv (envv, "COLORTERM"); + envv = g_environ_unsetenv (envv, "COLUMNS"); + envv = g_environ_unsetenv (envv, "DESKTOP_STARTUP_ID"); + envv = g_environ_unsetenv (envv, "EXIT_CODE"); + envv = g_environ_unsetenv (envv, "EXIT_STATUS"); + envv = g_environ_unsetenv (envv, "GIO_LAUNCHED_DESKTOP_FILE"); + envv = g_environ_unsetenv (envv, "GIO_LAUNCHED_DESKTOP_FILE_PID"); + envv = g_environ_unsetenv (envv, "GNOME_DESKTOP_ICON"); + envv = g_environ_unsetenv (envv, "INVOCATION_ID"); + envv = g_environ_unsetenv (envv, "JOURNAL_STREAM"); + envv = g_environ_unsetenv (envv, "LINES"); + envv = g_environ_unsetenv (envv, "LISTEN_FDNAMES"); + envv = g_environ_unsetenv (envv, "LISTEN_FDS"); + envv = g_environ_unsetenv (envv, "LISTEN_PID"); + envv = g_environ_unsetenv (envv, "MAINPID"); + envv = g_environ_unsetenv (envv, "MANAGERPID"); + envv = g_environ_unsetenv (envv, "NOTIFY_SOCKET"); + envv = g_environ_unsetenv (envv, "NOTIFY_SOCKET"); + envv = g_environ_unsetenv (envv, "PIDFILE"); + envv = g_environ_unsetenv (envv, "PWD"); + envv = g_environ_unsetenv (envv, "REMOTE_ADDR"); + envv = g_environ_unsetenv (envv, "REMOTE_PORT"); + envv = g_environ_unsetenv (envv, "SERVICE_RESULT"); + envv = g_environ_unsetenv (envv, "TERM"); + envv = g_environ_unsetenv (envv, "VTE_VERSION"); + envv = g_environ_unsetenv (envv, "WATCHDOG_PID"); + envv = g_environ_unsetenv (envv, "WATCHDOG_USEC"); + envv = g_environ_unsetenv (envv, "WINDOWID"); + + envv = g_environ_unsetenv (envv, TERMINAL_ENV_SERVICE_NAME); + envv = g_environ_unsetenv (envv, TERMINAL_ENV_SCREEN); + + g_variant_builder_add (builder, "{sv}", + "environ", + g_variant_new_bytestring_array ((const char * const *) envv, -1)); + } + + if (working_directory) + g_variant_builder_add (builder, "{sv}", + "cwd", g_variant_new_bytestring (working_directory)); + + if (shell) + g_variant_builder_add (builder, "{sv}", + "shell", + g_variant_new_boolean (TRUE)); + + if (fd_array_len) { + gsize i; + + g_variant_builder_open (builder, G_VARIANT_TYPE ("{sv}")); + g_variant_builder_add (builder, "s", "fd-set"); + + g_variant_builder_open (builder, G_VARIANT_TYPE ("v")); + g_variant_builder_open (builder, G_VARIANT_TYPE ("a(ih)")); + for (i = 0; i < fd_array_len; i++) { + g_variant_builder_add (builder, "(ih)", fd_array[i].fd, fd_array[i].index); + } + g_variant_builder_close (builder); /* a(ih) */ + g_variant_builder_close (builder); /* v */ + + g_variant_builder_close (builder); /* {sv} */ + } +} + +/** + * terminal_client_get_fallback_startup_id: + * + * Returns: a fallback startup ID, or %NULL + */ +char * +terminal_client_get_fallback_startup_id (void) +{ +#if defined(TERMINAL_COMPILATION) && defined(GDK_WINDOWING_X11) + GdkDisplay *display; + Display *xdisplay; + Window xwindow; + XEvent event; + + display = gdk_display_get_default (); + if (display == NULL || !GDK_IS_X11_DISPLAY (display)) + goto out; + + xdisplay = GDK_DISPLAY_XDISPLAY (display); + + { + XSetWindowAttributes attrs; + Atom atom_name; + Atom atom_type; + const char *name; + + attrs.override_redirect = True; + attrs.event_mask = PropertyChangeMask | StructureNotifyMask; + + xwindow = + XCreateWindow (xdisplay, + RootWindow (xdisplay, 0), + -100, -100, 1, 1, + 0, + CopyFromParent, + CopyFromParent, + (Visual *)CopyFromParent, + CWOverrideRedirect | CWEventMask, + &attrs); + + atom_name = XInternAtom (xdisplay, "WM_NAME", TRUE); + g_assert (atom_name != None); + atom_type = XInternAtom (xdisplay, "STRING", TRUE); + g_assert (atom_type != None); + + name = "Fake Window"; + XChangeProperty (xdisplay, + xwindow, atom_name, + atom_type, + 8, PropModeReplace, (unsigned char *)name, strlen (name)); + } + + XWindowEvent (xdisplay, + xwindow, + PropertyChangeMask, + &event); + + XDestroyWindow(xdisplay, xwindow); + + return g_strdup_printf ("_TIME%lu", event.xproperty.time); +out: +#endif + return NULL; +} diff --git a/src/terminal-client-utils.h b/src/terminal-client-utils.h new file mode 100644 index 0000000..0a70637 --- /dev/null +++ b/src/terminal-client-utils.h @@ -0,0 +1,54 @@ +/* + * Copyright © 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_CLIENT_UTILS_H +#define TERMINAL_CLIENT_UTILS_H + +#include +#include + +G_BEGIN_DECLS + +void terminal_client_append_create_instance_options (GVariantBuilder *builder, + const char *display_name, + const char *startup_id, + const char *geometry, + const char *role, + const char *profile, + const char *encoding, + const char *title, + gboolean active, + gboolean maximise_window, + gboolean fullscreen_window); + +typedef struct { + int index; + int fd; +} PassFdElement; + +void terminal_client_append_exec_options (GVariantBuilder *builder, + gboolean pass_environment, + const char *working_directory, + PassFdElement *fd_array, + gsize fd_array_len, + gboolean shell); + +char * terminal_client_get_fallback_startup_id (void); + +G_END_DECLS + +#endif /* TERMINAL_UTIL_UTILS_H */ diff --git a/src/terminal-debug.c b/src/terminal-debug.c new file mode 100644 index 0000000..d08829e --- /dev/null +++ b/src/terminal-debug.c @@ -0,0 +1,48 @@ +/* + * Copyright (C) 2002,2003 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include + +#include "terminal-debug.h" + +TerminalDebugFlags _terminal_debug_flags; + +void +_terminal_debug_init(void) +{ +#ifdef ENABLE_DEBUG + const GDebugKey keys[] = { + { "accels", TERMINAL_DEBUG_ACCELS }, + { "clipboard", TERMINAL_DEBUG_CLIPBOARD }, + { "encodings", TERMINAL_DEBUG_ENCODINGS }, + { "server", TERMINAL_DEBUG_SERVER }, + { "geometry", TERMINAL_DEBUG_GEOMETRY }, + { "mdi", TERMINAL_DEBUG_MDI }, + { "processes", TERMINAL_DEBUG_PROCESSES }, + { "profile", TERMINAL_DEBUG_PROFILE }, + { "settings-list", TERMINAL_DEBUG_SETTINGS_LIST }, + { "search", TERMINAL_DEBUG_SEARCH }, + }; + + _terminal_debug_flags = g_parse_debug_string (g_getenv ("GNOME_TERMINAL_DEBUG"), + keys, G_N_ELEMENTS (keys)); + +#endif /* ENABLE_DEBUG */ +} + diff --git a/src/terminal-debug.h b/src/terminal-debug.h new file mode 100644 index 0000000..0fafcc3 --- /dev/null +++ b/src/terminal-debug.h @@ -0,0 +1,76 @@ +/* + * Copyright (C) 2002 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* The interfaces in this file are subject to change at any time. */ + +#ifndef ENABLE_DEBUG_H +#define ENABLE_DEBUG_H + +#include + +G_BEGIN_DECLS + +typedef enum { + TERMINAL_DEBUG_ACCELS = 1 << 0, + TERMINAL_DEBUG_CLIPBOARD = 1 << 1, + TERMINAL_DEBUG_ENCODINGS = 1 << 2, + TERMINAL_DEBUG_SERVER = 1 << 3, + TERMINAL_DEBUG_GEOMETRY = 1 << 4, + TERMINAL_DEBUG_MDI = 1 << 5, + TERMINAL_DEBUG_PROCESSES = 1 << 6, + TERMINAL_DEBUG_PROFILE = 1 << 7, + TERMINAL_DEBUG_SETTINGS_LIST = 1 << 8, + TERMINAL_DEBUG_SEARCH = 1 << 9 +} TerminalDebugFlags; + +void _terminal_debug_init(void); + +extern TerminalDebugFlags _terminal_debug_flags; +static inline gboolean _terminal_debug_on (TerminalDebugFlags flags) G_GNUC_CONST G_GNUC_UNUSED; + +static inline gboolean +_terminal_debug_on (TerminalDebugFlags flags) +{ + return (_terminal_debug_flags & flags) == flags; +} + +#ifdef ENABLE_DEBUG +#define _TERMINAL_DEBUG_IF(flags) if (G_UNLIKELY (_terminal_debug_on (flags))) +#else +#define _TERMINAL_DEBUG_IF(flags) if (0) +#endif + +#if defined(__GNUC__) && G_HAVE_GNUC_VARARGS +#define _terminal_debug_print(flags, fmt, ...) \ + G_STMT_START { _TERMINAL_DEBUG_IF(flags) g_printerr(fmt, ##__VA_ARGS__); } G_STMT_END +#else +#include +#include +static void _terminal_debug_print (guint flags, const char *fmt, ...) +{ + if (_terminal_debug_on (flags)) { + va_list ap; + va_start (ap, fmt); + g_vfprintf (stderr, fmt, ap); + va_end (ap); + } +} +#endif + +G_END_DECLS + +#endif /* !ENABLE_DEBUG_H */ diff --git a/src/terminal-defines.h b/src/terminal-defines.h new file mode 100644 index 0000000..b9ffba2 --- /dev/null +++ b/src/terminal-defines.h @@ -0,0 +1,48 @@ +/* + * Copyright © 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_DEFINES_H +#define TERMINAL_DEFINES_H + +G_BEGIN_DECLS + +enum { + _EXIT_FAILURE_WRONG_ID = 7, + _EXIT_FAILURE_NO_UTF8 = 8, + _EXIT_FAILURE_UNSUPPORTED_LOCALE = 9, + _EXIT_FAILURE_GTK_INIT = 10 +}; + +#define TERMINAL_APPLICATION_ID "org.gnome.Terminal" + +#define TERMINAL_OBJECT_PATH_PREFIX "/org/gnome/Terminal" +#define TERMINAL_OBJECT_INTERFACE_PREFIX "org.gnome.Terminal" + +#define TERMINAL_FACTORY_OBJECT_PATH TERMINAL_OBJECT_PATH_PREFIX "/Factory0" +#define TERMINAL_FACTORY_INTERFACE_NAME TERMINAL_OBJECT_INTERFACE_PREFIX ".Factory0" + +#define TERMINAL_RECEIVER_OBJECT_PATH_FORMAT TERMINAL_OBJECT_PATH_PREFIX "/screen/%s" +#define TEMRINAL_RECEIVER_INTERFACE_NAME TERMINAL_OBJECT_INTERFACE_PREFIX ".Terminal0" + +#define TERMINAL_SEARCH_PROVIDER_PATH TERMINAL_OBJECT_PATH_PREFIX "/SearchProvider" + +#define TERMINAL_ENV_SERVICE_NAME "GNOME_TERMINAL_SERVICE" +#define TERMINAL_ENV_SCREEN "GNOME_TERMINAL_SCREEN" + +G_END_DECLS + +#endif /* !TERMINAL_DEFINES_H */ diff --git a/src/terminal-enums.h b/src/terminal-enums.h new file mode 100644 index 0000000..93f1460 --- /dev/null +++ b/src/terminal-enums.h @@ -0,0 +1,69 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2002 Mathias Hasselmann + * Copyright © 2008, 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_ENUMS_H +#define TERMINAL_ENUMS_H + +#include + +G_BEGIN_DECLS + +typedef enum { + TERMINAL_NEW_TERMINAL_MODE_WINDOW, + TERMINAL_NEW_TERMINAL_MODE_TAB +} TerminalNewTerminalMode; + +typedef enum { + TERMINAL_NEW_TAB_POSITION_LAST, + TERMINAL_NEW_TAB_POSITION_NEXT +} TerminalNewTabPosition; + +typedef enum +{ + TERMINAL_EXIT_CLOSE, + TERMINAL_EXIT_RESTART, + TERMINAL_EXIT_HOLD +} TerminalExitAction; + +typedef enum { + TERMINAL_SETTINGS_LIST_FLAG_NONE = 0, + TERMINAL_SETTINGS_LIST_FLAG_HAS_DEFAULT = 1 << 0, + TERMINAL_SETTINGS_LIST_FLAG_ALLOW_EMPTY = 1 << 1 +} TerminalSettingsListFlags; + +typedef enum { + TERMINAL_CJK_WIDTH_NARROW = 1, + TERMINAL_CJK_WIDTH_WIDE = 2 +} TerminalCJKWidth; + +typedef enum { + TERMINAL_THEME_VARIANT_SYSTEM = 0, + TERMINAL_THEME_VARIANT_LIGHT = 1, + TERMINAL_THEME_VARIANT_DARK = 2 +} TerminalThemeVariant; + +typedef enum { + TERMINAL_PRESERVE_WORKING_DIRECTORY_NEVER = 0, + TERMINAL_PRESERVE_WORKING_DIRECTORY_SAFE = 1, + TERMINAL_PRESERVE_WORKING_DIRECTORY_ALWAYS = 2, +} TerminalPreserveWorkingDirectory; + +G_END_DECLS + +#endif /* TERMINAL_ENUMS_H */ diff --git a/src/terminal-gdbus.c b/src/terminal-gdbus.c new file mode 100644 index 0000000..655bf3e --- /dev/null +++ b/src/terminal-gdbus.c @@ -0,0 +1,566 @@ +/* + * Copyright © 2011, 2012 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-gdbus.h" + +#include +#include + +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-defines.h" +#include "terminal-mdi-container.h" +#include "terminal-util.h" +#include "terminal-window.h" +#include "terminal-libgsystem.h" + +/* ------------------------------------------------------------------------- */ + +#define TERMINAL_RECEIVER_IMPL_GET_PRIVATE(impl)(G_TYPE_INSTANCE_GET_PRIVATE ((impl), TERMINAL_TYPE_RECEIVER_IMPL, TerminalReceiverImplPrivate)) + +struct _TerminalReceiverImplPrivate { + TerminalScreen *screen; /* unowned! */ +}; + +enum { + PROP_0, + PROP_SCREEN +}; + +/* helper functions */ + +static void +child_exited_cb (VteTerminal *terminal, + int exit_code, + TerminalReceiver *receiver) +{ + terminal_receiver_emit_child_exited (receiver, exit_code); +} + +static void +terminal_receiver_impl_set_screen (TerminalReceiverImpl *impl, + TerminalScreen *screen) +{ + TerminalReceiverImplPrivate *priv; + + g_return_if_fail (TERMINAL_IS_RECEIVER_IMPL (impl)); + g_return_if_fail (screen == NULL || TERMINAL_IS_SCREEN (screen)); + + priv = impl->priv; + if (priv->screen == screen) + return; + + if (priv->screen) { + g_signal_handlers_disconnect_matched (priv->screen, + G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, impl); + } + + priv->screen = screen; + if (screen) { + g_signal_connect (screen, "child-exited", + G_CALLBACK (child_exited_cb), + impl); + } + + g_object_notify (G_OBJECT (impl), "screen"); +} + +/* Class implementation */ + +typedef struct { + TerminalReceiver *receiver; + GDBusMethodInvocation *invocation; +} ExecData; + +static void +exec_data_free (ExecData *data) +{ + g_object_unref (data->receiver); + g_object_unref (data->invocation); + g_free (data); +} + +static void +exec_cb (TerminalScreen *screen, /* unused, may be %NULL */ + GError *error, /* set on error, %NULL on success */ + ExecData *data) +{ + /* Note: these calls transfer the ref */ + g_object_ref (data->invocation); + if (error) { + g_dbus_method_invocation_return_gerror (data->invocation, error); + } else { + terminal_receiver_complete_exec (data->receiver, data->invocation, NULL /* outfdlist */); + } +} + +static gboolean +terminal_receiver_impl_exec (TerminalReceiver *receiver, + GDBusMethodInvocation *invocation, + GUnixFDList *fd_list, + GVariant *options, + GVariant *arguments) +{ + TerminalReceiverImpl *impl = TERMINAL_RECEIVER_IMPL (receiver); + TerminalReceiverImplPrivate *priv = impl->priv; + const char *working_directory; + gboolean shell; + gsize exec_argc; + gs_free char **exec_argv = NULL; /* container needs to be freed, strings not owned */ + gs_free char **envv = NULL; /* container needs to be freed, strings not owned */ + gs_unref_variant GVariant *fd_array = NULL; + + if (priv->screen == NULL) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_FAILED, + "Terminal already closed"); + goto out; + } + + if (!g_variant_lookup (options, "cwd", "^&ay", &working_directory)) + working_directory = NULL; + if (!g_variant_lookup (options, "shell", "b", &shell)) + shell = FALSE; + if (!g_variant_lookup (options, "environ", "^a&ay", &envv)) + envv = NULL; + if (!g_variant_lookup (options, "fd-set", "@a(ih)", &fd_array)) + fd_array = NULL; + + /* Check environment */ + if (!terminal_util_check_envv((const char * const*)envv)) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Malformed environment"); + goto out; + } + + /* Check FD passing */ + if ((fd_list != NULL) ^ (fd_array != NULL)) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Must pass both fd-set options and a FD list"); + goto out; + } + if (fd_list != NULL && fd_array != NULL) { + const int *fd_array_data; + gsize fd_array_data_len, i; + int n_fds; + + fd_array_data = g_variant_get_fixed_array (fd_array, &fd_array_data_len, 2 * sizeof (int)); + n_fds = g_unix_fd_list_get_length (fd_list); + for (i = 0; i < fd_array_data_len; i++) { + const int fd = fd_array_data[2 * i]; + const int idx = fd_array_data[2 * i + 1]; + + if (fd == -1) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Passing of invalid FD %d not supported", fd); + goto out; + } + if (fd == STDIN_FILENO || + fd == STDOUT_FILENO || + fd == STDERR_FILENO) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Passing of std%s not supported", + fd == STDIN_FILENO ? "in" : fd == STDOUT_FILENO ? "out" : "err"); + goto out; + } + if (idx < 0 || idx >= n_fds) { + g_dbus_method_invocation_return_error_literal (invocation, + G_DBUS_ERROR, + G_DBUS_ERROR_INVALID_ARGS, + "Handle out of range"); + goto out; + } + } + } + + if (working_directory != NULL) + _terminal_debug_print (TERMINAL_DEBUG_SERVER, + "CWD is '%s'\n", working_directory); + + exec_argv = (char **) g_variant_get_bytestring_array (arguments, &exec_argc); + + ExecData *exec_data = g_new (ExecData, 1); + exec_data->receiver = g_object_ref (receiver); + /* We want to transfer the ownership of @invocation to ExecData here, but + * we have to temporarily ref it so that in the error case below (where + * terminal_screen_exec() frees the exec data via the supplied callback, + * the g_dbus_method_invocation_take_error() calll still can take ownership + * of the invocation's ref passed to this function (terminal_receiver_impl_exec()). + */ + exec_data->invocation = g_object_ref (invocation); + + GError *err = NULL; + if (!terminal_screen_exec (priv->screen, + exec_argc > 0 ? exec_argv : NULL, + envv, + shell, + working_directory, + fd_list, fd_array, + (TerminalScreenExecCallback) exec_cb, + exec_data /* adopted */, + (GDestroyNotify) exec_data_free, + NULL /* cancellable */, + &err)) { + /* Transfers ownership of @invocation */ + g_dbus_method_invocation_take_error (invocation, err); + } + + /* Now we can remove that extra ref again. */ + g_object_unref (invocation); + +out: + + return TRUE; /* handled */ +} + +static void +terminal_receiver_impl_iface_init (TerminalReceiverIface *iface) +{ + iface->handle_exec = terminal_receiver_impl_exec; +} + +G_DEFINE_TYPE_WITH_CODE (TerminalReceiverImpl, terminal_receiver_impl, TERMINAL_TYPE_RECEIVER_SKELETON, + G_IMPLEMENT_INTERFACE (TERMINAL_TYPE_RECEIVER, terminal_receiver_impl_iface_init)) + +static void +terminal_receiver_impl_init (TerminalReceiverImpl *impl) +{ + impl->priv = TERMINAL_RECEIVER_IMPL_GET_PRIVATE (impl); +} + +static void +terminal_receiver_impl_dispose (GObject *object) +{ + TerminalReceiverImpl *impl = TERMINAL_RECEIVER_IMPL (object); + + terminal_receiver_impl_set_screen (impl, NULL); + + G_OBJECT_CLASS (terminal_receiver_impl_parent_class)->dispose (object); +} + +static void +terminal_receiver_impl_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalReceiverImpl *impl = TERMINAL_RECEIVER_IMPL (object); + + switch (prop_id) { + case PROP_SCREEN: + g_value_set_object (value, terminal_receiver_impl_get_screen (impl)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_receiver_impl_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalReceiverImpl *impl = TERMINAL_RECEIVER_IMPL (object); + + switch (prop_id) { + case PROP_SCREEN: + terminal_receiver_impl_set_screen (impl, g_value_get_object (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_receiver_impl_class_init (TerminalReceiverImplClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = terminal_receiver_impl_dispose; + gobject_class->get_property = terminal_receiver_impl_get_property; + gobject_class->set_property = terminal_receiver_impl_set_property; + + g_object_class_install_property + (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", NULL, NULL, + TERMINAL_TYPE_SCREEN, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_type_class_add_private (gobject_class, sizeof (TerminalReceiverImplPrivate)); +} + +/* public API */ + +/** + * terminal_receiver_impl_new: + * @screen: a #TerminalScreen + * + * Returns: a new #TerminalReceiverImpl for @screen + */ +TerminalReceiverImpl * +terminal_receiver_impl_new (TerminalScreen *screen) +{ + return g_object_new (TERMINAL_TYPE_RECEIVER_IMPL, + "screen", screen, + NULL); +} + +/** + * terminal_receiver_impl_get_screen: + * @impl: a #TerminalReceiverImpl + * + * Returns: (transfer none): the impl's #TerminalScreen, or %NULL + */ +TerminalScreen * +terminal_receiver_impl_get_screen (TerminalReceiverImpl *impl) +{ + g_return_val_if_fail (TERMINAL_IS_RECEIVER_IMPL (impl), NULL); + + return impl->priv->screen; +} + +/** + * terminal_receiver_impl_unget_screen: + * @impl: a #TerminalReceiverImpl + * + * Unsets the impls #TerminalScreen. + */ +void +terminal_receiver_impl_unset_screen (TerminalReceiverImpl *impl) +{ + g_return_if_fail (TERMINAL_IS_RECEIVER_IMPL (impl)); + + terminal_receiver_impl_set_screen (impl, NULL); +} + +/* --------------------------------------------------------------------------- + * TerminalFactoryImpl + * --------------------------------------------------------------------------- + */ + +struct _TerminalFactoryImplPrivate { + gpointer dummy; +}; + +static gboolean +terminal_factory_impl_create_instance (TerminalFactory *factory, + GDBusMethodInvocation *invocation, + GVariant *options) +{ + TerminalApp *app = terminal_app_get (); + + /* If a parent screen is specified, use that to fill in missing information */ + TerminalScreen *parent_screen = NULL; + const char *parent_screen_object_path; + if (g_variant_lookup (options, "parent-screen", "&o", &parent_screen_object_path)) { + parent_screen = terminal_app_get_screen_by_object_path (app, parent_screen_object_path); + if (parent_screen == NULL) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Failed to get screen from object path %s", + parent_screen_object_path); + return TRUE; + } + } + + /* Try getting a parent window, first by parent screen then by window ID; + * if that fails, create a new window. + */ + TerminalWindow *window = NULL; + gboolean have_new_window = FALSE; + const char *window_from_screen_object_path; + if (g_variant_lookup (options, "window-from-screen", "&o", &window_from_screen_object_path)) { + TerminalScreen *window_screen = + terminal_app_get_screen_by_object_path (app, window_from_screen_object_path); + if (window_screen == NULL) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Failed to get screen from object path %s", + parent_screen_object_path); + return TRUE; + } + + GtkWidget *win = gtk_widget_get_toplevel (GTK_WIDGET (window_screen)); + if (TERMINAL_IS_WINDOW (win)) + window = TERMINAL_WINDOW (win); + } + + /* Support old client */ + guint window_id; + if (window == NULL && g_variant_lookup (options, "window-id", "u", &window_id)) { + GtkWindow *win = gtk_application_get_window_by_id (GTK_APPLICATION (app), window_id); + + if (!TERMINAL_IS_WINDOW (win)) { + g_dbus_method_invocation_return_error (invocation, + G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + "Nonexisting window %u referenced", + window_id); + return TRUE; + } + + window = TERMINAL_WINDOW (win); + } + + /* Still no parent window? Create a new one */ + if (window == NULL) { + const char *startup_id, *role; + gboolean start_maximized, start_fullscreen; + + window = terminal_window_new (G_APPLICATION (app)); + have_new_window = TRUE; + + if (g_variant_lookup (options, "desktop-startup-id", "^&ay", &startup_id)) + gtk_window_set_startup_id (GTK_WINDOW (window), startup_id); + + /* Overwrite the default, unique window role set in terminal_window_init */ + if (g_variant_lookup (options, "role", "&s", &role)) + gtk_window_set_role (GTK_WINDOW (window), role); + + gboolean show_menubar; + if (g_variant_lookup (options, "show-menubar", "b", &show_menubar)) + terminal_window_set_menubar_visible (window, show_menubar); + + if (g_variant_lookup (options, "fullscreen-window", "b", &start_fullscreen) && + start_fullscreen) { + gtk_window_fullscreen (GTK_WINDOW (window)); + } + if (g_variant_lookup (options, "maximize-window", "b", &start_maximized) && + start_maximized) { + gtk_window_maximize (GTK_WINDOW (window)); + } + + have_new_window = TRUE; + } + + g_assert_nonnull (window); + + const char *title; + if (!g_variant_lookup (options, "title", "&s", &title)) + title = NULL; + + double zoom; + if (!g_variant_lookup (options, "zoom", "d", &zoom)) { + if (parent_screen != NULL) + zoom = vte_terminal_get_font_scale (VTE_TERMINAL (parent_screen)); + else + zoom = 1.0; + } + + /* Look up the profile */ + gs_unref_object GSettings *profile = NULL; + const char *profile_uuid; + if (!g_variant_lookup (options, "profile", "&s", &profile_uuid)) + profile_uuid = NULL; + + if (profile_uuid == NULL && parent_screen != NULL) { + profile = terminal_screen_ref_profile (parent_screen); + } else { + GError *err = NULL; + profile = terminal_profiles_list_ref_profile_by_uuid (terminal_app_get_profiles_list (app), + profile_uuid /* default if NULL */, + &err); + if (profile == NULL) { + g_dbus_method_invocation_return_gerror (invocation, err); + g_error_free (err); + return TRUE; + } + } + + g_assert_nonnull (profile); + + /* Now we can create the new screen */ + TerminalScreen *screen = terminal_screen_new (profile, title, zoom); + terminal_window_add_screen (window, screen, -1); + + /* Apply window properties */ + gboolean active; + if (g_variant_lookup (options, "active", "b", &active) && + active) { + terminal_window_switch_screen (window, screen); + gtk_widget_grab_focus (GTK_WIDGET (screen)); + } + + if (have_new_window) { + const char *geometry; + + if (g_variant_lookup (options, "geometry", "&s", &geometry) && + !terminal_window_parse_geometry (window, geometry)) + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "Invalid geometry string \"%s\"", geometry); + } + + gboolean present_window; + gboolean present_window_set = g_variant_lookup (options, "present-window", "b", &present_window); + + if (have_new_window || (present_window_set && present_window)) + gtk_window_present (GTK_WINDOW (window)); + + gs_free char *object_path = terminal_app_dup_screen_object_path (app, screen); + terminal_factory_complete_create_instance (factory, invocation, object_path); + + return TRUE; /* handled */ +} + +static void +terminal_factory_impl_iface_init (TerminalFactoryIface *iface) +{ + iface->handle_create_instance = terminal_factory_impl_create_instance; +} + +G_DEFINE_TYPE_WITH_CODE (TerminalFactoryImpl, terminal_factory_impl, TERMINAL_TYPE_FACTORY_SKELETON, + G_IMPLEMENT_INTERFACE (TERMINAL_TYPE_FACTORY, terminal_factory_impl_iface_init)) + +static void +terminal_factory_impl_init (TerminalFactoryImpl *impl) +{ + impl->priv = G_TYPE_INSTANCE_GET_PRIVATE (impl, TERMINAL_TYPE_FACTORY_IMPL, TerminalFactoryImplPrivate); +} + +static void +terminal_factory_impl_class_init (TerminalFactoryImplClass *klass) +{ + /* g_type_class_add_private (klass, sizeof (TerminalFactoryImplPrivate)); */ +} + +/** + * terminal_factory_impl_new: + * + * Returns: (transfer full): a new #TerminalFactoryImpl + */ +TerminalFactory * +terminal_factory_impl_new (void) +{ + return g_object_new (TERMINAL_TYPE_FACTORY_IMPL, NULL); +} diff --git a/src/terminal-gdbus.h b/src/terminal-gdbus.h new file mode 100644 index 0000000..16e80d7 --- /dev/null +++ b/src/terminal-gdbus.h @@ -0,0 +1,90 @@ +/* + * Copyright © 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_RECEIVER_IMPL_H +#define TERMINAL_RECEIVER_IMPL_H + +#include + +#include "terminal-gdbus-generated.h" +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_RECEIVER_IMPL (terminal_receiver_impl_get_type ()) +#define TERMINAL_RECEIVER_IMPL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_RECEIVER_IMPL, TerminalReceiverImpl)) +#define TERMINAL_RECEIVER_IMPL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_RECEIVER_IMPL, TerminalReceiverImplClass)) +#define TERMINAL_IS_RECEIVER_IMPL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_RECEIVER_IMPL)) +#define TERMINAL_IS_RECEIVER_IMPL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_RECEIVER_IMPL)) +#define TERMINAL_RECEIVER_IMPL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_RECEIVER_IMPL, TerminalReceiverImplClass)) + +typedef struct _TerminalReceiverImpl TerminalReceiverImpl; +typedef struct _TerminalReceiverImplClass TerminalReceiverImplClass; +typedef struct _TerminalReceiverImplPrivate TerminalReceiverImplPrivate; + +struct _TerminalReceiverImpl +{ + TerminalReceiverSkeleton parent_instance; + + /*< private >*/ + TerminalReceiverImplPrivate *priv; +}; + +struct _TerminalReceiverImplClass +{ + TerminalReceiverSkeletonClass parent_class; +}; + +GType terminal_receiver_impl_get_type (void); + +TerminalReceiverImpl *terminal_receiver_impl_new (TerminalScreen *screen); + +TerminalScreen *terminal_receiver_impl_get_screen (TerminalReceiverImpl *impl); + +void terminal_receiver_impl_unset_screen (TerminalReceiverImpl *impl); + +/* ------------------------------------------------------------------------- */ + +#define TERMINAL_TYPE_FACTORY_IMPL (terminal_factory_impl_get_type ()) +#define TERMINAL_FACTORY_IMPL(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_FACTORY_IMPL, TerminalFactoryImpl)) +#define TERMINAL_FACTORY_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_FACTORY_IMPL, TerminalFactoryImplClass)) +#define TERMINAL_IS_FACTORY_IMPL(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_FACTORY_IMPL)) +#define TERMINAL_IS_FACTORY_IMPL_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_FACTORY_IMPL)) +#define TERMINAL_FACTORY_IMPL_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_FACTORY_IMPL, TerminalFactoryImplClass)) + +typedef struct _TerminalFactoryImpl TerminalFactoryImpl; +typedef struct _TerminalFactoryImplPrivate TerminalFactoryImplPrivate; +typedef struct _TerminalFactoryImplClass TerminalFactoryImplClass; + +struct _TerminalFactoryImplClass { + TerminalFactorySkeletonClass parent_class; +}; + +struct _TerminalFactoryImpl +{ + TerminalFactorySkeleton parent_instance; + + TerminalFactoryImplPrivate *priv; +}; + +GType terminal_factory_impl_get_type (void); + +TerminalFactory *terminal_factory_impl_new (void); + +G_END_DECLS + +#endif /* !TERMINAL_RECEIVER_IMPL_H */ diff --git a/src/terminal-headerbar.c b/src/terminal-headerbar.c new file mode 100644 index 0000000..fc929d7 --- /dev/null +++ b/src/terminal-headerbar.c @@ -0,0 +1,170 @@ +/* + * Copyright © 2018 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include "terminal-headerbar.h" +#include "terminal-app.h" +#include "terminal-libgsystem.h" + +typedef struct _TerminalHeaderbarPrivate TerminalHeaderbarPrivate; + +struct _TerminalHeaderbar +{ + GtkHeaderBar parent_instance; +}; + +struct _TerminalHeaderbarClass +{ + GtkHeaderBarClass parent_class; +}; + +struct _TerminalHeaderbarPrivate +{ + GtkWidget *profilebutton; + GtkWidget *menubutton; +}; + +enum { + PROP_0, + LAST_PROP +}; + +enum { + LAST_SIGNAL +}; + +/* static guint signals[LAST_SIGNAL]; */ +/* static GParamSpec *pspecs[LAST_PROP]; */ + +G_DEFINE_TYPE_WITH_PRIVATE (TerminalHeaderbar, terminal_headerbar, GTK_TYPE_HEADER_BAR) + +#define PRIV(obj) ((TerminalHeaderbarPrivate *) terminal_headerbar_get_instance_private ((TerminalHeaderbar *)(obj))) + +static void +profilemenu_items_changed_cb (GMenuModel *menu, + int position G_GNUC_UNUSED, + int removed G_GNUC_UNUSED, + int added G_GNUC_UNUSED, + TerminalHeaderbarPrivate *priv) +{ + if (g_menu_model_get_n_items (menu) > 0) + gtk_widget_show (priv->profilebutton); + else + gtk_widget_hide (priv->profilebutton); +} + +/* Class implementation */ + +static void +terminal_headerbar_init (TerminalHeaderbar *headerbar) +{ + + TerminalHeaderbarPrivate *priv = PRIV (headerbar); + GtkWidget *widget = GTK_WIDGET (headerbar); + TerminalApp *app = terminal_app_get (); + GMenuModel *profilemenu; + + gtk_widget_init_template (widget); + + gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->menubutton), + terminal_app_get_headermenu (app)); + + profilemenu = terminal_app_get_profilemenu (app); + gtk_menu_button_set_menu_model (GTK_MENU_BUTTON (priv->profilebutton), + profilemenu); + + g_signal_connect (profilemenu, "items-changed", + G_CALLBACK (profilemenu_items_changed_cb), priv); + profilemenu_items_changed_cb (profilemenu, 0, 0, 0, priv); +} + +static void +terminal_headerbar_dispose (GObject *object) +{ + TerminalHeaderbar *headerbar = TERMINAL_HEADERBAR (object); + TerminalHeaderbarPrivate *priv = PRIV (headerbar); + TerminalApp *app = terminal_app_get (); + + GMenuModel *profilemenu = terminal_app_get_profilemenu (app); + g_signal_handlers_disconnect_by_func (profilemenu, + G_CALLBACK (profilemenu_items_changed_cb), + priv); + + G_OBJECT_CLASS (terminal_headerbar_parent_class)->dispose (object); +} + +static void +terminal_headerbar_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + // TerminalHeaderbar *headerbar = TERMINAL_HEADERBAR (object); + + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_headerbar_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_headerbar_class_init (TerminalHeaderbarClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gobject_class->dispose = terminal_headerbar_dispose; + gobject_class->get_property = terminal_headerbar_get_property; + gobject_class->set_property = terminal_headerbar_set_property; + + /* g_object_class_install_properties (gobject_class, G_N_ELEMENTS (pspecs), pspecs); */ + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/terminal/ui/headerbar.ui"); + gtk_widget_class_bind_template_child_private (widget_class, TerminalHeaderbar, menubutton); + gtk_widget_class_bind_template_child_private (widget_class, TerminalHeaderbar, profilebutton); +} + +/* public API */ + +/** + * terminal_headerbar_new: + * + * Returns: a new #TerminalHeaderbar + */ +GtkWidget * +terminal_headerbar_new (void) +{ + return g_object_new (TERMINAL_TYPE_HEADERBAR, + NULL); +} diff --git a/src/terminal-headerbar.h b/src/terminal-headerbar.h new file mode 100644 index 0000000..f4ee6f7 --- /dev/null +++ b/src/terminal-headerbar.h @@ -0,0 +1,40 @@ +/* + * Copyright © 2018 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_HEADERBAR (terminal_headerbar_get_type ()) +#define TERMINAL_HEADERBAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_HEADERBAR, TerminalHeaderbar)) +#define TERMINAL_HEADERBAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_HEADERBAR, TerminalHeaderbarClass)) +#define TERMINAL_IS_HEADERBAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_HEADERBAR)) +#define TERMINAL_IS_HEADERBAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_HEADERBAR)) +#define TERMINAL_HEADERBAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_HEADERBAR, TerminalHeaderbarClass)) + +typedef struct _TerminalHeaderbar TerminalHeaderbar; +typedef struct _TerminalHeaderbarClass TerminalHeaderbarClass; + +GType terminal_headerbar_get_type (void); + +GtkWidget *terminal_headerbar_new (void); + +G_END_DECLS diff --git a/src/terminal-headerbar.ui b/src/terminal-headerbar.ui new file mode 100644 index 0000000..c48a350 --- /dev/null +++ b/src/terminal-headerbar.ui @@ -0,0 +1,111 @@ + + + + + diff --git a/src/terminal-headermenu.ui b/src/terminal-headermenu.ui new file mode 100644 index 0000000..42d5296 --- /dev/null +++ b/src/terminal-headermenu.ui @@ -0,0 +1,119 @@ + + + + +
+ horizontal-buttons + + Zoom _Out + zoom-out-symbolic + win.zoom-out + + + 100% + win.zoom-normal + + + Zoom _In + zoom-in-symbolic + win.zoom-in + +
+
+ + New _Window + win.new-terminal + ('window', 'current') + + + _Full Screen + win.enter-fullscreen + +
+
+ + Read-_Only + win.read-only + + + Set _Title… + win.set-title + action-missing + +
+ + _Advanced +
+ + _Reset + win.reset + false + + + Reset and C_lear + win.reset + true + +
+
+ + _1. 80×24 + win.size-to + (80, 24) + + + _2. 80×43 + win.size-to + (80, 43) + + + _3. 132×24 + win.size-to + (132, 24) + + + _4. 132×43 + win.size-to + (132, 43) + +
+
+ + _Inspector + win.inspector + action-disabled + +
+
+
+
+ + _Preferences + app.preferences + + + _Help + app.help + + + _About + app.about + +
+
+
diff --git a/src/terminal-i18n.c b/src/terminal-i18n.c new file mode 100644 index 0000000..7ae520e --- /dev/null +++ b/src/terminal-i18n.c @@ -0,0 +1,31 @@ +/* + * Copyright © 2002 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" +#include "terminal-i18n.h" + +#include + +void +terminal_i18n_init (gboolean set_default) +{ + bindtextdomain (GETTEXT_PACKAGE, TERM_LOCALEDIR); + bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8"); + + if (set_default) + textdomain (GETTEXT_PACKAGE); +} diff --git a/src/terminal-i18n.h b/src/terminal-i18n.h new file mode 100644 index 0000000..689bb82 --- /dev/null +++ b/src/terminal-i18n.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2002 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_I18N_H +#define TERMINAL_I18N_H + +#include + +G_BEGIN_DECLS + +void terminal_i18n_init (gboolean set_default); + +G_END_DECLS + +#endif /* TERMINAL_I18N_H */ diff --git a/src/terminal-icon-button.c b/src/terminal-icon-button.c new file mode 100644 index 0000000..3014fc0 --- /dev/null +++ b/src/terminal-icon-button.c @@ -0,0 +1,50 @@ +/* + * terminal-icon-button.c + * + * Copyright © 2010 - Paolo Borelli + * Copyright © 2011 - Ignacio Casal Quinteiro + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-icon-button.h" +#include "terminal-libgsystem.h" + +GtkWidget * +terminal_icon_button_new (const char *gicon_name) +{ + GtkWidget *button, *image; + gs_unref_object GIcon *icon; + + button = (GtkWidget *) g_object_new (GTK_TYPE_BUTTON, + "relief", GTK_RELIEF_NONE, + "focus-on-click", FALSE, + NULL); + + icon = g_themed_icon_new_with_default_fallbacks (gicon_name); + image = gtk_image_new_from_gicon (icon, GTK_ICON_SIZE_MENU); + + gtk_widget_show (image); + gtk_container_add (GTK_CONTAINER (button), image); + + return button; +} + +GtkWidget * +terminal_close_button_new (void) +{ + return terminal_icon_button_new ("window-close-symbolic"); +} diff --git a/src/terminal-icon-button.h b/src/terminal-icon-button.h new file mode 100644 index 0000000..ec0a8db --- /dev/null +++ b/src/terminal-icon-button.h @@ -0,0 +1,33 @@ +/* + * terminal-close-button.h + * + * Copyright © 2010 - Paolo Borelli + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __TERMINAL_ICON_BUTTON_H__ +#define __TERMINAL_ICON_BUTTON_H__ + +#include + +G_BEGIN_DECLS + +GtkWidget *terminal_icon_button_new (const char *gicon_name); + +GtkWidget *terminal_close_button_new (void); + +G_END_DECLS + +#endif /* __TERMINAL_ICON_BUTTON_H__ */ diff --git a/src/terminal-info-bar.c b/src/terminal-info-bar.c new file mode 100644 index 0000000..8ffca18 --- /dev/null +++ b/src/terminal-info-bar.c @@ -0,0 +1,119 @@ +/* + * Copyright © 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "terminal-info-bar.h" +#include "terminal-libgsystem.h" + +#include + +#define TERMINAL_INFO_BAR_GET_PRIVATE(info_bar)(G_TYPE_INSTANCE_GET_PRIVATE ((info_bar), TERMINAL_TYPE_INFO_BAR, TerminalInfoBarPrivate)) + +struct _TerminalInfoBarPrivate +{ + GtkWidget *content_box; +}; + +G_DEFINE_TYPE (TerminalInfoBar, terminal_info_bar, GTK_TYPE_INFO_BAR) + +/* helper functions */ + +static void +terminal_info_bar_init (TerminalInfoBar *bar) +{ + GtkInfoBar *info_bar = GTK_INFO_BAR (bar); + TerminalInfoBarPrivate *priv; + + priv = bar->priv = TERMINAL_INFO_BAR_GET_PRIVATE (bar); + + priv->content_box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 6); + gtk_box_pack_start (GTK_BOX (gtk_info_bar_get_content_area (info_bar)), + priv->content_box, TRUE, TRUE, 0); +} + +static void +terminal_info_bar_class_init (TerminalInfoBarClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (gobject_class, sizeof (TerminalInfoBarPrivate)); +} + +/* public API */ + +/** + * terminal_info_bar_new: + * @type: a #GtkMessageType + * + * Returns: a new #TerminalInfoBar for @screen + */ +GtkWidget * +terminal_info_bar_new (GtkMessageType type, + const char *first_button_text, + ...) +{ + GtkWidget *info_bar; + va_list args; + + info_bar = g_object_new (TERMINAL_TYPE_INFO_BAR, + "message-type", type, + NULL); + + va_start (args, first_button_text); + while (first_button_text != NULL) { + int response_id; + + response_id = va_arg (args, int); + gtk_info_bar_add_button (GTK_INFO_BAR (info_bar), + first_button_text, response_id); + + first_button_text = va_arg (args, const char *); + } + va_end (args); + + return info_bar; +} + +void +terminal_info_bar_format_text (TerminalInfoBar *bar, + const char *format, + ...) +{ + TerminalInfoBarPrivate *priv; + gs_free char *text = NULL; + GtkWidget *label; + va_list args; + + g_return_if_fail (TERMINAL_IS_INFO_BAR (bar)); + + priv = bar->priv; + + va_start (args, format); + text = g_strdup_vprintf (format, args); + va_end (args); + + label = gtk_label_new (text); + + gtk_label_set_line_wrap (GTK_LABEL (label), TRUE); + gtk_label_set_selectable (GTK_LABEL (label), TRUE); + gtk_label_set_xalign (GTK_LABEL (label), 0.0); + gtk_label_set_yalign (GTK_LABEL (label), 0.0); + + gtk_box_pack_start (GTK_BOX (priv->content_box), label, FALSE, FALSE, 0); + gtk_widget_show_all (priv->content_box); +} diff --git a/src/terminal-info-bar.h b/src/terminal-info-bar.h new file mode 100644 index 0000000..87a5234 --- /dev/null +++ b/src/terminal-info-bar.h @@ -0,0 +1,61 @@ +/* + * Copyright © 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_INFO_BAR_H +#define TERMINAL_INFO_BAR_H + +#include + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_INFO_BAR (terminal_info_bar_get_type ()) +#define TERMINAL_INFO_BAR(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_INFO_BAR, TerminalInfoBar)) +#define TERMINAL_INFO_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_INFO_BAR, TerminalInfoBarClass)) +#define TERMINAL_IS_INFO_BAR(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_INFO_BAR)) +#define TERMINAL_IS_INFO_BAR_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_INFO_BAR)) +#define TERMINAL_INFO_BAR_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_INFO_BAR, TerminalInfoBarClass)) + +typedef struct _TerminalInfoBar TerminalInfoBar; +typedef struct _TerminalInfoBarClass TerminalInfoBarClass; +typedef struct _TerminalInfoBarPrivate TerminalInfoBarPrivate; + +struct _TerminalInfoBar +{ + GtkInfoBar parent_instance; + + /*< private >*/ + TerminalInfoBarPrivate *priv; +}; + +struct _TerminalInfoBarClass +{ + GtkInfoBarClass parent_class; +}; + +GType terminal_info_bar_get_type (void); + +GtkWidget *terminal_info_bar_new (GtkMessageType type, + const char *first_button_text, + ...) G_GNUC_NULL_TERMINATED; + +void terminal_info_bar_format_text (TerminalInfoBar *bar, + const char *format, + ...) G_GNUC_PRINTF (2, 3); + +G_END_DECLS + +#endif /* !TERMINAL_INFO_BAR_H */ diff --git a/src/terminal-intl.h b/src/terminal-intl.h new file mode 100644 index 0000000..daaa963 --- /dev/null +++ b/src/terminal-intl.h @@ -0,0 +1,29 @@ +/* + * Copyright © 2002 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_INTL_H +#define TERMINAL_INTL_H + +#include + +G_BEGIN_DECLS + +#define I_(string) g_intern_static_string (string) + +G_END_DECLS + +#endif /* TERMINAL_INTL_H */ diff --git a/src/terminal-libgsystem.h b/src/terminal-libgsystem.h new file mode 100644 index 0000000..906a127 --- /dev/null +++ b/src/terminal-libgsystem.h @@ -0,0 +1,258 @@ +/* + * Copyright © 2012 Colin Walters . + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef __GSYSTEM_LOCAL_ALLOC_H__ +#define __GSYSTEM_LOCAL_ALLOC_H__ + +#include + +G_BEGIN_DECLS + +#define gs_transfer_out_value(outp, srcp) G_STMT_START { \ + if (outp) \ + { \ + *(outp) = *(srcp); \ + *(srcp) = NULL; \ + } \ + } G_STMT_END; + +#define GS_DEFINE_CLEANUP_FUNCTION(Type, name, func) \ + static inline void name (void *v) \ + { \ + func (*(Type*)v); \ + } + +#define GS_DEFINE_CLEANUP_FUNCTION0(Type, name, func) \ + static inline void name (void *v) \ + { \ + if (*(Type*)v) \ + func (*(Type*)v); \ + } + +/* These functions shouldn't be invoked directly; + * they are stubs that: + * 1) Take a pointer to the location (typically itself a pointer). + * 2) Provide %NULL-safety where it doesn't exist already (e.g. g_object_unref) + */ +GS_DEFINE_CLEANUP_FUNCTION0(GArray*, gs_local_array_unref, g_array_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GBytes*, gs_local_bytes_unref, g_bytes_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GChecksum*, gs_local_checksum_free, g_checksum_free) +GS_DEFINE_CLEANUP_FUNCTION0(GError*, gs_local_free_error, g_error_free) +GS_DEFINE_CLEANUP_FUNCTION0(GHashTable*, gs_local_hashtable_unref, g_hash_table_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GKeyFile*, gs_local_key_file_unref, g_key_file_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GList*, gs_local_list_free, g_list_free) +GS_DEFINE_CLEANUP_FUNCTION0(GMatchInfo*, gs_local_match_info_free, g_match_info_free) +GS_DEFINE_CLEANUP_FUNCTION0(GObject*, gs_local_obj_unref, g_object_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GPtrArray*, gs_local_ptrarray_unref, g_ptr_array_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GRegex*, gs_local_regex_unref, g_regex_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GSettingsSchema*, gs_local_settings_schema_unref, g_settings_schema_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GSettingsSchemaKey*, gs_local_settings_schema_key_unref, g_settings_schema_key_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GVariant*, gs_local_variant_unref, g_variant_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantBuilder*, gs_local_variant_builder_unref, g_variant_builder_unref) +GS_DEFINE_CLEANUP_FUNCTION0(GVariantIter*, gs_local_variant_iter_free, g_variant_iter_free) + +GS_DEFINE_CLEANUP_FUNCTION(char**, gs_local_strfreev, g_strfreev) +GS_DEFINE_CLEANUP_FUNCTION(void*, gs_local_free, g_free) + +/* special */ + +static inline void gs_local_gstring_free (void *v) \ +{ \ + if (*(GString**)v) \ + g_string_free (*(GString**)v, TRUE); \ +} + +/** + * gs_free: + * + * Call g_free() on a variable location when it goes out of scope. + */ +#define gs_free __attribute__ ((cleanup(gs_local_free))) + +/** + * gs_unref_object: + * + * Call g_object_unref() on a variable location when it goes out of + * scope. Note that unlike g_object_unref(), the variable may be + * %NULL. + */ +#define gs_unref_object __attribute__ ((cleanup(gs_local_obj_unref))) + +/** + * gs_unref_variant: + * + * Call g_variant_unref() on a variable location when it goes out of + * scope. Note that unlike g_variant_unref(), the variable may be + * %NULL. + */ +#define gs_unref_variant __attribute__ ((cleanup(gs_local_variant_unref))) + +/** + * gs_free_variant_iter: + * + * Call g_variant_iter_free() on a variable location when it goes out of + * scope. + */ +#define gs_free_variant_iter __attribute__ ((cleanup(gs_local_variant_iter_free))) + +/** + * gs_free_variant_builder: + * + * Call g_variant_builder_unref() on a variable location when it goes out of + * scope. + */ +#define gs_unref_variant_builder __attribute__ ((cleanup(gs_local_variant_builder_unref))) + +/** + * gs_unref_array: + * + * Call g_array_unref() on a variable location when it goes out of + * scope. Note that unlike g_array_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_array __attribute__ ((cleanup(gs_local_array_unref))) + +/** + * gs_unref_ptrarray: + * + * Call g_ptr_array_unref() on a variable location when it goes out of + * scope. Note that unlike g_ptr_array_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_ptrarray __attribute__ ((cleanup(gs_local_ptrarray_unref))) + +/** + * gs_unref_hashtable: + * + * Call g_hash_table_unref() on a variable location when it goes out + * of scope. Note that unlike g_hash_table_unref(), the variable may + * be %NULL. + */ +#define gs_unref_hashtable __attribute__ ((cleanup(gs_local_hashtable_unref))) + +/** + * gs_unref_key_file: + * + * Call g_key_file_unref() on a variable location when it goes out + * of scope. Note that unlike g_key_file_unref(), the variable may + * be %NULL. + */ +#define gs_unref_key_file __attribute__ ((cleanup(gs_local_key_file_unref))) + +/** + * gs_free_checksum: + * + * Call g_checksum_free() on a variable location when it goes out + * of scope. Note that unlike g_checksum_free(), the variable may + * be %NULL. + */ +#define gs_free_checksum __attribute__ ((cleanup(gs_local_checksum_free))) + +/** + * gs_unref_bytes: + * + * Call g_bytes_unref() on a variable location when it goes out + * of scope. Note that unlike g_bytes_unref(), the variable may + * be %NULL. + */ +#define gs_unref_bytes __attribute__ ((cleanup(gs_local_bytes_unref))) + +/** + * gs_strfreev: + * + * Call g_strfreev() on a variable location when it goes out of scope. + */ +#define gs_strfreev __attribute__ ((cleanup(gs_local_strfreev))) + +/** + * gs_free_error: + * + * Call g_error_free() on a variable location when it goes out of scope. + */ +#define gs_free_error __attribute__ ((cleanup(gs_local_free_error))) + +/** + * gs_free_list: + * + * Call g_list_free() on a variable location when it goes out of scope. + */ +#define gs_free_list __attribute__ ((cleanup(gs_local_list_free))) + +/** + * gs_unref_regex: + * + * Call g_regex_unref() on a variable location when it goes out of + * scope. Note that unlike g_regex_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_regex __attribute__ ((cleanup(gs_local_regex_unref))) + +/** + * gs_free_match_info: + * + * Call g_regex_unref() on a variable location when it goes out of + * scope. Note that unlike g_regex_unref(), the variable may be + * %NULL. + + */ +#define gs_free_match_info __attribute__ ((cleanup(gs_local_match_info_free))) + +/** + * gs_unref_settings_schema: + * + * Call g_settings_schema_unref() on a variable location when it goes out of + * scope. Note that unlike g_settings_schema_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_settings_schema __attribute__ ((cleanup(gs_local_settings_schema_unref))) + +/** + * gs_unref_settings_schema_source: + * + * Call g_settings_schema_source_unref() on a variable location when it goes out of + * scope. Note that unlike g_settings_schema_source_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_settings_schema_source __attribute__ ((cleanup(gs_local_settings_schema_source_unref))) + +/** + * gs_unref_settings_schema_key: + * + * Call g_settings_schema_key_unref() on a variable location when it goes out of + * scope. Note that unlike g_settings_schema_key_unref(), the variable may be + * %NULL. + + */ +#define gs_unref_settings_schema_key __attribute__ ((cleanup(gs_local_settings_schema_key_unref))) + +/** + * gs_free_gstring: + * + * Call g_string_free(TRUE) on a variable location when it goes out + * of scope. Note that unlike g_string_free(), the variable may + * be %NULL. + */ +#define gs_free_gstring __attribute__ ((cleanup(gs_local_gstring_free))) + +G_END_DECLS + +#endif diff --git a/src/terminal-marshal.list b/src/terminal-marshal.list new file mode 100644 index 0000000..3e91f60 --- /dev/null +++ b/src/terminal-marshal.list @@ -0,0 +1 @@ +BOOLEAN:STRING,INT,UINT diff --git a/src/terminal-mdi-container.c b/src/terminal-mdi-container.c new file mode 100644 index 0000000..76464a9 --- /dev/null +++ b/src/terminal-mdi-container.c @@ -0,0 +1,208 @@ +/* + * Copyright © 2008, 2010, 2011, 2012 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "terminal-mdi-container.h" +#include "terminal-debug.h" +#include "terminal-intl.h" + +enum { + SCREEN_ADDED, + SCREEN_REMOVED, + SCREEN_SWITCHED, + SCREENS_REORDERED, + SCREEN_CLOSE_REQUEST, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_INTERFACE (TerminalMdiContainer, terminal_mdi_container, GTK_TYPE_WIDGET) + +static void +terminal_mdi_container_default_init (TerminalMdiContainerInterface *iface) +{ + signals[SCREEN_ADDED] = + g_signal_new (I_("screen-added"), + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMdiContainerInterface, screen_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TERMINAL_TYPE_SCREEN); + + signals[SCREEN_ADDED] = + g_signal_new (I_("screen-removed"), + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMdiContainerInterface, screen_added), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TERMINAL_TYPE_SCREEN); + + signals[SCREEN_ADDED] = + g_signal_new (I_("screen-switched"), + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMdiContainerInterface, screen_switched), + NULL, NULL, + NULL, + G_TYPE_NONE, + 2, TERMINAL_TYPE_SCREEN, TERMINAL_TYPE_SCREEN); + + signals[SCREENS_REORDERED] = + g_signal_new (I_("screens-reordered"), + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMdiContainerInterface, screens_reordered), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + signals[SCREEN_CLOSE_REQUEST] = + g_signal_new (I_("screen-close-request"), + G_TYPE_FROM_INTERFACE (iface), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMdiContainerInterface, screen_close_request), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, TERMINAL_TYPE_SCREEN); + + g_object_interface_install_property (iface, + g_param_spec_object ("active-screen", NULL, NULL, + TERMINAL_TYPE_SCREEN, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); +} + +/* public API */ + +void +terminal_mdi_container_add_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int position) +{ + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + g_return_if_fail (TERMINAL_IS_SCREEN (screen)); + + TERMINAL_MDI_CONTAINER_GET_IFACE (container)->add_screen (container, screen, position); +} + +void +terminal_mdi_container_remove_screen (TerminalMdiContainer *container, + TerminalScreen *screen) +{ + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + g_return_if_fail (TERMINAL_IS_SCREEN (screen)); + + TERMINAL_MDI_CONTAINER_GET_IFACE (container)->remove_screen (container, screen); +} + +TerminalScreen * +terminal_mdi_container_get_active_screen (TerminalMdiContainer *container) +{ + g_return_val_if_fail (TERMINAL_IS_MDI_CONTAINER (container), NULL); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->get_active_screen (container); +} + +void +terminal_mdi_container_set_active_screen (TerminalMdiContainer *container, + TerminalScreen *screen) +{ + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + g_return_if_fail (TERMINAL_IS_SCREEN (screen)); + + TERMINAL_MDI_CONTAINER_GET_IFACE (container)->set_active_screen (container, screen); +} + + +GList * +terminal_mdi_container_list_screens (TerminalMdiContainer *container) +{ + g_return_val_if_fail (TERMINAL_IS_MDI_CONTAINER (container), NULL); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->list_screens (container); +} + +GList * +terminal_mdi_container_list_screen_containers (TerminalMdiContainer *container) +{ + g_return_val_if_fail (TERMINAL_IS_MDI_CONTAINER (container), NULL); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->list_screen_containers (container); +} + +int +terminal_mdi_container_get_n_screens (TerminalMdiContainer *container) +{ + g_return_val_if_fail (TERMINAL_IS_MDI_CONTAINER (container), 0); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->get_n_screens (container); +} + +int +terminal_mdi_container_get_active_screen_num (TerminalMdiContainer *container) +{ + g_return_val_if_fail (TERMINAL_IS_MDI_CONTAINER (container), -1); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->get_active_screen_num (container); +} + +void +terminal_mdi_container_set_active_screen_num (TerminalMdiContainer *container, + int position) +{ + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + + TERMINAL_MDI_CONTAINER_GET_IFACE (container)->set_active_screen_num (container, position); +} + +void +terminal_mdi_container_reorder_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int new_position) +{ + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + + return TERMINAL_MDI_CONTAINER_GET_IFACE (container)->reorder_screen (container, screen, new_position); +} + +void +terminal_mdi_container_change_screen (TerminalMdiContainer *container, + int change) +{ + int active, n; + + g_return_if_fail (TERMINAL_IS_MDI_CONTAINER (container)); + g_return_if_fail (change == -1 || change == 1); + + n = terminal_mdi_container_get_n_screens (container); + active = terminal_mdi_container_get_active_screen_num (container); + + active += change; + if (active < 0) + active = n - 1; + else if (active >= n) + active = 0; + + terminal_mdi_container_set_active_screen_num (container, active); +} diff --git a/src/terminal-mdi-container.h b/src/terminal-mdi-container.h new file mode 100644 index 0000000..829521f --- /dev/null +++ b/src/terminal-mdi-container.h @@ -0,0 +1,104 @@ +/* + * Copyright © 2008, 2010, 2012 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_MDI_CONTAINER_H +#define TERMINAL_MDI_CONTAINER_H + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_MDI_CONTAINER (terminal_mdi_container_get_type ()) +#define TERMINAL_MDI_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), TERMINAL_TYPE_MDI_CONTAINER, TerminalMdiContainer)) +#define TERMINAL_IS_MDI_CONTAINER(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), TERMINAL_TYPE_MDI_CONTAINER)) +#define TERMINAL_MDI_CONTAINER_GET_IFACE(inst) (G_TYPE_INSTANCE_GET_INTERFACE ((inst), TERMINAL_TYPE_MDI_CONTAINER, TerminalMdiContainerInterface)) + +typedef struct _TerminalMdiContainer TerminalMdiContainer; +typedef struct _TerminalMdiContainerInterface TerminalMdiContainerInterface; + +struct _TerminalMdiContainerInterface { + GTypeInterface parent_iface; + + /* vfuncs */ + void (* add_screen) (TerminalMdiContainer *container, + TerminalScreen *screen, + int position); + void (* remove_screen) (TerminalMdiContainer *container, + TerminalScreen *screen); + TerminalScreen * (* get_active_screen) (TerminalMdiContainer *container); + void (* set_active_screen) (TerminalMdiContainer *container, + TerminalScreen *screen); + GList * (* list_screens) (TerminalMdiContainer *container); + GList * (* list_screen_containers) (TerminalMdiContainer *container); + int (* get_n_screens) (TerminalMdiContainer *container); + int (* get_active_screen_num) (TerminalMdiContainer *container); + void (* set_active_screen_num) (TerminalMdiContainer *container, + int position); + void (* reorder_screen) (TerminalMdiContainer *container, + TerminalScreen *screen, + int new_position); + + /* signals */ + void (* screen_added) (TerminalMdiContainer *container, + TerminalScreen *screen); + void (* screen_removed) (TerminalMdiContainer *container, + TerminalScreen *screen); + void (* screen_switched) (TerminalMdiContainer *container, + TerminalScreen *old_active_screen, + TerminalScreen *new_active_screen); + void (* screens_reordered) (TerminalMdiContainer *container); + void (* screen_close_request) (TerminalMdiContainer *container, + TerminalScreen *screen); +}; + +GType terminal_mdi_container_get_type (void); + +void terminal_mdi_container_add_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int position); + +void terminal_mdi_container_remove_screen (TerminalMdiContainer *container, + TerminalScreen *screen); + +TerminalScreen *terminal_mdi_container_get_active_screen (TerminalMdiContainer *container); + +void terminal_mdi_container_set_active_screen (TerminalMdiContainer *container, + TerminalScreen *screen); + +void terminal_mdi_container_set_active_screen_num (TerminalMdiContainer *container, + int position); + +GList *terminal_mdi_container_list_screens (TerminalMdiContainer *container); + +GList *terminal_mdi_container_list_screen_containers (TerminalMdiContainer *container); + +int terminal_mdi_container_get_n_screens (TerminalMdiContainer *container); + +int terminal_mdi_container_get_active_screen_num (TerminalMdiContainer *container); + +void terminal_mdi_container_reorder_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int new_position); + +void terminal_mdi_container_change_screen (TerminalMdiContainer *container, + int change); + +G_END_DECLS + +#endif /* TERMINAL_MDI_CONTAINER_H */ diff --git a/src/terminal-menu-button.c b/src/terminal-menu-button.c new file mode 100644 index 0000000..fbe30f2 --- /dev/null +++ b/src/terminal-menu-button.c @@ -0,0 +1,147 @@ +/* + * Copyright © 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANMENUILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-menu-button.h" +#include "terminal-intl.h" +#include "terminal-libgsystem.h" + +/* All this just because GtkToggleButton:toggled is RUN_FIRST (and the + * notify::active comes after the toggled signal). :-( + */ + +enum +{ + UPDATE_MENU, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +static void popup_menu_selection_done_cb (GtkMenu *menu, + GtkMenuButton *button); + +/* The menu button sets itself insensitive when it has no menu. + * Work around this by using an empty menu. + */ +static void +set_empty_menu (GtkMenuButton *button) +{ + gs_unref_object GMenu *menu = g_menu_new (); + gtk_menu_button_set_menu_model (button, G_MENU_MODEL (menu)); +} + +static void +disconnect_popup_menu (GtkMenuButton *button) +{ + GtkMenu *popup_menu = gtk_menu_button_get_popup (button); + + if (popup_menu) + g_signal_handlers_disconnect_by_func + (popup_menu, G_CALLBACK (popup_menu_selection_done_cb), button); +} + +static void +popup_menu_selection_done_cb (GtkMenu *menu, + GtkMenuButton *button) +{ + disconnect_popup_menu (button); + set_empty_menu (button); +} + +/* Class implementation */ + +G_DEFINE_TYPE (TerminalMenuButton, terminal_menu_button, GTK_TYPE_MENU_BUTTON); + +static void +terminal_menu_button_init (TerminalMenuButton *button_) +{ + GtkButton *button = GTK_BUTTON (button_); + GtkMenuButton *menu_button = GTK_MENU_BUTTON (button_); + + gtk_button_set_relief (button, GTK_RELIEF_NONE); + gtk_button_set_focus_on_click (button, FALSE); + gtk_menu_button_set_use_popover (menu_button, FALSE); + set_empty_menu (menu_button); +} + +static void +terminal_menu_button_toggled (GtkToggleButton *button) +{ + gboolean active = gtk_toggle_button_get_active (button); /* this is already the new state */ + + /* On activate, update the menu */ + if (active) + g_signal_emit (button, signals[UPDATE_MENU], 0); + + GTK_TOGGLE_BUTTON_CLASS (terminal_menu_button_parent_class)->toggled (button); +} + +static void +terminal_menu_button_update_menu (TerminalMenuButton *button) +{ + GtkMenuButton *gtk_button = GTK_MENU_BUTTON (button); + GtkMenu *popup_menu = gtk_menu_button_get_popup (gtk_button); + + if (popup_menu) + g_signal_connect (popup_menu, "selection-done", + G_CALLBACK (popup_menu_selection_done_cb), button); +} + +static void +terminal_menu_button_dispose (GObject *object) +{ + disconnect_popup_menu (GTK_MENU_BUTTON (object)); + + G_OBJECT_CLASS (terminal_menu_button_parent_class)->dispose (object); +} + +static void +terminal_menu_button_class_init (TerminalMenuButtonClass *klass) +{ + klass->update_menu = terminal_menu_button_update_menu; + + GObjectClass *object_class = G_OBJECT_CLASS (klass); + object_class->dispose = terminal_menu_button_dispose; + + GtkToggleButtonClass *toggle_button_class = GTK_TOGGLE_BUTTON_CLASS (klass); + toggle_button_class->toggled = terminal_menu_button_toggled; + + signals[UPDATE_MENU] = + g_signal_new (I_("update-menu"), + G_OBJECT_CLASS_TYPE (klass), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalMenuButtonClass, update_menu), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); +} + +/* public API */ + +/** + * terminal_menu_button_new: + * + * Returns: a new #TerminalMenuButton + */ +GtkWidget * +terminal_menu_button_new (void) +{ + return g_object_new (TERMINAL_TYPE_MENU_BUTTON, NULL); +} diff --git a/src/terminal-menu-button.h b/src/terminal-menu-button.h new file mode 100644 index 0000000..c9362d0 --- /dev/null +++ b/src/terminal-menu-button.h @@ -0,0 +1,57 @@ +/* + * Copyright © 2008, 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANMENUILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_MENU_BUTTON_H +#define TERMINAL_MENU_BUTTON_H + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_MENU_BUTTON (terminal_menu_button_get_type ()) +#define TERMINAL_MENU_BUTTON(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_MENU_BUTTON, TerminalMenuButton)) +#define TERMINAL_MENU_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_MENU_BUTTON, TerminalMenuButtonClass)) +#define TERMINAL_IS_MENU_BUTTON(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_MENU_BUTTON)) +#define TERMINAL_IS_MENU_BUTTON_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_MENU_BUTTON)) +#define TERMINAL_MENU_BUTTON_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_MENU_BUTTON, TerminalMenuButtonClass)) + +typedef struct _TerminalMenuButton TerminalMenuButton; +typedef struct _TerminalMenuButtonClass TerminalMenuButtonClass; +typedef struct _TerminalMenuButtonPrivate TerminalMenuButtonPrivate; + +struct _TerminalMenuButton +{ + GtkMenuButton parent_instance; +}; + +struct _TerminalMenuButtonClass +{ + GtkMenuButtonClass parent_class; + + /* Signals */ + void (* update_menu) (TerminalMenuButton *menu_button); +}; + +GType terminal_menu_button_get_type (void); + +GtkWidget *terminal_menu_button_new (void); + +G_END_DECLS + +#endif /* !TERMINAL_MENU_BUTTON_H */ diff --git a/src/terminal-menubar.ui.in b/src/terminal-menubar.ui.in new file mode 100644 index 0000000..794d92d --- /dev/null +++ b/src/terminal-menubar.ui.in @@ -0,0 +1,248 @@ + + + + + + _File + File +
+
+ + _Save Contents… + win.save-contents + action-missing + + + _Export… + win.export + action-missing + + + _Print… + win.print + action-missing + +
+
+ + C_lose Tab + win.close + tab + + + _Close Window + win.close + window + +
+ + + _Edit + Edit +
+ + _Copy + win.copy + text + + + Copy as _HTML + win.copy + html + + + _Paste + win.paste-text + + + Paste as _Filenames + win.paste-uris + action-disabled + +
+
+ + Select _All + win.select-all + +
+
+ + P_references + win.edit-preferences + +
+
+ + _View + View +
+ + Show _Menubar + win.menubar-visible + action-disabled + + + _Full Screen + win.fullscreen + +
+
+ + Zoom _In + win.zoom-in + + + _Normal Size + win.zoom-normal + + + Zoom _Out + win.zoom-out + +
+
+ + _Search + Search +
+ + _Find… + win.find + + + Find _Next + win.find-forward + + + Find _Previous + win.find-backward + + + _Clear Highlight + win.find-clear + +
+
+ + _Terminal + Terminal +
+
+ + Set _Title… + win.set-title + action-missing + +
+
+ + Read-_Only + win.read-only + +
+
+ + _Reset + win.reset + false + + + Reset and C_lear + win.reset + true + +
+
+ + _1. 80×24 + win.size-to + (80, 24) + + + _2. 80×43 + win.size-to + (80, 43) + + + _3. 132×24 + win.size-to + (132, 24) + + + _4. 132×43 + win.size-to + (132, 43) + +
+ + + Ta_bs + Tabs + win.tabs-menu + action-disabled +
+ + _Previous Tab + win.tab-switch-left + + + _Next Tab + win.tab-switch-right + +
+
+ + Move Terminal _Left + win.tab-move-left + + + Move Terminal _Right + win.tab-move-right + +
+
+ + _Detach Terminal + win.tab-detach + +
+
+ + _Help + Help +
+ + _Contents + win.help + + + _About + win.about + +
+
+ + _Inspector + win.inspector + action-disabled + +
+
+
+
diff --git a/src/terminal-nautilus.c b/src/terminal-nautilus.c new file mode 100644 index 0000000..6e9a341 --- /dev/null +++ b/src/terminal-nautilus.c @@ -0,0 +1,770 @@ +/* + * Copyright (C) 2004, 2005 Free Software Foundation, Inc. + * Copyright © 2011 Christian Persch + * Author: Christian Neumair + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include +#include + +#include + +#include +#include +#include +#include + +#include "terminal-i18n.h" +#include "terminal-client-utils.h" +#include "terminal-defines.h" +#include "terminal-gdbus-generated.h" + +/* Nautilus extension class */ + +#define TERMINAL_TYPE_NAUTILUS (terminal_nautilus_get_type ()) +#define TERMINAL_NAUTILUS(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_NAUTILUS, TerminalNautilus)) +#define TERMINAL_NAUTILUS_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_NAUTILUS, TerminalNautilusClass)) +#define TERMINAL_IS_NAUTILUS(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_NAUTILUS)) +#define TERMINAL_IS_NAUTILUS_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_NAUTILUS)) +#define TERMINAL_NAUTILUS_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_NAUTILUS, TerminalNautilusClass)) + +typedef struct _TerminalNautilus TerminalNautilus; +typedef struct _TerminalNautilusClass TerminalNautilusClass; + +struct _TerminalNautilus { + GObject parent_instance; + + GSettings *lockdown_prefs; +}; + +struct _TerminalNautilusClass { + GObjectClass parent_class; +}; + +static GType terminal_nautilus_get_type (void); + +/* Nautilus menu item class */ + +#define TERMINAL_TYPE_NAUTILUS_MENU_ITEM (terminal_nautilus_menu_item_get_type ()) +#define TERMINAL_NAUTILUS_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_NAUTILUS_MENU_ITEM, TerminalNautilusMenuItem)) +#define TERMINAL_NAUTILUS_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_NAUTILUS_MENU_ITEM, TerminalNautilusMenuItemClass)) +#define TERMINAL_IS_NAUTILUS_MENU_ITEM(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_NAUTILUS_MENU_ITEM)) +#define TERMINAL_IS_NAUTILUS_MENU_ITEM_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_NAUTILUS_MENU_ITEM)) +#define TERMINAL_NAUTILUS_MENU_ITEM_GET_CLASS(o)(G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_NAUTILUS_MENU_ITEM, TerminalNautilusMenuItemClass)) + +typedef struct _TerminalNautilusMenuItem TerminalNautilusMenuItem; +typedef struct _TerminalNautilusMenuItemClass TerminalNautilusMenuItemClass; + +struct _TerminalNautilusMenuItem { + NautilusMenuItem parent_instance; + + TerminalNautilus *nautilus; + NautilusFileInfo *file_info; + gboolean remote_terminal; +}; + +struct _TerminalNautilusMenuItemClass { + NautilusMenuItemClass parent_class; +}; + +static GType terminal_nautilus_menu_item_get_type (void); + +/* --- */ + +#define TERMINAL_ICON_NAME "org.gnome.Terminal" + +typedef enum { + /* local files. Always open "conventionally", i.e. cd and spawn. */ + FILE_INFO_LOCAL, + FILE_INFO_DESKTOP, + /* SFTP: Shell terminals are opened "remote" (i.e. with ssh client), + * commands are executed like OTHER. + */ + FILE_INFO_SFTP, + /* OTHER: Terminals and commands are opened by mapping the URI back + * to ~/.gvfs, i.e. to the GVFS FUSE bridge. + */ + FILE_INFO_OTHER +} TerminalFileInfo; + +static TerminalFileInfo +get_terminal_file_info_from_uri (const char *uri) +{ + TerminalFileInfo ret; + char *uri_scheme; + + uri_scheme = g_uri_parse_scheme (uri); + + if (uri_scheme == NULL) { + ret = FILE_INFO_OTHER; + } else if (strcmp (uri_scheme, "file") == 0) { + ret = FILE_INFO_LOCAL; + } else if (strcmp (uri_scheme, "x-nautilus-desktop") == 0) { + ret = FILE_INFO_DESKTOP; + } else if (strcmp (uri_scheme, "sftp") == 0 || + strcmp (uri_scheme, "ssh") == 0) { + ret = FILE_INFO_SFTP; + } else { + ret = FILE_INFO_OTHER; + } + + g_free (uri_scheme); + + return ret; +} + +/* Helpers */ + +#define NAUTILUS_SETTINGS_SCHEMA "org.gnome.Nautilus" +#define GNOME_DESKTOP_LOCKDOWN_SETTINGS_SCHEMA "org.gnome.desktop.lockdown" + +/* a very simple URI parsing routine from Launchpad #333462, until GLib supports URI parsing (GNOME #489862) */ +#define SFTP_PREFIX "sftp://" +static void +parse_sftp_uri (GFile *file, + char **user, + char **host, + unsigned int *port, + char **path) +{ + char *tmp, *save; + char *uri; + + uri = g_file_get_uri (file); + g_assert (uri != NULL); + save = uri; + + *path = NULL; + *user = NULL; + *host = NULL; + *port = 0; + + /* skip intial 'sftp:// prefix */ + g_assert (!strncmp (uri, SFTP_PREFIX, strlen (SFTP_PREFIX))); + uri += strlen (SFTP_PREFIX); + + /* cut out the path */ + tmp = strchr (uri, '/'); + if (tmp != NULL) { + *path = g_uri_unescape_string (tmp, "/"); + *tmp = '\0'; + } + + /* read the username - it ends with @ */ + tmp = strchr (uri, '@'); + if (tmp != NULL) { + *tmp++ = '\0'; + + *user = strdup (uri); + if (strchr (*user, ':') != NULL) { + /* chop the password */ + *(strchr (*user, ':')) = '\0'; + } + + uri = tmp; + } + + /* now read the port, starts with : */ + tmp = strchr (uri, ':'); + if (tmp != NULL) { + *tmp++ = '\0'; + *port = atoi (tmp); /*FIXME: getservbyname*/ + } + + /* what is left is the host */ + *host = strdup (uri); + g_free (save); +} + +static char ** +ssh_argv (const char *uri, + int *argcp) +{ + GFile *file; + char **argv; + int argc; + char *host_name, *path, *user_name, *quoted_path; + guint host_port; + + g_assert (uri != NULL); + + argv = g_new0 (char *, 9); + argc = 0; + argv[argc++] = g_strdup ("ssh"); + argv[argc++] = g_strdup ("-t"); + + file = g_file_new_for_uri (uri); + parse_sftp_uri (file, &user_name, &host_name, &host_port, &path); + g_object_unref (file); + + if (user_name != NULL) { + argv[argc++ ]= g_strdup_printf ("%s@%s", user_name, host_name); + g_free (host_name); + g_free (user_name); + } else { + argv[argc++] = host_name; + } + + if (host_port != 0) { + argv[argc++] = g_strdup ("-p"); + argv[argc++] = g_strdup_printf ("%u", host_port); + } + + /* FIXME to we have to consider the remote file encoding? */ + quoted_path = g_shell_quote (path); + + /* login shell */ + argv[argc++] = g_strdup_printf ("cd %s && exec $SHELL -l", quoted_path); + + g_free (path); + g_free (quoted_path); + + *argcp = argc; + return argv; +} + +static gboolean +terminal_locked_down (TerminalNautilus *nautilus) +{ + return g_settings_get_boolean (nautilus->lockdown_prefs, + "disable-command-line"); +} + +/* used to determine for remote URIs whether GVFS is capable of mapping them to ~/.gvfs */ +static gboolean +uri_has_local_path (const char *uri) +{ + GFile *file; + char *path; + gboolean ret; + + file = g_file_new_for_uri (uri); + path = g_file_get_path (file); + + ret = (path != NULL); + + g_free (path); + g_object_unref (file); + + return ret; +} + +/* Nautilus menu item class */ + +typedef struct { + TerminalNautilus *nautilus; + guint32 timestamp; + char *path; + char *uri; + TerminalFileInfo info; + gboolean remote; +} ExecData; + +static void +exec_data_free (ExecData *data) +{ + g_object_unref (data->nautilus); + g_free (data->path); + g_free (data->uri); + + g_free (data); +} + +/* FIXME: make this async */ +static gboolean +create_terminal (ExecData *data /* transfer full */) +{ + TerminalFactory *factory; + TerminalReceiver *receiver; + GError *error = NULL; + GVariantBuilder builder; + char *object_path; + char startup_id[32]; + char **argv; + int argc; + + factory = terminal_factory_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + TERMINAL_APPLICATION_ID, + TERMINAL_FACTORY_OBJECT_PATH, + NULL /* cancellable */, + &error); + if (factory == NULL) { + g_dbus_error_strip_remote_error (error); + g_printerr ("Error constructing proxy for %s:%s: %s\n", + TERMINAL_APPLICATION_ID, TERMINAL_FACTORY_OBJECT_PATH, + error->message); + g_error_free (error); + exec_data_free (data); + return FALSE; + } + + g_snprintf (startup_id, sizeof (startup_id), "_TIME%u", data->timestamp); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + terminal_client_append_create_instance_options (&builder, + gdk_display_get_name (gdk_display_get_default ()), + startup_id, + NULL /* geometry */, + NULL /* role */, + NULL /* use default profile */, + NULL /* use profile encoding */, + NULL /* title */, + TRUE, /* active */ + FALSE /* maximised */, + FALSE /* fullscreen */); + + if (!terminal_factory_call_create_instance_sync + (factory, + g_variant_builder_end (&builder), + &object_path, + NULL /* cancellable */, + &error)) { + g_dbus_error_strip_remote_error (error); + g_printerr ("Error creating terminal: %s\n", error->message); + g_error_free (error); + g_object_unref (factory); + exec_data_free (data); + return FALSE; + } + + g_object_unref (factory); + + receiver = terminal_receiver_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + TERMINAL_APPLICATION_ID, + object_path, + NULL /* cancellable */, + &error); + if (receiver == NULL) { + g_dbus_error_strip_remote_error (error); + g_printerr ("Failed to create proxy for terminal: %s\n", error->message); + g_error_free (error); + g_free (object_path); + exec_data_free (data); + return FALSE; + } + + g_free (object_path); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + terminal_client_append_exec_options (&builder, + TRUE, /* pass environment */ + data->path, + NULL, 0, /* FD array */ + TRUE /* shell */); + + if (data->info == FILE_INFO_SFTP && + data->remote) { + argv = ssh_argv (data->uri, &argc); + } else { + argv = NULL; argc = 0; + } + + if (!terminal_receiver_call_exec_sync (receiver, + g_variant_builder_end (&builder), + g_variant_new_bytestring_array ((const char * const *) argv, argc), + NULL /* in FD list */, + NULL /* out FD list */, + NULL /* cancellable */, + &error)) { + g_dbus_error_strip_remote_error (error); + g_printerr ("Error: %s\n", error->message); + g_error_free (error); + g_strfreev (argv); + g_object_unref (receiver); + exec_data_free (data); + return FALSE; + } + + g_strfreev (argv); + + exec_data_free (data); + + g_object_unref (receiver); + + return TRUE; +} + +static void +terminal_nautilus_menu_item_activate (NautilusMenuItem *item) +{ + TerminalNautilusMenuItem *menu_item = TERMINAL_NAUTILUS_MENU_ITEM (item); + TerminalNautilus *nautilus = menu_item->nautilus; + char *uri, *path; + TerminalFileInfo info; + ExecData *data; + + uri = nautilus_file_info_get_activation_uri (menu_item->file_info); + if (uri == NULL) + return; + + path = NULL; + info = get_terminal_file_info_from_uri (uri); + + switch (info) { + case FILE_INFO_LOCAL: + path = g_filename_from_uri (uri, NULL, NULL); + break; + + case FILE_INFO_DESKTOP: + path = g_strdup (g_get_home_dir ()); + break; + + case FILE_INFO_SFTP: + if (menu_item->remote_terminal) + break; + + /* fall through */ + + case FILE_INFO_OTHER: { + GFile *file; + + /* map back remote URI to local path */ + file = g_file_new_for_uri (uri); + path = g_file_get_path (file); + g_object_unref (file); + break; + } + + default: + g_assert_not_reached (); + } + + if (path == NULL && (info != FILE_INFO_SFTP || !menu_item->remote_terminal)) { + g_free (uri); + return; + } + + data = g_new (ExecData, 1); + data->nautilus = g_object_ref (nautilus); + data->timestamp = gtk_get_current_event_time (); + data->path = path; + data->uri = uri; + data->info = info; + data->remote = menu_item->remote_terminal; + + create_terminal (data); +} + +G_DEFINE_DYNAMIC_TYPE (TerminalNautilusMenuItem, terminal_nautilus_menu_item, NAUTILUS_TYPE_MENU_ITEM) + +static void +terminal_nautilus_menu_item_init (TerminalNautilusMenuItem *nautilus_menu_item) +{ +} + +static void +terminal_nautilus_menu_item_dispose (GObject *object) +{ + TerminalNautilusMenuItem *menu_item = TERMINAL_NAUTILUS_MENU_ITEM (object); + + if (menu_item->file_info != NULL) { + g_object_unref (menu_item->file_info); + menu_item->file_info = NULL; + } + if (menu_item->nautilus != NULL) { + g_object_unref (menu_item->nautilus); + menu_item->nautilus = NULL; + } + + G_OBJECT_CLASS (terminal_nautilus_menu_item_parent_class)->dispose (object); +} + +static void +terminal_nautilus_menu_item_class_init (TerminalNautilusMenuItemClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + NautilusMenuItemClass *menu_item_class = NAUTILUS_MENU_ITEM_CLASS (klass); + + gobject_class->dispose = terminal_nautilus_menu_item_dispose; + + menu_item_class->activate = terminal_nautilus_menu_item_activate; +} + +static void +terminal_nautilus_menu_item_class_finalize (TerminalNautilusMenuItemClass *class) +{ +} + +static NautilusMenuItem * +terminal_nautilus_menu_item_new (TerminalNautilus *nautilus, + NautilusFileInfo *file_info, + TerminalFileInfo terminal_file_info, + gboolean remote_terminal, + gboolean is_file_item) +{ + TerminalNautilusMenuItem *item; + const char *action_name; + const char *name; + const char *tooltip; + + if (is_file_item) { + action_name = remote_terminal ? "TerminalNautilus:OpenRemote" + : "TerminalNautilus:OpenLocal"; + } else { + action_name = remote_terminal ? "TerminalNautilus:OpenFolderRemote" + : "TerminalNautilus:OpenFolderLocal"; + } + + switch (terminal_file_info) { + case FILE_INFO_SFTP: + if (remote_terminal) { + name = _("Open in _Remote Terminal"); + } else { + name = _("Open in _Local Terminal"); + } + + if (is_file_item) { + tooltip = _("Open the currently selected folder in a terminal"); + } else { + tooltip = _("Open the currently open folder in a terminal"); + } + break; + + case FILE_INFO_LOCAL: + case FILE_INFO_OTHER: + name = _("Open in T_erminal"); + + if (is_file_item) { + tooltip = _("Open the currently selected folder in a terminal"); + } else { + tooltip = _("Open the currently open folder in a terminal"); + } + break; + + case FILE_INFO_DESKTOP: + name = _("Open T_erminal"); + tooltip = _("Open a terminal"); + break; + + default: + g_assert_not_reached (); + } + + item = g_object_new (TERMINAL_TYPE_NAUTILUS_MENU_ITEM, + "name", action_name, + "label", name, + "tip", tooltip, + "icon", TERMINAL_ICON_NAME, + NULL); + + item->nautilus = g_object_ref (nautilus); + item->file_info = g_object_ref (file_info); + item->remote_terminal = remote_terminal; + + return (NautilusMenuItem *) item; +} + +/* Nautilus extension class implementation */ + +static GList * +terminal_nautilus_get_background_items (NautilusMenuProvider *provider, + GtkWidget *window, + NautilusFileInfo *file_info) +{ + TerminalNautilus *nautilus = TERMINAL_NAUTILUS (provider); + gchar *uri; + GList *items; + NautilusMenuItem *item; + TerminalFileInfo terminal_file_info; + + if (terminal_locked_down (nautilus)) + return NULL; + + uri = nautilus_file_info_get_activation_uri (file_info); + if (uri == NULL) + return NULL; + + items = NULL; + + terminal_file_info = get_terminal_file_info_from_uri (uri); + + + if (terminal_file_info == FILE_INFO_SFTP) { + /* remote SSH location */ + item = terminal_nautilus_menu_item_new (nautilus, + file_info, + terminal_file_info, + TRUE, + FALSE); + items = g_list_append (items, item); + } + + if (terminal_file_info == FILE_INFO_DESKTOP || + uri_has_local_path (uri)) { + /* local locations and remote locations that offer local back-mapping */ + item = terminal_nautilus_menu_item_new (nautilus, + file_info, + terminal_file_info, + FALSE, + FALSE); + items = g_list_append (items, item); + } + + g_free (uri); + + return items; +} + +static GList * +terminal_nautilus_get_file_items (NautilusMenuProvider *provider, + GtkWidget *window, + GList *files) +{ + TerminalNautilus *nautilus = TERMINAL_NAUTILUS (provider); + gchar *uri; + GList *items; + NautilusMenuItem *item; + NautilusFileInfo *file_info; + GFileType file_type; + TerminalFileInfo terminal_file_info; + + if (terminal_locked_down (nautilus)) + return NULL; + + /* Only add items when passed exactly one file */ + if (files == NULL || files->next != NULL) + return NULL; + + file_info = (NautilusFileInfo *) files->data; + file_type = nautilus_file_info_get_file_type (file_info); + if (!nautilus_file_info_is_directory (file_info) && + file_type != G_FILE_TYPE_SHORTCUT && + file_type != G_FILE_TYPE_MOUNTABLE) + return NULL; + + uri = nautilus_file_info_get_activation_uri (file_info); + if (uri == NULL) + return NULL; + + items = NULL; + + terminal_file_info = get_terminal_file_info_from_uri (uri); + + switch (terminal_file_info) { + case FILE_INFO_LOCAL: + case FILE_INFO_SFTP: + case FILE_INFO_OTHER: + if (terminal_file_info == FILE_INFO_SFTP || + uri_has_local_path (uri)) { + item = terminal_nautilus_menu_item_new (nautilus, + file_info, + terminal_file_info, + terminal_file_info == FILE_INFO_SFTP, + TRUE); + items = g_list_append (items, item); + } + + if (terminal_file_info == FILE_INFO_SFTP && + uri_has_local_path (uri)) { + item = terminal_nautilus_menu_item_new (nautilus, + file_info, + terminal_file_info, + FALSE, + TRUE); + items = g_list_append (items, item); + } + + case FILE_INFO_DESKTOP: + break; + + default: + g_assert_not_reached (); + } + + g_free (uri); + + return items; +} + +static void +terminal_nautilus_menu_provider_iface_init (NautilusMenuProviderIface *iface) +{ + iface->get_background_items = terminal_nautilus_get_background_items; + iface->get_file_items = terminal_nautilus_get_file_items; +} + +G_DEFINE_DYNAMIC_TYPE_EXTENDED (TerminalNautilus, terminal_nautilus, G_TYPE_OBJECT, 0, + G_IMPLEMENT_INTERFACE_DYNAMIC (NAUTILUS_TYPE_MENU_PROVIDER, + terminal_nautilus_menu_provider_iface_init)) + +static void +terminal_nautilus_init (TerminalNautilus *nautilus) +{ + nautilus->lockdown_prefs = g_settings_new (GNOME_DESKTOP_LOCKDOWN_SETTINGS_SCHEMA); +} + +static void +terminal_nautilus_dispose (GObject *object) +{ + TerminalNautilus *nautilus = TERMINAL_NAUTILUS (object); + + g_clear_object (&nautilus->lockdown_prefs); + + G_OBJECT_CLASS (terminal_nautilus_parent_class)->dispose (object); +} + +static void +terminal_nautilus_class_init (TerminalNautilusClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = terminal_nautilus_dispose; + + terminal_i18n_init (FALSE); +} + +static void +terminal_nautilus_class_finalize (TerminalNautilusClass *class) +{ +} + +/* Nautilus extension */ + +static GType type_list[1]; + +#define EXPORT __attribute__((__visibility__("default"))) extern + +EXPORT void +nautilus_module_initialize (GTypeModule *module) +{ + terminal_nautilus_register_type (module); + terminal_nautilus_menu_item_register_type (module); + + type_list[0] = TERMINAL_TYPE_NAUTILUS; +} + +EXPORT void +nautilus_module_shutdown (void) +{ +} + +EXPORT void +nautilus_module_list_types (const GType **types, + int *num_types) +{ + *types = type_list; + *num_types = G_N_ELEMENTS (type_list); +} diff --git a/src/terminal-notebook-menu.ui b/src/terminal-notebook-menu.ui new file mode 100644 index 0000000..d5c7f41 --- /dev/null +++ b/src/terminal-notebook-menu.ui @@ -0,0 +1,49 @@ + + + + +
+ + Move Terminal _Left + win.tab-move-left + + + Move Terminal _Right + win.tab-move-right + +
+
+ + _Detach Terminal + win.tab-detach + + + Set _Title… + win.set-title + action-missing + +
+
+ + C_lose Terminal + win.close + tab + +
+
+
diff --git a/src/terminal-notebook.c b/src/terminal-notebook.c new file mode 100644 index 0000000..356a389 --- /dev/null +++ b/src/terminal-notebook.c @@ -0,0 +1,593 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2008, 2010, 2011, 2012 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include "terminal-notebook.h" + +#include + +#include "terminal-debug.h" +#include "terminal-app.h" +#include "terminal-intl.h" +#include "terminal-mdi-container.h" +#include "terminal-screen-container.h" +#include "terminal-tab-label.h" +#include "terminal-schemas.h" +#include "terminal-libgsystem.h" + +#define TERMINAL_NOTEBOOK_GET_PRIVATE(notebook)(G_TYPE_INSTANCE_GET_PRIVATE ((notebook), TERMINAL_TYPE_NOTEBOOK, TerminalNotebookPrivate)) + +struct _TerminalNotebookPrivate +{ + TerminalScreen *active_screen; + GtkPolicyType policy; +}; + +enum +{ + PROP_0, + PROP_ACTIVE_SCREEN, + PROP_TAB_POLICY +}; + +#define ACTION_AREA_BORDER_WIDTH (2) +#define ACTION_BUTTON_SPACING (6) + +/* helper functions */ + +static void +update_tab_visibility (TerminalNotebook *notebook, + int change) +{ + TerminalNotebookPrivate *priv = notebook->priv; + GtkNotebook *gtk_notebook = GTK_NOTEBOOK (notebook); + int new_n_pages; + gboolean show_tabs; + + if (gtk_widget_in_destruction (GTK_WIDGET (notebook))) + return; + + new_n_pages = gtk_notebook_get_n_pages (gtk_notebook) + change; + /* Don't do anything if we're going to have zero pages (and thus close the window) */ + if (new_n_pages == 0) + return; + + switch (priv->policy) { + case GTK_POLICY_ALWAYS: + show_tabs = TRUE; + break; + case GTK_POLICY_AUTOMATIC: + show_tabs = new_n_pages > 1; + break; + case GTK_POLICY_NEVER: + case GTK_POLICY_EXTERNAL: + default: + show_tabs = FALSE; + break; + } + + gtk_notebook_set_show_tabs (gtk_notebook, show_tabs); +} + +static void +close_button_clicked_cb (TerminalTabLabel *tab_label, + gpointer user_data) +{ + TerminalScreen *screen; + TerminalNotebook *notebook; + + screen = terminal_tab_label_get_screen (tab_label); + + /* notebook is not passed as user_data because it can change during DND + * and the close button is not notified about that, see bug 731998. + */ + notebook = TERMINAL_NOTEBOOK (gtk_widget_get_ancestor (GTK_WIDGET (screen), + TERMINAL_TYPE_NOTEBOOK)); + + if (notebook != NULL) + g_signal_emit_by_name (notebook, "screen-close-request", screen); +} + + +static void +remove_reorder_bindings (GtkBindingSet *binding_set, + guint keysym) +{ + guint keypad_keysym = keysym - GDK_KEY_Left + GDK_KEY_KP_Left; + gtk_binding_entry_skip (binding_set, keysym, GDK_MOD1_MASK); + gtk_binding_entry_skip (binding_set, keypad_keysym, GDK_MOD1_MASK); +} + +/* TerminalMdiContainer impl */ + +static void +terminal_notebook_add_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int position) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (container); + GtkNotebook *gtk_notebook = GTK_NOTEBOOK (notebook); + GtkWidget *screen_container, *tab_label; + + g_warn_if_fail (gtk_widget_get_parent (GTK_WIDGET (screen)) == NULL); + + screen_container = terminal_screen_container_new (screen); + gtk_widget_show (screen_container); + + update_tab_visibility (notebook, +1); + + tab_label = terminal_tab_label_new (screen); + g_signal_connect (tab_label, "close-button-clicked", + G_CALLBACK (close_button_clicked_cb), NULL); + + gtk_notebook_insert_page (gtk_notebook, + screen_container, + tab_label, + position); + gtk_container_child_set (GTK_CONTAINER (notebook), + screen_container, + "tab-expand", TRUE, + "tab-fill", TRUE, + NULL); + gtk_notebook_set_tab_reorderable (gtk_notebook, screen_container, TRUE); +#if 0 + gtk_notebook_set_tab_detachable (gtk_notebook, screen_container, TRUE); +#endif +} + +static void +terminal_notebook_remove_screen (TerminalMdiContainer *container, + TerminalScreen *screen) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (container); + TerminalScreenContainer *screen_container; + + g_warn_if_fail (gtk_widget_is_ancestor (GTK_WIDGET (screen), GTK_WIDGET (notebook))); + + update_tab_visibility (notebook, -1); + + screen_container = terminal_screen_container_get_from_screen (screen); + gtk_container_remove (GTK_CONTAINER (notebook), + GTK_WIDGET (screen_container)); +} + +static TerminalScreen * +terminal_notebook_get_active_screen (TerminalMdiContainer *container) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (container); + GtkNotebook *gtk_notebook = GTK_NOTEBOOK (notebook); + GtkWidget *widget; + + widget = gtk_notebook_get_nth_page (gtk_notebook, gtk_notebook_get_current_page (gtk_notebook)); + return terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (widget)); +} + +static void +terminal_notebook_set_active_screen (TerminalMdiContainer *container, + TerminalScreen *screen) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (container); + GtkNotebook *gtk_notebook = GTK_NOTEBOOK (notebook); + TerminalScreenContainer *screen_container; + GtkWidget *widget; + + screen_container = terminal_screen_container_get_from_screen (screen); + widget = GTK_WIDGET (screen_container); + + gtk_notebook_set_current_page (gtk_notebook, + gtk_notebook_page_num (gtk_notebook, widget)); +} + +static GList * +terminal_notebook_list_screen_containers (TerminalMdiContainer *container) +{ + /* We are trusting that GtkNotebook will return pages in order */ + return gtk_container_get_children (GTK_CONTAINER (container)); +} + +static GList * +terminal_notebook_list_screens (TerminalMdiContainer *container) +{ + GList *list, *l; + + list = terminal_notebook_list_screen_containers (container); + for (l = list; l != NULL; l = l->next) + l->data = terminal_screen_container_get_screen ((TerminalScreenContainer *) l->data); + + return list; +} + +static int +terminal_notebook_get_n_screens (TerminalMdiContainer *container) +{ + return gtk_notebook_get_n_pages (GTK_NOTEBOOK (container)); +} + +static int +terminal_notebook_get_active_screen_num (TerminalMdiContainer *container) +{ + return gtk_notebook_get_current_page (GTK_NOTEBOOK (container)); +} + +static void +terminal_notebook_set_active_screen_num (TerminalMdiContainer *container, + int position) +{ + GtkNotebook *gtk_notebook = GTK_NOTEBOOK (container); + + gtk_notebook_set_current_page (gtk_notebook, position); +} + +static void +terminal_notebook_reorder_screen (TerminalMdiContainer *container, + TerminalScreen *screen, + int new_position) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (container); + GtkWidget *child; + int n, pos; + + g_return_if_fail (new_position == 1 || new_position == -1); + + child = GTK_WIDGET (terminal_screen_container_get_from_screen (screen)); + n = gtk_notebook_get_n_pages (notebook); + pos = gtk_notebook_page_num (notebook, child); + + pos += new_position; + gtk_notebook_reorder_child (notebook, child, + pos < 0 ? n - 1 : pos < n ? pos : 0); +} + +static void +terminal_notebook_mdi_iface_init (TerminalMdiContainerInterface *iface) +{ + iface->add_screen = terminal_notebook_add_screen; + iface->remove_screen = terminal_notebook_remove_screen; + iface->get_active_screen = terminal_notebook_get_active_screen; + iface->set_active_screen = terminal_notebook_set_active_screen; + iface->list_screens = terminal_notebook_list_screens; + iface->list_screen_containers = terminal_notebook_list_screen_containers; + iface->get_n_screens = terminal_notebook_get_n_screens; + iface->get_active_screen_num = terminal_notebook_get_active_screen_num; + iface->set_active_screen_num = terminal_notebook_set_active_screen_num; + iface->reorder_screen = terminal_notebook_reorder_screen; +} + +G_DEFINE_TYPE_WITH_CODE (TerminalNotebook, terminal_notebook, GTK_TYPE_NOTEBOOK, + G_IMPLEMENT_INTERFACE (TERMINAL_TYPE_MDI_CONTAINER, terminal_notebook_mdi_iface_init)) + +/* GtkNotebookClass impl */ + +static void +terminal_notebook_switch_page (GtkNotebook *gtk_notebook, + GtkWidget *child, + guint page_num) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (gtk_notebook); + TerminalNotebookPrivate *priv = notebook->priv; + TerminalScreen *screen, *old_active_screen; + + GTK_NOTEBOOK_CLASS (terminal_notebook_parent_class)->switch_page (gtk_notebook, child, page_num); + + screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (child)); + + old_active_screen = priv->active_screen; + if (screen == old_active_screen) + return; + + /* Workaround to remove gtknotebook's feature of computing its size based on + * all pages. When the widget is hidden, its size will not be taken into + * account. + * FIXME! + */ +// if (old_active_screen) +// gtk_widget_hide (GTK_WIDGET (terminal_screen_container_get_from_screen (old_active_screen))); + /* Make sure that the widget is no longer hidden due to the workaround */ +// if (child) +// gtk_widget_show (child); + if (old_active_screen) + gtk_widget_hide (GTK_WIDGET (old_active_screen)); + if (screen) + gtk_widget_show (GTK_WIDGET (screen)); + + priv->active_screen = screen; + + g_signal_emit_by_name (notebook, "screen-switched", old_active_screen, screen); + g_object_notify (G_OBJECT (notebook), "active-screen"); +} + +static void +terminal_notebook_page_added (GtkNotebook *gtk_notebook, + GtkWidget *child, + guint page_num) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (gtk_notebook); + void (* page_added) (GtkNotebook *, GtkWidget *, guint) = + GTK_NOTEBOOK_CLASS (terminal_notebook_parent_class)->page_added; + + if (page_added) + page_added (gtk_notebook, child, page_num); + + update_tab_visibility (notebook, 0); + g_signal_emit_by_name (gtk_notebook, "screen-added", + terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (child))); +} + +static void +terminal_notebook_page_removed (GtkNotebook *gtk_notebook, + GtkWidget *child, + guint page_num) +{ + TerminalNotebook *notebook = TERMINAL_NOTEBOOK (gtk_notebook); + void (* page_removed) (GtkNotebook *, GtkWidget *, guint) = + GTK_NOTEBOOK_CLASS (terminal_notebook_parent_class)->page_removed; + + if (page_removed) + page_removed (gtk_notebook, child, page_num); + + update_tab_visibility (notebook, 0); + g_signal_emit_by_name (gtk_notebook, "screen-removed", + terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (child))); +} + +static void +terminal_notebook_page_reordered (GtkNotebook *notebook, + GtkWidget *child, + guint page_num) +{ + void (* page_reordered) (GtkNotebook *, GtkWidget *, guint) = + GTK_NOTEBOOK_CLASS (terminal_notebook_parent_class)->page_reordered; + + if (page_reordered) + page_reordered (notebook, child, page_num); + + g_signal_emit_by_name (notebook, "screens-reordered"); +} + +static GtkNotebook * +terminal_notebook_create_window (GtkNotebook *notebook, + GtkWidget *page, + gint x, + gint y) +{ + return GTK_NOTEBOOK_CLASS (terminal_notebook_parent_class)->create_window (notebook, page, x, y); +} + +/* GtkWidgetClass impl */ + +static void +terminal_notebook_grab_focus (GtkWidget *widget) +{ + TerminalScreen *screen; + + screen = terminal_mdi_container_get_active_screen (TERMINAL_MDI_CONTAINER (widget)); + gtk_widget_grab_focus (GTK_WIDGET (screen)); +} + +/* GObjectClass impl */ + +static void +terminal_notebook_init (TerminalNotebook *notebook) +{ + TerminalNotebookPrivate *priv; + + priv = notebook->priv = TERMINAL_NOTEBOOK_GET_PRIVATE (notebook); + + priv->active_screen = NULL; + priv->policy = GTK_POLICY_AUTOMATIC; +} + +static void +terminal_notebook_constructed (GObject *object) +{ + GSettings *settings; + GtkWidget *widget = GTK_WIDGET (object); + GtkNotebook *notebook = GTK_NOTEBOOK (object); + + G_OBJECT_CLASS (terminal_notebook_parent_class)->constructed (object); + + settings = terminal_app_get_global_settings (terminal_app_get ()); + + update_tab_visibility (TERMINAL_NOTEBOOK (notebook), 0); + g_settings_bind (settings, + TERMINAL_SETTING_TAB_POLICY_KEY, + object, + "tab-policy", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + + g_settings_bind (settings, + TERMINAL_SETTING_TAB_POSITION_KEY, + object, + "tab-pos", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + + gtk_notebook_set_scrollable (notebook, TRUE); + gtk_notebook_set_show_border (notebook, FALSE); + gtk_notebook_set_group_name (notebook, I_("gnome-terminal-window")); + + /* Necessary for scroll events */ + gtk_widget_add_events (widget, GDK_SCROLL_MASK); +} + +static void +terminal_notebook_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalMdiContainer *mdi_container = TERMINAL_MDI_CONTAINER (object); + + switch (prop_id) { + case PROP_ACTIVE_SCREEN: + g_value_set_object (value, terminal_notebook_get_active_screen (mdi_container)); + break; + case PROP_TAB_POLICY: + g_value_set_enum (value, terminal_notebook_get_tab_policy (TERMINAL_NOTEBOOK (mdi_container))); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_notebook_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalMdiContainer *mdi_container = TERMINAL_MDI_CONTAINER (object); + + switch (prop_id) { + case PROP_ACTIVE_SCREEN: + terminal_notebook_set_active_screen (mdi_container, g_value_get_object (value)); + break; + case PROP_TAB_POLICY: + terminal_notebook_set_tab_policy (TERMINAL_NOTEBOOK (mdi_container), g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_notebook_class_init (TerminalNotebookClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + GtkNotebookClass *notebook_class = GTK_NOTEBOOK_CLASS (klass); + + g_type_class_add_private (gobject_class, sizeof (TerminalNotebookPrivate)); + + gobject_class->constructed = terminal_notebook_constructed; + gobject_class->get_property = terminal_notebook_get_property; + gobject_class->set_property = terminal_notebook_set_property; + + g_object_class_override_property (gobject_class, PROP_ACTIVE_SCREEN, "active-screen"); + + widget_class->grab_focus = terminal_notebook_grab_focus; + + notebook_class->switch_page = terminal_notebook_switch_page; + notebook_class->create_window = terminal_notebook_create_window; + notebook_class->page_added = terminal_notebook_page_added; + notebook_class->page_removed = terminal_notebook_page_removed; + notebook_class->page_reordered = terminal_notebook_page_reordered; + + g_object_class_install_property + (gobject_class, + PROP_TAB_POLICY, + g_param_spec_enum ("tab-policy", NULL, NULL, + GTK_TYPE_POLICY_TYPE, + GTK_POLICY_AUTOMATIC, + G_PARAM_READWRITE | G_PARAM_STATIC_STRINGS)); + + /* Remove unwanted and interfering keybindings */ + GtkBindingSet *binding_set = gtk_binding_set_by_class (terminal_notebook_parent_class); + gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK); + gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Up, GDK_CONTROL_MASK | GDK_MOD1_MASK); + gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK); + gtk_binding_entry_skip (binding_set, GDK_KEY_Page_Down, GDK_CONTROL_MASK | GDK_MOD1_MASK); + remove_reorder_bindings (binding_set, GDK_KEY_Up); + remove_reorder_bindings (binding_set, GDK_KEY_Down); + remove_reorder_bindings (binding_set, GDK_KEY_Left); + remove_reorder_bindings (binding_set, GDK_KEY_Right); + remove_reorder_bindings (binding_set, GDK_KEY_Home); + remove_reorder_bindings (binding_set, GDK_KEY_Home); + remove_reorder_bindings (binding_set, GDK_KEY_End); + remove_reorder_bindings (binding_set, GDK_KEY_End); +} + +/* public API */ + +/** + * terminal_notebook_new: + * + * Returns: (transfer full): a new #TerminalNotebook + */ +GtkWidget * +terminal_notebook_new (void) +{ + return g_object_new (TERMINAL_TYPE_NOTEBOOK, NULL); +} + +void +terminal_notebook_set_tab_policy (TerminalNotebook *notebook, + GtkPolicyType policy) +{ + TerminalNotebookPrivate *priv = notebook->priv; + + if (priv->policy == policy) + return; + + priv->policy = policy; + update_tab_visibility (notebook, 0); + + g_object_notify (G_OBJECT (notebook), "tab-policy"); +} + +GtkPolicyType +terminal_notebook_get_tab_policy (TerminalNotebook *notebook) +{ + return notebook->priv->policy; +} + +GtkWidget * +terminal_notebook_get_action_box (TerminalNotebook *notebook, + GtkPackType pack_type) +{ + GtkNotebook *gtk_notebook; + GtkWidget *box, *inner_box; + + g_return_val_if_fail (TERMINAL_IS_NOTEBOOK (notebook), NULL); + + gtk_notebook = GTK_NOTEBOOK (notebook); + box = gtk_notebook_get_action_widget (gtk_notebook, pack_type); + if (box != NULL) { + gs_free_list GList *list; + + list = gtk_container_get_children (GTK_CONTAINER (box)); + g_assert (list->data != NULL); + return list->data; + } + + /* Create container for the buttons */ + box = gtk_box_new (GTK_ORIENTATION_VERTICAL, 0); + gtk_container_set_border_width (GTK_CONTAINER (box), ACTION_AREA_BORDER_WIDTH); + + inner_box = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, ACTION_BUTTON_SPACING); + gtk_box_pack_start (GTK_BOX (box), inner_box, TRUE, FALSE, 0); + gtk_widget_show (inner_box); + + gtk_notebook_set_action_widget (gtk_notebook, box, pack_type); + gtk_widget_show (box); + + /* FIXME: this appears to be necessary to make the icon buttons contained + * in the action area render the same way as buttons in the tab labels (e.g. + * the close button). gtk+ bug? + */ + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_style_context_add_region (gtk_widget_get_style_context (box), + GTK_STYLE_REGION_TAB, + pack_type == GTK_PACK_START ? GTK_REGION_FIRST : GTK_REGION_LAST); + G_GNUC_END_IGNORE_DEPRECATIONS + + return inner_box; +} diff --git a/src/terminal-notebook.h b/src/terminal-notebook.h new file mode 100644 index 0000000..68cd51f --- /dev/null +++ b/src/terminal-notebook.h @@ -0,0 +1,62 @@ +/* + * Copyright © 2008, 2010, 2012 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_NOTEBOOK_H +#define TERMINAL_NOTEBOOK_H + +#include + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_NOTEBOOK (terminal_notebook_get_type ()) +#define TERMINAL_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_NOTEBOOK, TerminalNotebook)) +#define TERMINAL_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_NOTEBOOK, TerminalNotebookClass)) +#define TERMINAL_IS_NOTEBOOK(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_NOTEBOOK)) +#define TERMINAL_IS_NOTEBOOK_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_NOTEBOOK)) +#define TERMINAL_NOTEBOOK_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_NOTEBOOK, TerminalNotebookClass)) + +typedef struct _TerminalNotebook TerminalNotebook; +typedef struct _TerminalNotebookClass TerminalNotebookClass; +typedef struct _TerminalNotebookPrivate TerminalNotebookPrivate; + +struct _TerminalNotebook +{ + GtkNotebook parent_instance; + + /*< private >*/ + TerminalNotebookPrivate *priv; +}; + +struct _TerminalNotebookClass +{ + GtkNotebookClass parent_class; +}; + +GType terminal_notebook_get_type (void); + +GtkWidget *terminal_notebook_new (void); + +void terminal_notebook_set_tab_policy (TerminalNotebook *notebook, + GtkPolicyType policy); +GtkPolicyType terminal_notebook_get_tab_policy (TerminalNotebook *notebook); + +GtkWidget *terminal_notebook_get_action_box (TerminalNotebook *notebook, + GtkPackType pack_type); + +G_END_DECLS + +#endif /* TERMINAL_NOTEBOOK_H */ diff --git a/src/terminal-options.c b/src/terminal-options.c new file mode 100644 index 0000000..afe4545 --- /dev/null +++ b/src/terminal-options.c @@ -0,0 +1,1696 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008, 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include + +#include +#include +#include + +#include +#include +#include + +#include "terminal-options.h" +#include "terminal-client-utils.h" +#include "terminal-defines.h" +#include "terminal-schemas.h" +#include "terminal-screen.h" +#include "terminal-app.h" +#include "terminal-util.h" +#include "terminal-version.h" +#include "terminal-libgsystem.h" + +static int verbosity = 1; + +void +terminal_fprintf (FILE* fp, + int verbosity_level, + const char* format, + ...) +{ + if (verbosity < verbosity_level) + return; + + va_list args; + va_start(args, format); + gs_free char *str = g_strdup_vprintf(format, args); + va_end(args); + + gs_strfreev char **lines = g_strsplit_set(str, "\n\r", -1); + for (gsize i = 0; lines[i]; ++i) { + if (lines[i][0] != '\0') + g_fprintf(fp, "# %s\n", lines[i]); + } +} + +static TerminalVerbosity +verbosity_from_log_level (GLogLevelFlags log_level) +{ + guint level = log_level & G_LOG_LEVEL_MASK; + TerminalVerbosity res; + level = level & ~(level - 1); /* extract the highest bit */ + switch (level) { + case G_LOG_LEVEL_DEBUG: + res = TERMINAL_VERBOSITY_DEBUG; + break; + case G_LOG_LEVEL_INFO: + res = TERMINAL_VERBOSITY_DETAIL; + break; + default: + /* better display than lose important messages */ + res = TERMINAL_VERBOSITY_NORMAL; + } + return res; +} + +/* Need to install a special log writer so we never output + * anything without the '# ' prepended, in case --print-environment + * is used. + * + * FIXME: Until issue glib#2087 is fixed, apply a simple log level filter + * to prevent spamming dconf (and other) debug messages to stderr, + * see issue gnome-terminal#42. + */ +GLogWriterOutput +terminal_log_writer (GLogLevelFlags log_level, + const GLogField *fields, + gsize n_fields, + gpointer user_data) +{ + TerminalVerbosity level = verbosity_from_log_level(log_level); + for (gsize i = 0; i < n_fields; i++) { + if (g_str_equal (fields[i].key, "MESSAGE")) + terminal_fprintf (stderr, level, "%s\n", (const char*)fields[i].value); + } + + return G_LOG_WRITER_HANDLED; +} + +static GOptionContext *get_goption_context (TerminalOptions *options); + +static TerminalSettingsList * +terminal_options_ensure_profiles_list (TerminalOptions *options) +{ + if (options->profiles_list == NULL) + options->profiles_list = terminal_profiles_list_new (); + + return options->profiles_list; +} + +static char * +terminal_util_key_file_get_string_unescape (GKeyFile *key_file, + const char *group, + const char *key, + GError **error) +{ + char *escaped, *unescaped; + + escaped = g_key_file_get_string (key_file, group, key, error); + if (!escaped) + return NULL; + + unescaped = g_strcompress (escaped); + g_free (escaped); + + return unescaped; +} + +static char ** +terminal_util_key_file_get_argv (GKeyFile *key_file, + const char *group, + const char *key, + int *argc, + GError **error) +{ + char **argv; + char *flat; + gboolean retval; + + flat = terminal_util_key_file_get_string_unescape (key_file, group, key, error); + if (!flat) + return NULL; + + retval = g_shell_parse_argv (flat, argc, &argv, error); + g_free (flat); + + if (retval) + return argv; + + return NULL; +} + +static InitialTab* +initial_tab_new (char *profile /* adopts */) +{ + InitialTab *it; + + it = g_slice_new (InitialTab); + + it->profile = profile; + it->exec_argv = NULL; + it->title = NULL; + it->working_dir = NULL; + it->zoom = 1.0; + it->zoom_set = FALSE; + it->active = FALSE; + it->fd_list = NULL; + it->fd_array = NULL; + + return it; +} + +static void +initial_tab_free (InitialTab *it) +{ + g_free (it->profile); + g_strfreev (it->exec_argv); + g_free (it->title); + g_free (it->working_dir); + g_clear_object (&it->fd_list); + if (it->fd_array) + g_array_unref (it->fd_array); + g_slice_free (InitialTab, it); +} + +static InitialWindow* +initial_window_new (guint source_tag) +{ + InitialWindow *iw; + + iw = g_slice_new0 (InitialWindow); + iw->source_tag = source_tag; + + return iw; +} + +static void +initial_window_free (InitialWindow *iw) +{ + g_list_free_full (iw->tabs, (GDestroyNotify) initial_tab_free); + g_free (iw->geometry); + g_free (iw->role); + g_slice_free (InitialWindow, iw); +} + +static void +apply_window_defaults (TerminalOptions *options, + InitialWindow *iw) +{ + if (options->default_role) + { + iw->role = options->default_role; + options->default_role = NULL; + } + + if (iw->geometry == NULL) + iw->geometry = g_strdup (options->default_geometry); + + if (options->default_window_menubar_forced) + { + iw->force_menubar_state = TRUE; + iw->menubar_state = options->default_window_menubar_state; + + options->default_window_menubar_forced = FALSE; + } + + iw->start_fullscreen |= options->default_fullscreen; + iw->start_maximized |= options->default_maximize; +} + +static void +apply_tab_defaults (TerminalOptions *options, + InitialTab *it) +{ + it->wait = options->default_wait; +} + +static InitialWindow* +add_new_window (TerminalOptions *options, + char *profile /* adopts */, + gboolean implicit_if_first_window) +{ + InitialWindow *iw; + InitialTab *it; + + iw = initial_window_new (0); + iw->implicit_first_window = (options->initial_windows == NULL) && implicit_if_first_window; + apply_window_defaults (options, iw); + + it = initial_tab_new (profile); + + /* If this is an implicit first window, the new tab should be active */ + if (iw->implicit_first_window) + it->active = TRUE; + + iw->tabs = g_list_prepend (NULL, it); + apply_tab_defaults (options, it); + + options->initial_windows = g_list_append (options->initial_windows, iw); + return iw; +} + +static InitialWindow* +ensure_top_window (TerminalOptions *options, + gboolean implicit_if_first_window) +{ + InitialWindow *iw; + + if (options->initial_windows == NULL) + iw = add_new_window (options, NULL /* profile */, implicit_if_first_window); + else + iw = g_list_last (options->initial_windows)->data; + + g_assert_nonnull (iw->tabs); + + return iw; +} + +static InitialTab* +ensure_top_tab (TerminalOptions *options) +{ + InitialWindow *iw; + InitialTab *it; + + iw = ensure_top_window (options, TRUE); + + g_assert_nonnull (iw->tabs); + + it = g_list_last (iw->tabs)->data; + + return it; +} + +/* handle deprecated command line options */ + +static void +deprecated_option_warning (const gchar *option_name) +{ + terminal_printerr (_("Option “%s” is deprecated and might be removed in a later version of gnome-terminal."), + option_name); + terminal_printerr ("\n"); +} + +static void +deprecated_command_option_warning (const char *option_name) +{ + deprecated_option_warning (option_name); + + /* %s is being replaced with "-- " (without quotes), which must be used literally, not translatable */ + terminal_printerr (_("Use “%s” to terminate the options and put the command line to execute after it."), "-- "); + terminal_printerr ("\n"); +} + +static gboolean +unsupported_option_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + terminal_printerr (_("Option “%s” is no longer supported in this version of gnome-terminal."), + option_name); + terminal_printerr ("\n"); + return TRUE; /* we do not want to bail out here but continue */ +} + +static gboolean +unsupported_option_fatal_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_UNKNOWN_OPTION, + _("Option “%s” is no longer supported in this version of gnome-terminal."), + option_name); + return FALSE; +} + + +static gboolean G_GNUC_NORETURN +option_version_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + terminal_print ("GNOME Terminal %s using VTE %u.%u.%u %s\n", + VERSION, + vte_get_major_version (), + vte_get_minor_version (), + vte_get_micro_version (), + vte_get_features ()); + exit (EXIT_SUCCESS); +} + +static gboolean +option_verbosity_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + if (g_str_equal (option_name, "--quiet") || g_str_equal (option_name, "-q")) + verbosity = 0; + else + verbosity++; + + return TRUE; +} + +static gboolean +option_app_id_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (!g_application_id_is_valid (value)) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "\"%s\" is not a valid application ID", value); + return FALSE; + } + + g_free (options->server_app_id); + options->server_app_id = g_strdup (value); + + return TRUE; +} + +static gboolean +option_command_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + GError *err = NULL; + char **exec_argv; + + deprecated_command_option_warning (option_name); + + if (!g_shell_parse_argv (value, NULL, &exec_argv, &err)) + { + g_set_error(error, + G_OPTION_ERROR, + G_OPTION_ERROR_BAD_VALUE, + _("Argument to “%s” is not a valid command: %s"), + "--command/-e", + err->message); + g_error_free (err); + return FALSE; + } + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_strfreev (it->exec_argv); + it->exec_argv = exec_argv; + } + else + { + g_strfreev (options->exec_argv); + options->exec_argv = exec_argv; + } + + return TRUE; +} + +static gboolean +option_profile_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + char *profile; + + profile = terminal_profiles_list_dup_uuid_or_name (terminal_options_ensure_profiles_list (options), + value, error); + if (profile == NULL) + { + terminal_printerr ("Profile '%s' specified but not found. Attempting to fall back " + "to the default profile.\n", value); + g_clear_error (error); + profile = terminal_profiles_list_dup_uuid_or_name (terminal_options_ensure_profiles_list (options), + NULL, error); + } + + if (profile == NULL) + return FALSE; + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_free (it->profile); + it->profile = profile; + } + else + { + g_free (options->default_profile); + options->default_profile = profile; + } + + return TRUE; +} + +static gboolean +option_profile_id_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + char *profile; + + profile = terminal_profiles_list_dup_uuid (terminal_options_ensure_profiles_list (options), + value, error); + if (profile == NULL) + return FALSE; + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_free (it->profile); + it->profile = profile; + } + else + { + g_free (options->default_profile); + options->default_profile = profile; + } + + return TRUE; +} + + +static gboolean +option_window_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + char *profile; + + if (value != NULL) { + profile = terminal_profiles_list_dup_uuid_or_name (terminal_options_ensure_profiles_list (options), + value, error); + + if (value && profile == NULL) { + terminal_printerr ("Profile '%s' specified but not found. Attempting to fall back " + "to the default profile.\n", value); + g_clear_error (error); + profile = terminal_profiles_list_dup_uuid_or_name (terminal_options_ensure_profiles_list (options), + NULL, error); + } + + if (profile == NULL) + return FALSE; + } else + profile = NULL; + + add_new_window (options, profile /* adopts */, FALSE); + + return TRUE; +} + +static gboolean +option_tab_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + char *profile; + + if (value != NULL) { + profile = terminal_profiles_list_dup_uuid_or_name (terminal_options_ensure_profiles_list (options), + value, error); + if (profile == NULL) + return FALSE; + } else + profile = NULL; + + if (options->initial_windows) + { + InitialWindow *iw; + + iw = g_list_last (options->initial_windows)->data; + iw->tabs = g_list_append (iw->tabs, initial_tab_new (profile /* adopts */)); + } + else + add_new_window (options, profile /* adopts */, TRUE); + + return TRUE; +} + +static gboolean +option_role_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialWindow *iw; + + if (options->initial_windows) + { + iw = g_list_last (options->initial_windows)->data; + iw->role = g_strdup (value); + } + else if (!options->default_role) + options->default_role = g_strdup (value); + else + { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_FAILED, + "%s", _("Two roles given for one window")); + return FALSE; + } + + return TRUE; +} + +static gboolean +option_show_menubar_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialWindow *iw; + + if (options->initial_windows) + { + iw = g_list_last (options->initial_windows)->data; + if (iw->force_menubar_state && iw->menubar_state == TRUE) + { + terminal_printerr_detail (_("“%s” option given twice for the same window\n"), + "--show-menubar"); + + return TRUE; + } + + iw->force_menubar_state = TRUE; + iw->menubar_state = TRUE; + } + else + { + options->default_window_menubar_forced = TRUE; + options->default_window_menubar_state = TRUE; + } + + return TRUE; +} + +static gboolean +option_hide_menubar_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialWindow *iw; + + if (options->initial_windows) + { + iw = g_list_last (options->initial_windows)->data; + + if (iw->force_menubar_state && iw->menubar_state == FALSE) + { + terminal_printerr_detail (_("“%s” option given twice for the same window\n"), + "--hide-menubar"); + return TRUE; + } + + iw->force_menubar_state = TRUE; + iw->menubar_state = FALSE; + } + else + { + options->default_window_menubar_forced = TRUE; + options->default_window_menubar_state = FALSE; + } + + return TRUE; +} + +static gboolean +option_maximize_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialWindow *iw; + + if (options->initial_windows) + { + iw = g_list_last (options->initial_windows)->data; + iw->start_maximized = TRUE; + } + else + options->default_maximize = TRUE; + + return TRUE; +} + +static gboolean +option_fullscreen_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (options->initial_windows) + { + InitialWindow *iw; + + iw = g_list_last (options->initial_windows)->data; + iw->start_fullscreen = TRUE; + } + else + options->default_fullscreen = TRUE; + + return TRUE; +} + +static gboolean +option_geometry_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (options->initial_windows) + { + InitialWindow *iw; + + iw = g_list_last (options->initial_windows)->data; + iw->geometry = g_strdup (value); + } + else + options->default_geometry = g_strdup (value); + + return TRUE; +} + +static gboolean +option_load_config_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + GFile *file; + char *config_file; + GKeyFile *key_file; + gboolean result; + + file = g_file_new_for_commandline_arg (value); + config_file = g_file_get_path (file); + g_object_unref (file); + + key_file = g_key_file_new (); + result = g_key_file_load_from_file (key_file, config_file, 0, error) && + terminal_options_merge_config (options, key_file, + strcmp (option_name, "load-config") == 0 ? SOURCE_DEFAULT : SOURCE_SESSION, + error); + g_key_file_free (key_file); + g_free (config_file); + + return result; +} + +static gboolean +option_title_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_free (it->title); + it->title = g_strdup (value); + } + else + { + g_free (options->default_title); + options->default_title = g_strdup (value); + } + + return TRUE; +} + +static gboolean +option_working_directory_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_free (it->working_dir); + it->working_dir = g_strdup (value); + } + else + { + g_free (options->default_working_dir); + options->default_working_dir = g_strdup (value); + } + + return TRUE; +} + +static gboolean +option_wait_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + + g_free (it->working_dir); + it->wait = TRUE; + } + else + { + options->default_wait = TRUE; + } + + return TRUE; +} + +static gboolean +option_pass_fd_cb (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + + errno = 0; + char *end; + gint64 v = g_ascii_strtoll (value, &end, 10); + if (errno || end == value || v == -1 || v < G_MININT || v > G_MAXINT) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "Failed to parse \"%s\" as file descriptor number", + value); + return FALSE; + } + + int fd = v; + if (fd == STDIN_FILENO || + fd == STDOUT_FILENO || + fd == STDERR_FILENO) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "FD passing of %s is not supported", + fd == STDIN_FILENO ? "stdin" : fd == STDOUT_FILENO ? "stdout" : "stderr"); + return FALSE; + } + + InitialTab *it = ensure_top_tab (options); + if (it->fd_list == NULL) + it->fd_list = g_unix_fd_list_new (); + if (it->fd_array == NULL) + it->fd_array = g_array_sized_new (FALSE /* zero terminate */, + TRUE /* clear */, + sizeof (PassFdElement), + 8 /* that should be plenty */); + + + for (guint i = 0; i < it->fd_array->len; i++) { + PassFdElement *e = &g_array_index (it->fd_array, PassFdElement, i); + if (e->fd == fd) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + _("Cannot pass FD %d twice"), fd); + return FALSE; + } + } + + int idx = g_unix_fd_list_append (it->fd_list, fd, error); + if (idx == -1) { + g_prefix_error (error, "%d: ", fd); + return FALSE; + } + + PassFdElement e = { idx, fd }; + g_array_append_val (it->fd_array, e); + +#if 0 + if (fd == STDOUT_FILENO || + fd == STDERR_FILENO) + verbosity = 0; + if (fd == STDIN_FILENO) + it->wait = TRUE; +#endif + + return TRUE; +} + +static gboolean +option_active_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialTab *it; + + it = ensure_top_tab (options); + it->active = TRUE; + + return TRUE; +} + +static gboolean +option_zoom_callback (const gchar *option_name, + const gchar *value, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + double zoom; + char *end; + + /* Try reading a locale-style double first, in case it was + * typed by a person, then fall back to ascii_strtod (we + * always save session in C locale format) + */ + end = NULL; + errno = 0; + zoom = g_strtod (value, &end); + if (end == NULL || *end != '\0') + { + g_set_error (error, + G_OPTION_ERROR, + G_OPTION_ERROR_BAD_VALUE, + _("“%s” is not a valid zoom factor"), + value); + return FALSE; + } + + if (zoom < (TERMINAL_SCALE_MINIMUM + 1e-6)) + { + terminal_printerr (_("Zoom factor “%g” is too small, using %g\n"), + zoom, + TERMINAL_SCALE_MINIMUM); + zoom = TERMINAL_SCALE_MINIMUM; + } + + if (zoom > (TERMINAL_SCALE_MAXIMUM - 1e-6)) + { + terminal_printerr (_("Zoom factor “%g” is too large, using %g\n"), + zoom, + TERMINAL_SCALE_MAXIMUM); + zoom = TERMINAL_SCALE_MAXIMUM; + } + + if (options->initial_windows) + { + InitialTab *it = ensure_top_tab (options); + it->zoom = zoom; + it->zoom_set = TRUE; + } + else + { + options->zoom = zoom; + options->zoom_set = TRUE; + } + + return TRUE; +} + +/* Evaluation of the arguments given to the command line options */ +static gboolean +digest_options_callback (GOptionContext *context, + GOptionGroup *group, + gpointer data, + GError **error) +{ + TerminalOptions *options = data; + InitialTab *it; + + if (options->execute) + { + if (options->exec_argv == NULL) + { + g_set_error (error, + G_OPTION_ERROR, + G_OPTION_ERROR_BAD_VALUE, + _("Option “%s” requires specifying the command to run" + " on the rest of the command line"), + "--execute/-x"); + return FALSE; + } + + /* Apply -x/--execute command only to the first tab */ + it = ensure_top_tab (options); + it->exec_argv = options->exec_argv; + options->exec_argv = NULL; + } + + return TRUE; +} + +/** + * terminal_options_parse: + * @argcp: (inout) address of the argument count. Changed if any arguments were handled + * @argvp: (inout) address of the argument vector. Any parameters understood by + * the terminal #GOptionContext are removed + * @error: a #GError to fill in + * + * Parses the argument vector *@argvp. + * + * Returns: a new #TerminalOptions containing the windows and tabs to open, + * or %NULL on error. + */ +TerminalOptions * +terminal_options_parse (int *argcp, + char ***argvp, + GError **error) +{ + TerminalOptions *options; + GOptionContext *context; + gboolean retval; + int i; + char **argv = *argvp; + + options = g_new0 (TerminalOptions, 1); + + options->print_environment = FALSE; + options->default_window_menubar_forced = FALSE; + options->default_window_menubar_state = TRUE; + options->default_fullscreen = FALSE; + options->default_maximize = FALSE; + options->execute = FALSE; + + const char *startup_id = g_getenv ("DESKTOP_STARTUP_ID"); + if (startup_id && startup_id[0] && + g_utf8_validate (startup_id, -1, NULL)) + options->startup_id = g_strdup (startup_id); + else + options->startup_id = NULL; + options->display_name = NULL; + options->initial_windows = NULL; + options->default_role = NULL; + options->default_geometry = NULL; + options->default_title = NULL; + options->zoom = 1.0; + options->zoom_set = FALSE; + + options->default_working_dir = g_get_current_dir (); + + /* Collect info from gnome-terminal private env vars */ + const char *server_unique_name = g_getenv (TERMINAL_ENV_SERVICE_NAME); + if (server_unique_name != NULL) { + if (g_dbus_is_unique_name (server_unique_name)) + options->server_unique_name = g_strdup (server_unique_name); + else + terminal_printerr ("Warning: %s set but \"%s\" is not a unique D-Bus name.\n", + TERMINAL_ENV_SERVICE_NAME, + server_unique_name); + } + + const char *parent_screen_object_path = g_getenv (TERMINAL_ENV_SCREEN); + if (parent_screen_object_path != NULL) { + if (g_variant_is_object_path (parent_screen_object_path)) + options->parent_screen_object_path = g_strdup (parent_screen_object_path); + else + terminal_printerr ("Warning: %s set but \"%s\" is not a valid D-Bus object path.\n", + TERMINAL_ENV_SCREEN, + parent_screen_object_path); + } + + /* The old -x/--execute option is broken, so we need to pre-scan for it. */ + /* We now also support passing the command after the -- switch. */ + options->exec_argv = NULL; + for (i = 1 ; i < *argcp; ++i) + { + gboolean is_execute; + gboolean is_dashdash; + int j, last; + + is_execute = strcmp (argv[i], "-x") == 0 || strcmp (argv[i], "--execute") == 0; + is_dashdash = strcmp (argv[i], "--") == 0; + + if (!is_execute && !is_dashdash) + continue; + + if (is_execute) + deprecated_command_option_warning (argv[i]); + + options->execute = is_execute; + + /* Skip the switch */ + last = i; + ++i; + if (i == *argcp) + break; /* we'll complain about this later for -x/--execute; it's fine for -- */ + + /* Collect the args, and remove them from argv */ + options->exec_argv = g_new0 (char*, *argcp - i + 1); + for (j = 0; i < *argcp; ++i, ++j) + options->exec_argv[j] = g_strdup (argv[i]); + options->exec_argv[j] = NULL; + + *argcp = last; + break; + } + + context = get_goption_context (options); + retval = g_option_context_parse (context, argcp, argvp, error); + g_option_context_free (context); + + if (!retval) { + terminal_options_free (options); + return NULL; + } + + /* Do this here so that gdk_display is initialized */ + if (options->startup_id == NULL) + options->startup_id = terminal_client_get_fallback_startup_id (); + /* Still NULL? */ + if (options->startup_id == NULL) + terminal_printerr_detail ("Warning: DESKTOP_STARTUP_ID not set and no fallback available.\n"); + + GdkDisplay *display = gdk_display_get_default (); + if (display != NULL) + options->display_name = g_strdup (gdk_display_get_name (display)); + + /* Sanity check */ + guint wait = 0; + for (GList *lw = options->initial_windows; lw != NULL; lw = lw->next) { + InitialWindow *iw = lw->data; + for (GList *lt = iw->tabs; lt != NULL; lt = lt->next) { + InitialTab *it = lt->data; + if (it->wait) + wait++; + } + } + + if (wait > 1) { + g_set_error_literal (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + _("Can only use --wait once")); + return FALSE; + } + + options->wait = wait != 0; + return options; +} + +/** + * terminal_options_merge_config: + * @options: + * @key_file: a #GKeyFile containing to merge the options from + * @source_tag: a source_tag to use in new #InitialWindows + * @error: a #GError to fill in + * + * Merges the saved options from @key_file into @options. + * + * Returns: %TRUE if @key_file was a valid key file containing a stored + * terminal configuration, or %FALSE on error + */ +gboolean +terminal_options_merge_config (TerminalOptions *options, + GKeyFile *key_file, + guint source_tag, + GError **error) +{ + int version, compat_version; + char **groups; + guint i; + gboolean have_error = FALSE; + GList *initial_windows = NULL; + + if (!g_key_file_has_group (key_file, TERMINAL_CONFIG_GROUP)) + { + g_set_error_literal (error, TERMINAL_OPTION_ERROR, + TERMINAL_OPTION_ERROR_INVALID_CONFIG_FILE, + _("Not a valid terminal config file.")); + return FALSE; + } + + version = g_key_file_get_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_VERSION, NULL); + compat_version = g_key_file_get_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_COMPAT_VERSION, NULL); + + if (version <= 0 || + compat_version <= 0 || + compat_version > TERMINAL_CONFIG_COMPAT_VERSION) + { + g_set_error_literal (error, TERMINAL_OPTION_ERROR, + TERMINAL_OPTION_ERROR_INCOMPATIBLE_CONFIG_FILE, + _("Incompatible terminal config file version.")); + return FALSE; + } + + groups = g_key_file_get_string_list (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_WINDOWS, NULL, error); + if (!groups) + return FALSE; + + for (i = 0; groups[i]; ++i) + { + const char *window_group = groups[i]; + char *active_terminal; + char **tab_groups; + InitialWindow *iw; + guint j; + + tab_groups = g_key_file_get_string_list (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_TABS, NULL, error); + if (!tab_groups) + continue; /* no tabs in this window, skip it */ + + iw = initial_window_new (source_tag); + initial_windows = g_list_append (initial_windows, iw); + apply_window_defaults (options, iw); + + active_terminal = g_key_file_get_string (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_ACTIVE_TAB, NULL); + iw->role = g_key_file_get_string (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_ROLE, NULL); + iw->geometry = g_key_file_get_string (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_GEOMETRY, NULL); + iw->start_fullscreen = g_key_file_get_boolean (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_FULLSCREEN, NULL); + iw->start_maximized = g_key_file_get_boolean (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_MAXIMIZED, NULL); + if (g_key_file_has_key (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_MENUBAR_VISIBLE, NULL)) + { + iw->force_menubar_state = TRUE; + iw->menubar_state = g_key_file_get_boolean (key_file, window_group, TERMINAL_CONFIG_WINDOW_PROP_MENUBAR_VISIBLE, NULL); + } + + for (j = 0; tab_groups[j]; ++j) + { + const char *tab_group = tab_groups[j]; + InitialTab *it; + char *profile; + + profile = g_key_file_get_string (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_PROFILE_ID, NULL); + it = initial_tab_new (profile /* adopts */); + + iw->tabs = g_list_append (iw->tabs, it); + + if (g_strcmp0 (active_terminal, tab_group) == 0) + it->active = TRUE; + +/* it->width = g_key_file_get_integer (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_WIDTH, NULL); + it->height = g_key_file_get_integer (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_HEIGHT, NULL);*/ + it->working_dir = terminal_util_key_file_get_string_unescape (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_WORKING_DIRECTORY, NULL); + it->title = g_key_file_get_string (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_TITLE, NULL); + + if (g_key_file_has_key (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_COMMAND, NULL) && + !(it->exec_argv = terminal_util_key_file_get_argv (key_file, tab_group, TERMINAL_CONFIG_TERMINAL_PROP_COMMAND, NULL, error))) + { + have_error = TRUE; + break; + } + } + + g_free (active_terminal); + g_strfreev (tab_groups); + + if (have_error) + break; + } + + g_strfreev (groups); + + if (have_error) + { + g_list_free_full (initial_windows, (GDestroyNotify) initial_window_free); + return FALSE; + } + + options->initial_windows = g_list_concat (options->initial_windows, initial_windows); + + return TRUE; +} + +/** + * terminal_options_ensure_window: + * @options: + * + * Ensure that @options will contain at least one window to open. + */ +void +terminal_options_ensure_window (TerminalOptions *options) +{ + gs_unref_object GSettings *global_settings = + g_settings_new (TERMINAL_SETTING_SCHEMA); + + gs_free char *mode_str = g_settings_get_string (global_settings, + TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY); + + gboolean implicit_if_first_window = g_str_equal (mode_str, "tab"); + ensure_top_window (options, implicit_if_first_window); +} + +/** + * terminal_options_free: + * @options: + * + * Frees @options. + */ +void +terminal_options_free (TerminalOptions *options) +{ + g_list_free_full (options->initial_windows, (GDestroyNotify) initial_window_free); + + g_free (options->default_role); + g_free (options->default_geometry); + g_free (options->default_working_dir); + g_free (options->default_title); + g_free (options->default_profile); + + g_strfreev (options->exec_argv); + + g_free (options->server_unique_name); + g_free (options->parent_screen_object_path); + + g_free (options->display_name); + g_free (options->startup_id); + g_free (options->server_app_id); + + g_free (options->sm_client_id); + g_free (options->sm_config_prefix); + + g_clear_object (&options->profiles_list); + + g_free (options); +} + +static GOptionContext * +get_goption_context (TerminalOptions *options) +{ + const GOptionEntry global_unique_goptions[] = { + { + "app-id", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_app_id_callback, + "Server application ID", + "ID" + }, + { + "disable-factory", + 0, + G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + unsupported_option_fatal_callback, + N_("Do not register with the activation nameserver, do not re-use an active terminal"), + NULL + }, + { + "load-config", + 0, + G_OPTION_FLAG_FILENAME, + G_OPTION_ARG_CALLBACK, + option_load_config_cb, + N_("Load a terminal configuration file"), + N_("FILE") + }, + { + "save-config", + 0, + G_OPTION_FLAG_FILENAME | G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + unsupported_option_callback, + NULL, NULL + }, + { + "no-environment", + 0, + 0, + G_OPTION_ARG_NONE, + &options->no_environment, + N_("Do not pass the environment"), + NULL + }, + { + "preferences", + 0, + 0, + G_OPTION_ARG_NONE, + &options->show_preferences, + N_("Show preferences window"), + NULL + }, + { + "print-environment", + 'p', + 0, + G_OPTION_ARG_NONE, + &options->print_environment, + N_("Print environment variables to interact with the terminal"), + NULL + }, + { + "version", + 0, + G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_version_cb, + NULL, + NULL + }, + { + "verbose", + 'v', + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_verbosity_cb, + N_("Increase diagnostic verbosity"), + NULL + }, + { + "quiet", + 'q', + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_verbosity_cb, + N_("Suppress output"), + NULL + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + const GOptionEntry global_multiple_goptions[] = { + { + "window", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_window_callback, + N_("Open a new window containing a tab with the default profile"), + NULL + }, + { + "tab", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_tab_callback, + N_("Open a new tab in the last-opened window with the default profile"), + NULL + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + const GOptionEntry window_goptions[] = { + { + "show-menubar", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_show_menubar_callback, + N_("Turn on the menubar"), + NULL + }, + { + "hide-menubar", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_hide_menubar_callback, + N_("Turn off the menubar"), + NULL + }, + { + "maximize", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_maximize_callback, + N_("Maximize the window"), + NULL + }, + { + "full-screen", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_fullscreen_callback, + N_("Full-screen the window"), + NULL + }, + { + "geometry", + 0, + 0, + G_OPTION_ARG_CALLBACK, + option_geometry_callback, + N_("Set the window size; for example: 80x24, or 80x24+200+200 (COLSxROWS+X+Y)"), + N_("GEOMETRY") + }, + { + "role", + 0, + 0, + G_OPTION_ARG_CALLBACK, + option_role_callback, + N_("Set the window role"), + N_("ROLE") + }, + { + "active", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_active_callback, + N_("Set the last specified tab as the active one in its window"), + NULL + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + const GOptionEntry terminal_goptions[] = { + { + "command", + 'e', + G_OPTION_FLAG_FILENAME, + G_OPTION_ARG_CALLBACK, + option_command_callback, + N_("Execute the argument to this option inside the terminal"), + NULL + }, + { + "profile", + 0, + 0, + G_OPTION_ARG_CALLBACK, + option_profile_cb, + N_("Use the given profile instead of the default profile"), + N_("PROFILE-NAME") + }, + { + "title", + 't', + 0, + G_OPTION_ARG_CALLBACK, + option_title_callback, + N_("Set the initial terminal title"), + N_("TITLE") + }, + { + "working-directory", + 0, + G_OPTION_FLAG_FILENAME, + G_OPTION_ARG_CALLBACK, + option_working_directory_callback, + N_("Set the working directory"), + N_("DIRNAME") + }, + { + "wait", + 0, + G_OPTION_FLAG_NO_ARG, + G_OPTION_ARG_CALLBACK, + option_wait_cb, + N_("Wait until the child exits"), + NULL + }, + { + "fd", + 0, + 0, + G_OPTION_ARG_CALLBACK, + option_pass_fd_cb, + N_("Forward file descriptor"), + /* FD = file descriptor */ + N_("FD") + }, + { + "zoom", + 0, + 0, + G_OPTION_ARG_CALLBACK, + option_zoom_callback, + N_("Set the terminal’s zoom factor (1.0 = normal size)"), + N_("ZOOM") + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + const GOptionEntry internal_goptions[] = { + { + "profile-id", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_profile_id_cb, + NULL, NULL + }, + { + "window-with-profile", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_window_callback, + NULL, NULL + }, + { + "tab-with-profile", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_tab_callback, + NULL, NULL + }, + { + "window-with-profile-internal-id", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_window_callback, + NULL, NULL + }, + { + "tab-with-profile-internal-id", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + option_tab_callback, + NULL, NULL + }, + { + "default-working-directory", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_FILENAME, + &options->default_working_dir, + NULL, NULL, + }, + { + "use-factory", + 0, + G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_CALLBACK, + unsupported_option_callback, + NULL, NULL + }, + { + "startup-id", + 0, + G_OPTION_FLAG_HIDDEN, + G_OPTION_ARG_STRING, + &options->startup_id, + NULL, + NULL + }, + { NULL, 0, 0, 0, NULL, NULL, NULL } + }; + + const GOptionEntry smclient_goptions[] = { + { "sm-client-disable", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options->sm_client_disable, NULL, NULL }, + { "sm-client-state-file", 0, G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_FILENAME, G_OPTION_ARG_CALLBACK, option_load_config_cb, NULL, NULL }, + { "sm-client-id", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options->sm_client_id, NULL, NULL }, + { "sm-disable", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_NONE, &options->sm_client_disable, NULL, NULL }, + { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_STRING, &options->sm_config_prefix, NULL, NULL }, + { NULL } + }; + + GOptionContext *context; + GOptionGroup *group; + gs_free char *parameter; + + parameter = g_strdup_printf ("[-- %s …]", _("COMMAND")); + context = g_option_context_new (parameter); + g_option_context_set_translation_domain (context, GETTEXT_PACKAGE); + g_option_context_set_ignore_unknown_options (context, FALSE); + + g_option_context_add_group (context, gtk_get_option_group (TRUE)); + + group = g_option_group_new ("gnome-terminal", + N_("GNOME Terminal Emulator"), + N_("Show GNOME Terminal options"), + options, + NULL); + g_option_group_set_translation_domain (group, GETTEXT_PACKAGE); + g_option_group_add_entries (group, global_unique_goptions); + g_option_group_add_entries (group, internal_goptions); + g_option_group_set_parse_hooks (group, NULL, digest_options_callback); + g_option_context_set_main_group (context, group); + + group = g_option_group_new ("terminal", + N_("Options to open new windows or terminal tabs; more than one of these may be specified:"), + N_("Show terminal options"), + options, + NULL); + g_option_group_set_translation_domain (group, GETTEXT_PACKAGE); + g_option_group_add_entries (group, global_multiple_goptions); + g_option_context_add_group (context, group); + + group = g_option_group_new ("window-options", + N_("Window options; if used before the first --window or --tab argument, sets the default for all windows:"), + N_("Show per-window options"), + options, + NULL); + g_option_group_set_translation_domain (group, GETTEXT_PACKAGE); + g_option_group_add_entries (group, window_goptions); + g_option_context_add_group (context, group); + + group = g_option_group_new ("terminal-options", + N_("Terminal options; if used before the first --window or --tab argument, sets the default for all terminals:"), + N_("Show per-terminal options"), + options, + NULL); + g_option_group_set_translation_domain (group, GETTEXT_PACKAGE); + g_option_group_add_entries (group, terminal_goptions); + g_option_context_add_group (context, group); + + group = g_option_group_new ("sm-client", "", "", options, NULL); + g_option_group_add_entries (group, smclient_goptions); + g_option_context_add_group (context, group); + + return context; +} diff --git a/src/terminal-options.h b/src/terminal-options.h new file mode 100644 index 0000000..3ac4070 --- /dev/null +++ b/src/terminal-options.h @@ -0,0 +1,193 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_OPTIONS_H +#define TERMINAL_OPTIONS_H + +#include +#include + +#include + +#include "terminal-profiles-list.h" + +G_BEGIN_DECLS + +#define TERMINAL_CONFIG_VERSION (1) /* Bump this for any changes */ +#define TERMINAL_CONFIG_COMPAT_VERSION (1) /* Bump this for incompatible changes */ + +#define TERMINAL_CONFIG_GROUP "GNOME Terminal Configuration" +#define TERMINAL_CONFIG_PROP_VERSION "Version" +#define TERMINAL_CONFIG_PROP_COMPAT_VERSION "CompatVersion" +#define TERMINAL_CONFIG_PROP_WINDOWS "Windows" + +#define TERMINAL_CONFIG_WINDOW_PROP_ACTIVE_TAB "ActiveTerminal" +#define TERMINAL_CONFIG_WINDOW_PROP_FULLSCREEN "Fullscreen" +#define TERMINAL_CONFIG_WINDOW_PROP_GEOMETRY "Geometry" +#define TERMINAL_CONFIG_WINDOW_PROP_MAXIMIZED "Maximized" +#define TERMINAL_CONFIG_WINDOW_PROP_MENUBAR_VISIBLE "MenubarVisible" +#define TERMINAL_CONFIG_WINDOW_PROP_ROLE "Role" +#define TERMINAL_CONFIG_WINDOW_PROP_TABS "Terminals" + +#define TERMINAL_CONFIG_TERMINAL_PROP_HEIGHT "Height" +#define TERMINAL_CONFIG_TERMINAL_PROP_COMMAND "Command" +#define TERMINAL_CONFIG_TERMINAL_PROP_PROFILE_ID "ProfileID" +#define TERMINAL_CONFIG_TERMINAL_PROP_TITLE "Title" +#define TERMINAL_CONFIG_TERMINAL_PROP_WIDTH "Width" +#define TERMINAL_CONFIG_TERMINAL_PROP_WORKING_DIRECTORY "WorkingDirectory" +#define TERMINAL_CONFIG_TERMINAL_PROP_ZOOM "Zoom" + +enum +{ + SOURCE_DEFAULT = 0, + SOURCE_SESSION = 1 +}; + +typedef struct +{ + TerminalSettingsList *profiles_list; /* may be NULL */ + + gboolean print_environment; + + char *server_unique_name; + char *parent_screen_object_path; + + char *server_app_id; + char *startup_id; + char *display_name; + gboolean show_preferences; + GList *initial_windows; + gboolean default_window_menubar_forced; + gboolean default_window_menubar_state; + gboolean default_fullscreen; + gboolean default_maximize; + gboolean default_wait; + char *default_role; + char *default_geometry; + char *default_working_dir; + char *default_title; + char **exec_argv; + char *default_profile; + gboolean default_profile_is_id; + gboolean no_environment; + + gboolean execute; + double zoom; + + gboolean sm_client_disable; + char *sm_client_id; + char *sm_config_prefix; + + guint zoom_set : 1; + guint wait : 1; +} TerminalOptions; + +typedef struct +{ + char *profile; + gboolean profile_is_id; + char **exec_argv; + char *title; + char *working_dir; + double zoom; + GUnixFDList *fd_list; + GArray *fd_array; + guint zoom_set : 1; + guint active : 1; + guint wait : 1; +} InitialTab; + +typedef struct +{ + guint source_tag; + gboolean implicit_first_window; + + GList *tabs; /* list of InitialTab */ + + gboolean force_menubar_state; + gboolean menubar_state; + + gboolean start_fullscreen; + gboolean start_maximized; + + char *geometry; + char *role; + +} InitialWindow; + +#define TERMINAL_OPTION_ERROR (g_quark_from_static_string ("terminal-option-error")) + +typedef enum { + TERMINAL_OPTION_ERROR_NOT_SUPPORTED, + TERMINAL_OPTION_ERROR_NOT_IN_FACTORY, + TERMINAL_OPTION_ERROR_EXCLUSIVE_OPTIONS, + TERMINAL_OPTION_ERROR_INVALID_CONFIG_FILE, + TERMINAL_OPTION_ERROR_INCOMPATIBLE_CONFIG_FILE +} TerminalOptionError; + +TerminalOptions *terminal_options_parse (int *argcp, + char ***argvp, + GError **error); + +gboolean terminal_options_merge_config (TerminalOptions *options, + GKeyFile *key_file, + guint source_tag, + GError **error); + +void terminal_options_ensure_window (TerminalOptions *options); + +const char *terminal_options_get_service_name (TerminalOptions *options); + +const char *terminal_options_get_parent_screen_object_path (TerminalOptions *options); + +void terminal_options_free (TerminalOptions *options); + +typedef enum { + TERMINAL_VERBOSITY_QUIET = 0, + TERMINAL_VERBOSITY_NORMAL = 1, + TERMINAL_VERBOSITY_DETAIL = 2, + TERMINAL_VERBOSITY_DEBUG = 3 +} TerminalVerbosity; + +void terminal_fprintf (FILE* fp, + int verbosity_level, + const char* format, + ...) G_GNUC_PRINTF(3, 4); + +#define terminal_print_level(level,...) terminal_fprintf(stdout, TERMINAL_VERBOSITY_ ## level, __VA_ARGS__) +#define terminal_printerr_level(level,...) terminal_fprintf(stderr, TERMINAL_VERBOSITY_ ## level, __VA_ARGS__) + +#define terminal_print(...) terminal_print_level(NORMAL, __VA_ARGS__) +#define terminal_print_detail(...) terminal_print_level(DETAIL, __VA_ARGS__) +#define terminal_print_debug(...) terminal_print_level(DEBUG, __VA_ARGS__) + +#define terminal_printerr_detail(...) terminal_printerr_level(DETAIL, __VA_ARGS__) +#define terminal_printerr(...) terminal_printerr_level(NORMAL, __VA_ARGS__) +#define terminal_printerr_debug(...) terminal_printerr_level(DEBUG, __VA_ARGS__) + +GLogWriterOutput terminal_log_writer (GLogLevelFlags log_level, + const GLogField *fields, + gsize n_fields, + gpointer user_data); + +G_END_DECLS + +#endif /* !TERMINAL_OPTIONS_H */ diff --git a/src/terminal-pcre2.h b/src/terminal-pcre2.h new file mode 100644 index 0000000..af7e8e4 --- /dev/null +++ b/src/terminal-pcre2.h @@ -0,0 +1,25 @@ +/* + * Copyright © 2015 Christian Persch + * + * This library is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public + * License as published by the Free Software Foundation; either + * version 3 of the License, or (at your option) any later version. + * + * This programme is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU + * General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#pragma once + +#ifdef __VTE_VTE_H__ +#error "Must include terminal-pcre2.h before vte/vte.h" +#endif + +#define PCRE2_CODE_UNIT_WIDTH 0 +#include diff --git a/src/terminal-prefs.c b/src/terminal-prefs.c new file mode 100644 index 0000000..05d2cf8 --- /dev/null +++ b/src/terminal-prefs.c @@ -0,0 +1,922 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington, Red Hat Inc. + * Copyright © 2008, 2011, 2012, 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include +#include + +#include +#include +#include + +#include "profile-editor.h" +#include "terminal-prefs.h" +#include "terminal-accels.h" +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-schemas.h" +#include "terminal-util.h" +#include "terminal-profiles-list.h" +#include "terminal-libgsystem.h" + +PrefData *the_pref_data = NULL; /* global */ + +/* Bottom */ + +static void +prefs_dialog_help_button_clicked_cb (GtkWidget *button, + PrefData *data) +{ + terminal_util_show_help ("pref"); +} + +static void +prefs_dialog_close_button_clicked_cb (GtkWidget *button, + PrefData *data) +{ + gtk_widget_destroy (data->dialog); +} + +/* Sidebar */ + +static inline GSimpleAction * +lookup_action (GtkWindow *window, + const char *name) +{ + GAction *action; + + action = g_action_map_lookup_action (G_ACTION_MAP (window), name); + g_return_val_if_fail (action != NULL, NULL); + + return G_SIMPLE_ACTION (action); +} + +/* Update the sidebar (visibility of icons, sensitivity of menu entries) to reflect the default and the selected profiles. */ +static void +listbox_update (GtkListBox *box) +{ + int i; + GtkListBoxRow *row; + GSettings *profile; + gs_unref_object GSettings *default_profile; + GtkStack *stack; + GtkMenuButton *button; + + default_profile = terminal_settings_list_ref_default_child (the_pref_data->profiles_list); + + /* GTK+ doesn't seem to like if a popover is assigned to multiple buttons at once + * (not even temporarily), so make sure to remove it from the previous button first. */ + for (i = 0; (row = gtk_list_box_get_row_at_index (box, i)) != NULL; i++) { + button = g_object_get_data (G_OBJECT (row), "popover-button"); + gtk_menu_button_set_popover (button, NULL); + } + + for (i = 0; (row = gtk_list_box_get_row_at_index (box, i)) != NULL; i++) { + profile = g_object_get_data (G_OBJECT (row), "gsettings"); + + gboolean is_selected_profile = (profile != NULL && profile == the_pref_data->selected_profile); + gboolean is_default_profile = (profile != NULL && profile == default_profile); + + stack = g_object_get_data (G_OBJECT (row), "home-stack"); + gtk_stack_set_visible_child_name (stack, is_default_profile ? "home" : "placeholder"); + + stack = g_object_get_data (G_OBJECT (row), "popover-stack"); + gtk_stack_set_visible_child_name (stack, is_selected_profile ? "button" : "placeholder"); + if (is_selected_profile) { + g_simple_action_set_enabled (lookup_action (GTK_WINDOW (the_pref_data->dialog), "delete"), !is_default_profile); + g_simple_action_set_enabled (lookup_action (GTK_WINDOW (the_pref_data->dialog), "set-as-default"), !is_default_profile); + + GtkPopover *popover_menu = GTK_POPOVER (gtk_builder_get_object (the_pref_data->builder, "popover-menu")); + button = g_object_get_data (G_OBJECT (row), "popover-button"); + gtk_menu_button_set_popover (button, GTK_WIDGET (popover_menu)); + gtk_popover_set_relative_to (popover_menu, GTK_WIDGET (button)); + } + } +} + +static void +update_window_title (void) +{ + GtkListBoxRow *row = the_pref_data->selected_list_box_row; + if (row == NULL) + return; + + GSettings *profile = g_object_get_data (G_OBJECT (row), "gsettings"); + GtkLabel *label = g_object_get_data (G_OBJECT (row), "label"); + const char *text = gtk_label_get_text (label); + gs_free char *subtitle; + gs_free char *title; + + if (profile == NULL) { + subtitle = g_strdup (text); + } else { + subtitle = g_strdup_printf (_("Profile “%s”"), text); + } + + title = g_strdup_printf (_("Preferences – %s"), subtitle); + gtk_window_set_title (GTK_WINDOW (the_pref_data->dialog), title); +} + +/* A new entry is selected in the sidebar */ +static void +listbox_row_selected_cb (GtkListBox *box, + GtkListBoxRow *row, + GtkStack *stack) +{ + profile_prefs_unload (); + + /* row can be NULL intermittently during a profile meta operations */ + g_free (the_pref_data->selected_profile_uuid); + if (row != NULL) { + the_pref_data->selected_profile = g_object_get_data (G_OBJECT (row), "gsettings"); + the_pref_data->selected_profile_uuid = g_strdup (g_object_get_data (G_OBJECT (row), "uuid")); + } else { + the_pref_data->selected_profile = NULL; + the_pref_data->selected_profile_uuid = NULL; + } + the_pref_data->selected_list_box_row = row; + + listbox_update (box); + + if (row != NULL) { + if (the_pref_data->selected_profile != NULL) { + profile_prefs_load (the_pref_data->selected_profile_uuid, the_pref_data->selected_profile); + } + + char *stack_child_name = g_object_get_data (G_OBJECT (row), "stack_child_name"); + gtk_stack_set_visible_child_name (stack, stack_child_name); + } + + update_window_title (); +} + +/* A profile's name changed, perhaps externally */ +static void +profile_name_changed_cb (GtkLabel *label, + GParamSpec *pspec, + GtkListBoxRow *row) +{ + gtk_list_box_row_changed (row); /* trigger re-sorting */ + + if (row == the_pref_data->selected_list_box_row) + update_window_title (); +} + +/* Select a profile in the sidebar by UUID */ +static gboolean +listbox_select_profile (const char *uuid) +{ + GtkListBoxRow *row; + for (int i = 0; (row = gtk_list_box_get_row_at_index (the_pref_data->listbox, i)) != NULL; i++) { + const char *rowuuid = g_object_get_data (G_OBJECT (row), "uuid"); + if (g_strcmp0 (rowuuid, uuid) == 0) { + g_signal_emit_by_name (row, "activate"); + return TRUE; + } + } + return FALSE; +} + +/* Create a new profile now, select it, update the UI. */ +static void +profile_new_now (const char *name) +{ + gs_free char *uuid = terminal_app_new_profile (terminal_app_get (), NULL, name); + + listbox_select_profile (uuid); +} + +/* Clone the selected profile now, select it, update the UI. */ +static void +profile_clone_now (const char *name) +{ + if (the_pref_data->selected_profile == NULL) + return; + + gs_free char *uuid = terminal_app_new_profile (terminal_app_get (), the_pref_data->selected_profile, name); + + listbox_select_profile (uuid); +} + +/* Rename the selected profile now, update the UI. */ +static void +profile_rename_now (const char *name) +{ + if (the_pref_data->selected_profile == NULL) + return; + + /* This will automatically trigger a call to profile_name_changed_cb(). */ + g_settings_set_string (the_pref_data->selected_profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY, name); +} + +/* Delete the selected profile now, update the UI. */ +static void +profile_delete_now (const char *dummy) +{ + if (the_pref_data->selected_profile == NULL) + return; + + /* Prepare to select the next one, or if there's no such then the previous one. */ + int index = gtk_list_box_row_get_index (the_pref_data->selected_list_box_row); + GtkListBoxRow *new_selected_row = gtk_list_box_get_row_at_index (the_pref_data->listbox, index + 1); + if (new_selected_row == NULL) + new_selected_row = gtk_list_box_get_row_at_index (the_pref_data->listbox, index - 1); + GSettings *new_selected_profile = g_object_get_data (G_OBJECT (new_selected_row), "gsettings"); + gs_free char *uuid = NULL; + if (new_selected_profile != NULL) + uuid = terminal_settings_list_dup_uuid_from_child (the_pref_data->profiles_list, new_selected_profile); + + terminal_app_remove_profile (terminal_app_get (), the_pref_data->selected_profile); + + listbox_select_profile (uuid); +} + +/* "Set as default" selected. Do it now without asking for confirmation. */ +static void +profile_set_as_default_cb (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + if (the_pref_data->selected_profile_uuid == NULL) + return; + + /* This will automatically trigger a call to listbox_update() via "default-changed". */ + terminal_settings_list_set_default_child (the_pref_data->profiles_list, the_pref_data->selected_profile_uuid); +} + + +static void +popover_dialog_cancel_clicked_cb (GtkButton *button, + gpointer user_data) +{ + GtkPopover *popover_dialog = GTK_POPOVER (gtk_builder_get_object (the_pref_data->builder, "popover-dialog")); + + gtk_popover_popdown (popover_dialog); +} + +static void +popover_dialog_ok_clicked_cb (GtkButton *button, + void (*fn) (const char *)) +{ + GtkEntry *entry = GTK_ENTRY (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-entry")); + const char *name = gtk_entry_get_text (entry); + + /* Perform what we came for */ + (*fn) (name); + + /* Hide/popdown the popover */ + popover_dialog_cancel_clicked_cb (button, NULL); +} + +static void +popover_dialog_closed_cb (GtkPopover *popover, + gpointer user_data) +{ + + GtkEntry *entry = GTK_ENTRY (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-entry")); + gtk_entry_set_text (entry, ""); + + GtkButton *ok = GTK_BUTTON (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-ok")); + GtkButton *cancel = GTK_BUTTON (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-cancel")); + + g_signal_handlers_disconnect_matched (ok, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, + G_CALLBACK (popover_dialog_ok_clicked_cb), NULL); + g_signal_handlers_disconnect_matched (cancel, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, + G_CALLBACK (popover_dialog_cancel_clicked_cb), NULL); + g_signal_handlers_disconnect_matched (popover, G_SIGNAL_MATCH_FUNC, 0, 0, NULL, + G_CALLBACK (popover_dialog_closed_cb), NULL); +} + + +/* Updates the OK button's sensitivity (insensitive if entry field is empty or whitespace only). + * The entry's initial value and OK's initial sensitivity have to match in the .ui file. */ +static void +popover_dialog_notify_text_cb (GtkEntry *entry, + GParamSpec *pspec, + GtkWidget *ok) +{ + gs_free char *text = g_strchomp (g_strdup (gtk_entry_get_text (entry))); + gtk_widget_set_sensitive (ok, text[0] != '\0'); +} + + +/* Common dialog for entering new profile name, or confirming deletion */ +static void +profile_popup_dialog (GtkWidget *relative_to, + const char *header, + const char *body, + const char *entry_text, + const char *ok_text, + void (*fn) (const char *)) +{ + GtkLabel *label1 = GTK_LABEL (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-label1")); + gtk_label_set_text (label1, header); + + GtkLabel *label2 = GTK_LABEL (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-label2")); + gtk_label_set_text (label2, body); + + GtkEntry *entry = GTK_ENTRY (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-entry")); + if (entry_text != NULL) { + gtk_entry_set_text (entry, entry_text); + gtk_widget_show (GTK_WIDGET (entry)); + } else { + gtk_entry_set_text (entry, "."); /* to make the OK button sensitive */ + gtk_widget_hide (GTK_WIDGET (entry)); + } + + GtkButton *ok = GTK_BUTTON (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-ok")); + gtk_button_set_label (ok, ok_text); + GtkButton *cancel = GTK_BUTTON (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-cancel")); + GtkPopover *popover_dialog = GTK_POPOVER (gtk_builder_get_object (the_pref_data->builder, "popover-dialog")); + + g_signal_connect (ok, "clicked", G_CALLBACK (popover_dialog_ok_clicked_cb), fn); + g_signal_connect (cancel, "clicked", G_CALLBACK (popover_dialog_cancel_clicked_cb), NULL); + g_signal_connect (popover_dialog, "closed", G_CALLBACK (popover_dialog_closed_cb), NULL); + + gtk_popover_set_relative_to (popover_dialog, relative_to); + gtk_popover_set_position (popover_dialog, GTK_POS_BOTTOM); + gtk_popover_set_default_widget (popover_dialog, GTK_WIDGET (ok)); + + gtk_popover_popup (popover_dialog); + + gtk_widget_grab_focus (entry_text != NULL ? GTK_WIDGET (entry) : GTK_WIDGET (cancel)); +} + +/* "New" selected, ask for profile name */ +static void +profile_new_cb (GtkButton *button, + gpointer user_data) +{ + profile_popup_dialog (GTK_WIDGET (the_pref_data->new_profile_button), + _("New Profile"), + _("Enter name for new profile with default settings:"), + "", + _("Create"), + profile_new_now); +} + +/* "Clone" selected, ask for profile name */ +static void +profile_clone_cb (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + gs_free char *name = g_settings_get_string (the_pref_data->selected_profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + + gs_free char *label = g_strdup_printf (_("Enter name for new profile based on “%s”:"), name); + gs_free char *clone_name = g_strdup_printf (_("%s (Copy)"), name); + + profile_popup_dialog (GTK_WIDGET (the_pref_data->selected_list_box_row), + _("Clone Profile"), + label, + clone_name, + _("Clone"), + profile_clone_now); +} + +/* "Rename" selected, ask for new name */ +static void +profile_rename_cb (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + if (the_pref_data->selected_profile == NULL) + return; + + gs_free char *name = g_settings_get_string (the_pref_data->selected_profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + + gs_free char *label = g_strdup_printf (_("Enter new name for profile “%s”:"), name); + + profile_popup_dialog (GTK_WIDGET (the_pref_data->selected_list_box_row), + _("Rename Profile"), + label, + name, + _("Rename"), + profile_rename_now); +} + +/* "Delete" selected, ask for confirmation */ +static void +profile_delete_cb (GSimpleAction *simple, + GVariant *parameter, + gpointer user_data) +{ + if (the_pref_data->selected_profile == NULL) + return; + + gs_free char *name = g_settings_get_string (the_pref_data->selected_profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + + gs_free char *label = g_strdup_printf (_("Really delete profile “%s”?"), name); + + profile_popup_dialog (GTK_WIDGET (the_pref_data->selected_list_box_row), + _("Delete Profile"), + label, + NULL, + _("Delete"), + profile_delete_now); +} + +/* Create a (non-header) row of the sidebar, either a global or a profile entry. */ +static GtkListBoxRow * +listbox_create_row (const char *name, + const char *stack_child_name, + const char *uuid, + GSettings *gsettings /* adopted */, + gpointer sort_order) +{ + GtkListBoxRow *row = GTK_LIST_BOX_ROW (gtk_list_box_row_new ()); + + g_object_set_data_full (G_OBJECT (row), "stack_child_name", g_strdup (stack_child_name), g_free); + g_object_set_data_full (G_OBJECT (row), "uuid", g_strdup (uuid), g_free); + if (gsettings != NULL) + g_object_set_data_full (G_OBJECT (row), "gsettings", gsettings, (GDestroyNotify)g_object_unref); + g_object_set_data (G_OBJECT (row), "sort_order", sort_order); + + GtkBox *hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + gtk_widget_set_margin_start (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_end (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_top (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_bottom (GTK_WIDGET (hbox), 6); + + GtkLabel *label = GTK_LABEL (gtk_label_new (name)); + if (gsettings != NULL) { + g_signal_connect (label, "notify::label", G_CALLBACK (profile_name_changed_cb), row); + g_settings_bind (gsettings, + TERMINAL_PROFILE_VISIBLE_NAME_KEY, + label, + "label", + G_SETTINGS_BIND_GET); + } + gtk_label_set_xalign (label, 0); + gtk_box_pack_start (hbox, GTK_WIDGET (label), TRUE, TRUE, 0); + g_object_set_data (G_OBJECT (row), "label", label); + + /* Always add the "default" symbol and the "menu" button, even on rows of global prefs. + * Use GtkStack to possible achieve visibility:hidden on it. + * This is so that all listbox rows have the same dimensions, and the width doesn't change + * as you switch the default profile. */ + + GtkStack *popover_stack = GTK_STACK (gtk_stack_new ()); + gtk_widget_set_margin_start (GTK_WIDGET (popover_stack), 6); + GtkMenuButton *popover_button = GTK_MENU_BUTTON (gtk_menu_button_new ()); + gtk_button_set_relief (GTK_BUTTON (popover_button), GTK_RELIEF_NONE); + gtk_stack_add_named (popover_stack, GTK_WIDGET (popover_button), "button"); + GtkLabel *popover_label = GTK_LABEL (gtk_label_new ("")); + gtk_stack_add_named (popover_stack, GTK_WIDGET (popover_label), "placeholder"); + g_object_set_data (G_OBJECT (row), "popover-stack", popover_stack); + g_object_set_data (G_OBJECT (row), "popover-button", popover_button); + + gtk_box_pack_end (hbox, GTK_WIDGET (popover_stack), FALSE, FALSE, 0); + + GtkStack *home_stack = GTK_STACK (gtk_stack_new ()); + gtk_widget_set_margin_start (GTK_WIDGET (home_stack), 12); + GtkImage *home_image = GTK_IMAGE (gtk_image_new_from_icon_name ("emblem-default-symbolic", GTK_ICON_SIZE_BUTTON)); + gtk_widget_set_tooltip_text (GTK_WIDGET (home_image), _("This is the default profile")); + gtk_stack_add_named (home_stack, GTK_WIDGET (home_image), "home"); + GtkLabel *home_label = GTK_LABEL (gtk_label_new ("")); + gtk_stack_add_named (home_stack, GTK_WIDGET (home_label), "placeholder"); + g_object_set_data (G_OBJECT (row), "home-stack", home_stack); + + gtk_box_pack_end (hbox, GTK_WIDGET (home_stack), FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (row), GTK_WIDGET (hbox)); + + gtk_widget_show_all (GTK_WIDGET (row)); + + gtk_stack_set_visible_child_name (popover_stack, "placeholder"); + gtk_stack_set_visible_child_name (home_stack, "placeholder"); + + return row; +} + +/* Add all the non-profile rows to the sidebar */ +static void +listbox_add_all_globals (PrefData *data) +{ + GtkListBoxRow *row; + + row = listbox_create_row (_("General"), + "general-prefs", + NULL, NULL, (gpointer) 0); + gtk_list_box_insert (data->listbox, GTK_WIDGET (row), -1); + + row = listbox_create_row (_("Shortcuts"), + "shortcut-prefs", + NULL, NULL, (gpointer) 1); + gtk_list_box_insert (data->listbox, GTK_WIDGET (row), -1); +} + +/* Remove all the profile rows from the sidebar */ +static void +listbox_remove_all_profiles (PrefData *data) +{ + int i = 0; + + data->selected_profile = NULL; + g_free (data->selected_profile_uuid); + data->selected_profile_uuid = NULL; + profile_prefs_unload (); + + GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (the_pref_data->listbox), 0); + g_signal_emit_by_name (row, "activate"); + + while ((row = gtk_list_box_get_row_at_index (data->listbox, i)) != NULL) { + if (g_object_get_data (G_OBJECT (row), "gsettings") != NULL) { + gtk_widget_destroy (GTK_WIDGET (row)); + } else { + i++; + } + } +} + +/* Add all the profiles to the sidebar */ +static void +listbox_add_all_profiles (PrefData *data) +{ + GList *list, *l; + GtkListBoxRow *row; + + list = terminal_settings_list_ref_children (data->profiles_list); + + for (l = list; l != NULL; l = l->next) { + GSettings *profile = (GSettings *) l->data; + gs_free gchar *uuid = terminal_settings_list_dup_uuid_from_child (data->profiles_list, profile); + + row = listbox_create_row (NULL, + "profile-prefs", + uuid, + profile /* adopts */, + (gpointer) 42); + gtk_list_box_insert (data->listbox, GTK_WIDGET (row), -1); + } + + g_list_free(list); /* the items themselves were adopted into the model above */ + + listbox_update (data->listbox); /* FIXME: This is not needed but I don't know why :-) */ +} + +/* Re-add all the profiles to the sidebar. + * This is called when a profile is added or removed, and also when the list of profiles is + * modified externally. + * Try to keep the selected profile, whenever possible. + * When the list is modified externally, the terminal_settings_list_*() methods seem to preserve + * the GSettings object for every profile that remains in the list. There's no guarantee however + * that a newly created GSettings can't receive the same address that a ceased one used to have. + * So don't rely on GSettings* to keep track of the selected profile, use the UUID instead. */ +static void +listbox_readd_profiles (PrefData *data) +{ + gs_free char *uuid = g_strdup (data->selected_profile_uuid); + + listbox_remove_all_profiles (data); + listbox_add_all_profiles (data); + + if (uuid != NULL) + listbox_select_profile (uuid); +} + +/* Create a header row ("Global" or "Profiles +") */ +static GtkWidget * +listboxrow_create_header (const char *text, + gboolean visible_button) +{ + GtkBox *hbox = GTK_BOX (gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0)); + gtk_widget_set_margin_start (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_end (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_top (GTK_WIDGET (hbox), 6); + gtk_widget_set_margin_bottom (GTK_WIDGET (hbox), 6); + + GtkLabel *label = GTK_LABEL (gtk_label_new (NULL)); + gs_free char *markup = g_markup_printf_escaped ("%s", text); + gtk_label_set_markup (label, markup); + gtk_label_set_xalign (label, 0); + gtk_box_pack_start (hbox, GTK_WIDGET (label), TRUE, TRUE, 0); + + /* Always add a "new profile" button. Use GtkStack to possible achieve visibility:hidden on it. + * This is so that both header rows have the same dimensions. */ + + GtkStack *stack = GTK_STACK (gtk_stack_new ()); + GtkButton *button = GTK_BUTTON (gtk_button_new_from_icon_name ("list-add-symbolic", GTK_ICON_SIZE_BUTTON)); + gtk_button_set_relief (button, GTK_RELIEF_NONE); + gtk_stack_add_named (stack, GTK_WIDGET (button), "button"); + GtkLabel *labelx = GTK_LABEL (gtk_label_new ("")); + gtk_stack_add_named (stack, GTK_WIDGET (labelx), "placeholder"); + + gtk_box_pack_end (hbox, GTK_WIDGET (stack), FALSE, FALSE, 0); + + gtk_widget_show_all (GTK_WIDGET (hbox)); + + if (visible_button) { + gtk_stack_set_visible_child_name (stack, "button"); + g_signal_connect (button, "clicked", G_CALLBACK (profile_new_cb), NULL); + the_pref_data->new_profile_button = GTK_WIDGET (button); + } else { + gtk_stack_set_visible_child_name (stack, "placeholder"); + } + + return GTK_WIDGET (hbox); +} + +/* Manage the creation or removal of the header row ("Global" or "Profiles +") */ +static void +listboxrow_update_header (GtkListBoxRow *row, + GtkListBoxRow *before, + gpointer user_data) +{ + if (before == NULL) { + if (gtk_list_box_row_get_header (row) == NULL) { + gtk_list_box_row_set_header (row, listboxrow_create_header (_("Global"), FALSE)); + } + return; + } + + GSettings *profile = g_object_get_data (G_OBJECT (row), "gsettings"); + if (profile != NULL) { + GSettings *profile_before = g_object_get_data (G_OBJECT (before), "gsettings"); + if (profile_before != NULL) { + gtk_list_box_row_set_header (row, NULL); + } else { + if (gtk_list_box_row_get_header (row) == NULL) { + gtk_list_box_row_set_header (row, listboxrow_create_header (_("Profiles"), TRUE)); + } + } + } +} + +/* Sort callback for rows of the sidebar (global and profile ones). + * Global ones are kept at the top in fixed order. This is implemented via sort_order + * which is an integer disguised as a pointer for ease of implementation. + * Profile ones are sorted lexicographically. */ +static gint +listboxrow_compare_cb (GtkListBoxRow *row1, + GtkListBoxRow *row2, + gpointer user_data) +{ + gpointer sort_order_1 = g_object_get_data (G_OBJECT (row1), "sort_order"); + gpointer sort_order_2 = g_object_get_data (G_OBJECT (row2), "sort_order"); + + if (sort_order_1 != sort_order_2) + return sort_order_1 < sort_order_2 ? -1 : 1; + + GtkLabel *label1 = g_object_get_data (G_OBJECT (row1), "label"); + const char *text1 = gtk_label_get_text (label1); + GtkLabel *label2 = g_object_get_data (G_OBJECT (row2), "label"); + const char *text2 = gtk_label_get_text (label2); + + return g_utf8_collate (text1, text2); +} + +/* Keybindings tab */ + +/* Make sure the treeview is repainted with the correct text color, see bug 792139. */ +static void +shortcuts_button_toggled_cb (GtkWidget *widget, + GtkTreeView *tree_view) +{ + gtk_widget_queue_draw (GTK_WIDGET (tree_view)); +} + +/* misc */ + +static void +prefs_dialog_destroy_cb (GtkWidget *widget, + PrefData *data) +{ + /* Don't run this handler again */ + g_signal_handlers_disconnect_by_func (widget, G_CALLBACK (prefs_dialog_destroy_cb), data); + + g_signal_handlers_disconnect_by_func (data->profiles_list, + G_CALLBACK (listbox_readd_profiles), data); + g_signal_handlers_disconnect_by_func (data->profiles_list, + G_CALLBACK (listbox_update), data->listbox); + + profile_prefs_destroy (); + + g_object_unref (data->builder); + g_free (data->selected_profile_uuid); + g_free (data); +} + +void +terminal_prefs_show_preferences (GSettings *profile, const char *widget_name) +{ + TerminalApp *app = terminal_app_get (); + PrefData *data; + GtkWidget *dialog, *tree_view; + GtkWidget *show_menubar_button, *disable_mnemonics_button, *disable_menu_accel_button; + GtkWidget *disable_shortcuts_button; + GtkWidget *theme_variant_label, *theme_variant_combo; + GtkWidget *new_terminal_mode_label, *new_terminal_mode_combo; + GtkWidget *new_tab_position_combo; + GtkWidget *close_button, *help_button; + GtkWidget *content_box, *general_frame, *keybindings_frame; + GSettings *settings; + + const GActionEntry action_entries[] = { + { "clone", profile_clone_cb, NULL, NULL, NULL }, + { "rename", profile_rename_cb, NULL, NULL, NULL }, + { "delete", profile_delete_cb, NULL, NULL, NULL }, + { "set-as-default", profile_set_as_default_cb, NULL, NULL, NULL }, + }; + + if (the_pref_data != NULL) + goto done; + + the_pref_data = g_new0 (PrefData, 1); + data = the_pref_data; + data->profiles_list = terminal_app_get_profiles_list (app); + + /* FIXME this method is only used from here. Inline it here instead. */ + data->builder = terminal_util_load_widgets_resource ("/org/gnome/terminal/ui/preferences.ui", + "preferences-dialog", + "preferences-dialog", &dialog, + "dialogue-content-box", &content_box, + "general-frame", &general_frame, + "keybindings-frame", &keybindings_frame, + "close-button", &close_button, + "help-button", &help_button, + "default-show-menubar-checkbutton", &show_menubar_button, + "theme-variant-label", &theme_variant_label, + "theme-variant-combobox", &theme_variant_combo, + "new-terminal-mode-label", &new_terminal_mode_label, + "new-terminal-mode-combobox", &new_terminal_mode_combo, + "disable-mnemonics-checkbutton", &disable_mnemonics_button, + "disable-shortcuts-checkbutton", &disable_shortcuts_button, + "disable-menu-accel-checkbutton", &disable_menu_accel_button, + "new-tab-position-combobox", &new_tab_position_combo, + "accelerators-treeview", &tree_view, + "the-stack", &data->stack, + "the-listbox", &data->listbox, + NULL); + + data->dialog = dialog; + + gtk_window_set_application (GTK_WINDOW (data->dialog), GTK_APPLICATION (terminal_app_get ())); + + terminal_util_bind_mnemonic_label_sensitivity (dialog); + + settings = terminal_app_get_global_settings (app); + + g_action_map_add_action_entries (G_ACTION_MAP (dialog), + action_entries, G_N_ELEMENTS (action_entries), + data); + + /* Sidebar */ + + gtk_list_box_set_header_func (GTK_LIST_BOX (data->listbox), + listboxrow_update_header, + NULL, + NULL); + g_signal_connect (data->listbox, "row-selected", G_CALLBACK (listbox_row_selected_cb), data->stack); + gtk_list_box_set_sort_func (data->listbox, listboxrow_compare_cb, NULL, NULL); + + listbox_add_all_globals (data); + listbox_add_all_profiles (data); + g_signal_connect_swapped (data->profiles_list, "children-changed", + G_CALLBACK (listbox_readd_profiles), data); + g_signal_connect_swapped (data->profiles_list, "default-changed", + G_CALLBACK (listbox_update), data->listbox); + + GtkEntry *entry = GTK_ENTRY (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-entry")); + GtkButton *ok = GTK_BUTTON (gtk_builder_get_object (the_pref_data->builder, "popover-dialog-ok")); + g_signal_connect (entry, "notify::text", G_CALLBACK (popover_dialog_notify_text_cb), ok); + + /* General page */ + + gboolean shell_shows_menubar; + g_object_get (gtk_settings_get_default (), + "gtk-shell-shows-menubar", &shell_shows_menubar, + NULL); + if (shell_shows_menubar || terminal_app_get_use_headerbar (app)) { + gtk_widget_set_visible (show_menubar_button, FALSE); + } else { + g_settings_bind (settings, + TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY, + show_menubar_button, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + } + + g_settings_bind (settings, + TERMINAL_SETTING_THEME_VARIANT_KEY, + theme_variant_combo, + "active-id", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + if (terminal_app_get_menu_unified (app) || + terminal_app_get_use_headerbar (app)) { + g_settings_bind (settings, + TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY, + new_terminal_mode_combo, + "active-id", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + } else { + gtk_widget_set_visible (new_terminal_mode_label, FALSE); + gtk_widget_set_visible (new_terminal_mode_combo, FALSE); + } + + g_settings_bind (settings, + TERMINAL_SETTING_NEW_TAB_POSITION_KEY, + new_tab_position_combo, + "active-id", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + if (shell_shows_menubar) { + gtk_widget_set_visible (disable_mnemonics_button, FALSE); + } else { + g_settings_bind (settings, + TERMINAL_SETTING_ENABLE_MNEMONICS_KEY, + disable_mnemonics_button, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + } + g_settings_bind (settings, + TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, + disable_menu_accel_button, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + /* Shortcuts page */ + + g_settings_bind (settings, + TERMINAL_SETTING_ENABLE_SHORTCUTS_KEY, + disable_shortcuts_button, + "active", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_SET); + + g_signal_connect (disable_shortcuts_button, "toggled", + G_CALLBACK (shortcuts_button_toggled_cb), tree_view); + + terminal_accels_fill_treeview (tree_view, disable_shortcuts_button); + + /* Profile page */ + + profile_prefs_init (); + + /* Move action widgets to titlebar when headerbar is used */ + if (terminal_app_get_dialog_use_headerbar (app)) { + GtkWidget *headerbar; + GtkWidget *bbox; + + headerbar = g_object_new (GTK_TYPE_HEADER_BAR, + "show-close-button", TRUE, + NULL); + bbox = gtk_widget_get_parent (help_button); + + gtk_container_remove (GTK_CONTAINER (bbox), g_object_ref (help_button)); + gtk_header_bar_pack_start (GTK_HEADER_BAR (headerbar), help_button); + g_object_unref (help_button); + + gtk_style_context_add_class (gtk_widget_get_style_context (help_button), + "text-button"); + + gtk_widget_show (headerbar); + gtk_widget_hide (bbox); + + gtk_window_set_titlebar (GTK_WINDOW (dialog), headerbar); + + /* Remove extra spacing around the content, and extra frames */ + g_object_set (G_OBJECT (content_box), "margin", 0, NULL); + gtk_frame_set_shadow_type (GTK_FRAME (general_frame), GTK_SHADOW_NONE); + gtk_frame_set_shadow_type (GTK_FRAME (keybindings_frame), GTK_SHADOW_NONE); + } + + /* misc */ + + g_signal_connect (close_button, "clicked", G_CALLBACK (prefs_dialog_close_button_clicked_cb), data); + g_signal_connect (help_button, "clicked", G_CALLBACK (prefs_dialog_help_button_clicked_cb), data); + g_signal_connect (dialog, "destroy", G_CALLBACK (prefs_dialog_destroy_cb), data); + + g_object_add_weak_pointer (G_OBJECT (dialog), (gpointer *) &the_pref_data); + +done: + if (profile != NULL) { + gs_free char *uuid = terminal_settings_list_dup_uuid_from_child (the_pref_data->profiles_list, profile); + listbox_select_profile (uuid); + } else { + GtkListBoxRow *row = gtk_list_box_get_row_at_index (GTK_LIST_BOX (the_pref_data->listbox), 0); + g_signal_emit_by_name (row, "activate"); + } + + terminal_util_dialog_focus_widget (the_pref_data->builder, widget_name); + + gtk_window_present (GTK_WINDOW (the_pref_data->dialog)); +} diff --git a/src/terminal-prefs.h b/src/terminal-prefs.h new file mode 100644 index 0000000..ecb4129 --- /dev/null +++ b/src/terminal-prefs.h @@ -0,0 +1,55 @@ +/* + * Copyright © 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_PREFS_H +#define TERMINAL_PREFS_H + +#include + +#include "terminal-profiles-list.h" + +G_BEGIN_DECLS + +/* FIXME move back to the .c file if profile-editor.c is also merged there, + * also remove the terminal-profiles-list.h incude above. */ +/* FIXME PrefData is a very bad name, rename to PrefsDialog maybe? */ + +/* Everything about a preferences dialog */ +typedef struct { + TerminalSettingsList *profiles_list; + + GSettings *selected_profile; + GtkListBoxRow *selected_list_box_row; + char *selected_profile_uuid; /* a copy thereof, to survive changes to profiles_list */ + + GtkBuilder *builder; + GtkWidget *dialog; + GtkListBox *listbox; + GtkWidget *new_profile_button; + GtkWidget *stack; + + GArray *profile_signals; + GArray *profile_bindings; +} PrefData; + +extern PrefData *the_pref_data; /* global */ + +void terminal_prefs_show_preferences (GSettings *profile, const char *widget_name); + +G_END_DECLS + +#endif /* TERMINAL_PREFS_H */ diff --git a/src/terminal-profiles-list.c b/src/terminal-profiles-list.c new file mode 100644 index 0000000..6a85bc1 --- /dev/null +++ b/src/terminal-profiles-list.c @@ -0,0 +1,267 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2011, 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-profiles-list.h" +#include "terminal-schemas.h" +#include "terminal-libgsystem.h" + +#include +#include + +/* Counts occurrences of @str in @strv */ +static guint +strv_contains (char **strv, + const char *str, + guint *idx) +{ + guint n, i; + + if (strv == NULL) + return 0; + + n = 0; + for (i = 0; strv[i]; i++) { + if (strcmp (strv[i], str) == 0) { + n++; + if (idx) + *idx = i; + } + } + + return n; +} + +static gboolean +valid_uuid (const char *str, + GError **error) +{ + if (terminal_settings_list_valid_uuid (str)) + return TRUE; + + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "\"%s\" is not a valid UUID", str); + return FALSE; +} + +/** + * terminal_profiles_list_new: + * + * Returns: (transfer full): a new #TerminalSettingsList for the profiles list + */ +TerminalSettingsList * +terminal_profiles_list_new (void) +{ + return terminal_settings_list_new (TERMINAL_PROFILES_PATH_PREFIX, + TERMINAL_PROFILES_LIST_SCHEMA, + TERMINAL_PROFILE_SCHEMA, + TERMINAL_SETTINGS_LIST_FLAG_HAS_DEFAULT); +} + +static void +get_profile_names (TerminalSettingsList *list, + char ***profilesp, + char ***namesp) +{ + char **profiles, **names; + guint i, n; + + *profilesp = profiles = terminal_settings_list_dupv_children (list); + + n = g_strv_length (profiles); + *namesp = names = g_new0 (char *, n + 1); + for (i = 0; i < n; i++) { + gs_unref_object GSettings *profile; + + profile = terminal_settings_list_ref_child (list, profiles[i]); + names[i] = g_settings_get_string (profile, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + } + + names[n] = NULL; +} + +/** + * terminal_profiles_list_ref_children_sorted: + * @list: + * + * Returns: (transfer full): + */ +GList * +terminal_profiles_list_ref_children_sorted (TerminalSettingsList *list) +{ + return g_list_sort (terminal_settings_list_ref_children (list), + terminal_profiles_compare); +} + +/** + * terminal_profiles_list_dup_uuid: + * @list: + * @uuid: (allow-none): + * @error: + * + * Returns: (transfer full): the UUID of the profile specified by @uuid, or %NULL + */ +char * +terminal_profiles_list_dup_uuid (TerminalSettingsList *list, + const char *uuid, + GError **error) +{ + char *rv; + + if (uuid == NULL) { + rv = terminal_settings_list_dup_default_child (list); + if (rv == NULL) + goto err; + return rv; + } else if (!valid_uuid (uuid, error)) + return NULL; + + if (terminal_settings_list_has_child (list, uuid)) + return g_strdup (uuid); + + err: + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "No profile with UUID \"%s\" exists", uuid); + return NULL; +} + +/** + * terminal_profiles_list_ref_profile_by_uuid_or_name: + * @list: + * @uuid: + * @error: + * + * Returns: (transfer full): the profile #GSettings specified by @uuid, or %NULL + */ +GSettings * +terminal_profiles_list_ref_profile_by_uuid (TerminalSettingsList *list, + const char *uuid, + GError **error) +{ + gs_free char *profile_uuid; + GSettings *profile; + + profile_uuid = terminal_profiles_list_dup_uuid (list, uuid, error); + if (profile_uuid == NULL) + return NULL; + + profile = terminal_settings_list_ref_child (list, profile_uuid); + return profile; +} + +/** + * terminal_profiles_list_get_profile_by_uuid: + * @list: + * @uuid: (allow-none): + * @error: + * + * Returns: (transfer full): the UUID of the profile specified by @uuid, or %NULL + */ +char * +terminal_profiles_list_dup_uuid_or_name (TerminalSettingsList *list, + const char *uuid_or_name, + GError **error) +{ + char **profiles, **profile_names; + char *rv; + guint n, i; + + rv = terminal_profiles_list_dup_uuid (list, uuid_or_name, NULL); + if (rv != NULL) + return rv; + + /* Not found as UUID; try finding a profile with this string as 'visible-name' */ + get_profile_names (list, &profiles, &profile_names); + n = strv_contains (profile_names, uuid_or_name, &i); + + if (n == 0) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "No profile with UUID or name \"%s\" exists", uuid_or_name); + rv = NULL; + } else if (n != 1) { + g_set_error (error, G_OPTION_ERROR, G_OPTION_ERROR_BAD_VALUE, + "No profile with UUID \"%s\" found and name is ambiguous", uuid_or_name); + rv = NULL; + } else { + rv = g_strdup (profiles[i]); + } + + g_strfreev (profiles); + g_strfreev (profile_names); + + return rv; +} + +/** + * terminal_profiles_list_ref_profile_by_uuid_or_name: + * @list: + * @uuid: + * @error: + * + * Returns: (transfer full): the profile #GSettings specified by @uuid, or %NULL + */ +GSettings * +terminal_profiles_list_ref_profile_by_uuid_or_name (TerminalSettingsList *list, + const char *uuid_or_name, + GError **error) +{ + gs_free char *uuid; + GSettings *profile; + + uuid = terminal_profiles_list_dup_uuid_or_name (list, uuid_or_name, error); + if (uuid == NULL) + return NULL; + + profile = terminal_settings_list_ref_child (list, uuid); + g_assert (profile != NULL); + return profile; +} + +int +terminal_profiles_compare (gconstpointer pa, + gconstpointer pb) +{ + GSettings *a = (GSettings *) pa; + GSettings *b = (GSettings *) pb; + gs_free char *na = NULL; + gs_free char *nb = NULL; + gs_free char *patha = NULL; + gs_free char *pathb = NULL; + int result; + + if (pa == pb) + return 0; + if (pa == NULL) + return 1; + if (pb == NULL) + return -1; + + na = g_settings_get_string (a, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + nb = g_settings_get_string (b, TERMINAL_PROFILE_VISIBLE_NAME_KEY); + result = g_utf8_collate (na, nb); + if (result != 0) + return result; + + g_object_get (a, "path", &patha, NULL); + g_object_get (b, "path", &pathb, NULL); + return strcmp (patha, pathb); +} diff --git a/src/terminal-profiles-list.h b/src/terminal-profiles-list.h new file mode 100644 index 0000000..179d3e3 --- /dev/null +++ b/src/terminal-profiles-list.h @@ -0,0 +1,53 @@ +/* + * Copyright © 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_PROFILES_LIST_H +#define TERMINAL_PROFILES_LIST_H + +#include +#include + +#include "terminal-settings-list.h" + +G_BEGIN_DECLS + +TerminalSettingsList *terminal_profiles_list_new (void); + +GList *terminal_profiles_list_ref_children_sorted (TerminalSettingsList *list); + +char *terminal_profiles_list_dup_uuid (TerminalSettingsList *list, + const char *uuid, + GError **error); + +GSettings *terminal_profiles_list_ref_profile_by_uuid (TerminalSettingsList *list, + const char *uuid, + GError **error); + +char *terminal_profiles_list_dup_uuid_or_name (TerminalSettingsList *list, + const char *uuid_or_name, + GError **error); + +GSettings *terminal_profiles_list_ref_profile_by_uuid_or_name (TerminalSettingsList *list, + const char *uuid_or_name, + GError **error); + +int terminal_profiles_compare (gconstpointer pa, + gconstpointer pb); + +G_END_DECLS + +#endif /* TERMINAL_PROFILES_LIST_H */ diff --git a/src/terminal-regex.c b/src/terminal-regex.c new file mode 100644 index 0000000..cf51453 --- /dev/null +++ b/src/terminal-regex.c @@ -0,0 +1,374 @@ +/* + * Copyright © 2015 Egmont Koblinger + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include + +#include "terminal-regex.h" + +#ifdef TERMINAL_REGEX_MAIN + +/* Shorthand for expecting the pattern to match the entire input string */ +#define ENTIRE ((char *) 1) + +static char* +get_match (const char *pattern, const char *string, GRegexMatchFlags match_flags) +{ + GRegex *regex; + GMatchInfo *match_info; + gchar *match; + + regex = g_regex_new (pattern, 0, 0, NULL); + g_regex_match (regex, string, match_flags, &match_info); + match = g_match_info_fetch (match_info, 0); + + g_free (regex); + g_free (match_info); + return match; +} + +/* Macros rather than functions to report useful line numbers on failure. */ +#define assert_match(__pattern, __string, __expected) do { \ + gchar *__actual_match = get_match(__pattern, __string, 0); \ + const gchar *__expected_match = __expected; \ + if (__expected_match == ENTIRE) __expected_match = __string; \ + g_assert_cmpstr(__actual_match, ==, __expected_match); \ + g_free (__actual_match); \ +} while (0) + +#define assert_match_anchored(__pattern, __string, __expected) do { \ + gchar *__actual_match = get_match(__pattern, __string, G_REGEX_MATCH_ANCHORED); \ + const gchar *__expected_match = __expected; \ + if (__expected_match == ENTIRE) __expected_match = __string; \ + g_assert_cmpstr(__actual_match, ==, __expected_match); \ + g_free (__actual_match); \ +} while (0) + +int +main (int argc, char **argv) +{ + /* SCHEME is case insensitive */ + assert_match_anchored (SCHEME, "http", ENTIRE); + assert_match_anchored (SCHEME, "HTTPS", ENTIRE); + + /* USER is nonempty, alphanumeric, dot, plus and dash */ + assert_match_anchored (USER, "", NULL); + assert_match_anchored (USER, "dr.john-smith", ENTIRE); + assert_match_anchored (USER, "abc+def@ghi", "abc+def"); + + /* PASS is optional colon-prefixed value, allowing quite some characters, but definitely not @ */ + assert_match_anchored (PASS, "", ENTIRE); + assert_match_anchored (PASS, "nocolon", ""); + assert_match_anchored (PASS, ":s3cr3T", ENTIRE); + assert_match_anchored (PASS, ":$?#@host", ":$?#"); + + /* Hostname of at least 1 component, containing at least one non-digit in at least one of the segments */ + assert_match_anchored (HOSTNAME1, "example.com", ENTIRE); + assert_match_anchored (HOSTNAME1, "a-b.c-d", ENTIRE); + assert_match_anchored (HOSTNAME1, "a_b", "a"); /* TODO: can/should we totally abort here? */ + assert_match_anchored (HOSTNAME1, "déjà-vu.com", ENTIRE); + assert_match_anchored (HOSTNAME1, "➡.ws", ENTIRE); + assert_match_anchored (HOSTNAME1, "cömbining-áccents", ENTIRE); + assert_match_anchored (HOSTNAME1, "12", NULL); + assert_match_anchored (HOSTNAME1, "12.34", NULL); + assert_match_anchored (HOSTNAME1, "12.ab", ENTIRE); +// assert_match_anchored (HOSTNAME1, "ab.12", NULL); /* errr... could we fail here?? */ + + /* Hostname of at least 2 components, containing at least one non-digit in at least one of the segments */ + assert_match_anchored (HOSTNAME2, "example.com", ENTIRE); + assert_match_anchored (HOSTNAME2, "example", NULL); + assert_match_anchored (HOSTNAME2, "12", NULL); + assert_match_anchored (HOSTNAME2, "12.34", NULL); + assert_match_anchored (HOSTNAME2, "12.ab", ENTIRE); + assert_match_anchored (HOSTNAME2, "ab.12", NULL); +// assert_match_anchored (HOSTNAME2, "ab.cd.12", NULL); /* errr... could we fail here?? */ + + /* IPv4 segment (number between 0 and 255) */ + assert_match_anchored (DEFS "(?&S4)", "0", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "1", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "9", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "10", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "99", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "100", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "200", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "250", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "255", ENTIRE); + assert_match_anchored (DEFS "(?&S4)", "256", NULL); + assert_match_anchored (DEFS "(?&S4)", "260", NULL); + assert_match_anchored (DEFS "(?&S4)", "300", NULL); + assert_match_anchored (DEFS "(?&S4)", "1000", NULL); + assert_match_anchored (DEFS "(?&S4)", "", NULL); + assert_match_anchored (DEFS "(?&S4)", "a1b", NULL); + + /* IPv4 addresses */ + assert_match_anchored (DEFS "(?&IPV4)", "11.22.33.44", ENTIRE); + assert_match_anchored (DEFS "(?&IPV4)", "0.1.254.255", ENTIRE); + assert_match_anchored (DEFS "(?&IPV4)", "75.150.225.300", NULL); + assert_match_anchored (DEFS "(?&IPV4)", "1.2.3.4.5", "1.2.3.4"); /* we could also bail out and not match at all */ + + /* IPv6 addresses */ + assert_match_anchored (DEFS "(?&IPV6)", "11:::22", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22::33:44::55:66", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "dead::beef", ENTIRE); + assert_match_anchored (DEFS "(?&IPV6)", "faded::bee", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "live::pork", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "::1", ENTIRE); + assert_match_anchored (DEFS "(?&IPV6)", "11::22:33::44", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:::33", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "dead:beef::192.168.1.1", ENTIRE); + assert_match_anchored (DEFS "(?&IPV6)", "192.168.1.1", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77:87654", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22::33:45678", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:192.168.1.12345", NULL); + + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77", NULL); /* no :: */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77:88", ENTIRE); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77:88:99", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "::11:22:33:44:55:66:77", ENTIRE); /* :: at the start */ + assert_match_anchored (DEFS "(?&IPV6)", "::11:22:33:44:55:66:77:88", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33::44:55:66:77", ENTIRE); /* :: in the middle */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33::44:55:66:77:88", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77::", ENTIRE); /* :: at the end */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77:88::", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "::", ENTIRE); /* :: only */ + + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:192.168.1.1", NULL); /* no :: */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:192.168.1.1", ENTIRE); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66:77:192.168.1.1", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "::11:22:33:44:55:192.168.1.1", ENTIRE); /* :: at the start */ + assert_match_anchored (DEFS "(?&IPV6)", "::11:22:33:44:55:66:192.168.1.1", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33::44:55:192.168.1.1", ENTIRE); /* :: in the imddle */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33::44:55:66:192.168.1.1", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55::192.168.1.1", ENTIRE); /* :: at the end(ish) */ + assert_match_anchored (DEFS "(?&IPV6)", "11:22:33:44:55:66::192.168.1.1", NULL); + assert_match_anchored (DEFS "(?&IPV6)", "::192.168.1.1", ENTIRE); /* :: only(ish) */ + + /* URL_HOST is either a hostname, or an IPv4 address, or a bracket-enclosed IPv6 address */ + assert_match_anchored (DEFS URL_HOST, "example", ENTIRE); + assert_match_anchored (DEFS URL_HOST, "example.com", ENTIRE); + assert_match_anchored (DEFS URL_HOST, "11.22.33.44", ENTIRE); + assert_match_anchored (DEFS URL_HOST, "[11.22.33.44]", NULL); + assert_match_anchored (DEFS URL_HOST, "dead::be:ef", "dead"); /* TODO: can/should we totally abort here? */ + assert_match_anchored (DEFS URL_HOST, "[dead::be:ef]", ENTIRE); + + /* EMAIL_HOST is either an at least two-component hostname, or a bracket-enclosed IPv[46] address */ + assert_match_anchored (DEFS EMAIL_HOST, "example", NULL); + assert_match_anchored (DEFS EMAIL_HOST, "example.com", ENTIRE); + assert_match_anchored (DEFS EMAIL_HOST, "11.22.33.44", NULL); + assert_match_anchored (DEFS EMAIL_HOST, "[11.22.33.44]", ENTIRE); + assert_match_anchored (DEFS EMAIL_HOST, "[11.22.33.456]", NULL); + assert_match_anchored (DEFS EMAIL_HOST, "dead::be:ef", NULL); + assert_match_anchored (DEFS EMAIL_HOST, "[dead::be:ef]", ENTIRE); + + /* Number between 1 and 65535 (helper for port) */ + assert_match_anchored (N_1_65535, "0", NULL); + assert_match_anchored (N_1_65535, "1", ENTIRE); + assert_match_anchored (N_1_65535, "10", ENTIRE); + assert_match_anchored (N_1_65535, "100", ENTIRE); + assert_match_anchored (N_1_65535, "1000", ENTIRE); + assert_match_anchored (N_1_65535, "10000", ENTIRE); + assert_match_anchored (N_1_65535, "60000", ENTIRE); + assert_match_anchored (N_1_65535, "65000", ENTIRE); + assert_match_anchored (N_1_65535, "65500", ENTIRE); + assert_match_anchored (N_1_65535, "65530", ENTIRE); + assert_match_anchored (N_1_65535, "65535", ENTIRE); + assert_match_anchored (N_1_65535, "65536", NULL); + assert_match_anchored (N_1_65535, "65540", NULL); + assert_match_anchored (N_1_65535, "65600", NULL); + assert_match_anchored (N_1_65535, "66000", NULL); + assert_match_anchored (N_1_65535, "70000", NULL); + assert_match_anchored (N_1_65535, "100000", NULL); + assert_match_anchored (N_1_65535, "", NULL); + assert_match_anchored (N_1_65535, "a1b", NULL); + + /* PORT is an optional colon-prefixed value */ + assert_match_anchored (PORT, "", ENTIRE); + assert_match_anchored (PORT, ":1", ENTIRE); + assert_match_anchored (PORT, ":65535", ENTIRE); + assert_match_anchored (PORT, ":65536", ""); /* TODO: can/should we totally abort here? */ + + /* Parentheses are only allowed in matching pairs, see bug 763980. */ + /* TODO: add tests for PATHCHARS and PATHNONTERM; and/or URLPATH */ + assert_match_anchored (DEFS URLPATH, "/ab/cd", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/ab/cd.html.", "/ab/cd.html"); + assert_match_anchored (DEFS URLPATH, "/The_Offspring_(album)", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/The_Offspring)", "/The_Offspring"); + assert_match_anchored (DEFS URLPATH, "/a((b(c)d)e(f))", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/a((b(c)d)e(f)))", "/a((b(c)d)e(f))"); + assert_match_anchored (DEFS URLPATH, "/a(b).(c).", "/a(b).(c)"); + assert_match_anchored (DEFS URLPATH, "/a.(b.(c.).).(d.(e.).).)", "/a.(b.(c.).).(d.(e.).)"); + assert_match_anchored (DEFS URLPATH, "/a)b(c", "/a"); + assert_match_anchored (DEFS URLPATH, "/.", "/"); + assert_match_anchored (DEFS URLPATH, "/(.", "/"); + assert_match_anchored (DEFS URLPATH, "/).", "/"); + assert_match_anchored (DEFS URLPATH, "/().", "/()"); + assert_match_anchored (DEFS URLPATH, "/", ENTIRE); + assert_match_anchored (DEFS URLPATH, "", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/php?param[]=value1¶m[]=value2", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/foo?param1[index1]=value1¶m2[index2]=value2", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/[[[]][]]", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/[([])]([()])", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/([()])[([])]", ENTIRE); + assert_match_anchored (DEFS URLPATH, "/[(])", "/"); + assert_match_anchored (DEFS URLPATH, "/([)]", "/"); + + + /* Put the components together and test the big picture */ + + assert_match (REGEX_URL_AS_IS, "There's no URL here http:/foo", NULL); + assert_match (REGEX_URL_AS_IS, "Visit http://example.com for details", "http://example.com"); + assert_match (REGEX_URL_AS_IS, "Trailing dot http://foo/bar.html.", "http://foo/bar.html"); + assert_match (REGEX_URL_AS_IS, "Trailing ellipsis http://foo/bar.html...", "http://foo/bar.html"); + assert_match (REGEX_URL_AS_IS, "Trailing comma http://foo/bar,baz,", "http://foo/bar,baz"); + assert_match (REGEX_URL_AS_IS, "Trailing semicolon http://foo/bar;baz;", "http://foo/bar;baz"); + assert_match (REGEX_URL_AS_IS, "See ", "http://foo/bar"); + assert_match (REGEX_URL_AS_IS, "", "http://foo.bar/asdf.qwer.html"); + assert_match (REGEX_URL_AS_IS, "Go to http://192.168.1.1.", "http://192.168.1.1"); + assert_match (REGEX_URL_AS_IS, "If not, see .", "http://www.gnu.org/licenses/"); + assert_match (REGEX_URL_AS_IS, "foo", "http://foo/bar"); + assert_match (REGEX_URL_AS_IS, "foo", "http://foo/bar"); + assert_match (REGEX_URL_AS_IS, "http://foo/bar", "http://foo/bar"); + + assert_match (REGEX_URL_AS_IS, "http://", NULL); + assert_match (REGEX_URL_AS_IS, "http://a", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://aa.", "http://aa"); + assert_match (REGEX_URL_AS_IS, "http://aa.b", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://aa.bb", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://aa.bb/c", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://aa.bb/cc", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://aa.bb/cc/", ENTIRE); + + assert_match (REGEX_URL_AS_IS, "HtTp://déjà-vu.com:10000/déjà/vu", ENTIRE); + assert_match (REGEX_URL_AS_IS, "HTTP://joe:sEcReT@➡.ws:1080", ENTIRE); + assert_match (REGEX_URL_AS_IS, "https://cömbining-áccents", ENTIRE); + + assert_match (REGEX_URL_AS_IS, "http://111.222.33.44", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://111.222.33.44/", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://111.222.33.44/foo", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://1.2.3.4:5555/xyz", ENTIRE); + assert_match (REGEX_URL_AS_IS, "https://[dead::beef]:12345/ipv6", ENTIRE); + assert_match (REGEX_URL_AS_IS, "https://[dead::beef:11.22.33.44]", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://1.2.3.4:", "http://1.2.3.4"); /* TODO: can/should we totally abort here? */ + assert_match (REGEX_URL_AS_IS, "https://dead::beef/no-brackets-ipv6", "https://dead"); /* ditto */ + assert_match (REGEX_URL_AS_IS, "http://111.222.333.444/", NULL); + assert_match (REGEX_URL_AS_IS, "http://1.2.3.4:70000", "http://1.2.3.4"); /* TODO: can/should we totally abort here? */ + assert_match (REGEX_URL_AS_IS, "http://[dead::beef:111.222.333.444]", NULL); + + /* Username, password */ + assert_match (REGEX_URL_AS_IS, "http://joe@example.com", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://user.name:sec.ret@host.name", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://joe:secret@[::1]", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://dudewithnopassword:@example.com", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://safeguy:!#$%^&*@host", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http://invalidusername!@host", "http://invalidusername"); + + assert_match (REGEX_URL_AS_IS, "http://ab.cd/ef?g=h&i=j|k=l#m=n:o=p", ENTIRE); + assert_match (REGEX_URL_AS_IS, "http:///foo", NULL); + + /* Parentheses are only allowed in matching pairs, see bug 763980. */ + assert_match (REGEX_URL_AS_IS, "https://en.wikipedia.org/wiki/The_Offspring_(album)", ENTIRE); + assert_match (REGEX_URL_AS_IS, "[markdown](https://en.wikipedia.org/wiki/The_Offspring)", "https://en.wikipedia.org/wiki/The_Offspring"); + assert_match (REGEX_URL_AS_IS, "[markdown](https://en.wikipedia.org/wiki/The_Offspring_(album))", "https://en.wikipedia.org/wiki/The_Offspring_(album)"); + assert_match (REGEX_URL_AS_IS, "[markdown](http://foo.bar/(a(b)c)d)e)f", "http://foo.bar/(a(b)c)d"); + assert_match (REGEX_URL_AS_IS, "[markdown](http://foo.bar/a)b(c", "http://foo.bar/a"); + + /* Apostrophes are allowed, except at trailing position if the URL is preceded by an apostrophe, see bug 448044. */ + assert_match (REGEX_URL_AS_IS, "https://en.wikipedia.org/wiki/Moore's_law", ENTIRE); + assert_match (REGEX_URL_AS_IS, "", "https://en.wikipedia.org/wiki/Moore's_law"); + assert_match (REGEX_URL_AS_IS, "https://en.wikipedia.org/wiki/Cryin'", ENTIRE); + assert_match (REGEX_URL_AS_IS, "", "https://en.wikipedia.org/wiki/Cryin'"); + assert_match (REGEX_URL_AS_IS, "", "https://en.wikipedia.org/wiki/Aerosmith"); + + /* No scheme */ + assert_match (REGEX_URL_HTTP, "www.foo.bar/baz", ENTIRE); + assert_match (REGEX_URL_HTTP, "WWW3.foo.bar/baz", ENTIRE); + assert_match (REGEX_URL_HTTP, "FTP.FOO.BAR/BAZ", ENTIRE); /* FIXME if no scheme is given and url starts with ftp, can we make the protocol ftp instead of http? */ + assert_match (REGEX_URL_HTTP, "ftpxy.foo.bar/baz", ENTIRE); +// assert_match (REGEX_URL_HTTP, "ftp.123/baz", NULL); /* errr... could we fail here?? */ + assert_match (REGEX_URL_HTTP, "foo.bar/baz", NULL); + assert_match (REGEX_URL_HTTP, "abc.www.foo.bar/baz", NULL); + assert_match (REGEX_URL_HTTP, "uvwww.foo.bar/baz", NULL); + assert_match (REGEX_URL_HTTP, "xftp.foo.bar/baz", NULL); + + /* file:/ or file://(hostname)?/ */ + assert_match (REGEX_URL_FILE, "file:", NULL); + assert_match (REGEX_URL_FILE, "file:/", ENTIRE); + assert_match (REGEX_URL_FILE, "file://", NULL); + assert_match (REGEX_URL_FILE, "file:///", ENTIRE); + assert_match (REGEX_URL_FILE, "file:////", NULL); + assert_match (REGEX_URL_FILE, "file:etc/passwd", NULL); + assert_match (REGEX_URL_FILE, "File:/etc/passwd", ENTIRE); + assert_match (REGEX_URL_FILE, "FILE:///etc/passwd", ENTIRE); + assert_match (REGEX_URL_FILE, "file:////etc/passwd", NULL); + assert_match (REGEX_URL_FILE, "file://host.name", NULL); + assert_match (REGEX_URL_FILE, "file://host.name/", ENTIRE); + assert_match (REGEX_URL_FILE, "file://host.name/etc", ENTIRE); + + assert_match (REGEX_URL_FILE, "See file:/.", "file:/"); + assert_match (REGEX_URL_FILE, "See file:///.", "file:///"); + assert_match (REGEX_URL_FILE, "See file:/lost+found.", "file:/lost+found"); + assert_match (REGEX_URL_FILE, "See file:///lost+found.", "file:///lost+found"); + + /* Email */ + assert_match (REGEX_EMAIL, "Write to foo@bar.com.", "foo@bar.com"); + assert_match (REGEX_EMAIL, "Write to ", "foo@bar.com"); + assert_match (REGEX_EMAIL, "Write to mailto:foo@bar.com.", "mailto:foo@bar.com"); + assert_match (REGEX_EMAIL, "Write to MAILTO:FOO@BAR.COM.", "MAILTO:FOO@BAR.COM"); + assert_match (REGEX_EMAIL, "Write to foo@[1.2.3.4]", "foo@[1.2.3.4]"); + assert_match (REGEX_EMAIL, "Write to foo@[1.2.3.456]", NULL); + assert_match (REGEX_EMAIL, "Write to foo@[1::2345]", "foo@[1::2345]"); + assert_match (REGEX_EMAIL, "Write to foo@[dead::beef]", "foo@[dead::beef]"); + assert_match (REGEX_EMAIL, "Write to foo@1.2.3.4", NULL); + assert_match (REGEX_EMAIL, "Write to foo@1.2.3.456", NULL); + assert_match (REGEX_EMAIL, "Write to foo@1::2345", NULL); + assert_match (REGEX_EMAIL, "Write to foo@dead::beef", NULL); + assert_match (REGEX_EMAIL, "", "foo@bar.com"); + assert_match (REGEX_EMAIL, "", "foo@bar.com"); + assert_match (REGEX_EMAIL, "foo@bar.com", "foo@bar.com"); + + /* Sip, examples from rfc 3261 */ + assert_match (REGEX_URL_VOIP, "sip:alice@atlanta.com;maddr=239.255.255.1;ttl=15", ENTIRE); + assert_match (REGEX_URL_VOIP, "sip:alice@atlanta.com", ENTIRE); + assert_match (REGEX_URL_VOIP, "sip:alice:secretword@atlanta.com;transport=tcp", ENTIRE); + assert_match (REGEX_URL_VOIP, "sips:alice@atlanta.com?subject=project%20x&priority=urgent", ENTIRE); + assert_match (REGEX_URL_VOIP, "sip:+1-212-555-1212:1234@gateway.com;user=phone", ENTIRE); + assert_match (REGEX_URL_VOIP, "sips:1212@gateway.com", ENTIRE); + assert_match (REGEX_URL_VOIP, "sip:alice@192.0.2.4", ENTIRE); + assert_match (REGEX_URL_VOIP, "sip:atlanta.com;method=REGISTER?to=alice%40atlanta.com", ENTIRE); + assert_match (REGEX_URL_VOIP, "SIP:alice;day=tuesday@atlanta.com", ENTIRE); + assert_match (REGEX_URL_VOIP, "Dial sip:alice@192.0.2.4.", "sip:alice@192.0.2.4"); + + /* Extremely long match, bug 770147 */ + assert_match (REGEX_URL_AS_IS, "http://www.example.com/ThisPathConsistsOfMoreThan1024Characters" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890" + "1234567890123456789012345678901234567890123456789012345678901234567890123456789012345678901234567890", ENTIRE); + + printf("terminal-regex tests passed :)\n"); + return 0; +} + +#endif /* TERMINAL_REGEX_MAIN */ diff --git a/src/terminal-regex.h b/src/terminal-regex.h new file mode 100644 index 0000000..143a8fa --- /dev/null +++ b/src/terminal-regex.h @@ -0,0 +1,162 @@ +/* + * Copyright © 2015 Egmont Koblinger + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +/* + * Mini style-guide: + * + * #define'd fragments should preferably have an outermost group, for the + * exact same reason as why usually in C/C++ #define's the values are enclosed + * in parentheses: that is, so that you don't get surprised when you use the + * macro and append a quantifier. + * + * For repeated fragments prefer regex-style (?(DEFINE)(?(...))) and use + * as (?&NAME), so that the regex string and the compiled regex object is + * smaller. + * + * Build small blocks, comment and unittest them heavily. + * + * Use free-spacing mode for improved readability. The hardest to read is + * which additional characters belong to a "(?" prefix. To improve + * readability, place a space after this, and for symmetry, before the closing + * parenthesis. Also place a space around "|" characters. No space before + * quantifiers. Try to be consistent with the existing style (yes I know the + * existing style is not consistent either, but please do your best). + * + * See http://www.rexegg.com/regex-disambiguation.html for all the "(?" + * syntaxes. + */ + +#ifndef TERMINAL_REGEX_H +#define TERMINAL_REGEX_H + +/* Lookbehind to see if there's a preceding apostrophe. + * Unlike the other *_DEF macros which define regex subroutines, + * this one is a named capture that defines APOS_START to either + * an apostrophe or the empty string, depending on the character + * preceding this APOS_START_DEF construct. */ +#define APOS_START_DEF "(?(?<='))?" + +#define SCHEME "(?ix: news | telnet | nntp | https? | ftps? | sftp | webcal )" + +#define USERCHARS "-+.[:alnum:]" +/* Nonempty username, e.g. "john.smith" */ +#define USER "[" USERCHARS "]+" + +#define PASSCHARS_CLASS "[-[:alnum:]\\Q,?;.:/!%$^*&~\"#'\\E]" +/* Optional colon-prefixed password. I guess empty password should be allowed, right? E.g. ":secret", ":", "" */ +#define PASS "(?x: :" PASSCHARS_CLASS "* )?" + +/* Optional at-terminated username (with perhaps a password too), e.g. "joe@", "pete:secret@", "" */ +#define USERPASS "(?:" USER PASS "@)?" + +/* S4: IPv4 segment (number between 0 and 255) with lookahead at the end so that we don't match "25" in the string "256". + The lookahead could go to the last segment of IPv4 only but this construct allows nicer unittesting. */ +#define S4_DEF "(?(DEFINE)(?(?x: (?: [0-9] | [1-9][0-9] | 1[0-9]{2} | 2[0-4][0-9] | 25[0-5] ) (?! [0-9] ) )))" + +/* IPV4: Decimal IPv4, e.g. "1.2.3.4", with lookahead (implemented in S4) at the end so that we don't match "192.168.1.123" in the string "192.168.1.1234". */ +#define IPV4_DEF S4_DEF "(?(DEFINE)(?(?x: (?: (?&S4) \\. ){3} (?&S4) )))" + +/* IPv6, including embedded IPv4, e.g. "::1", "dead:beef::1.2.3.4". + * Lookahead for the next char not being a dot or digit, so it doesn't get stuck matching "dead:beef::1" in "dead:beef::1.2.3.4". + * This is not required since the surrounding brackets would trigger backtracking, but it allows nicer unittesting. + * TODO: more strict check (right number of colons, etc.) + * TODO: add zone_id: RFC 4007 section 11, RFC 6874 */ + +/* S6: IPv6 segment, S6C: IPv6 segment followed by a comma, CS6: comma followed by an IPv6 segment */ +#define S6_DEF "(?(DEFINE)(?[[:xdigit:]]{1,4})(?:(?&S6))(?(?&S6):))" + +/* No :: shorthand */ +#define IPV6_FULL "(?x: (?&S6C){7} (?&S6) )" +/* Begins with :: */ +#define IPV6_LEFT "(?x: : (?&CS6){1,7} )" +/* :: somewhere in the middle - use negative lookahead to make sure there aren't too many colons in total */ +#define IPV6_MID "(?x: (?! (?: [[:xdigit:]]*: ){8} ) (?&S6C){1,6} (?&CS6){1,6} )" +/* Ends with :: */ +#define IPV6_RIGHT "(?x: (?&S6C){1,7} : )" +/* Is "::" and nothing more */ +#define IPV6_NULL "(?x: :: )" + +/* The same ones for IPv4-embedded notation, without the actual IPv4 part */ +#define IPV6V4_FULL "(?x: (?&S6C){6} )" +#define IPV6V4_LEFT "(?x: :: (?&S6C){0,5} )" /* includes "::" */ +#define IPV6V4_MID "(?x: (?! (?: [[:xdigit:]]*: ){7} ) (?&S6C){1,4} (?&CS6){1,4} ) :" +#define IPV6V4_RIGHT "(?x: (?&S6C){1,5} : )" + +/* IPV6: An IPv6 address (possibly with an embedded IPv4). + * This macro defines both IPV4 and IPV6, since the latter one requires the former. */ +#define IP_DEF IPV4_DEF S6_DEF "(?(DEFINE)(?(?x: (?: " IPV6_NULL " | " IPV6_LEFT " | " IPV6_MID " | " IPV6_RIGHT " | " IPV6_FULL " | (?: " IPV6V4_FULL " | " IPV6V4_LEFT " | " IPV6V4_MID " | " IPV6V4_RIGHT " ) (?&IPV4) ) (?! [.:[:xdigit:]] ) )))" + +/* Either an alphanumeric character or dash; or if [negative lookahead] not ASCII + * then any graphical Unicode character. + * A segment can consist entirely of numbers. + * (Note: PCRE doesn't support character class subtraction/intersection.) */ +#define HOSTNAMESEGMENTCHARS_CLASS "(?x: [-[:alnum:]] | (?! [[:ascii:]] ) [[:graph:]] )" + +/* A hostname of at least 1 component. The last component cannot be entirely numbers. + * E.g. "foo", "example.com", "1234.com", but not "foo.123" */ +#define HOSTNAME1 "(?x: (?: " HOSTNAMESEGMENTCHARS_CLASS "+ \\. )* " HOSTNAMESEGMENTCHARS_CLASS "* (?! [0-9] ) " HOSTNAMESEGMENTCHARS_CLASS "+ )" + +/* A hostname of at least 2 components. The last component cannot be entirely numbers. + * E.g. "example.com", "1234.com", but not "1234.56" */ +#define HOSTNAME2 "(?x: (?: " HOSTNAMESEGMENTCHARS_CLASS "+ \\.)+ " HOSTNAME1 " )" + +/* For URL: Hostname, IPv4, or bracket-enclosed IPv6, e.g. "example.com", "1.2.3.4", "[::1]" */ +#define URL_HOST "(?x: " HOSTNAME1 " | (?&IPV4) | \\[ (?&IPV6) \\] )" + +/* For e-mail: Hostname of at least two segments, or bracket-enclosed IPv4 or IPv6, e.g. "example.com", "[1.2.3.4]", "[::1]". + * Technically an e-mail with a single-component hostname might be valid on a local network, but let's avoid tons of false positives (e.g. in a typical shell prompt). */ +#define EMAIL_HOST "(?x: " HOSTNAME2 " | \\[ (?: (?&IPV4) | (?&IPV6) ) \\] )" + +/* Number between 1 and 65535, with lookahead at the end so that we don't match "6789" in the string "67890", + and in turn we don't eventually match "http://host:6789" in "http://host:67890". */ +#define N_1_65535 "(?x: (?: [1-9][0-9]{0,3} | [1-5][0-9]{4} | 6[0-4][0-9]{3} | 65[0-4][0-9]{2} | 655[0-2][0-9] | 6553[0-5] ) (?! [0-9] ) )" + +/* Optional colon-prefixed port, e.g. ":1080", "" */ +#define PORT "(?x: \\:" N_1_65535 " )?" + +/* Omit the parentheses, see below */ +#define PATHCHARS_CLASS "[-[:alnum:]\\Q_$.+!*,:;@&=?/~#|%'\\E]" +/* Chars to end a URL. Apostrophe only allowed if there wasn't one in front of the URL, see bug 448044 */ +#define PATHTERM_CLASS "[-[:alnum:]\\Q_$+*:@&=/~#|%'\\E]" +#define PATHTERM_NOAPOS_CLASS "[-[:alnum:]\\Q_$+*:@&=/~#|%\\E]" + +/* Recursive definition of PATH that allows parentheses and square brackets only if balanced, see bug 763980. */ +#define PATH_INNER_DEF "(?(DEFINE)(?(?x: (?: " PATHCHARS_CLASS "* (?: \\( (?&PATH_INNER) \\) | \\[ (?&PATH_INNER) \\] ) )* " PATHCHARS_CLASS "* )))" +/* Same as above, but the last character (if exists and is not a parenthesis) must be from PATHTERM_CLASS. */ +#define PATH_DEF "(?(DEFINE)(?(?x: (?: " PATHCHARS_CLASS "* (?: \\( (?&PATH_INNER) \\) | \\[ (?&PATH_INNER) \\] ) )* (?: " PATHCHARS_CLASS "* (?()" PATHTERM_NOAPOS_CLASS "|" PATHTERM_CLASS ") )? )))" + +#define URLPATH "(?x: /(?&PATH) )?" +#define VOIP_PATH "(?x: [;?](?&PATH) )?" + +/* Now let's put these fragments together */ + +#define DEFS APOS_START_DEF IP_DEF PATH_INNER_DEF PATH_DEF + +#define REGEX_URL_AS_IS DEFS SCHEME "://" USERPASS URL_HOST PORT URLPATH +/* TODO: also support file:/etc/passwd */ +#define REGEX_URL_FILE DEFS "(?ix: file:/ (?: / (?: " HOSTNAME1 " )? / )? (?! / ) )(?&PATH)" +/* Lookbehind so that we don't catch "abc.www.foo.bar", bug 739757. Lookahead for www/ftp for convenience (so that we can reuse HOSTNAME1). */ +/* The commented-out variant looks more like our other definitions, but fails with PCRE 10.34. See GNOME/gnome-terminal#221. + * TODO: revert to this nicer pattern some time after 10.35's release. + * #define REGEX_URL_HTTP DEFS "(?. + */ + +#ifndef TERMINAL_SCHEMAS_H +#define TERMINAL_SCHEMAS_H + +#include + +G_BEGIN_DECLS + +#define TERMINAL_SCHEMA_VERSION (3u) + +#define TERMINAL_KEYBINDINGS_SCHEMA "org.gnome.Terminal.Legacy.Keybindings" +#define TERMINAL_PROFILE_SCHEMA "org.gnome.Terminal.Legacy.Profile" +#define TERMINAL_SETTING_SCHEMA "org.gnome.Terminal.Legacy.Settings" +#define TERMINAL_SETTINGS_LIST_SCHEMA "org.gnome.Terminal.SettingsList" +#define TERMINAL_PROFILES_LIST_SCHEMA "org.gnome.Terminal.ProfilesList" + +#define TERMINAL_PROFILE_AUDIBLE_BELL_KEY "audible-bell" +#define TERMINAL_PROFILE_BOLD_IS_BRIGHT_KEY "bold-is-bright" +#define TERMINAL_PROFILE_BACKGROUND_COLOR_KEY "background-color" +#define TERMINAL_PROFILE_BACKSPACE_BINDING_KEY "backspace-binding" +#define TERMINAL_PROFILE_BOLD_COLOR_KEY "bold-color" +#define TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY "bold-color-same-as-fg" +#define TERMINAL_PROFILE_CELL_HEIGHT_SCALE_KEY "cell-height-scale" +#define TERMINAL_PROFILE_CELL_WIDTH_SCALE_KEY "cell-width-scale" +#define TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY "cursor-colors-set" +#define TERMINAL_PROFILE_CURSOR_BACKGROUND_COLOR_KEY "cursor-background-color" +#define TERMINAL_PROFILE_CURSOR_FOREGROUND_COLOR_KEY "cursor-foreground-color" +#define TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY "cjk-utf8-ambiguous-width" +#define TERMINAL_PROFILE_CURSOR_BLINK_MODE_KEY "cursor-blink-mode" +#define TERMINAL_PROFILE_CURSOR_SHAPE_KEY "cursor-shape" +#define TERMINAL_PROFILE_CUSTOM_COMMAND_KEY "custom-command" +#define TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY "default-size-columns" +#define TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY "default-size-rows" +#define TERMINAL_PROFILE_DELETE_BINDING_KEY "delete-binding" +#define TERMINAL_PROFILE_ENABLE_BIDI_KEY "enable-bidi" +#define TERMINAL_PROFILE_ENABLE_SHAPING_KEY "enable-shaping" +#define TERMINAL_PROFILE_ENABLE_SIXEL_KEY "enable-sixel" +#define TERMINAL_PROFILE_ENCODING_KEY "encoding" +#define TERMINAL_PROFILE_EXIT_ACTION_KEY "exit-action" +#define TERMINAL_PROFILE_FONT_KEY "font" +#define TERMINAL_PROFILE_FOREGROUND_COLOR_KEY "foreground-color" +#define TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY "highlight-colors-set" +#define TERMINAL_PROFILE_HIGHLIGHT_BACKGROUND_COLOR_KEY "highlight-background-color" +#define TERMINAL_PROFILE_HIGHLIGHT_FOREGROUND_COLOR_KEY "highlight-foreground-color" +#define TERMINAL_PROFILE_LOGIN_SHELL_KEY "login-shell" +#define TERMINAL_PROFILE_NAME_KEY "name" +#define TERMINAL_PROFILE_PALETTE_KEY "palette" +#define TERMINAL_PROFILE_PRESERVE_WORKING_DIRECTORY_KEY "preserve-working-directory" +#define TERMINAL_PROFILE_REWRAP_ON_RESIZE_KEY "rewrap-on-resize" +#define TERMINAL_PROFILE_SCROLLBACK_LINES_KEY "scrollback-lines" +#define TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY "scrollback-unlimited" +#define TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY "scrollbar-policy" +#define TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY "scroll-on-keystroke" +#define TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY "scroll-on-output" +#define TERMINAL_PROFILE_TEXT_BLINK_MODE_KEY "text-blink-mode" +#define TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY "use-custom-command" +#define TERMINAL_PROFILE_USE_SKEY_KEY "use-skey" +#define TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY "use-system-font" +#define TERMINAL_PROFILE_USE_THEME_COLORS_KEY "use-theme-colors" +#define TERMINAL_PROFILE_VISIBLE_NAME_KEY "visible-name" +#define TERMINAL_PROFILE_WORD_CHAR_EXCEPTIONS_KEY "word-char-exceptions" + +#define TERMINAL_SETTING_CONFIRM_CLOSE_KEY "confirm-close" +#define TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY "default-show-menubar" +#define TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY "menu-accelerator-enabled" +#define TERMINAL_SETTING_ENABLE_MNEMONICS_KEY "mnemonics-enabled" +#define TERMINAL_SETTING_ENABLE_SHORTCUTS_KEY "shortcuts-enabled" +#define TERMINAL_SETTING_HEADERBAR_KEY "headerbar" +#define TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY "new-terminal-mode" +#define TERMINAL_SETTING_NEW_TAB_POSITION_KEY "new-tab-position" +#define TERMINAL_SETTING_SCHEMA_VERSION "schema-version" +#define TERMINAL_SETTING_SHELL_INTEGRATION_KEY "shell-integration-enabled" +#define TERMINAL_SETTING_TAB_POLICY_KEY "tab-policy" +#define TERMINAL_SETTING_TAB_POSITION_KEY "tab-position" +#define TERMINAL_SETTING_THEME_VARIANT_KEY "theme-variant" +#define TERMINAL_SETTING_UNIFIED_MENU_KEY "unified-menu" + +#define TERMINAL_SETTINGS_LIST_LIST_KEY "list" +#define TERMINAL_SETTINGS_LIST_DEFAULT_KEY "default" + +#define TERMINAL_PROFILES_PATH_PREFIX "/org/gnome/terminal/legacy/profiles:/" + +G_END_DECLS + +#endif /* TERMINAL_SCHEMAS_H */ diff --git a/src/terminal-screen-container.c b/src/terminal-screen-container.c new file mode 100644 index 0000000..459157b --- /dev/null +++ b/src/terminal-screen-container.c @@ -0,0 +1,391 @@ +/* + * Copyright © 2008, 2010, 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-screen-container.h" +#include "terminal-debug.h" + +#if 0 +#define USE_SCROLLED_WINDOW +#endif + +#include + +#define TERMINAL_SCREEN_CONTAINER_GET_PRIVATE(screen_container)(G_TYPE_INSTANCE_GET_PRIVATE ((screen_container), TERMINAL_TYPE_SCREEN_CONTAINER, TerminalScreenContainerPrivate)) + +struct _TerminalScreenContainerPrivate +{ + TerminalScreen *screen; +#ifdef USE_SCROLLED_WINDOW + GtkWidget *scrolled_window; +#else + GtkWidget *hbox; + GtkWidget *vscrollbar; +#endif + GtkPolicyType hscrollbar_policy; + GtkPolicyType vscrollbar_policy; +}; + +enum +{ + PROP_0, + PROP_SCREEN, + PROP_HSCROLLBAR_POLICY, + PROP_VSCROLLBAR_POLICY +}; + +G_DEFINE_TYPE (TerminalScreenContainer, terminal_screen_container, GTK_TYPE_OVERLAY) + +#define TERMINAL_SCREEN_CONTAINER_CSS_NAME "terminal-screen-container" + +/* helper functions */ + +/* Widget class implementation */ + +static void +terminal_screen_container_realize (GtkWidget *widget) +{ + + GTK_WIDGET_CLASS (terminal_screen_container_parent_class)->realize (widget); + + /* We need to realize the screen itself too, see issue #203 */ + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (widget); + TerminalScreenContainerPrivate *priv = container->priv; + gtk_widget_realize (GTK_WIDGET (priv->screen)); +} + +#ifndef USE_SCROLLED_WINDOW + +static void +terminal_screen_container_style_updated (GtkWidget *widget) +{ + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (widget); + TerminalScreenContainerPrivate *priv = container->priv; + GtkCornerType corner; + gboolean set; + + GTK_WIDGET_CLASS (terminal_screen_container_parent_class)->style_updated (widget); + + gtk_widget_style_get (widget, + "window-placement", &corner, + "window-placement-set", &set, + NULL); + + if (!set) { + g_object_get (gtk_widget_get_settings (widget), + "gtk-scrolled-window-placement", &corner, + NULL); + } + + switch (corner) { + case GTK_CORNER_TOP_LEFT: + case GTK_CORNER_BOTTOM_LEFT: + gtk_box_reorder_child (GTK_BOX (priv->hbox), priv->vscrollbar, -1); + break; + case GTK_CORNER_TOP_RIGHT: + case GTK_CORNER_BOTTOM_RIGHT: + gtk_box_reorder_child (GTK_BOX (priv->hbox), priv->vscrollbar, 0); + break; + default: + g_assert_not_reached (); + } +} + +#endif /* !USE_SCROLLED_WINDOW */ + +/* Class implementation */ + +static void +terminal_screen_container_init (TerminalScreenContainer *container) +{ + TerminalScreenContainerPrivate *priv; + + priv = container->priv = TERMINAL_SCREEN_CONTAINER_GET_PRIVATE (container); + + priv->hscrollbar_policy = GTK_POLICY_AUTOMATIC; + priv->vscrollbar_policy = GTK_POLICY_AUTOMATIC; +} + +static void +terminal_screen_container_constructed (GObject *object) +{ + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (object); + TerminalScreenContainerPrivate *priv = container->priv; + + G_OBJECT_CLASS (terminal_screen_container_parent_class)->constructed (object); + + g_assert (priv->screen != NULL); + +#ifdef USE_SCROLLED_WINDOW +{ + GtkAdjustment *hadjustment; + GtkAdjustment *vadjustment; + + hadjustment = gtk_scrollable_get_hadjustment (GTK_SCROLLABLE (priv->screen)); + vadjustment = gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (priv->screen)); + + priv->scrolled_window = gtk_scrolled_window_new (hadjustment, vadjustment); + gtk_scrolled_window_set_overlay_scrolling (GTK_SCROLLED_WINDOW (priv->scrolled_window), FALSE); + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), + priv->hscrollbar_policy, + priv->vscrollbar_policy); + gtk_container_add (GTK_CONTAINER (priv->scrolled_window), GTK_WIDGET (priv->screen)); + + gtk_container_add (GTK_CONTAINER (container), priv->scrolled_window); + gtk_widget_show_all (priv->scrolled_window); +} +#else + priv->hbox = gtk_box_new (GTK_ORIENTATION_HORIZONTAL, 0); + + priv->vscrollbar = gtk_scrollbar_new (GTK_ORIENTATION_VERTICAL, + gtk_scrollable_get_vadjustment (GTK_SCROLLABLE (priv->screen))); + + gtk_box_pack_start (GTK_BOX (priv->hbox), GTK_WIDGET (priv->screen), TRUE, TRUE, 0); + gtk_box_pack_start (GTK_BOX (priv->hbox), priv->vscrollbar, FALSE, FALSE, 0); + + gtk_container_add (GTK_CONTAINER (container), priv->hbox); + gtk_widget_show_all (priv->hbox); +#endif + + _terminal_screen_update_scrollbar (priv->screen); +} + +static void +terminal_screen_container_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (object); + TerminalScreenContainerPrivate *priv = container->priv; + + switch (prop_id) { + case PROP_SCREEN: + break; + case PROP_HSCROLLBAR_POLICY: + g_value_set_enum (value, priv->hscrollbar_policy); + break; + case PROP_VSCROLLBAR_POLICY: + g_value_set_enum (value, priv->vscrollbar_policy); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_screen_container_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (object); + TerminalScreenContainerPrivate *priv = container->priv; + + switch (prop_id) { + case PROP_SCREEN: + priv->screen = g_value_get_object (value); + break; + case PROP_HSCROLLBAR_POLICY: + terminal_screen_container_set_policy (container, + g_value_get_enum (value), + priv->vscrollbar_policy); + break; + case PROP_VSCROLLBAR_POLICY: + terminal_screen_container_set_policy (container, + priv->hscrollbar_policy, + g_value_get_enum (value)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_screen_container_class_init (TerminalScreenContainerClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + g_type_class_add_private (gobject_class, sizeof (TerminalScreenContainerPrivate)); + + gobject_class->constructed = terminal_screen_container_constructed; + gobject_class->get_property = terminal_screen_container_get_property; + gobject_class->set_property = terminal_screen_container_set_property; + + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + widget_class->realize = terminal_screen_container_realize; + +#ifndef USE_SCROLLED_WINDOW + widget_class->style_updated = terminal_screen_container_style_updated; + + gtk_widget_class_install_style_property (widget_class, + g_param_spec_enum ("window-placement", NULL, NULL, + GTK_TYPE_CORNER_TYPE, + GTK_CORNER_BOTTOM_RIGHT, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + gtk_widget_class_install_style_property (widget_class, + g_param_spec_boolean ("window-placement-set", NULL, NULL, + FALSE, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +#endif + + gtk_widget_class_set_css_name(widget_class, TERMINAL_SCREEN_CONTAINER_CSS_NAME); + + g_object_class_install_property + (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", NULL, NULL, + TERMINAL_TYPE_SCREEN, + G_PARAM_READWRITE | + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_STATIC_STRINGS)); + + g_object_class_install_property + (gobject_class, + PROP_HSCROLLBAR_POLICY, + g_param_spec_enum ("hscrollbar-policy", NULL, NULL, + GTK_TYPE_POLICY_TYPE, + GTK_POLICY_AUTOMATIC, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); + g_object_class_install_property + (gobject_class, + PROP_VSCROLLBAR_POLICY, + g_param_spec_enum ("vscrollbar-policy", NULL, NULL, + GTK_TYPE_POLICY_TYPE, + GTK_POLICY_AUTOMATIC, + G_PARAM_READWRITE | + G_PARAM_STATIC_STRINGS)); +} + +/* public API */ + +/** + * terminal_screen_container_new: + * @screen: a #TerminalScreen + * + * Returns: a new #TerminalScreenContainer for @screen + */ +GtkWidget * +terminal_screen_container_new (TerminalScreen *screen) +{ + return g_object_new (TERMINAL_TYPE_SCREEN_CONTAINER, + "screen", screen, + NULL); +} + +/** + * terminal_screen_container_get_screen: + * @container: a #TerminalScreenContainer + * + * Returns: @container's #TerminalScreen + */ +TerminalScreen * +terminal_screen_container_get_screen (TerminalScreenContainer *container) +{ + if (container == NULL) + return NULL; + + g_return_val_if_fail (TERMINAL_IS_SCREEN_CONTAINER (container), NULL); + + return container->priv->screen; +} + +/** + * terminal_screen_container_get_from_screen: + * @screen: a #TerminalScreenContainerPrivate + * + * Returns the #TerminalScreenContainer containing @screen. + */ +TerminalScreenContainer * +terminal_screen_container_get_from_screen (TerminalScreen *screen) +{ + if (screen == NULL) + return NULL; + + g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL); + + return TERMINAL_SCREEN_CONTAINER (gtk_widget_get_ancestor (GTK_WIDGET (screen), TERMINAL_TYPE_SCREEN_CONTAINER)); +} + +/** + * terminal_screen_container_set_policy: + * @container: a #TerminalScreenContainer + * @hpolicy: a #GtkPolicyType + * @vpolicy: a #GtkPolicyType + * + * Sets @container's scrollbar policy. + */ +void +terminal_screen_container_set_policy (TerminalScreenContainer *container, + GtkPolicyType hpolicy, + GtkPolicyType vpolicy) +{ + TerminalScreenContainerPrivate *priv; + GObject *object; + + g_return_if_fail (TERMINAL_IS_SCREEN_CONTAINER (container)); + + object = G_OBJECT (container); + priv = container->priv; + + g_object_freeze_notify (object); + + if (priv->hscrollbar_policy != hpolicy) { + priv->hscrollbar_policy = hpolicy; + g_object_notify (object, "hscrollbar-policy"); + } + if (priv->vscrollbar_policy != vpolicy) { + priv->vscrollbar_policy = vpolicy; + g_object_notify (object, "vscrollbar-policy"); + } + +#ifdef USE_SCROLLED_WINDOW + switch (vpolicy) { + case GTK_POLICY_NEVER: + vpolicy = GTK_POLICY_EXTERNAL; + break; + case GTK_POLICY_AUTOMATIC: + case GTK_POLICY_ALWAYS: + vpolicy = GTK_POLICY_ALWAYS; + break; + default: + g_assert_not_reached (); + } + + gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window), hpolicy, vpolicy); +#else + switch (vpolicy) { + case GTK_POLICY_NEVER: + gtk_widget_hide (priv->vscrollbar); + break; + case GTK_POLICY_AUTOMATIC: + case GTK_POLICY_ALWAYS: + gtk_widget_show (priv->vscrollbar); + break; + default: + g_assert_not_reached (); + } +#endif /* USE_SCROLLED_WINDOW */ + + g_object_thaw_notify (object); +} diff --git a/src/terminal-screen-container.h b/src/terminal-screen-container.h new file mode 100644 index 0000000..6f816e6 --- /dev/null +++ b/src/terminal-screen-container.h @@ -0,0 +1,64 @@ +/* + * Copyright © 2008, 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_SCREEN_CONTAINER_H +#define TERMINAL_SCREEN_CONTAINER_H + +#include +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_SCREEN_CONTAINER (terminal_screen_container_get_type ()) +#define TERMINAL_SCREEN_CONTAINER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_SCREEN_CONTAINER, TerminalScreenContainer)) +#define TERMINAL_SCREEN_CONTAINER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_SCREEN_CONTAINER, TerminalScreenContainerClass)) +#define TERMINAL_IS_SCREEN_CONTAINER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_SCREEN_CONTAINER)) +#define TERMINAL_IS_SCREEN_CONTAINER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_SCREEN_CONTAINER)) +#define TERMINAL_SCREEN_CONTAINER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_SCREEN_CONTAINER, TerminalScreenContainerClass)) + +typedef struct _TerminalScreenContainer TerminalScreenContainer; +typedef struct _TerminalScreenContainerClass TerminalScreenContainerClass; +typedef struct _TerminalScreenContainerPrivate TerminalScreenContainerPrivate; + +struct _TerminalScreenContainer +{ + GtkOverlay parent_instance; + + /*< private >*/ + TerminalScreenContainerPrivate *priv; +}; + +struct _TerminalScreenContainerClass +{ + GtkOverlayClass parent_class; +}; + +GType terminal_screen_container_get_type (void); + +GtkWidget *terminal_screen_container_new (TerminalScreen *screen); + +TerminalScreen *terminal_screen_container_get_screen (TerminalScreenContainer *container); + +TerminalScreenContainer *terminal_screen_container_get_from_screen (TerminalScreen *screen); + +void terminal_screen_container_set_policy (TerminalScreenContainer *container, + GtkPolicyType hpolicy, + GtkPolicyType vpolicy); + +G_END_DECLS + +#endif /* TERMINAL_SCREEN_CONTAINER_H */ diff --git a/src/terminal-screen.c b/src/terminal-screen.c new file mode 100644 index 0000000..0c4ee50 --- /dev/null +++ b/src/terminal-screen.c @@ -0,0 +1,2324 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2007, 2008, 2010, 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-pcre2.h" +#include "terminal-regex.h" +#include "terminal-screen.h" + +#include +#include +#include +#include +#include +#include +#include + +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) +#include +#endif + +#include +#include +#include +#include + +#include + +#ifdef GDK_WINDOWING_X11 +#include +#endif + +#include "terminal-accels.h" +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-defines.h" +#include "terminal-enums.h" +#include "terminal-intl.h" +#include "terminal-marshal.h" +#include "terminal-schemas.h" +#include "terminal-screen-container.h" +#include "terminal-util.h" +#include "terminal-window.h" +#include "terminal-info-bar.h" +#include "terminal-libgsystem.h" + +#include "eggshell.h" + +#define URL_MATCH_CURSOR (GDK_HAND2) + +typedef struct { + volatile int refcount; + char **argv; /* as passed */ + char **exec_argv; /* as processed */ + char **envv; + char *cwd; + gboolean as_shell; + + VtePtyFlags pty_flags; + GSpawnFlags spawn_flags; + + /* FD passing */ + GUnixFDList *fd_list; + int n_fd_map; + int* fd_map; + + /* async exec callback */ + TerminalScreenExecCallback callback; + gpointer callback_data; + GDestroyNotify callback_data_destroy_notify; + + /* Cancellable */ + GCancellable *cancellable; +} ExecData; + +typedef struct +{ + int tag; + TerminalURLFlavor flavor; +} TagData; + +struct _TerminalScreenPrivate +{ + char *uuid; + gboolean registered; /* D-Bus interface is registered */ + + GSettings *profile; /* never NULL */ + guint profile_changed_id; + guint profile_forgotten_id; + int child_pid; + GSList *match_tags; + gboolean exec_on_realize; + guint idle_exec_source; + ExecData *exec_data; +}; + +enum +{ + PROFILE_SET, + SHOW_POPUP_MENU, + MATCH_CLICKED, + CLOSE_SCREEN, + LAST_SIGNAL +}; + +enum { + PROP_0, + PROP_PROFILE, + PROP_TITLE, +}; + +enum +{ + TARGET_COLOR, + TARGET_BGIMAGE, + TARGET_RESET_BG, + TARGET_MOZ_URL, + TARGET_NETSCAPE_URL, + TARGET_TAB +}; + +static void terminal_screen_constructed (GObject *object); +static void terminal_screen_dispose (GObject *object); +static void terminal_screen_finalize (GObject *object); +static void terminal_screen_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint time); +static void terminal_screen_set_font (TerminalScreen *screen); +static void terminal_screen_system_font_changed_cb (GSettings *, + const char*, + TerminalScreen *screen); +static gboolean terminal_screen_popup_menu (GtkWidget *widget); +static gboolean terminal_screen_button_press (GtkWidget *widget, + GdkEventButton *event); +static void terminal_screen_child_exited (VteTerminal *terminal, + int status); + +static void terminal_screen_window_title_changed (VteTerminal *vte_terminal, + TerminalScreen *screen); + +static void update_color_scheme (TerminalScreen *screen); + +static char* terminal_screen_check_hyperlink (TerminalScreen *screen, + GdkEvent *event); +static void terminal_screen_check_extra (TerminalScreen *screen, + GdkEvent *event, + char **number_info); +static char* terminal_screen_check_match (TerminalScreen *screen, + GdkEvent *event, + int *flavor); + +static void terminal_screen_show_info_bar (TerminalScreen *screen, + GError *error, + gboolean show_relaunch); + + +static char**terminal_screen_get_child_environment (TerminalScreen *screen, + char **initial_envv, + char **path, + char **shell); + +static gboolean terminal_screen_get_child_command (TerminalScreen *screen, + char **exec_argv, + const char *path_env, + const char *shell_env, + gboolean shell, + gboolean *preserve_cwd_p, + GSpawnFlags *spawn_flags_p, + char ***argv_p, + GError **err); + +static void terminal_screen_queue_idle_exec (TerminalScreen *screen); + +static guint signals[LAST_SIGNAL]; + +typedef struct { + const char *pattern; + TerminalURLFlavor flavor; +} TerminalRegexPattern; + +static const TerminalRegexPattern url_regex_patterns[] = { + { REGEX_URL_AS_IS, FLAVOR_AS_IS }, + { REGEX_URL_HTTP, FLAVOR_DEFAULT_TO_HTTP }, + { REGEX_URL_FILE, FLAVOR_AS_IS }, + { REGEX_URL_VOIP, FLAVOR_VOIP_CALL }, + { REGEX_EMAIL, FLAVOR_EMAIL }, + { REGEX_NEWS_MAN, FLAVOR_AS_IS }, +}; + +static const TerminalRegexPattern extra_regex_patterns[] = { + { "(0[Xx][[:xdigit:]]+|[[:digit:]]+)", FLAVOR_NUMBER }, +}; + +static VteRegex **url_regexes; +static VteRegex **extra_regexes; +static TerminalURLFlavor *url_regex_flavors; +static TerminalURLFlavor *extra_regex_flavors; +static guint n_url_regexes; +static guint n_extra_regexes; + +/* See bug #697024 */ +#ifndef __linux__ + +#undef dup3 +#define dup3 fake_dup3 + +static int +fake_dup3 (int fd, int fd2, int flags) +{ + if (dup2 (fd, fd2) == -1) + return -1; + + return fcntl (fd2, F_SETFD, flags); +} +#endif /* !__linux__ */ + +static char* +strv_to_string (char **strv) +{ + return strv ? g_strjoinv (" ", strv) : g_strdup ("(null)"); +} + +static char* +exec_data_to_string (ExecData *data) +{ + gs_free char *str1 = NULL; + gs_free char *str2 = NULL; + return data ? g_strdup_printf ("data %p argv:[%s] exec-argv:[%s] envv:%p(%u) as-shell:%s cwd:%s", + data, + (str1 = strv_to_string (data->argv)), + (str2 = strv_to_string (data->exec_argv)), + data->envv, data->envv ? g_strv_length (data->envv) : 0, + data->as_shell ? "true" : "false", + data->cwd) + : g_strdup ("(null)"); +} + +static ExecData* +exec_data_new (void) +{ + ExecData *data = g_new0 (ExecData, 1); + data->refcount = 1; + + return data; +} + +static ExecData * +exec_data_clone (ExecData *data, + gboolean preserve_argv) +{ + if (data == NULL) + return NULL; + + ExecData *clone = exec_data_new (); + clone->envv = g_strdupv (data->envv); + clone->cwd = g_strdup (data->cwd); + + /* If FDs were passed, cannot repeat argv. Return data only for env and cwd */ + if (!preserve_argv || + data->fd_list != NULL) { + clone->as_shell = TRUE; + return clone; + } + + clone->argv = g_strdupv (data->argv); + clone->as_shell = data->as_shell; + + return clone; +} + +static void +exec_data_callback (ExecData *data, + GError *error, + TerminalScreen *screen) +{ + if (data->callback) + data->callback (screen, error, data->callback_data); +} + +static ExecData* +exec_data_ref (ExecData *data) +{ + data->refcount++; + return data; +} + +static void +exec_data_unref (ExecData *data) +{ + if (data == NULL) + return; + + if (--data->refcount > 0) + return; + + g_strfreev (data->argv); + g_strfreev (data->exec_argv); + g_strfreev (data->envv); + g_free (data->cwd); + g_clear_object (&data->fd_list); + g_free (data->fd_map); + + if (data->callback_data_destroy_notify && data->callback_data) + data->callback_data_destroy_notify (data->callback_data); + + g_clear_object (&data->cancellable); + + g_free (data); +} + +GS_DEFINE_CLEANUP_FUNCTION0(ExecData*, _terminal_local_unref_exec_data, exec_data_unref) +#define terminal_unref_exec_data __attribute__((__cleanup__(_terminal_local_unref_exec_data))) + +static void +terminal_screen_clear_exec_data (TerminalScreen *screen, + gboolean cancelled) +{ + TerminalScreenPrivate *priv = screen->priv; + + if (priv->exec_data == NULL) + return; + + if (cancelled) { + gs_free_error GError *err = NULL; + g_set_error_literal (&err, G_IO_ERROR, G_IO_ERROR_CANCELLED, + "Spawning was cancelled"); + exec_data_callback (priv->exec_data, err, screen); + } + + exec_data_unref (priv->exec_data); + priv->exec_data = NULL; +} + +G_DEFINE_TYPE (TerminalScreen, terminal_screen, VTE_TYPE_TERMINAL) + +static void +free_tag_data (TagData *tagdata) +{ + g_slice_free (TagData, tagdata); +} + +static void +precompile_regexes (const TerminalRegexPattern *regex_patterns, + guint n_regexes, + VteRegex ***regexes, + TerminalURLFlavor **regex_flavors) +{ + guint i; + + *regexes = g_new0 (VteRegex*, n_regexes); + *regex_flavors = g_new0 (TerminalURLFlavor, n_regexes); + + for (i = 0; i < n_regexes; ++i) + { + GError *error = NULL; + + (*regexes)[i] = vte_regex_new_for_match (regex_patterns[i].pattern, -1, + PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_UCP | PCRE2_MULTILINE, + &error); + g_assert_no_error (error); + + if (!vte_regex_jit ((*regexes)[i], PCRE2_JIT_COMPLETE, &error) || + !vte_regex_jit ((*regexes)[i], PCRE2_JIT_PARTIAL_SOFT, &error)) { + g_printerr ("Failed to JIT regex '%s': %s\n", regex_patterns[i].pattern, error->message); + g_clear_error (&error); + } + + (*regex_flavors)[i] = regex_patterns[i].flavor; + } +} + +static void +terminal_screen_class_enable_menu_bar_accel_notify_cb (GSettings *settings, + const char *key, + TerminalScreenClass *klass) +{ + static gboolean is_enabled = TRUE; /* the binding is enabled by default since GtkWidgetClass installs it */ + gboolean enable; + GtkBindingSet *binding_set; + + enable = g_settings_get_boolean (settings, key); + + /* Only remove the 'skip' entry when we have added it previously! */ + if (enable == is_enabled) + return; + + is_enabled = enable; + + binding_set = gtk_binding_set_by_class (klass); + if (enable) + gtk_binding_entry_remove (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK); + else + gtk_binding_entry_skip (binding_set, GDK_KEY_F10, GDK_SHIFT_MASK); +} + +static TerminalWindow * +terminal_screen_get_window (TerminalScreen *screen) +{ + GtkWidget *widget = GTK_WIDGET (screen); + GtkWidget *toplevel; + + toplevel = gtk_widget_get_toplevel (widget); + if (!gtk_widget_is_toplevel (toplevel)) + return NULL; + + return TERMINAL_WINDOW (toplevel); +} + +static void +terminal_screen_realize (GtkWidget *widget) +{ + TerminalScreen *screen = TERMINAL_SCREEN (widget); + + GTK_WIDGET_CLASS (terminal_screen_parent_class)->realize (widget); + + terminal_screen_set_font (screen); + + TerminalScreenPrivate *priv = screen->priv; + if (priv->exec_on_realize) + terminal_screen_queue_idle_exec (screen); + + priv->exec_on_realize = FALSE; + +} + +static void +terminal_screen_update_style (TerminalScreen *screen) +{ + update_color_scheme (screen); + terminal_screen_set_font (screen); +} + +static void +terminal_screen_style_updated (GtkWidget *widget) +{ + TerminalScreen *screen = TERMINAL_SCREEN (widget); + + GTK_WIDGET_CLASS (terminal_screen_parent_class)->style_updated (widget); + + terminal_screen_update_style (screen); +} + +#ifdef ENABLE_DEBUG +static void +size_request (GtkWidget *widget, + GtkRequisition *req) +{ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[screen %p] size-request %d : %d\n", + widget, req->width, req->height); +} + +static void +size_allocate (GtkWidget *widget, + GtkAllocation *allocation) +{ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[screen %p] size-alloc %d : %d at (%d, %d)\n", + widget, allocation->width, allocation->height, allocation->x, allocation->y); +} +#endif + +static void +terminal_screen_init (TerminalScreen *screen) +{ + const GtkTargetEntry target_table[] = { + { (char *) "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, TARGET_TAB }, + { (char *) "application/x-color", 0, TARGET_COLOR }, + { (char *) "x-special/gnome-reset-background", 0, TARGET_RESET_BG }, + { (char *) "text/x-moz-url", 0, TARGET_MOZ_URL }, + { (char *) "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL } + }; + VteTerminal *terminal = VTE_TERMINAL (screen); + TerminalScreenPrivate *priv; + TerminalApp *app; + GtkTargetList *target_list; + GtkTargetEntry *targets; + int n_targets; + guint i; + uuid_t u; + char uuidstr[37]; + + priv = screen->priv = G_TYPE_INSTANCE_GET_PRIVATE (screen, TERMINAL_TYPE_SCREEN, TerminalScreenPrivate); + + uuid_generate (u); + uuid_unparse (u, uuidstr); + priv->uuid = g_strdup (uuidstr); + + vte_terminal_set_mouse_autohide (terminal, TRUE); + + priv->child_pid = -1; + + vte_terminal_set_allow_hyperlink (terminal, TRUE); + + for (i = 0; i < n_url_regexes; ++i) + { + TagData *tag_data; + + tag_data = g_slice_new (TagData); + tag_data->flavor = url_regex_flavors[i]; + tag_data->tag = vte_terminal_match_add_regex (terminal, url_regexes[i], 0); + vte_terminal_match_set_cursor_type (terminal, tag_data->tag, URL_MATCH_CURSOR); + + priv->match_tags = g_slist_prepend (priv->match_tags, tag_data); + } + + /* Setup DND */ + target_list = gtk_target_list_new (NULL, 0); + gtk_target_list_add_uri_targets (target_list, 0); + gtk_target_list_add_text_targets (target_list, 0); + gtk_target_list_add_table (target_list, target_table, G_N_ELEMENTS (target_table)); + + targets = gtk_target_table_new_from_list (target_list, &n_targets); + + gtk_drag_dest_set (GTK_WIDGET (screen), + GTK_DEST_DEFAULT_MOTION | + GTK_DEST_DEFAULT_HIGHLIGHT | + GTK_DEST_DEFAULT_DROP, + targets, n_targets, + GDK_ACTION_COPY | GDK_ACTION_MOVE); + + gtk_target_table_free (targets, n_targets); + gtk_target_list_unref (target_list); + + g_signal_connect (screen, "window-title-changed", + G_CALLBACK (terminal_screen_window_title_changed), + screen); + + app = terminal_app_get (); + g_signal_connect (terminal_app_get_desktop_interface_settings (app), "changed::" MONOSPACE_FONT_KEY_NAME, + G_CALLBACK (terminal_screen_system_font_changed_cb), screen); + +#ifdef ENABLE_DEBUG + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_GEOMETRY) + { + g_signal_connect_after (screen, "size-request", G_CALLBACK (size_request), NULL); + g_signal_connect_after (screen, "size-allocate", G_CALLBACK (size_allocate), NULL); + } +#endif +} + +static void +terminal_screen_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalScreen *screen = TERMINAL_SCREEN (object); + + switch (prop_id) + { + case PROP_PROFILE: + g_value_set_object (value, terminal_screen_get_profile (screen)); + break; + case PROP_TITLE: + g_value_set_string (value, terminal_screen_get_title (screen)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_screen_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalScreen *screen = TERMINAL_SCREEN (object); + + switch (prop_id) + { + case PROP_PROFILE: + terminal_screen_set_profile (screen, g_value_get_object (value)); + break; + case PROP_TITLE: + /* not writable */ + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_screen_class_init (TerminalScreenClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS(klass); + VteTerminalClass *terminal_class = VTE_TERMINAL_CLASS (klass); + GSettings *settings; + + object_class->constructed = terminal_screen_constructed; + object_class->dispose = terminal_screen_dispose; + object_class->finalize = terminal_screen_finalize; + object_class->get_property = terminal_screen_get_property; + object_class->set_property = terminal_screen_set_property; + + widget_class->realize = terminal_screen_realize; + widget_class->style_updated = terminal_screen_style_updated; + widget_class->drag_data_received = terminal_screen_drag_data_received; + widget_class->button_press_event = terminal_screen_button_press; + widget_class->popup_menu = terminal_screen_popup_menu; + + terminal_class->child_exited = terminal_screen_child_exited; + + signals[PROFILE_SET] = + g_signal_new (I_("profile-set"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalScreenClass, profile_set), + NULL, NULL, + g_cclosure_marshal_VOID__OBJECT, + G_TYPE_NONE, + 1, G_TYPE_SETTINGS); + + signals[SHOW_POPUP_MENU] = + g_signal_new (I_("show-popup-menu"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalScreenClass, show_popup_menu), + NULL, NULL, + g_cclosure_marshal_VOID__POINTER, + G_TYPE_NONE, + 1, + G_TYPE_POINTER); + + signals[MATCH_CLICKED] = + g_signal_new (I_("match-clicked"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalScreenClass, match_clicked), + g_signal_accumulator_true_handled, NULL, + _terminal_marshal_BOOLEAN__STRING_INT_UINT, + G_TYPE_BOOLEAN, + 3, G_TYPE_STRING, G_TYPE_INT, G_TYPE_UINT); + + signals[CLOSE_SCREEN] = + g_signal_new (I_("close-screen"), + G_OBJECT_CLASS_TYPE (object_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalScreenClass, close_screen), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_object_class_install_property + (object_class, + PROP_PROFILE, + g_param_spec_object ("profile", NULL, NULL, + G_TYPE_SETTINGS, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + g_object_class_install_property + (object_class, + PROP_TITLE, + g_param_spec_string ("title", NULL, NULL, + NULL, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)); + + g_type_class_add_private (object_class, sizeof (TerminalScreenPrivate)); + + n_url_regexes = G_N_ELEMENTS (url_regex_patterns); + precompile_regexes (url_regex_patterns, n_url_regexes, &url_regexes, &url_regex_flavors); + n_extra_regexes = G_N_ELEMENTS (extra_regex_patterns); + precompile_regexes (extra_regex_patterns, n_extra_regexes, &extra_regexes, &extra_regex_flavors); + + /* This fixes bug #329827 */ + settings = terminal_app_get_global_settings (terminal_app_get ()); + terminal_screen_class_enable_menu_bar_accel_notify_cb (settings, TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, klass); + g_signal_connect (settings, "changed::" TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, + G_CALLBACK (terminal_screen_class_enable_menu_bar_accel_notify_cb), klass); +} + +static void +terminal_screen_constructed (GObject *object) +{ + TerminalScreen *screen = TERMINAL_SCREEN (object); + TerminalScreenPrivate *priv = screen->priv; + + G_OBJECT_CLASS (terminal_screen_parent_class)->constructed (object); + + terminal_app_register_screen (terminal_app_get (), screen); + priv->registered = TRUE; +} + +static void +terminal_screen_dispose (GObject *object) +{ + TerminalScreen *screen = TERMINAL_SCREEN (object); + TerminalScreenPrivate *priv = screen->priv; + GtkSettings *settings; + + /* Unset child PID so that when an eventual child-exited signal arrives, + * we don't emit "close". + */ + priv->child_pid = -1; + + settings = gtk_widget_get_settings (GTK_WIDGET (screen)); + g_signal_handlers_disconnect_matched (settings, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, + screen); + + if (priv->idle_exec_source != 0) + { + g_source_remove (priv->idle_exec_source); + priv->idle_exec_source = 0; + } + + terminal_screen_clear_exec_data (screen, TRUE); + + G_OBJECT_CLASS (terminal_screen_parent_class)->dispose (object); + + /* Unregister *after* chaining up to the parent's dispose, + * since that will terminate the child process if there still + * is any, and we need to get the dbus signal out + * from the TerminalReceiver. + */ + if (priv->registered) { + terminal_app_unregister_screen (terminal_app_get (), screen); + priv->registered = FALSE; + } +} + +static void +terminal_screen_finalize (GObject *object) +{ + TerminalScreen *screen = TERMINAL_SCREEN (object); + TerminalScreenPrivate *priv = screen->priv; + + g_signal_handlers_disconnect_by_func (terminal_app_get_desktop_interface_settings (terminal_app_get ()), + G_CALLBACK (terminal_screen_system_font_changed_cb), + screen); + + terminal_screen_set_profile (screen, NULL); + + g_slist_free_full (priv->match_tags, (GDestroyNotify) free_tag_data); + + g_free (priv->uuid); + + G_OBJECT_CLASS (terminal_screen_parent_class)->finalize (object); +} + +TerminalScreen * +terminal_screen_new (GSettings *profile, + const char *title, + double zoom) +{ + g_return_val_if_fail (G_IS_SETTINGS (profile), NULL); + + TerminalScreen *screen = g_object_new (TERMINAL_TYPE_SCREEN, NULL); + + terminal_screen_set_profile (screen, profile); + + vte_terminal_set_size (VTE_TERMINAL (screen), + g_settings_get_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS_KEY), + g_settings_get_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS_KEY)); + + /* If given an initial title, strip it of control characters and + * feed it to the terminal. + */ + if (title != NULL) { + GString *seq; + const char *p; + + seq = g_string_new ("\033]0;"); + for (p = title; *p; p = g_utf8_next_char (p)) { + gunichar c = g_utf8_get_char (p); + if (c < 0x20 || (c >= 0x7f && c <= 0x9f)) + continue; + else if (c == ';') + break; + + g_string_append_unichar (seq, c); + } + g_string_append (seq, "\033\\"); + + vte_terminal_feed (VTE_TERMINAL (screen), seq->str, seq->len); + g_string_free (seq, TRUE); + } + + vte_terminal_set_font_scale (VTE_TERMINAL (screen), zoom); + terminal_screen_set_font (screen); + + return screen; +} + +static gboolean +terminal_screen_reexec_from_exec_data (TerminalScreen *screen, + ExecData *data, + char **envv, + const char *cwd, + GCancellable *cancellable, + GError **error) +{ + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROCESSES) { + gs_free char *str = exec_data_to_string (data); + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] reexec_from_data: envv:%p(%u) cwd:%s data:[%s]\n", + screen, + envv, envv ? g_strv_length (envv) : 0, + cwd, + str); + } + + return terminal_screen_exec (screen, + data ? data->argv : NULL, + envv ? envv : data ? data->envv : NULL, + data ? data->as_shell : TRUE, + /* If we have command line args, must always pass the cwd from the command line, too */ + data && data->argv ? data->cwd : cwd ? cwd : data ? data->cwd : NULL, + NULL /* fd list */, NULL /* fd array */, + NULL, NULL, NULL, /* callback + data + destroy notify */ + cancellable, + error); +} + +gboolean +terminal_screen_reexec_from_screen (TerminalScreen *screen, + TerminalScreen *parent_screen, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE); + + if (parent_screen == NULL) + return TRUE; + + g_return_val_if_fail (TERMINAL_IS_SCREEN (parent_screen), FALSE); + + terminal_unref_exec_data ExecData* data = exec_data_clone (parent_screen->priv->exec_data, FALSE); + gs_free char* cwd = terminal_screen_get_current_dir (parent_screen); + + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] reexec_from_screen: parent:%p cwd:%s\n", + screen, + parent_screen, + cwd); + + return terminal_screen_reexec_from_exec_data (screen, + data, + NULL /* envv */, + cwd, + cancellable, + error); +} + +gboolean +terminal_screen_reexec (TerminalScreen *screen, + char **envv, + const char *cwd, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE); + + + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] reexec: envv:%p(%u) cwd:%s\n", + screen, + envv, envv ? g_strv_length (envv) : 0, + cwd); + + return terminal_screen_reexec_from_exec_data (screen, + screen->priv->exec_data, + envv, + cwd, + cancellable, + error); +} + +gboolean +terminal_screen_exec (TerminalScreen *screen, + char **argv, + char **initial_envv, + gboolean as_shell, + const char *cwd, + GUnixFDList *fd_list, + GVariant *fd_array, + TerminalScreenExecCallback callback, + gpointer user_data, + GDestroyNotify destroy_notify, + GCancellable *cancellable, + GError **error) +{ + g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), FALSE); + g_return_val_if_fail (cancellable == NULL || G_IS_CANCELLABLE (cancellable), FALSE); + g_return_val_if_fail (error == NULL || *error == NULL, FALSE); + g_return_val_if_fail (gtk_widget_get_parent (GTK_WIDGET (screen)) != NULL, FALSE); + + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROCESSES) { + gs_free char *argv_str = NULL; + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] exec: argv:[%s] envv:%p(%u) as-shell:%s cwd:%s\n", + screen, + (argv_str = strv_to_string(argv)), + initial_envv, initial_envv ? g_strv_length (initial_envv) : 0, + as_shell ? "true":"false", + cwd); + } + + TerminalScreenPrivate *priv = screen->priv; + + ExecData *data = exec_data_new (); + data->callback = callback; + data->callback_data = user_data; + data->callback_data_destroy_notify = destroy_notify; + + GError *err = NULL; + if (priv->child_pid != -1) { + g_set_error_literal (&err, G_DBUS_ERROR, G_DBUS_ERROR_FAILED, + "Cannot launch a new child process while the terminal is still running another child process"); + + terminal_screen_show_info_bar (screen, err, FALSE); + g_propagate_error (error, err); + exec_data_unref (data); /* frees the callback data */ + return FALSE; + } + + gs_free char *path = NULL; + gs_free char *shell = NULL; + gs_strfreev char **envv = terminal_screen_get_child_environment (screen, + initial_envv, + &path, + &shell); + + gboolean preserve_cwd = FALSE; + GSpawnFlags spawn_flags = G_SPAWN_SEARCH_PATH_FROM_ENVP; + if (initial_envv) + spawn_flags |= VTE_SPAWN_NO_PARENT_ENVV; + gs_strfreev char **exec_argv = NULL; + if (!terminal_screen_get_child_command (screen, + argv, + path, + shell, + as_shell, + &preserve_cwd, + &spawn_flags, + &exec_argv, + &err)) { + terminal_screen_show_info_bar (screen, err, FALSE); + g_propagate_error (error, err); + exec_data_unref (data); /* frees the callback data */ + return FALSE; + } + + if (!preserve_cwd) { + cwd = g_get_home_dir (); + envv = g_environ_unsetenv (envv, "PWD"); + } + + data->fd_list = fd_list ? g_object_ref(fd_list) : NULL; + + if (fd_array) { + g_assert_nonnull(fd_list); + int n_fds = g_unix_fd_list_get_length(fd_list); + + gsize fd_array_data_len; + const int *fd_array_data = g_variant_get_fixed_array (fd_array, &fd_array_data_len, 2 * sizeof (int)); + + data->n_fd_map = fd_array_data_len; + data->fd_map = g_new (int, data->n_fd_map); + for (gsize i = 0; i < fd_array_data_len; i++) { + const int fd = fd_array_data[2 * i]; + const int idx = fd_array_data[2 * i + 1]; + g_assert_cmpint(idx, >=, 0); + g_assert_cmpuint(idx, <, n_fds); + + data->fd_map[idx] = fd; + } + } else { + data->n_fd_map = 0; + data->fd_map = NULL; + } + + data->argv = g_strdupv (argv); + data->exec_argv = g_strdupv (exec_argv); + data->cwd = g_strdup (cwd); + data->envv = g_strdupv (envv); + data->as_shell = as_shell; + data->pty_flags = VTE_PTY_DEFAULT; + data->spawn_flags = spawn_flags; + data->cancellable = cancellable ? g_object_ref (cancellable) : NULL; + + terminal_screen_clear_exec_data (screen, TRUE); + priv->exec_data = data; + + terminal_screen_queue_idle_exec (screen); + + return TRUE; +} + +const char* +terminal_screen_get_title (TerminalScreen *screen) +{ + return vte_terminal_get_window_title (VTE_TERMINAL (screen)); +} + +static void +terminal_screen_profile_changed_cb (GSettings *profile, + const char *prop_name, + TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + GObject *object = G_OBJECT (screen); + VteTerminal *vte_terminal = VTE_TERMINAL (screen); + TerminalWindow *window; + + g_object_freeze_notify (object); + + if ((window = terminal_screen_get_window (screen))) + { + /* We need these in line for the set_size in + * update_on_realize + */ + terminal_window_update_geometry (window); + } + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY)) + _terminal_screen_update_scrollbar (screen); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ENCODING_KEY)) + { + gs_free char *charset = g_settings_get_string (profile, TERMINAL_PROFILE_ENCODING_KEY); + const char *encoding = terminal_util_translate_encoding (charset); + if (encoding != NULL) + vte_terminal_set_encoding (vte_terminal, encoding, NULL); + } + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY)) + { + TerminalCJKWidth width; + + width = g_settings_get_enum (profile, TERMINAL_PROFILE_CJK_UTF8_AMBIGUOUS_WIDTH_KEY); + vte_terminal_set_cjk_ambiguous_width (vte_terminal, (int) width); + } + + if (gtk_widget_get_realized (GTK_WIDGET (screen)) && + (!prop_name || + prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY) || + prop_name == I_(TERMINAL_PROFILE_FONT_KEY) || + prop_name == I_(TERMINAL_PROFILE_CELL_WIDTH_SCALE_KEY) || + prop_name == I_(TERMINAL_PROFILE_CELL_HEIGHT_SCALE_KEY))) + terminal_screen_set_font (screen); + + if (!prop_name || + prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS_KEY) || + prop_name == I_(TERMINAL_PROFILE_FOREGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_BACKGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY) || + prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY) || + prop_name == I_(TERMINAL_PROFILE_CURSOR_BACKGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_CURSOR_FOREGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY) || + prop_name == I_(TERMINAL_PROFILE_HIGHLIGHT_BACKGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_HIGHLIGHT_FOREGROUND_COLOR_KEY) || + prop_name == I_(TERMINAL_PROFILE_PALETTE_KEY)) + update_color_scheme (screen); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_AUDIBLE_BELL_KEY)) + vte_terminal_set_audible_bell (vte_terminal, g_settings_get_boolean (profile, TERMINAL_PROFILE_AUDIBLE_BELL_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY)) + vte_terminal_set_scroll_on_keystroke (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE_KEY)); + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY)) + vte_terminal_set_scroll_on_output (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT_KEY)); + if (!prop_name || + prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_LINES_KEY) || + prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY)) + { + glong lines = g_settings_get_boolean (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED_KEY) ? + -1 : g_settings_get_int (profile, TERMINAL_PROFILE_SCROLLBACK_LINES_KEY); + vte_terminal_set_scrollback_lines (vte_terminal, lines); + } + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING_KEY)) + vte_terminal_set_backspace_binding (vte_terminal, + g_settings_get_enum (profile, TERMINAL_PROFILE_BACKSPACE_BINDING_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING_KEY)) + vte_terminal_set_delete_binding (vte_terminal, + g_settings_get_enum (profile, TERMINAL_PROFILE_DELETE_BINDING_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ENABLE_BIDI_KEY)) + vte_terminal_set_enable_bidi (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_ENABLE_BIDI_KEY)); + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ENABLE_SHAPING_KEY)) + vte_terminal_set_enable_shaping (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_ENABLE_SHAPING_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ENABLE_SIXEL_KEY)) + vte_terminal_set_enable_sixel (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_ENABLE_SIXEL_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BOLD_IS_BRIGHT_KEY)) + vte_terminal_set_bold_is_bright (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_BOLD_IS_BRIGHT_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_BLINK_MODE_KEY)) + vte_terminal_set_cursor_blink_mode (vte_terminal, + g_settings_get_enum (priv->profile, TERMINAL_PROFILE_CURSOR_BLINK_MODE_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_SHAPE_KEY)) + vte_terminal_set_cursor_shape (vte_terminal, + g_settings_get_enum (priv->profile, TERMINAL_PROFILE_CURSOR_SHAPE_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_REWRAP_ON_RESIZE_KEY)) + vte_terminal_set_rewrap_on_resize (vte_terminal, + g_settings_get_boolean (profile, TERMINAL_PROFILE_REWRAP_ON_RESIZE_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_TEXT_BLINK_MODE_KEY)) + vte_terminal_set_text_blink_mode (vte_terminal, + g_settings_get_enum (profile, TERMINAL_PROFILE_TEXT_BLINK_MODE_KEY)); + + if (!prop_name || prop_name == I_(TERMINAL_PROFILE_WORD_CHAR_EXCEPTIONS_KEY)) + { + gs_free char *word_char_exceptions; + g_settings_get (profile, TERMINAL_PROFILE_WORD_CHAR_EXCEPTIONS_KEY, "ms", &word_char_exceptions); + vte_terminal_set_word_char_exceptions (vte_terminal, word_char_exceptions); + } + + g_object_thaw_notify (object); +} + +static void +update_color_scheme (TerminalScreen *screen) +{ + GtkWidget *widget = GTK_WIDGET (screen); + TerminalScreenPrivate *priv = screen->priv; + GSettings *profile = priv->profile; + gs_free GdkRGBA *colors; + gsize n_colors; + GdkRGBA fg, bg, bold, theme_fg, theme_bg; + GdkRGBA cursor_bg, cursor_fg; + GdkRGBA highlight_bg, highlight_fg; + GdkRGBA *boldp; + GdkRGBA *cursor_bgp = NULL, *cursor_fgp = NULL; + GdkRGBA *highlight_bgp = NULL, *highlight_fgp = NULL; + GtkStyleContext *context; + gboolean use_theme_colors; + + context = gtk_widget_get_style_context (widget); + gtk_style_context_get_color (context, gtk_style_context_get_state (context), &theme_fg); + G_GNUC_BEGIN_IGNORE_DEPRECATIONS + gtk_style_context_get_background_color (context, gtk_style_context_get_state (context), &theme_bg); + G_GNUC_END_IGNORE_DEPRECATIONS + + use_theme_colors = g_settings_get_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS_KEY); + if (use_theme_colors || + (!terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_FOREGROUND_COLOR_KEY, &fg) || + !terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, &bg))) + { + fg = theme_fg; + bg = theme_bg; + } + + if (!g_settings_get_boolean (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG_KEY) && + !use_theme_colors && + terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_BOLD_COLOR_KEY, &bold)) + boldp = &bold; + else + boldp = NULL; + + if (g_settings_get_boolean (profile, TERMINAL_PROFILE_CURSOR_COLORS_SET_KEY) && + !use_theme_colors) + { + if (terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_CURSOR_BACKGROUND_COLOR_KEY, &cursor_bg)) + cursor_bgp = &cursor_bg; + if (terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_CURSOR_FOREGROUND_COLOR_KEY, &cursor_fg)) + cursor_fgp = &cursor_fg; + } + + if (g_settings_get_boolean (profile, TERMINAL_PROFILE_HIGHLIGHT_COLORS_SET_KEY) && + !use_theme_colors) + { + if (terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_HIGHLIGHT_BACKGROUND_COLOR_KEY, &highlight_bg)) + highlight_bgp = &highlight_bg; + if (terminal_g_settings_get_rgba (profile, TERMINAL_PROFILE_HIGHLIGHT_FOREGROUND_COLOR_KEY, &highlight_fg)) + highlight_fgp = &highlight_fg; + } + + colors = terminal_g_settings_get_rgba_palette (priv->profile, TERMINAL_PROFILE_PALETTE_KEY, &n_colors); + vte_terminal_set_colors (VTE_TERMINAL (screen), &fg, &bg, + colors, n_colors); + vte_terminal_set_color_bold (VTE_TERMINAL (screen), boldp); + vte_terminal_set_color_cursor (VTE_TERMINAL (screen), cursor_bgp); + vte_terminal_set_color_cursor_foreground (VTE_TERMINAL (screen), cursor_fgp); + vte_terminal_set_color_highlight (VTE_TERMINAL (screen), highlight_bgp); + vte_terminal_set_color_highlight_foreground (VTE_TERMINAL (screen), highlight_fgp); +} + +static void +terminal_screen_set_font (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + GSettings *profile = priv->profile; + PangoFontDescription *desc; + int size; + + if (g_settings_get_boolean (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY)) + { + desc = terminal_app_get_system_font (terminal_app_get ()); + } + else + { + gs_free char *font; + font = g_settings_get_string (profile, TERMINAL_PROFILE_FONT_KEY); + desc = pango_font_description_from_string (font); + } + + size = pango_font_description_get_size (desc); + /* Sanity check */ + if (size == 0) { + if (pango_font_description_get_size_is_absolute (desc)) + pango_font_description_set_absolute_size (desc, 10); + else + pango_font_description_set_size (desc, 10); + } + + vte_terminal_set_font (VTE_TERMINAL (screen), desc); + + pango_font_description_free (desc); + + vte_terminal_set_cell_width_scale (VTE_TERMINAL (screen), + g_settings_get_double (profile, TERMINAL_PROFILE_CELL_WIDTH_SCALE_KEY)); + vte_terminal_set_cell_height_scale (VTE_TERMINAL (screen), + g_settings_get_double (profile, TERMINAL_PROFILE_CELL_HEIGHT_SCALE_KEY)); +} + +static void +terminal_screen_system_font_changed_cb (GSettings *settings, + const char *key, + TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + + if (!gtk_widget_get_realized (GTK_WIDGET (screen))) + return; + + if (!g_settings_get_boolean (priv->profile, TERMINAL_PROFILE_USE_SYSTEM_FONT_KEY)) + return; + + terminal_screen_set_font (screen); +} + +void +terminal_screen_set_profile (TerminalScreen *screen, + GSettings *profile) +{ + TerminalScreenPrivate *priv = screen->priv; + GSettings*old_profile; + + old_profile = priv->profile; + if (profile == old_profile) + return; + + if (priv->profile_changed_id) + { + g_signal_handler_disconnect (G_OBJECT (priv->profile), + priv->profile_changed_id); + priv->profile_changed_id = 0; + } + + priv->profile = profile; + if (profile) + { + g_object_ref (profile); + priv->profile_changed_id = + g_signal_connect (profile, "changed", + G_CALLBACK (terminal_screen_profile_changed_cb), + screen); + terminal_screen_profile_changed_cb (profile, NULL, screen); + + g_signal_emit (G_OBJECT (screen), signals[PROFILE_SET], 0, old_profile); + } + + if (old_profile) + g_object_unref (old_profile); + + g_object_notify (G_OBJECT (screen), "profile"); +} + +GSettings* +terminal_screen_get_profile (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + + return priv->profile; +} + +GSettings* +terminal_screen_ref_profile (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + + if (priv->profile != NULL) + return g_object_ref (priv->profile); + return NULL; +} + +static gboolean +should_preserve_cwd (TerminalPreserveWorkingDirectory preserve_cwd, + const char *path, + const char *arg0) +{ + switch (preserve_cwd) { + case TERMINAL_PRESERVE_WORKING_DIRECTORY_SAFE: { + gs_free char *resolved_arg0 = terminal_util_find_program_in_path (path, arg0); + return resolved_arg0 != NULL && + terminal_util_get_is_shell (resolved_arg0); + } + + case TERMINAL_PRESERVE_WORKING_DIRECTORY_ALWAYS: + return TRUE; + + case TERMINAL_PRESERVE_WORKING_DIRECTORY_NEVER: + default: + return FALSE; + } +} + +static gboolean +terminal_screen_get_child_command (TerminalScreen *screen, + char **argv, + const char *path_env, + const char *shell_env, + gboolean as_shell, + gboolean *preserve_cwd_p, + GSpawnFlags *spawn_flags_p, + char ***exec_argv_p, + GError **err) +{ + TerminalScreenPrivate *priv = screen->priv; + GSettings *profile = priv->profile; + TerminalPreserveWorkingDirectory preserve_cwd; + char **exec_argv; + + g_assert (spawn_flags_p != NULL && exec_argv_p != NULL && preserve_cwd_p != NULL); + + *exec_argv_p = exec_argv = NULL; + + preserve_cwd = g_settings_get_enum (profile, TERMINAL_PROFILE_PRESERVE_WORKING_DIRECTORY_KEY); + + if (argv) + { + exec_argv = g_strdupv (argv); + + /* argv and cwd come from the command line client, so it must always be used */ + *preserve_cwd_p = TRUE; + *spawn_flags_p |= G_SPAWN_SEARCH_PATH_FROM_ENVP; + } + else if (g_settings_get_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND_KEY)) + { + gs_free char *exec_argv_str; + + exec_argv_str = g_settings_get_string (profile, TERMINAL_PROFILE_CUSTOM_COMMAND_KEY); + if (!g_shell_parse_argv (exec_argv_str, NULL, &exec_argv, err)) + return FALSE; + + *preserve_cwd_p = should_preserve_cwd (preserve_cwd, path_env, exec_argv[0]); + *spawn_flags_p |= G_SPAWN_SEARCH_PATH_FROM_ENVP; + } + else if (as_shell) + { + const char *only_name; + char *shell; + int argc = 0; + + shell = egg_shell (shell_env); + + only_name = strrchr (shell, '/'); + if (only_name != NULL) + only_name++; + else { + only_name = shell; + *spawn_flags_p |= G_SPAWN_SEARCH_PATH_FROM_ENVP; + } + + exec_argv = g_new (char*, 3); + + exec_argv[argc++] = shell; + + if (g_settings_get_boolean (profile, TERMINAL_PROFILE_LOGIN_SHELL_KEY)) + exec_argv[argc++] = g_strconcat ("-", only_name, NULL); + else + exec_argv[argc++] = g_strdup (only_name); + + exec_argv[argc++] = NULL; + + *preserve_cwd_p = should_preserve_cwd (preserve_cwd, path_env, shell); + *spawn_flags_p |= G_SPAWN_FILE_AND_ARGV_ZERO; + } + + else + { + g_set_error_literal (err, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS, + _("No command supplied nor shell requested")); + return FALSE; + } + + *exec_argv_p = exec_argv; + + return TRUE; +} + +static char** +terminal_screen_get_child_environment (TerminalScreen *screen, + char **initial_envv, + char **path, + char **shell) +{ + TerminalApp *app = terminal_app_get (); + char **env; + char *e, *v; + GHashTable *env_table; + GHashTableIter iter; + GPtrArray *retval; + guint i; + + env_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free); + + env = initial_envv; + if (env) + { + for (i = 0; env[i]; ++i) + { + v = strchr (env[i], '='); + if (v) + g_hash_table_replace (env_table, g_strndup (env[i], v - env[i]), g_strdup (v + 1)); + else + g_hash_table_replace (env_table, g_strdup (env[i]), NULL); + } + } + + g_hash_table_remove (env_table, "COLUMNS"); + g_hash_table_remove (env_table, "LINES"); + g_hash_table_remove (env_table, "GNOME_DESKTOP_ICON"); + + /* WINDOWID does not work correctly ever since we don't use a native + * GdkWindow anymore, and it also becomes incorrect if the screen is + * moved to a different window, or the window unrealized and re-realized. + * Additionally, it cannot ever work on non-X11 displays like wayland. + * And on X11, the only use for this is broken foreign drawing on the + * window (w3m etc), and trying to find the focused screen (brltty), + * which can now be done correctly using DECSET 1004. + * Therefore we do not set WINDOWID, and remove an existing variable. + */ + g_hash_table_remove (env_table, "WINDOWID"); + + terminal_util_add_proxy_env (env_table); + + /* Add gnome-terminal private env vars used to communicate back to g-t-server */ + GDBusConnection *connection = g_application_get_dbus_connection (G_APPLICATION (app)); + g_hash_table_replace (env_table, g_strdup (TERMINAL_ENV_SERVICE_NAME), + g_strdup (g_dbus_connection_get_unique_name (connection))); + + g_hash_table_replace (env_table, g_strdup (TERMINAL_ENV_SCREEN), + terminal_app_dup_screen_object_path (app, screen)); + + /* Convert to strv */ + retval = g_ptr_array_sized_new (g_hash_table_size (env_table)); + g_hash_table_iter_init (&iter, env_table); + while (g_hash_table_iter_next (&iter, (gpointer *) &e, (gpointer *) &v)) + g_ptr_array_add (retval, g_strdup_printf ("%s=%s", e, v ? v : "")); + g_ptr_array_add (retval, NULL); + + *path = g_strdup (g_hash_table_lookup (env_table, "PATH")); + *shell = g_strdup (g_hash_table_lookup (env_table, "SHELL")); + + g_hash_table_destroy (env_table); + return (char **) g_ptr_array_free (retval, FALSE); +} + +enum { + RESPONSE_RELAUNCH, + RESPONSE_EDIT_PREFERENCES +}; + +static void +info_bar_response_cb (GtkWidget *info_bar, + int response, + TerminalScreen *screen) +{ + gtk_widget_grab_focus (GTK_WIDGET (screen)); + + switch (response) { + case GTK_RESPONSE_CANCEL: + gtk_widget_destroy (info_bar); + g_signal_emit (screen, signals[CLOSE_SCREEN], 0); + break; + case RESPONSE_RELAUNCH: + gtk_widget_destroy (info_bar); + terminal_screen_reexec (screen, NULL, NULL, NULL, NULL); + break; + case RESPONSE_EDIT_PREFERENCES: + terminal_app_edit_preferences (terminal_app_get (), + terminal_screen_get_profile (screen), + "custom-command-entry"); + break; + default: + gtk_widget_destroy (info_bar); + break; + } +} + +static void +terminal_screen_show_info_bar (TerminalScreen *screen, + GError *error, + gboolean show_relaunch) +{ + GtkWidget *info_bar; + + if (!gtk_widget_get_parent (GTK_WIDGET (screen))) + return; + + info_bar = terminal_info_bar_new (GTK_MESSAGE_ERROR, + _("_Preferences"), RESPONSE_EDIT_PREFERENCES, + !show_relaunch ? NULL : _("_Relaunch"), RESPONSE_RELAUNCH, + NULL); + terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), + _("There was an error creating the child process for this terminal")); + terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), + "%s", error->message); + g_signal_connect (info_bar, "response", + G_CALLBACK (info_bar_response_cb), screen); + + gtk_widget_set_halign (info_bar, GTK_ALIGN_FILL); + gtk_widget_set_valign (info_bar, GTK_ALIGN_START); + gtk_overlay_add_overlay (GTK_OVERLAY (terminal_screen_container_get_from_screen (screen)), + info_bar); + gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL); + gtk_widget_show (info_bar); +} + +static void +spawn_result_cb (VteTerminal *terminal, + GPid pid, + GError *error, + gpointer user_data) +{ + TerminalScreen *screen = TERMINAL_SCREEN (terminal); + ExecData *exec_data = user_data; + + /* Terminal was destroyed while the spawn operation was in progress; nothing to do. */ + if (terminal == NULL) + goto out; + + TerminalScreenPrivate *priv = screen->priv; + + priv->child_pid = pid; + + if (error) { + // FIXMEchpe should be unnecessary, vte already does this internally + vte_terminal_set_pty (terminal, NULL); + + gboolean can_reexec = TRUE; /* FIXME */ + terminal_screen_show_info_bar (screen, error, can_reexec); + } + + /* Retain info for reexec, if possible */ + ExecData *new_exec_data = exec_data_clone (exec_data, TRUE); + terminal_screen_clear_exec_data (screen, FALSE); + priv->exec_data = new_exec_data; + +out: + + /* Must do this even if the terminal was destroyed */ + exec_data_callback (exec_data, error, screen); + + exec_data_unref (exec_data); +} + +static gboolean +idle_exec_cb (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + + priv->idle_exec_source = 0; + + ExecData *data = priv->exec_data; + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROCESSES) { + gs_free char *str = exec_data_to_string (data); + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] now launching the child process: %s\n", + screen, str); + } + + int n_fds; + int *fds; + if (data->fd_list) { + fds = g_unix_fd_list_steal_fds(data->fd_list, &n_fds); + } else { + fds = NULL; + n_fds = 0; + } + + VteTerminal *terminal = VTE_TERMINAL (screen); + vte_terminal_spawn_with_fds_async (terminal, + data->pty_flags, + data->cwd, + (char const* const*)data->exec_argv, + (char const* const*)data->envv, + fds, n_fds, + data->fd_map, data->n_fd_map, + data->spawn_flags, + NULL, NULL, NULL, /* child setup, data, destroy */ + -1, + data->cancellable, + spawn_result_cb, + exec_data_ref (data)); + + return FALSE; /* don't run again */ +} + +static void +terminal_screen_queue_idle_exec (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + + if (priv->idle_exec_source != 0) + return; + + if (!gtk_widget_get_realized (GTK_WIDGET (screen))) { + priv->exec_on_realize = TRUE; + return; + } + + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] scheduling launching the child process on idle\n", + screen); + + priv->idle_exec_source = g_idle_add ((GSourceFunc) idle_exec_cb, screen); +} + +static TerminalScreenPopupInfo * +terminal_screen_popup_info_new (TerminalScreen *screen) +{ + TerminalScreenPopupInfo *info; + + info = g_slice_new0 (TerminalScreenPopupInfo); + info->ref_count = 1; + + return info; +} + +TerminalScreenPopupInfo * +terminal_screen_popup_info_ref (TerminalScreenPopupInfo *info) +{ + g_return_val_if_fail (info != NULL, NULL); + + info->ref_count++; + return info; +} + +void +terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info) +{ + g_return_if_fail (info != NULL); + + if (--info->ref_count > 0) + return; + + g_free (info->hyperlink); + g_free (info->url); + g_free (info->number_info); + g_slice_free (TerminalScreenPopupInfo, info); +} + +static gboolean +terminal_screen_popup_menu (GtkWidget *widget) +{ + TerminalScreen *screen = TERMINAL_SCREEN (widget); + TerminalScreenPopupInfo *info; + + info = terminal_screen_popup_info_new (screen); + info->button = 0; + info->timestamp = gtk_get_current_event_time (); + + g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info); + terminal_screen_popup_info_unref (info); + + return TRUE; +} + +static void +terminal_screen_do_popup (TerminalScreen *screen, + GdkEventButton *event, + char *hyperlink, + char *url, + int url_flavor, + char *number_info) +{ + TerminalScreenPopupInfo *info; + + info = terminal_screen_popup_info_new (screen); + info->button = event->button; + info->state = event->state & gtk_accelerator_get_default_mod_mask (); + info->timestamp = event->time; + info->hyperlink = hyperlink; /* adopted */ + info->url = url; /* adopted */ + info->url_flavor = url_flavor; + info->number_info = number_info; /* adopted */ + + g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info); + terminal_screen_popup_info_unref (info); +} + +static gboolean +terminal_screen_button_press (GtkWidget *widget, + GdkEventButton *event) +{ + TerminalScreen *screen = TERMINAL_SCREEN (widget); + gboolean (* button_press_event) (GtkWidget*, GdkEventButton*) = + GTK_WIDGET_CLASS (terminal_screen_parent_class)->button_press_event; + gs_free char *hyperlink = NULL; + gs_free char *url = NULL; + int url_flavor = 0; + gs_free char *number_info = NULL; + guint state; + + state = event->state & gtk_accelerator_get_default_mod_mask (); + + hyperlink = terminal_screen_check_hyperlink (screen, (GdkEvent*)event); + url = terminal_screen_check_match (screen, (GdkEvent*)event, &url_flavor); + terminal_screen_check_extra (screen, (GdkEvent*)event, &number_info); + + if (hyperlink != NULL && + (event->button == 1 || event->button == 2) && + (state & GDK_CONTROL_MASK)) + { + gboolean handled = FALSE; + + g_signal_emit (screen, signals[MATCH_CLICKED], 0, + hyperlink, + FLAVOR_AS_IS, + state, + &handled); + if (handled) + return TRUE; /* don't do anything else such as select with the click */ + } + + if (url != NULL && + (event->button == 1 || event->button == 2) && + (state & GDK_CONTROL_MASK)) + { + gboolean handled = FALSE; + + g_signal_emit (screen, signals[MATCH_CLICKED], 0, + url, + url_flavor, + state, + &handled); + if (handled) + return TRUE; /* don't do anything else such as select with the click */ + } + + if (event->type == GDK_BUTTON_PRESS && event->button == 3) + { + if (!(event->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK))) + { + /* on right-click, we should first try to send the mouse event to + * the client, and popup only if that's not handled. */ + if (button_press_event && button_press_event (widget, event)) + return TRUE; + + terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info); + hyperlink = NULL; /* adopted to the popup info */ + url = NULL; /* ditto */ + number_info = NULL; /* ditto */ + return TRUE; + } + else if (!(event->state & (GDK_CONTROL_MASK | GDK_MOD1_MASK))) + { + /* do popup on shift+right-click */ + terminal_screen_do_popup (screen, event, hyperlink, url, url_flavor, number_info); + hyperlink = NULL; /* adopted to the popup info */ + url = NULL; /* ditto */ + number_info = NULL; /* ditto */ + return TRUE; + } + } + + /* default behavior is to let the terminal widget deal with it */ + if (button_press_event) + return button_press_event (widget, event); + + return FALSE; +} + +/** + * terminal_screen_get_current_dir: + * @screen: + * + * Tries to determine the current working directory of the foreground process + * in @screen's PTY. + * + * Returns: a newly allocated string containing the current working directory, + * or %NULL on failure + */ +char * +terminal_screen_get_current_dir (TerminalScreen *screen) +{ + const char *uri; + + uri = vte_terminal_get_current_directory_uri (VTE_TERMINAL (screen)); + if (uri != NULL) + return g_filename_from_uri (uri, NULL, NULL); + + ExecData *data = screen->priv->exec_data; + if (data && data->cwd) + return g_strdup (data->cwd); + + return NULL; +} + +static void +terminal_screen_window_title_changed (VteTerminal *vte_terminal, + TerminalScreen *screen) +{ + g_object_notify (G_OBJECT (screen), "title"); +} + +static void +terminal_screen_child_exited (VteTerminal *terminal, + int status) +{ + TerminalScreen *screen = TERMINAL_SCREEN (terminal); + TerminalScreenPrivate *priv = screen->priv; + TerminalExitAction action; + + /* Don't do anything if we don't have a child */ + if (priv->child_pid == -1) + return; + + /* No need to chain up to VteTerminalClass::child_exited since it's NULL */ + + _terminal_debug_print (TERMINAL_DEBUG_PROCESSES, + "[screen %p] child process exited\n", + screen); + + priv->child_pid = -1; + + action = g_settings_get_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION_KEY); + + switch (action) + { + case TERMINAL_EXIT_CLOSE: + g_signal_emit (screen, signals[CLOSE_SCREEN], 0); + break; + case TERMINAL_EXIT_RESTART: + terminal_screen_reexec (screen, NULL, NULL, NULL, NULL); + break; + case TERMINAL_EXIT_HOLD: { + GtkWidget *info_bar; + + info_bar = terminal_info_bar_new (GTK_MESSAGE_INFO, + _("_Relaunch"), RESPONSE_RELAUNCH, + NULL); + if (WIFEXITED (status)) { + terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), + _("The child process exited normally with status %d."), WEXITSTATUS (status)); + } else if (WIFSIGNALED (status)) { + terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), + _("The child process was aborted by signal %d."), WTERMSIG (status)); + } else { + terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar), + _("The child process was aborted.")); + } + g_signal_connect (info_bar, "response", + G_CALLBACK (info_bar_response_cb), screen); + + gtk_widget_set_halign (info_bar, GTK_ALIGN_FILL); + gtk_widget_set_valign (info_bar, GTK_ALIGN_START); + gtk_overlay_add_overlay (GTK_OVERLAY (terminal_screen_container_get_from_screen (screen)), + info_bar); + gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), RESPONSE_RELAUNCH); + gtk_widget_show (info_bar); + break; + } + + default: + break; + } +} + +static void +terminal_screen_drag_data_received (GtkWidget *widget, + GdkDragContext *context, + gint x, + gint y, + GtkSelectionData *selection_data, + guint info, + guint timestamp) +{ + TerminalScreen *screen = TERMINAL_SCREEN (widget); + TerminalScreenPrivate *priv = screen->priv; + const guchar *selection_data_data; + GdkAtom selection_data_target; + gint selection_data_length, selection_data_format; + + selection_data_data = gtk_selection_data_get_data (selection_data); + selection_data_target = gtk_selection_data_get_target (selection_data); + selection_data_length = gtk_selection_data_get_length (selection_data); + selection_data_format = gtk_selection_data_get_format (selection_data); + +#if 0 + { + GList *tmp; + + g_print ("info: %d\n", info); + tmp = context->targets; + while (tmp != NULL) + { + GdkAtom atom = GDK_POINTER_TO_ATOM (tmp->data); + + g_print ("Target: %s\n", gdk_atom_name (atom)); + + tmp = tmp->next; + } + + g_print ("Chosen target: %s\n", gdk_atom_name (selection_data->target)); + } +#endif + + if (gtk_targets_include_uri (&selection_data_target, 1)) + { + gs_strfreev char **uris; + gs_free char *text = NULL; + gsize len; + + uris = gtk_selection_data_get_uris (selection_data); + if (!uris) + return; + + terminal_util_transform_uris_to_quoted_fuse_paths (uris); + + text = terminal_util_concat_uris (uris, &len); + vte_terminal_feed_child (VTE_TERMINAL (screen), text, len); + } + else if (gtk_targets_include_text (&selection_data_target, 1)) + { + gs_free char *text; + + text = (char *) gtk_selection_data_get_text (selection_data); + if (text && text[0]) + vte_terminal_feed_child (VTE_TERMINAL (screen), text, strlen (text)); + } + else switch (info) + { + case TARGET_COLOR: + { + guint16 *data = (guint16 *)selection_data_data; + GdkRGBA color; + + /* We accept drops with the wrong format, since the KDE color + * chooser incorrectly drops application/x-color with format 8. + * So just check for the data length. + */ + if (selection_data_length != 8) + return; + + color.red = (double) data[0] / 65535.; + color.green = (double) data[1] / 65535.; + color.blue = (double) data[2] / 65535.; + color.alpha = 1.; + /* FIXME: use opacity from data[3] */ + + terminal_g_settings_set_rgba (priv->profile, + TERMINAL_PROFILE_BACKGROUND_COLOR_KEY, + &color); + g_settings_set_boolean (priv->profile, TERMINAL_PROFILE_USE_THEME_COLORS_KEY, FALSE); + } + break; + + case TARGET_MOZ_URL: + { + char *utf8_data, *text; + char *uris[2]; + gsize len; + + /* MOZ_URL is in UCS-2 but in format 8. BROKEN! + * + * The data contains the URL, a \n, then the + * title of the web page. + * + * Note that some producers (e.g. dolphin) delimit with a \r\n + * (see issue#293), so we need to handle that, too. + */ + if (selection_data_format != 8 || + selection_data_length == 0 || + (selection_data_length % 2) != 0) + return; + + utf8_data = g_utf16_to_utf8 ((const gunichar2*) selection_data_data, + selection_data_length / 2, + NULL, NULL, NULL); + if (!utf8_data) + return; + + uris[0] = g_strdelimit(utf8_data, "\r\n", 0); + uris[1] = NULL; + terminal_util_transform_uris_to_quoted_fuse_paths (uris); /* This may replace uris[0] */ + + text = terminal_util_concat_uris (uris, &len); + vte_terminal_feed_child (VTE_TERMINAL (screen), text, len); + g_free (text); + g_free (uris[0]); + } + break; + + case TARGET_NETSCAPE_URL: + { + char *utf8_data, *newline, *text; + char *uris[2]; + gsize len; + + /* The data contains the URL, a \n, then the + * title of the web page. + */ + if (selection_data_length < 0 || selection_data_format != 8) + return; + + utf8_data = g_strndup ((char *) selection_data_data, selection_data_length); + newline = strchr (utf8_data, '\n'); + if (newline) + *newline = '\0'; + + uris[0] = utf8_data; + uris[1] = NULL; + terminal_util_transform_uris_to_quoted_fuse_paths (uris); /* This may replace uris[0] */ + + text = terminal_util_concat_uris (uris, &len); + vte_terminal_feed_child (VTE_TERMINAL (screen), text, len); + g_free (text); + g_free (uris[0]); + } + break; + + case TARGET_RESET_BG: + g_settings_reset (priv->profile, TERMINAL_PROFILE_BACKGROUND_COLOR_KEY); + break; + + case TARGET_TAB: + { + GtkWidget *container; + TerminalScreen *moving_screen; + TerminalWindow *source_window; + TerminalWindow *dest_window; + + container = *(GtkWidget**) selection_data_data; + if (!GTK_IS_WIDGET (container)) + return; + + moving_screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container)); + g_warn_if_fail (TERMINAL_IS_SCREEN (moving_screen)); + if (!TERMINAL_IS_SCREEN (moving_screen)) + return; + + source_window = terminal_screen_get_window (moving_screen); + dest_window = terminal_screen_get_window (screen); + terminal_window_move_screen (source_window, dest_window, moving_screen, -1); + + gtk_drag_finish (context, TRUE, TRUE, timestamp); + } + break; + + default: + g_assert_not_reached (); + } +} + +void +_terminal_screen_update_scrollbar (TerminalScreen *screen) +{ + TerminalScreenPrivate *priv = screen->priv; + TerminalScreenContainer *container; + GtkPolicyType vpolicy; + + container = terminal_screen_container_get_from_screen (screen); + if (container == NULL) + return; + + vpolicy = g_settings_get_enum (priv->profile, TERMINAL_PROFILE_SCROLLBAR_POLICY_KEY); + + terminal_screen_container_set_policy (container, GTK_POLICY_NEVER, vpolicy); +} + +void +terminal_screen_get_size (TerminalScreen *screen, + int *width_chars, + int *height_chars) +{ + VteTerminal *terminal = VTE_TERMINAL (screen); + + *width_chars = vte_terminal_get_column_count (terminal); + *height_chars = vte_terminal_get_row_count (terminal); +} + +void +terminal_screen_get_cell_size (TerminalScreen *screen, + int *cell_width_pixels, + int *cell_height_pixels) +{ + VteTerminal *terminal = VTE_TERMINAL (screen); + + *cell_width_pixels = vte_terminal_get_char_width (terminal); + *cell_height_pixels = vte_terminal_get_char_height (terminal); +} + +static char* +terminal_screen_check_hyperlink (TerminalScreen *screen, + GdkEvent *event) +{ + return vte_terminal_hyperlink_check_event (VTE_TERMINAL (screen), event); +} + +static char* +terminal_screen_check_match (TerminalScreen *screen, + GdkEvent *event, + int *flavor) +{ + TerminalScreenPrivate *priv = screen->priv; + GSList *tags; + int tag; + char *match; + + match = vte_terminal_match_check_event (VTE_TERMINAL (screen), event, &tag); + for (tags = priv->match_tags; tags != NULL; tags = tags->next) + { + TagData *tag_data = (TagData*) tags->data; + if (tag_data->tag == tag) + { + if (flavor) + *flavor = tag_data->flavor; + return match; + } + } + + g_free (match); + return NULL; +} + +static void +terminal_screen_check_extra (TerminalScreen *screen, + GdkEvent *event, + char **number_info) +{ + guint i; + char **matches; + gboolean flavor_number_found = FALSE; + + matches = g_newa (char *, n_extra_regexes); + memset(matches, 0, sizeof(char*) * n_extra_regexes); + + if ( + vte_terminal_event_check_regex_simple (VTE_TERMINAL (screen), + event, + extra_regexes, + n_extra_regexes, + 0, + matches)) + { + for (i = 0; i < n_extra_regexes; i++) + { + if (matches[i] != NULL) + { + /* Store the first match for each flavor, free all the others */ + switch (extra_regex_flavors[i]) + { + case FLAVOR_NUMBER: + if (!flavor_number_found) + { + *number_info = terminal_util_number_info (matches[i]); + flavor_number_found = TRUE; + } + g_free (matches[i]); + break; + default: + g_free (matches[i]); + } + } + } + } +} + +/** + * terminal_screen_has_foreground_process: + * @screen: + * @process_name: (out) (allow-none): the basename of the program, or %NULL + * @cmdline: (out) (allow-none): the full command line, or %NULL + * + * Checks whether there's a foreground process running in + * this terminal. + * + * Returns: %TRUE iff there's a foreground process running in @screen + */ +gboolean +terminal_screen_has_foreground_process (TerminalScreen *screen, + char **process_name, + char **cmdline) +{ + TerminalScreenPrivate *priv = screen->priv; + gs_free char *command = NULL; + gs_free char *data_buf = NULL; + gs_free char *basename = NULL; + gs_free char *name = NULL; + VtePty *pty; + int fd; +#if defined(__FreeBSD__) || defined(__DragonFly__) || defined(__OpenBSD__) + int mib[4]; +#else + char filename[64]; +#endif + char *data; + gsize i; + gsize len; + int fgpid; + + if (priv->child_pid == -1) + return FALSE; + + pty = vte_terminal_get_pty (VTE_TERMINAL (screen)); + if (pty == NULL) + return FALSE; + + fd = vte_pty_get_fd (pty); + if (fd == -1) + return FALSE; + + fgpid = tcgetpgrp (fd); + if (fgpid == -1 || fgpid == priv->child_pid) + return FALSE; + +#if defined(__FreeBSD__) || defined(__DragonFly__) + mib[0] = CTL_KERN; + mib[1] = KERN_PROC; + mib[2] = KERN_PROC_ARGS; + mib[3] = fgpid; + if (sysctl (mib, G_N_ELEMENTS (mib), NULL, &len, NULL, 0) == -1) + return TRUE; + + data_buf = g_malloc0 (len); + if (sysctl (mib, G_N_ELEMENTS (mib), data_buf, &len, NULL, 0) == -1) + return TRUE; + data = data_buf; +#elif defined(__OpenBSD__) + mib[0] = CTL_KERN; + mib[1] = KERN_PROC_ARGS; + mib[2] = fgpid; + mib[3] = KERN_PROC_ARGV; + if (sysctl (mib, G_N_ELEMENTS (mib), NULL, &len, NULL, 0) == -1) + return TRUE; + + data_buf = g_malloc0 (len); + if (sysctl (mib, G_N_ELEMENTS (mib), data_buf, &len, NULL, 0) == -1) + return TRUE; + data = ((char**)data_buf)[0]; +#else + g_snprintf (filename, sizeof (filename), "/proc/%d/cmdline", fgpid); + if (!g_file_get_contents (filename, &data_buf, &len, NULL)) + return TRUE; + data = data_buf; +#endif + + basename = g_path_get_basename (data); + if (!basename) + return TRUE; + + name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL); + if (!name) + return TRUE; + + if (!process_name && !cmdline) + return TRUE; + + gs_transfer_out_value (process_name, &name); + + if (len > 0 && data[len - 1] == '\0') + len--; + for (i = 0; i < len; i++) + { + if (data[i] == '\0') + data[i] = ' '; + } + + command = g_filename_to_utf8 (data, -1, NULL, NULL, NULL); + if (!command) + return TRUE; + + gs_transfer_out_value (cmdline, &command); + + return TRUE; +} + +const char * +terminal_screen_get_uuid (TerminalScreen *screen) +{ + g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL); + + return screen->priv->uuid; +} diff --git a/src/terminal-screen.h b/src/terminal-screen.h new file mode 100644 index 0000000..8ea3378 --- /dev/null +++ b/src/terminal-screen.h @@ -0,0 +1,164 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2008, 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_SCREEN_H +#define TERMINAL_SCREEN_H + +#include +#include + +#include + +G_BEGIN_DECLS + +typedef enum { + FLAVOR_AS_IS, + FLAVOR_DEFAULT_TO_HTTP, + FLAVOR_VOIP_CALL, + FLAVOR_EMAIL, + FLAVOR_NUMBER, +} TerminalURLFlavor; + +/* Forward decls */ +typedef struct _TerminalScreenPopupInfo TerminalScreenPopupInfo; +typedef struct _TerminalWindow TerminalWindow; + +#define TERMINAL_TYPE_SCREEN (terminal_screen_get_type ()) +#define TERMINAL_SCREEN(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_SCREEN, TerminalScreen)) +#define TERMINAL_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_SCREEN, TerminalScreenClass)) +#define TERMINAL_IS_SCREEN(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_SCREEN)) +#define TERMINAL_IS_SCREEN_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_SCREEN)) +#define TERMINAL_SCREEN_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_SCREEN, TerminalScreenClass)) + +typedef struct _TerminalScreen TerminalScreen; +typedef struct _TerminalScreenClass TerminalScreenClass; +typedef struct _TerminalScreenPrivate TerminalScreenPrivate; + +struct _TerminalScreen +{ + VteTerminal parent_instance; + + TerminalScreenPrivate *priv; +}; + +struct _TerminalScreenClass +{ + VteTerminalClass parent_class; + + void (* profile_set) (TerminalScreen *screen, + GSettings *old_profile); + void (* show_popup_menu) (TerminalScreen *screen, + TerminalScreenPopupInfo *info); + gboolean (* match_clicked) (TerminalScreen *screen, + const char *url, + int flavor, + guint state); + void (* close_screen) (TerminalScreen *screen); +}; + +GType terminal_screen_get_type (void) G_GNUC_CONST; + +const char *terminal_screen_get_uuid (TerminalScreen *screen); + +TerminalScreen *terminal_screen_new (GSettings *profile, + const char *title, + double zoom); + +typedef void (* TerminalScreenExecCallback) (TerminalScreen *screen, + GError *error, + gpointer user_data); + +gboolean terminal_screen_exec (TerminalScreen *screen, + char **argv, + char **envv, + gboolean as_shell, + const char *cwd, + GUnixFDList *fd_list, + GVariant *fd_array, + TerminalScreenExecCallback callback, + gpointer user_data, + GDestroyNotify destroy_notify, + GCancellable *cancellable, + GError **error); + + +gboolean terminal_screen_reexec (TerminalScreen *screen, + char **envv, + const char *cwd, + GCancellable *cancellable, + GError **error); + +gboolean terminal_screen_reexec_from_screen (TerminalScreen *screen, + TerminalScreen *parent_screen, + GCancellable *cancellable, + GError **error); + +void terminal_screen_set_profile (TerminalScreen *screen, + GSettings *profile); +GSettings* terminal_screen_get_profile (TerminalScreen *screen); +GSettings* terminal_screen_ref_profile (TerminalScreen *screen); + +const char* terminal_screen_get_title (TerminalScreen *screen); + +char *terminal_screen_get_current_dir (TerminalScreen *screen); + +void terminal_screen_get_size (TerminalScreen *screen, + int *width_chars, + int *height_chars); +void terminal_screen_get_cell_size (TerminalScreen *screen, + int *width_chars, + int *height_chars); + +void _terminal_screen_update_scrollbar (TerminalScreen *screen); + +void terminal_screen_save_config (TerminalScreen *screen, + GKeyFile *key_file, + const char *group); + +gboolean terminal_screen_has_foreground_process (TerminalScreen *screen, + char **process_name, + char **cmdline); + +/* Allow scales a bit smaller and a bit larger than the usual pango ranges */ +#define TERMINAL_SCALE_XXX_SMALL (PANGO_SCALE_XX_SMALL/1.2) +#define TERMINAL_SCALE_XXXX_SMALL (TERMINAL_SCALE_XXX_SMALL/1.2) +#define TERMINAL_SCALE_XXXXX_SMALL (TERMINAL_SCALE_XXXX_SMALL/1.2) +#define TERMINAL_SCALE_XXX_LARGE (PANGO_SCALE_XX_LARGE*1.2) +#define TERMINAL_SCALE_XXXX_LARGE (TERMINAL_SCALE_XXX_LARGE*1.2) +#define TERMINAL_SCALE_XXXXX_LARGE (TERMINAL_SCALE_XXXX_LARGE*1.2) +#define TERMINAL_SCALE_MINIMUM (TERMINAL_SCALE_XXXXX_SMALL/1.2) +#define TERMINAL_SCALE_MAXIMUM (TERMINAL_SCALE_XXXXX_LARGE*1.2) + +struct _TerminalScreenPopupInfo { + int ref_count; + char *url; + TerminalURLFlavor url_flavor; + char *hyperlink; + char *number_info; + guint button; + guint state; + guint32 timestamp; +}; + +TerminalScreenPopupInfo *terminal_screen_popup_info_ref (TerminalScreenPopupInfo *info); + +void terminal_screen_popup_info_unref (TerminalScreenPopupInfo *info); + +G_END_DECLS + +#endif /* TERMINAL_SCREEN_H */ diff --git a/src/terminal-search-popover.c b/src/terminal-search-popover.c new file mode 100644 index 0000000..ff18f49 --- /dev/null +++ b/src/terminal-search-popover.c @@ -0,0 +1,580 @@ +/* + * Copyright © 2015 Christian Persch + * Copyright © 2005 Paolo Maggi + * Copyright © 2010 Red Hat (Red Hat author: Behdad Esfahbod) + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include + +#include "terminal-pcre2.h" +#include "terminal-search-popover.h" +#include "terminal-intl.h" +#include "terminal-window.h" +#include "terminal-app.h" +#include "terminal-libgsystem.h" + +typedef struct _TerminalSearchPopoverPrivate TerminalSearchPopoverPrivate; + +struct _TerminalSearchPopover +{ + GtkWindow parent_instance; +}; + +struct _TerminalSearchPopoverClass +{ + GtkWindowClass parent_class; + + /* Signals */ + void (* search) (TerminalSearchPopover *popover, + gboolean backward); +}; + +struct _TerminalSearchPopoverPrivate +{ + GtkWidget *search_entry; + GtkWidget *search_prev_button; + GtkWidget *search_next_button; + GtkWidget *reveal_button; + GtkWidget *close_button; + GtkWidget *revealer; + GtkWidget *match_case_checkbutton; + GtkWidget *entire_word_checkbutton; + GtkWidget *regex_checkbutton; + GtkWidget *wrap_around_checkbutton; + + gboolean search_text_changed; + + /* Cached regex */ + gboolean regex_caseless; + char *regex_pattern; + VteRegex *regex; +}; + +enum { + PROP_0, + PROP_REGEX, + PROP_WRAP_AROUND, + LAST_PROP +}; + +enum { + SEARCH, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; +static GParamSpec *pspecs[LAST_PROP]; +static GtkListStore *history_store; + +G_DEFINE_TYPE_WITH_PRIVATE (TerminalSearchPopover, terminal_search_popover, GTK_TYPE_WINDOW) + +#define PRIV(obj) ((TerminalSearchPopoverPrivate *) terminal_search_popover_get_instance_private ((TerminalSearchPopover *)(obj))) + +/* history */ + +#define HISTORY_MIN_ITEM_LEN (3) +#define HISTORY_LENGTH (10) + +static gboolean +history_enabled (void) +{ + gboolean enabled; + + /* not quite an exact setting for this, but close enough… */ + g_object_get (gtk_settings_get_default (), "gtk-recent-files-enabled", &enabled, NULL); + if (!enabled) + return FALSE; + + if (history_store == NULL) { + history_store = gtk_list_store_new (1, G_TYPE_STRING); + g_object_set_data_full (G_OBJECT (terminal_app_get ()), "search-history-store", + history_store, (GDestroyNotify) g_object_unref); + } + + return TRUE; +} + +static gboolean +history_remove_item (const char *text) +{ + GtkTreeModel *model = GTK_TREE_MODEL (history_store); + GtkTreeIter iter; + + if (!gtk_tree_model_get_iter_first (model, &iter)) + return FALSE; + + do { + gs_free gchar *item_text; + + gtk_tree_model_get (model, &iter, 0, &item_text, -1); + + if (item_text != NULL && strcmp (item_text, text) == 0) { + gtk_list_store_remove (history_store, &iter); + return TRUE; + } + } while (gtk_tree_model_iter_next (model, &iter)); + + return FALSE; +} + +static void +history_clamp (int max) +{ + GtkTreePath *path; + GtkTreeIter iter; + + /* -1 because TreePath counts from 0 */ + path = gtk_tree_path_new_from_indices (max - 1, -1); + + if (gtk_tree_model_get_iter (GTK_TREE_MODEL (history_store), &iter, path)) + while (1) + if (!gtk_list_store_remove (history_store, &iter)) + break; + + gtk_tree_path_free (path); +} + +static void +history_insert_item (const char *text) +{ + GtkTreeIter iter; + + if (!history_enabled () || text == NULL) + return; + + if (g_utf8_strlen (text, -1) <= HISTORY_MIN_ITEM_LEN) + return; + + /* remove the text from the store if it was already + * present. If it wasn't, clamp to max history - 1 + * before inserting the new row, otherwise appending + * would not work */ + if (!history_remove_item (text)) + history_clamp (HISTORY_LENGTH - 1); + + gtk_list_store_insert_with_values (history_store, &iter, 0, + 0, text, + -1); +} + +/* helper functions */ + +static void +update_sensitivity (TerminalSearchPopover *popover) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + gboolean can_search; + + can_search = priv->regex != NULL; + + gtk_widget_set_sensitive (priv->search_prev_button, can_search); + gtk_widget_set_sensitive (priv->search_next_button, can_search); +} + +static void +perform_search (TerminalSearchPopover *popover, + gboolean backward) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + + if (priv->regex == NULL) + return; + + /* Add to search history */ + if (priv->search_text_changed) { + const char *search_text; + + search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry)); + history_insert_item (search_text); + + priv->search_text_changed = FALSE; + } + + g_signal_emit (popover, signals[SEARCH], 0, backward); +} + +static void +previous_match_cb (GtkWidget *widget, + TerminalSearchPopover *popover) +{ + perform_search (popover, TRUE); +} + +static void +next_match_cb (GtkWidget *widget, + TerminalSearchPopover *popover) +{ + perform_search (popover, FALSE); +} + +static void +close_clicked_cb (GtkWidget *widget, + GtkWidget *popover) +{ + gtk_widget_hide (popover); +} + +static void +search_button_clicked_cb (GtkWidget *button, + TerminalSearchPopover *popover) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + + perform_search (popover, button == priv->search_prev_button); +} + +static gboolean +key_press_cb (GtkWidget *popover, + GdkEventKey *event, + gpointer user_data G_GNUC_UNUSED) +{ + if (event->keyval == GDK_KEY_Escape) { + gtk_widget_hide (popover); + return TRUE; + } + return FALSE; +} + +static void +update_regex (TerminalSearchPopover *popover) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + const char *search_text; + gboolean caseless; + gs_free char *pattern; + gs_free_error GError *error = NULL; + + search_text = gtk_entry_get_text (GTK_ENTRY (priv->search_entry)); + + caseless = !gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->match_case_checkbutton)); + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->regex_checkbutton))) { + pattern = g_strdup (search_text); + } else { + pattern = g_regex_escape_string (search_text, -1); + } + + if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->entire_word_checkbutton))) { + char *new_pattern; + new_pattern = g_strdup_printf ("\\b%s\\b", pattern); + g_free (pattern); + pattern = new_pattern; + } + + if (priv->regex_caseless == caseless && + g_strcmp0 (priv->regex_pattern, pattern) == 0) + return; + + if (priv->regex) { + vte_regex_unref (priv->regex); + } + + g_clear_pointer (&priv->regex_pattern, g_free); + + /* FIXME: if comping the regex fails, show the error message somewhere */ + if (search_text[0] != '\0') { + guint32 compile_flags; + + compile_flags = PCRE2_UTF | PCRE2_NO_UTF_CHECK | PCRE2_UCP | PCRE2_MULTILINE; + if (caseless) + compile_flags |= PCRE2_CASELESS; + + priv->regex = vte_regex_new_for_search (pattern, -1, compile_flags, &error); + if (priv->regex != NULL && + (!vte_regex_jit (priv->regex, PCRE2_JIT_COMPLETE, NULL) || + !vte_regex_jit (priv->regex, PCRE2_JIT_PARTIAL_SOFT, NULL))) { + } + + if (priv->regex != NULL) + gs_transfer_out_value (&priv->regex_pattern, &pattern); + } else { + priv->regex = NULL; + } + + priv->regex_caseless = caseless; + + update_sensitivity (popover); + + g_object_notify_by_pspec (G_OBJECT (popover), pspecs[PROP_REGEX]); +} + +static void +search_text_changed_cb (GtkToggleButton *button, + TerminalSearchPopover *popover) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + + update_regex (popover); + priv->search_text_changed = TRUE; +} + +static void +search_parameters_changed_cb (GtkToggleButton *button, + TerminalSearchPopover *popover) +{ + update_regex (popover); +} + +static void +wrap_around_toggled_cb (GtkToggleButton *button, + TerminalSearchPopover *popover) +{ + g_object_notify_by_pspec (G_OBJECT (popover), pspecs[PROP_WRAP_AROUND]); +} + +/* public functions */ + +/* Class implementation */ + +static void +terminal_search_popover_grab_focus (GtkWidget *widget) +{ + TerminalSearchPopover *popover = TERMINAL_SEARCH_POPOVER (widget); + TerminalSearchPopoverPrivate *priv = PRIV (popover); + + gtk_widget_grab_focus (priv->search_entry); +} + +static void +terminal_search_popover_init (TerminalSearchPopover *popover) +{ + TerminalSearchPopoverPrivate *priv = PRIV (popover); + GtkWidget *widget = GTK_WIDGET (popover); + + priv->regex_pattern = 0; + priv->regex_caseless = TRUE; + + gtk_widget_init_template (widget); + + /* Make the search entry reasonably wide */ + gtk_widget_set_size_request (priv->search_entry, 300, -1); + + /* Add entry completion with history */ +#if 0 + g_object_set (G_OBJECT (priv->search_entry), + "model", history_store, + "entry-text-column", 0, + NULL); +#endif + + if (history_enabled ()) { + gs_unref_object GtkEntryCompletion *completion; + + completion = gtk_entry_completion_new (); + gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (history_store)); + gtk_entry_completion_set_text_column (completion, 0); + gtk_entry_completion_set_minimum_key_length (completion, HISTORY_MIN_ITEM_LEN); + gtk_entry_completion_set_popup_completion (completion, FALSE); + gtk_entry_completion_set_inline_completion (completion, TRUE); + gtk_entry_set_completion (GTK_ENTRY (priv->search_entry), completion); + } + +#if 0 + gtk_popover_set_default_widget (GTK_POPOVER (popover), priv->search_prev_button); +#else + GtkWindow *window = GTK_WINDOW (popover); + gtk_window_set_default (window, priv->search_prev_button); +#endif + + g_signal_connect (priv->search_entry, "previous-match", G_CALLBACK (previous_match_cb), popover); + g_signal_connect (priv->search_entry, "next-match", G_CALLBACK (next_match_cb), popover); + + g_signal_connect (priv->search_prev_button, "clicked", G_CALLBACK (search_button_clicked_cb), popover); + g_signal_connect (priv->search_next_button, "clicked", G_CALLBACK (search_button_clicked_cb), popover); + + g_signal_connect (priv->close_button, "clicked", G_CALLBACK (close_clicked_cb), popover); + + g_object_bind_property (priv->reveal_button, "active", + priv->revealer, "reveal-child", + G_BINDING_DEFAULT); + + update_sensitivity (popover); + + g_signal_connect (priv->search_entry, "search-changed", G_CALLBACK (search_text_changed_cb), popover); + g_signal_connect (priv->match_case_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover); + g_signal_connect (priv->entire_word_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover); + g_signal_connect (priv->regex_checkbutton, "toggled", G_CALLBACK (search_parameters_changed_cb), popover); + + g_signal_connect (priv->wrap_around_checkbutton, "toggled", G_CALLBACK (wrap_around_toggled_cb), popover); + + g_signal_connect (popover, "key-press-event", G_CALLBACK (key_press_cb), NULL); + + if (terminal_app_get_dialog_use_headerbar (terminal_app_get ())) { + GtkWidget *headerbar; + + headerbar = g_object_new (GTK_TYPE_HEADER_BAR, + "title", gtk_window_get_title (window), + "has-subtitle", FALSE, + "show-close-button", TRUE, + "visible", TRUE, + NULL); + gtk_style_context_add_class (gtk_widget_get_style_context (headerbar), + "default-decoration"); + gtk_window_set_titlebar (window, headerbar); + } +} + +static void +terminal_search_popover_finalize (GObject *object) +{ + TerminalSearchPopover *popover = TERMINAL_SEARCH_POPOVER (object); + TerminalSearchPopoverPrivate *priv = PRIV (popover); + + if (priv->regex) { + vte_regex_unref (priv->regex); + } + + g_free (priv->regex_pattern); + + G_OBJECT_CLASS (terminal_search_popover_parent_class)->finalize (object); +} + +static void +terminal_search_popover_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalSearchPopover *popover = TERMINAL_SEARCH_POPOVER (object); + + switch (prop_id) { + case PROP_REGEX: + g_value_set_boxed (value, terminal_search_popover_get_regex (popover)); + break; + case PROP_WRAP_AROUND: + g_value_set_boolean (value, terminal_search_popover_get_wrap_around (popover)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_search_popover_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + switch (prop_id) { + case PROP_REGEX: + case PROP_WRAP_AROUND: + /* not writable */ + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_search_popover_class_init (TerminalSearchPopoverClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gobject_class->finalize = terminal_search_popover_finalize; + gobject_class->get_property = terminal_search_popover_get_property; + gobject_class->set_property = terminal_search_popover_set_property; + + widget_class->grab_focus = terminal_search_popover_grab_focus; + + signals[SEARCH] = + g_signal_new (I_("search"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalSearchPopoverClass, search), + NULL, NULL, + g_cclosure_marshal_VOID__BOOLEAN, + G_TYPE_NONE, + 1, + G_TYPE_BOOLEAN); + + pspecs[PROP_REGEX] = + g_param_spec_boxed ("regex", NULL, NULL, + VTE_TYPE_REGEX, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + + pspecs[PROP_WRAP_AROUND] = + g_param_spec_boolean ("wrap-around", NULL, NULL, + FALSE, + G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB); + + g_object_class_install_properties (gobject_class, G_N_ELEMENTS (pspecs), pspecs); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/terminal/ui/search-popover.ui"); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_entry); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_prev_button); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, search_next_button); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, reveal_button); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, close_button); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, revealer); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, match_case_checkbutton); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, entire_word_checkbutton); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, regex_checkbutton); + gtk_widget_class_bind_template_child_private (widget_class, TerminalSearchPopover, wrap_around_checkbutton); +} + +/* public API */ + +/** + * terminal_search_popover_new: + * + * Returns: a new #TerminalSearchPopover + */ +TerminalSearchPopover * +terminal_search_popover_new (GtkWidget *relative_to_widget) +{ + return g_object_new (TERMINAL_TYPE_SEARCH_POPOVER, +#if 0 + "relative-to", relative_to_widget, +#else + "transient-for", gtk_widget_get_toplevel (relative_to_widget), +#endif + NULL); +} + +/** + * terminal_search_popover_get_regex: + * @popover: a #TerminalSearchPopover + * + * Returns: (transfer none): the search regex, or %NULL + */ +VteRegex * +terminal_search_popover_get_regex (TerminalSearchPopover *popover) +{ + g_return_val_if_fail (TERMINAL_IS_SEARCH_POPOVER (popover), NULL); + + return PRIV (popover)->regex; +} + +/** + * terminal_search_popover_get_wrap_around: + * @popover: a #TerminalSearchPopover + * + * Returns: (transfer none): whether search should wrap around + */ +gboolean +terminal_search_popover_get_wrap_around (TerminalSearchPopover *popover) +{ + g_return_val_if_fail (TERMINAL_IS_SEARCH_POPOVER (popover), FALSE); + + return gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (PRIV (popover)->wrap_around_checkbutton)); +} diff --git a/src/terminal-search-popover.h b/src/terminal-search-popover.h new file mode 100644 index 0000000..10771d9 --- /dev/null +++ b/src/terminal-search-popover.h @@ -0,0 +1,49 @@ +/* + * Copyright © 2008 Christian Persch + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_SEARCH_POPOVER_H +#define TERMINAL_SEARCH_POPOVER_H + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_SEARCH_POPOVER (terminal_search_popover_get_type ()) +#define TERMINAL_SEARCH_POPOVER(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_SEARCH_POPOVER, TerminalSearchPopover)) +#define TERMINAL_SEARCH_POPOVER_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_SEARCH_POPOVER, TerminalSearchPopoverClass)) +#define TERMINAL_IS_SEARCH_POPOVER(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_SEARCH_POPOVER)) +#define TERMINAL_IS_SEARCH_POPOVER_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_SEARCH_POPOVER)) +#define TERMINAL_SEARCH_POPOVER_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_SEARCH_POPOVER, TerminalSearchPopoverClass)) + +typedef struct _TerminalSearchPopover TerminalSearchPopover; +typedef struct _TerminalSearchPopoverClass TerminalSearchPopoverClass; + +GType terminal_search_popover_get_type (void); + +TerminalSearchPopover *terminal_search_popover_new (GtkWidget *relative_to_widget); + +VteRegex * + terminal_search_popover_get_regex (TerminalSearchPopover *popover); + +gboolean terminal_search_popover_get_wrap_around (TerminalSearchPopover *popover); + +G_END_DECLS + +#endif /* !TERMINAL_SEARCH_POPOVER_H */ diff --git a/src/terminal-search-provider.c b/src/terminal-search-provider.c new file mode 100644 index 0000000..90c063e --- /dev/null +++ b/src/terminal-search-provider.c @@ -0,0 +1,379 @@ +/* + * Copyright © 2013, 2014 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include + +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-libgsystem.h" +#include "terminal-screen-container.h" +#include "terminal-search-provider.h" +#include "terminal-search-provider-gdbus-generated.h" +#include "terminal-window.h" + +struct _TerminalSearchProvider +{ + GObject parent; + + TerminalSearchProvider2 *skeleton; +}; + +struct _TerminalSearchProviderClass +{ + GObjectClass parent_class; +}; + +G_DEFINE_TYPE (TerminalSearchProvider, terminal_search_provider, G_TYPE_OBJECT) + +static char * +normalize_casefold_and_unaccent (const char *str) +{ + gs_free char *casefolded = NULL, *normalized = NULL; + char *retval = NULL; + + if (str == NULL) + goto out; + + normalized = g_utf8_normalize (str, -1, G_NORMALIZE_ALL_COMPOSE); + casefolded = g_utf8_casefold (normalized, -1); + retval = g_str_to_ascii (casefolded, NULL); + + out: + return retval; +} + +static char ** +normalize_casefold_and_unaccent_terms (const char* const *terms) +{ + char **casefolded_terms; + guint i, n; + + n = g_strv_length ((char **) terms); + casefolded_terms = g_new (char *, n + 1); + + for (i = 0; i < n; i++) + casefolded_terms[i] = normalize_casefold_and_unaccent (terms[i]); + casefolded_terms[n] = NULL; + + return casefolded_terms; +} + +static gboolean +match_terms (const char *str, + const char* const *terms) +{ + gs_free char *casefolded_str = NULL; + gboolean matches = TRUE; + guint i; + + if (str == NULL) + { + matches = FALSE; + goto out; + } + + casefolded_str = normalize_casefold_and_unaccent (str); + for (i = 0; terms[i] != NULL; i++) + { + if (strstr (casefolded_str, terms[i]) == NULL) + { + matches = FALSE; + break; + } + } + + out: + return matches; +} + +static gboolean +handle_get_initial_result_set_cb (TerminalSearchProvider2 *skeleton, + GDBusMethodInvocation *invocation, + const char *const *terms, + gpointer user_data) +{ + GList *l, *screens = NULL, *windows; + gs_unref_ptrarray GPtrArray *results; + TerminalApp *app; + gs_strfreev char **casefolded_terms = NULL; + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetInitialResultSet started\n"); + + app = terminal_app_get (); + windows = gtk_application_get_windows (GTK_APPLICATION (app)); + for (l = windows; l != NULL; l = l->next) + { + TerminalWindow *window = (TerminalWindow*)(l->data); + GList *c, *containers; + + if (!TERMINAL_IS_WINDOW (l->data)) + continue; + + containers = terminal_window_list_screen_containers (window); + for (c = containers; c != NULL; c = c->next) + { + TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (c->data); + TerminalScreen *screen; + + screen = terminal_screen_container_get_screen (container); + screens = g_list_prepend (screens, screen); + } + } + + casefolded_terms = normalize_casefold_and_unaccent_terms (terms); + results = g_ptr_array_new_with_free_func (g_free); + + for (l = screens; l != NULL; l = l->next) + { + TerminalScreen *screen = TERMINAL_SCREEN (l->data); + gs_free char *cmdline = NULL, *process = NULL; + const char *cwd, *title; + + cwd = vte_terminal_get_current_directory_uri (VTE_TERMINAL (screen)); + title = terminal_screen_get_title (screen); + terminal_screen_has_foreground_process (screen, &process, &cmdline); + if (match_terms (cwd, (const char *const *) casefolded_terms) || + match_terms (title, (const char *const *) casefolded_terms) || + match_terms (process, (const char *const *) casefolded_terms) || + match_terms (cmdline, (const char *const *) casefolded_terms)) + { + const char *uuid; + + uuid = terminal_screen_get_uuid (screen); + g_ptr_array_add (results, g_strdup (uuid)); + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "Search hit: %s\n", uuid); + } + } + + g_ptr_array_add (results, NULL); + terminal_search_provider2_complete_get_initial_result_set (skeleton, + invocation, + (const char *const *) results->pdata); + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetInitialResultSet completed\n"); + return TRUE; +} + +static gboolean +handle_get_subsearch_result_set_cb (TerminalSearchProvider2 *skeleton, + GDBusMethodInvocation *invocation, + const char *const *previous_results, + const char *const *terms, + gpointer user_data) +{ + gs_unref_ptrarray GPtrArray *results; + TerminalApp *app; + gs_strfreev char **casefolded_terms = NULL; + guint i; + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetSubsearchResultSet started\n"); + + app = terminal_app_get (); + casefolded_terms = normalize_casefold_and_unaccent_terms (terms); + results = g_ptr_array_new_with_free_func (g_free); + + for (i = 0; previous_results[i] != NULL; i++) + { + TerminalScreen *screen; + gs_free char *cmdline = NULL, *process = NULL; + const char *cwd, *title; + + screen = terminal_app_get_screen_by_uuid (app, previous_results[i]); + if (screen == NULL) + { + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "Not a screen: %s\n", previous_results[i]); + continue; + } + + cwd = vte_terminal_get_current_directory_uri (VTE_TERMINAL (screen)); + title = terminal_screen_get_title (screen); + terminal_screen_has_foreground_process (screen, &process, &cmdline); + if (match_terms (cwd, (const char *const *) casefolded_terms) || + match_terms (title, (const char *const *) casefolded_terms) || + match_terms (process, (const char *const *) casefolded_terms) || + match_terms (cmdline, (const char *const *) casefolded_terms)) + { + g_ptr_array_add (results, g_strdup (previous_results[i])); + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "Search hit: %s\n", previous_results[i]); + } + } + + g_ptr_array_add (results, NULL); + terminal_search_provider2_complete_get_subsearch_result_set (skeleton, + invocation, + (const char *const *) results->pdata); + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetSubsearchResultSet completed\n"); + return TRUE; +} + +static gboolean +handle_get_result_metas_cb (TerminalSearchProvider2 *skeleton, + GDBusMethodInvocation *invocation, + const char *const *results, + gpointer user_data) +{ + GVariantBuilder builder; + TerminalApp *app; + guint i; + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetResultMetas started\n"); + + app = terminal_app_get (); + g_variant_builder_init (&builder, G_VARIANT_TYPE ("aa{sv}")); + + for (i = 0; results[i] != NULL; i++) + { + TerminalScreen *screen; + const char *title; + gs_free char *escaped_text = NULL; + gs_free char *text = NULL; + + screen = terminal_app_get_screen_by_uuid (app, results[i]); + if (screen == NULL) + { + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "Not a screen: %s\n", results[i]); + continue; + } + + title = terminal_screen_get_title (screen); + if (terminal_screen_has_foreground_process (screen, NULL, NULL)) { + VteTerminal *terminal = VTE_TERMINAL (screen); + long cursor_row; + + vte_terminal_get_cursor_position (terminal, NULL, &cursor_row); + text = vte_terminal_get_text_range (terminal, + MAX(0, cursor_row - 1), + 0, + cursor_row + 1, + vte_terminal_get_column_count (terminal) - 1, + NULL, NULL, NULL); + } + + g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}")); + g_variant_builder_add (&builder, "{sv}", "id", g_variant_new_string (results[i])); + g_variant_builder_add (&builder, "{sv}", "name", g_variant_new_string (title)); + if (text != NULL) + { + escaped_text = g_markup_escape_text (text, -1); + g_variant_builder_add (&builder, "{sv}", "description", g_variant_new_string (escaped_text)); + } + g_variant_builder_close (&builder); + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "Meta for %s: %s\n", results[i], title); + } + + terminal_search_provider2_complete_get_result_metas (skeleton, invocation, g_variant_builder_end (&builder)); + + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "GetResultMetas completed\n"); + + return TRUE; +} + +static gboolean +handle_activate_result_cb (TerminalSearchProvider2 *skeleton, + GDBusMethodInvocation *invocation, + const char *identifier, + const char* const *terms, + guint timestamp, + gpointer user_data) +{ + GtkWidget *toplevel; + TerminalApp *app; + TerminalScreen *screen; + + app = terminal_app_get (); + screen = terminal_app_get_screen_by_uuid (app, identifier); + if (screen == NULL) + goto out; + + toplevel = gtk_widget_get_toplevel (GTK_WIDGET (screen)); + if (!gtk_widget_is_toplevel (toplevel)) + goto out; + + terminal_window_switch_screen (TERMINAL_WINDOW (toplevel), screen); + gtk_window_present_with_time (GTK_WINDOW (toplevel), timestamp); + _terminal_debug_print (TERMINAL_DEBUG_SEARCH, "ActivateResult: %s\n", identifier); + + out: + terminal_search_provider2_complete_activate_result (skeleton, invocation); + return TRUE; +} + +static void +terminal_search_provider_init (TerminalSearchProvider *provider) +{ + provider->skeleton = terminal_search_provider2_skeleton_new (); + + g_signal_connect (provider->skeleton, "handle-get-initial-result-set", + G_CALLBACK (handle_get_initial_result_set_cb), provider); + g_signal_connect (provider->skeleton, "handle-get-subsearch-result-set", + G_CALLBACK (handle_get_subsearch_result_set_cb), provider); + g_signal_connect (provider->skeleton, "handle-get-result-metas", + G_CALLBACK (handle_get_result_metas_cb), provider); + g_signal_connect (provider->skeleton, "handle-activate-result", + G_CALLBACK (handle_activate_result_cb), provider); +} + +static void +terminal_search_provider_dispose (GObject *object) +{ + TerminalSearchProvider *provider = TERMINAL_SEARCH_PROVIDER (object); + + g_clear_object (&provider->skeleton); + + G_OBJECT_CLASS (terminal_search_provider_parent_class)->dispose (object); +} + +static void +terminal_search_provider_class_init (TerminalSearchProviderClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + + gobject_class->dispose = terminal_search_provider_dispose; +} + +TerminalSearchProvider * +terminal_search_provider_new (void) +{ + return g_object_new (TERMINAL_TYPE_SEARCH_PROVIDER, NULL); +} + +gboolean +terminal_search_provider_dbus_register (TerminalSearchProvider *provider, + GDBusConnection *connection, + const char *object_path, + GError **error) +{ + return g_dbus_interface_skeleton_export (G_DBUS_INTERFACE_SKELETON (provider->skeleton), + connection, + object_path, + error); +} + +void +terminal_search_provider_dbus_unregister (TerminalSearchProvider *provider, + GDBusConnection *connection, + const char *object_path) +{ + if (g_dbus_interface_skeleton_has_connection (G_DBUS_INTERFACE_SKELETON (provider->skeleton), connection)) + g_dbus_interface_skeleton_unexport_from_connection (G_DBUS_INTERFACE_SKELETON (provider->skeleton), + connection); +} diff --git a/src/terminal-search-provider.h b/src/terminal-search-provider.h new file mode 100644 index 0000000..719bd3e --- /dev/null +++ b/src/terminal-search-provider.h @@ -0,0 +1,51 @@ +/* + * Copyright © 2013 Red Hat, Inc. + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_SEARCH_PROVIDER_H +#define TERMINAL_SEARCH_PROVIDER_H + +#include +#include + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_SEARCH_PROVIDER (terminal_search_provider_get_type ()) +#define TERMINAL_SEARCH_PROVIDER(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_SEARCH_PROVIDER, TerminalSearchProvider)) +#define TERMINAL_SEARCH_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_SEARCH_PROVIDER, TerminalSearchProviderClass)) +#define TERMINAL_IS_SEARCH_PROVIDER(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_SEARCH_PROVIDER)) +#define TERMINAL_IS_SEARCH_PROVIDER_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_SEARCH_PROVIDER)) +#define TERMINAL_SEARCH_PROVIDER_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_SEARCH_PROVIDER, TerminalSearchProviderClass)) + +typedef struct _TerminalSearchProvider TerminalSearchProvider; +typedef struct _TerminalSearchProviderClass TerminalSearchProviderClass; + +GType terminal_search_provider_get_type (void); + +TerminalSearchProvider *terminal_search_provider_new (void); + +gboolean terminal_search_provider_dbus_register (TerminalSearchProvider *provider, + GDBusConnection *connection, + const char *object_path, + GError **error); + +void terminal_search_provider_dbus_unregister (TerminalSearchProvider *provider, + GDBusConnection *connection, + const char *object_path); + +G_END_DECLS + +#endif /* !TERMINAL_SEARCH_PROVIDER_H */ diff --git a/src/terminal-settings-list.c b/src/terminal-settings-list.c new file mode 100644 index 0000000..5e52ca1 --- /dev/null +++ b/src/terminal-settings-list.c @@ -0,0 +1,938 @@ +/* + * Copyright © 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include "terminal-settings-list.h" + +#include +#include +#include + +#define G_SETTINGS_ENABLE_BACKEND +#include + +#include "terminal-type-builtins.h" +#include "terminal-schemas.h" +#include "terminal-debug.h" +#include "terminal-libgsystem.h" + +struct _TerminalSettingsList { + GSettings parent; + + char *path; + char *child_schema_id; + + char **uuids; + char *default_uuid; + + GHashTable *children; + + TerminalSettingsListFlags flags; +}; + +struct _TerminalSettingsListClass { + GSettingsClass parent; + + void (* children_changed) (TerminalSettingsList *list); + void (* default_changed) (TerminalSettingsList *list); +}; + +enum { + PROP_CHILD_SCHEMA_ID = 1, + PROP_FLAGS +}; + +enum { + SIGNAL_CHILDREN_CHANGED, + SIGNAL_DEFAULT_CHANGED, + N_SIGNALS +}; + +static guint signals[N_SIGNALS]; + +static void +strv_printerr (char **strv) +{ + char **p; + + if (strv == NULL) { + g_printerr ("(null)"); + return; + } + + for (p = strv; *p; p++) + g_printerr ("%s'%s'", p != strv ? ", " : "", *p); +} + +static char ** +strv_sort (char **strv) +{ + // FIXMEchpe + return strv; +} + +static gboolean +strv_equal (char **a, + char **b) +{ + char **e, **f; + + if (a == NULL || b == NULL) + return a == b; + + for (e = a, f = b; *e && *f; e++, f++) { + if (!g_str_equal (*e, *f)) + return FALSE; + } + + return *e == *f; +} + +static int +strv_find (char **strv, + const char *str) +{ + int i; + + if (strv == NULL || str == NULL) + return -1; + + for (i = 0; strv[i]; i++) { + if (!g_str_equal (strv[i], str)) + continue; + + return i; + } + + return -1; +} + +static char ** +strv_dupv_insert (char **strv, + const char *str) +{ + char **nstrv, **p, **q; + + if (strv == NULL) { + char *s[2] = { (char *) str, NULL }; + return g_strdupv (s); + } + + /* Is it already in the list? */ + for (p = strv; *p; p++) + if (g_str_equal (*p, str)) + return g_strdupv (strv); + + /* Not found; append */ + nstrv = g_new (char *, (p - strv) + 2); + for (p = strv, q = nstrv; *p; p++, q++) + *q = g_strdup (*p); + *q++ = g_strdup (str); + *q = NULL; + + return strv_sort (nstrv); +} + +static char ** +strv_dupv_remove (char **strv, + const char *str) +{ + char **nstrv, **p, **q; + + if (strv == NULL) + return NULL; + + nstrv = g_strdupv (strv); + for (p = q = nstrv; *p; p++) { + if (!g_str_equal (*p, str)) + *q++ = *p; + else + g_free (*p); + } + *q = NULL; + + return nstrv; +} + +gboolean +terminal_settings_list_valid_uuid (const char *str) +{ + uuid_t u; + + if (str == NULL) + return FALSE; + + return uuid_parse ((char *) str, u) == 0; +} + +static gboolean +settings_backend_is_dconf (void) +{ + gs_unref_object GSettingsBackend *backend; + + backend = g_settings_backend_get_default (); + + return g_str_equal (G_OBJECT_TYPE_NAME (backend), "DConfSettingsBackend"); +} + +static char * +new_list_entry (void) +{ + uuid_t u; + char name[37]; + + uuid_generate (u); + uuid_unparse (u, name); + + return g_strdup (name); +} + +static gboolean +validate_list (TerminalSettingsList *list, + char **entries) +{ + gboolean allow_empty = (list->flags & TERMINAL_SETTINGS_LIST_FLAG_ALLOW_EMPTY) != 0; + guint i; + + if (entries == NULL) + return allow_empty; + + for (i = 0; entries[i]; i++) { + if (!terminal_settings_list_valid_uuid (entries[i])) + return FALSE; + } + + return (i > 0) || allow_empty; +} + +static gboolean +list_map_func (GVariant *value, + gpointer *result, + gpointer user_data) +{ + TerminalSettingsList *list = user_data; + gs_strfreev char **entries; + + entries = strv_sort (g_variant_dup_strv (value, NULL)); + + if (validate_list (list, entries)) { + gs_transfer_out_value(result, &entries); + return TRUE; + } + + return FALSE; +} + +static char * +path_new (TerminalSettingsList *list, + const char *uuid) +{ + return g_strdup_printf ("%s:%s/", list->path, uuid); +} + +static GSettings * +terminal_settings_list_ref_child_internal (TerminalSettingsList *list, + const char *uuid) +{ + GSettings *child; + gs_free char *path = NULL; + + if (strv_find (list->uuids, uuid) == -1) + return NULL; + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s UUID %s\n", G_STRFUNC, uuid); + + child = g_hash_table_lookup (list->children, uuid); + if (child) + goto done; + + path = path_new (list, uuid); + child = g_settings_new_with_path (list->child_schema_id, path); + g_hash_table_insert (list->children, g_strdup (uuid), child /* adopted */); + + done: + return g_object_ref (child); +} + +static char * +new_child (TerminalSettingsList *list, + const char *name) +{ + char *new_uuid = new_list_entry (); + + if (name != NULL) { + gs_free char *new_path = path_new (list, new_uuid); + gs_unref_object GSettings *child = g_settings_new_with_path (list->child_schema_id, new_path); + g_settings_set_string (child, TERMINAL_PROFILE_VISIBLE_NAME_KEY, name); + } + + return new_uuid; +} + +static char * +clone_child (TerminalSettingsList *list, + const char *uuid, + const char *name) +{ + char *new_uuid; + gs_free char *path; + gs_free char *new_path; + guint i; + gs_unref_object DConfClient *client; + DConfChangeset *changeset; + + new_uuid = new_list_entry (); + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s UUID %s NEW UUID %s \n", G_STRFUNC, uuid ? uuid : "(null)", new_uuid); + + path = path_new (list, uuid); + new_path = path_new (list, new_uuid); + + client = dconf_client_new (); + changeset = dconf_changeset_new (); + + GSettingsSchemaSource *source = g_settings_schema_source_get_default (); /* unowned */ + gs_unref_settings_schema GSettingsSchema* schema = g_settings_schema_source_lookup (source, + list->child_schema_id, + TRUE); + /* shouldn't really happen ever */ + if (schema == NULL) + return new_uuid; + + gs_strfreev char **keys = g_settings_schema_list_keys (schema); + + for (i = 0; keys[i]; i++) { + gs_free char *rkey; + gs_unref_variant GVariant *value; + + rkey = g_strconcat (path, keys[i], NULL); + value = dconf_client_read (client, rkey); + if (value) { + gs_free char *wkey; + wkey = g_strconcat (new_path, keys[i], NULL); + dconf_changeset_set (changeset, wkey, value); + } + } + + if (name != NULL) { + GVariant *value; + value = g_variant_new_string (name); + if (value) { + gs_free char *wkey; + wkey = g_strconcat (new_path, TERMINAL_PROFILE_VISIBLE_NAME_KEY, NULL); + dconf_changeset_set (changeset, wkey, value); + } + } + + dconf_client_change_sync (client, changeset, NULL, NULL, NULL); + dconf_changeset_unref (changeset); + + return new_uuid; +} + +static char * +terminal_settings_list_add_child_internal (TerminalSettingsList *list, + const char *uuid, + const char *name) +{ + char *new_uuid; + gs_strfreev char **new_uuids; + + if (uuid && settings_backend_is_dconf ()) + new_uuid = clone_child (list, uuid, name); + else + new_uuid = new_child (list, name); + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s NEW UUID %s\n", G_STRFUNC, new_uuid); + + new_uuids = strv_dupv_insert (list->uuids, new_uuid); + g_settings_set_strv (&list->parent, TERMINAL_SETTINGS_LIST_LIST_KEY, + (const char * const *) new_uuids); + + return new_uuid; +} + +static void +terminal_settings_list_remove_child_internal (TerminalSettingsList *list, + const char *uuid) +{ + gs_strfreev char **new_uuids; + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s UUID %s\n", G_STRFUNC, uuid); + + new_uuids = strv_dupv_remove (list->uuids, uuid); + + if ((new_uuids == NULL || new_uuids[0] == NULL) && + (list->flags & TERMINAL_SETTINGS_LIST_FLAG_ALLOW_EMPTY) == 0) + return; + + g_settings_set_strv (&list->parent, TERMINAL_SETTINGS_LIST_LIST_KEY, (const char * const *) new_uuids); + + if (list->default_uuid != NULL && + g_str_equal (list->default_uuid, uuid)) + g_settings_set_string (&list->parent, TERMINAL_SETTINGS_LIST_DEFAULT_KEY, ""); + + /* Now we unset all keys under the child */ + if (settings_backend_is_dconf ()) { + gs_free char *path; + gs_unref_object DConfClient *client; + + path = path_new (list, uuid); + client = dconf_client_new (); + dconf_client_write_sync (client, path, NULL, NULL, NULL, NULL); + } +} + +static void +terminal_settings_list_update_list (TerminalSettingsList *list) +{ + char **uuids, *uuid; + GSettings *child; + GHashTable *new_children; + guint i; + gboolean changed; + + uuids = g_settings_get_mapped (&list->parent, + TERMINAL_SETTINGS_LIST_LIST_KEY, + list_map_func, list); + + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_SETTINGS_LIST) { + g_printerr ("%s: current UUIDs [", G_STRFUNC); + strv_printerr (list->uuids); + g_printerr ("]\n new UUIDs ["); + strv_printerr (uuids); + g_printerr ("]\n"); + } + + if (strv_equal (uuids, list->uuids) && + ((list->flags & TERMINAL_SETTINGS_LIST_FLAG_HAS_DEFAULT) == 0 || + strv_find (list->uuids, list->default_uuid) != -1)) { + g_strfreev (uuids); + return; + } + + new_children = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + if (uuids) { + for (i = 0; uuids[i] != NULL; i++) { + uuid = uuids[i]; + + child = g_hash_table_lookup (list->children, uuid); + + if (child) { + g_object_ref (child); + g_hash_table_remove (list->children, uuid); + g_hash_table_insert (new_children, g_strdup (uuid), child /* adopted */); + } + } + + changed = !strv_equal (uuids, list->uuids); + } else { + changed = g_strv_length (list->uuids) != 0; + } + + g_hash_table_unref (list->children); + list->children = new_children; + + g_strfreev (list->uuids); + list->uuids = uuids; /* adopts */ + + if (changed) + g_signal_emit (list, signals[SIGNAL_CHILDREN_CHANGED], 0); +} + +static void +terminal_settings_list_update_default (TerminalSettingsList *list) +{ + if ((list->flags & TERMINAL_SETTINGS_LIST_FLAG_HAS_DEFAULT) == 0) + return; + + g_free (list->default_uuid); + list->default_uuid = g_settings_get_string (&list->parent, + TERMINAL_SETTINGS_LIST_DEFAULT_KEY); + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s new default UUID %s\n", G_STRFUNC, list->default_uuid); + + g_signal_emit (list, signals[SIGNAL_DEFAULT_CHANGED], 0); +} + +G_DEFINE_TYPE (TerminalSettingsList, terminal_settings_list, G_TYPE_SETTINGS); + +static void +terminal_settings_list_changed (GSettings *list_settings, + const char *key) +{ + TerminalSettingsList *list = TERMINAL_SETTINGS_LIST (list_settings); + + _terminal_debug_print (TERMINAL_DEBUG_SETTINGS_LIST, + "%s key %s", G_STRFUNC, key ? key : "(null)"); + + if (key == NULL || + g_str_equal (key, TERMINAL_SETTINGS_LIST_LIST_KEY)) { + terminal_settings_list_update_list (list); + terminal_settings_list_update_default (list); + } + + if (key == NULL) + return; + + if (g_str_equal (key, TERMINAL_SETTINGS_LIST_DEFAULT_KEY)) { + terminal_settings_list_update_default (list); + } +} + +static void +terminal_settings_list_init (TerminalSettingsList *list) +{ + list->flags = TERMINAL_SETTINGS_LIST_FLAG_NONE; +} + +static void +terminal_settings_list_constructed (GObject *object) +{ + TerminalSettingsList *list = TERMINAL_SETTINGS_LIST (object); + + G_OBJECT_CLASS (terminal_settings_list_parent_class)->constructed (object); + + g_assert (list->child_schema_id != NULL); + + g_object_get (object, "path", &list->path, NULL); + + list->children = g_hash_table_new_full (g_str_hash, g_str_equal, + (GDestroyNotify) g_free, + (GDestroyNotify) g_object_unref); + + terminal_settings_list_changed (&list->parent, NULL); +} + +static void +terminal_settings_list_finalize (GObject *object) +{ + TerminalSettingsList *list = TERMINAL_SETTINGS_LIST (object); + + g_free (list->path); + g_free (list->child_schema_id); + g_strfreev (list->uuids); + g_free (list->default_uuid); + g_hash_table_unref (list->children); + + G_OBJECT_CLASS (terminal_settings_list_parent_class)->finalize (object); +} + +static void +terminal_settings_list_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalSettingsList *list = TERMINAL_SETTINGS_LIST (object); + + switch (prop_id) { + case PROP_CHILD_SCHEMA_ID: + list->child_schema_id = g_value_dup_string (value); + break; + case PROP_FLAGS: + list->flags = g_value_get_flags (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_settings_list_class_init (TerminalSettingsListClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GSettingsClass *settings_class = G_SETTINGS_CLASS (klass); + + object_class->set_property = terminal_settings_list_set_property; + object_class->constructed = terminal_settings_list_constructed; + object_class->finalize = terminal_settings_list_finalize; + + /** + * TerminalSettingsList:child-schema-id: + * + * The name of the schema of the children of this list. + */ + g_object_class_install_property (object_class, PROP_CHILD_SCHEMA_ID, + g_param_spec_string ("child-schema-id", NULL,NULL, + NULL, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + + /** + * TerminalSettingsList:flags: + * + * Flags from #TerminalSettingsListFlags. + */ + g_object_class_install_property (object_class, PROP_FLAGS, + g_param_spec_flags ("flags", NULL,NULL, + TERMINAL_TYPE_SETTINGS_LIST_FLAGS, + TERMINAL_SETTINGS_LIST_FLAG_NONE, + G_PARAM_CONSTRUCT_ONLY | + G_PARAM_WRITABLE | G_PARAM_STATIC_STRINGS)); + + /** + * TerminalSettingsList::children-changed: + * @list: the object on which the signal was emitted + * + * The "children-changed" signal is emitted when the list of children + * has potentially changed. + */ + signals[SIGNAL_CHILDREN_CHANGED] = + g_signal_new ("children-changed", TERMINAL_TYPE_SETTINGS_LIST, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalSettingsListClass, children_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + /** + * TerminalSettingsList::default-changed: + * @list: the object on which the signal was emitted + * + * The "default-changed" signal is emitted when the default child + * has potentially changed. + */ + signals[SIGNAL_DEFAULT_CHANGED] = + g_signal_new ("default-changed", TERMINAL_TYPE_SETTINGS_LIST, + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalSettingsListClass, default_changed), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + settings_class->changed = terminal_settings_list_changed; +} + + +/** + * terminal_settings_list_new: + * @path: the settings path for the list + * @schema_id: the schema of the list, equal to or derived from "org.gnome.Terminal.SettingsList" + * @child_schema_id: the schema of the list children + * @flags: list flags + * + * Returns: (transfer full): the newly created #TerminalSettingsList + */ +TerminalSettingsList * +terminal_settings_list_new (const char *path, + const char *schema_id, + const char *child_schema_id, + TerminalSettingsListFlags flags) +{ + g_return_val_if_fail (path != NULL, NULL); + g_return_val_if_fail (schema_id != NULL, NULL); + g_return_val_if_fail (child_schema_id != NULL, NULL); + g_return_val_if_fail (g_str_has_suffix (path, ":/"), NULL); + + return g_object_new (TERMINAL_TYPE_SETTINGS_LIST, + "schema-id", schema_id, + "child-schema-id", child_schema_id, + "path", path, + "flags", flags, + NULL); +} + +/** + * terminal_settings_list_dupv_children: + * @list: a #TerminalSettingsList + * + * Returns: (transfer full): the UUIDs of the children in the settings list, or %NULL + * if the list is empty + */ +char ** +terminal_settings_list_dupv_children (TerminalSettingsList *list) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + return g_strdupv (list->uuids); +} + +/** + * terminal_settings_list_dup_default_child: + * @list: a #TerminalSettingsList + * + * Returns: (transfer full): the UUID of the default child in the settings list + */ +char * +terminal_settings_list_dup_default_child (TerminalSettingsList *list) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + if ((list->flags & TERMINAL_SETTINGS_LIST_FLAG_HAS_DEFAULT) == 0) + return NULL; + + if ((strv_find (list->uuids, list->default_uuid)) != -1) + return g_strdup (list->default_uuid); + + /* Just randomly designate the first child as default, but don't write that + * to dconf. + */ + if (list->uuids == NULL || list->uuids[0] == NULL) { + g_warn_if_fail ((list->flags & TERMINAL_SETTINGS_LIST_FLAG_ALLOW_EMPTY)); + return NULL; + } + + return g_strdup (list->uuids[0]); +} + +/** + * terminal_settings_list_has_child: + * @list: a #TerminalSettingsList + * @uuid: the UUID of a list child + * + * Returns: %TRUE iff the child with @uuid exists + */ +gboolean +terminal_settings_list_has_child (TerminalSettingsList *list, + const char *uuid) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), FALSE); + g_return_val_if_fail (terminal_settings_list_valid_uuid (uuid), FALSE); + + return strv_find (list->uuids, uuid) != -1; +} + +/** + * terminal_settings_list_ref_child: + * @list: a #TerminalSettingsList + * @uuid: the UUID of a list child + * + * Returns the child #GSettings for the list child with UUID @uuid, or %NULL + * if @list has no such child. + * + * Returns: (transfer full): a reference to the #GSettings for the child, or %NULL + */ +GSettings * +terminal_settings_list_ref_child (TerminalSettingsList *list, + const char *uuid) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + g_return_val_if_fail (terminal_settings_list_valid_uuid (uuid), NULL); + + return terminal_settings_list_ref_child_internal (list, uuid); +} + +/** + * terminal_settings_list_ref_children: + * @list: a #TerminalSettingsList + * + * Returns the list of children #GSettings or @list. + * + * Returns: (transfer full): a list of child #GSettings of @list + */ +GList * +terminal_settings_list_ref_children (TerminalSettingsList *list) +{ + GList *l; + guint i; + + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + if (list->uuids == NULL) + return NULL; + + l = NULL; + for (i = 0; list->uuids[i]; i++) + l = g_list_prepend (l, terminal_settings_list_ref_child (list, list->uuids[i])); + + return g_list_reverse (l); +} + +/** + * terminal_settings_list_ref_default_child: + * @list: a #TerminalSettingsList + * + * Returns the default child #GSettings for the list, or %NULL if @list has no + * children. + * + * Returns: (transfer full): a reference to the #GSettings for the default child, or %NULL + */ +GSettings * +terminal_settings_list_ref_default_child (TerminalSettingsList *list) +{ + gs_free char *uuid = NULL; + + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + uuid = terminal_settings_list_dup_default_child (list); + if (uuid == NULL) + return NULL; + + return terminal_settings_list_ref_child_internal (list, uuid); +} + +/** + * terminal_settings_list_add_child: + * @list: a #TerminalSettingsList + * @name: the name of the new profile + * + * Adds a new child to the list, and returns a reference to its #GSettings. + * + * Returns: (transfer full): the UUID of new child + */ +char * +terminal_settings_list_add_child (TerminalSettingsList *list, + const char *name) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + return terminal_settings_list_add_child_internal (list, NULL, name); +} + +/** + * terminal_settings_list_clone_child: + * @list: a #TerminalSettingsList + * @uuid: the UUID of the child to clone + * @name: the name of the new child + * + * Adds a new child to the list, and returns a reference to its #GSettings. + * All keys of the new child will have the same value as @uuid's. + * + * Returns: (transfer full): the UUID of new child + */ +char * +terminal_settings_list_clone_child (TerminalSettingsList *list, + const char *uuid, + const char *name) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + g_return_val_if_fail (terminal_settings_list_valid_uuid (uuid), NULL); + + return terminal_settings_list_add_child_internal (list, uuid, name); +} + +/** + * terminal_settings_list_remove_child: + * @list: a #TerminalSettingsList + * @uuid: the UUID of a list child + * + * Removes the child with UUID @uuid from the list. + */ +void +terminal_settings_list_remove_child (TerminalSettingsList *list, + const char *uuid) +{ + g_return_if_fail (TERMINAL_IS_SETTINGS_LIST (list)); + g_return_if_fail (terminal_settings_list_valid_uuid (uuid)); + + terminal_settings_list_remove_child_internal (list, uuid); +} + +/** + * terminal_settings_list_dup_uuid_from_child: + * @list: a #TerminalSettingsList + * @child: a #GSettings of a child in the list + * + * Returns the UUID of @child in the list, or %NULL if @child is not in the list. + * + * Returns: (transfer full): the UUID of the child in the settings list, or %NULL + */ +char * +terminal_settings_list_dup_uuid_from_child (TerminalSettingsList *list, + GSettings *child) +{ + gs_free char *path; + char *p; + + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), NULL); + + g_object_get (child, "path", &path, NULL); + g_return_val_if_fail (g_str_has_prefix (path, list->path), NULL); + + p = path + strlen (list->path); + g_return_val_if_fail (p[0] == ':', NULL); + p++; + g_return_val_if_fail (strlen (p) == 37, NULL); + g_return_val_if_fail (p[36] == '/', NULL); + p[36] = '\0'; + g_assert (terminal_settings_list_valid_uuid (p)); + + return g_strdup (p); +} + +/** + * terminal_settings_list_get_set_default_child: + * @list: a #TerminalSettingsList + * @uuid: the UUID of a child in the list + * + * Sets @uuid as the default child. + */ +void +terminal_settings_list_set_default_child (TerminalSettingsList *list, + const char *uuid) +{ + g_return_if_fail (TERMINAL_IS_SETTINGS_LIST (list)); + g_return_if_fail (terminal_settings_list_valid_uuid (uuid)); + + if (!terminal_settings_list_has_child (list, uuid)) + return; + + g_settings_set_string (&list->parent, TERMINAL_SETTINGS_LIST_DEFAULT_KEY, uuid); +} + +/** + * terminal_settings_list_foreach_child: + * @list: a #TerminalSettingsList + * @callback: a #TerminalSettingsListForeachFunc + * @user_data: user data for @callback + * + * Calls @callback for each child of @list. + * + * NOTE: No changes to @list must be made from @callback. + */ +void +terminal_settings_list_foreach_child (TerminalSettingsList *list, + TerminalSettingsListForeachFunc callback, + gpointer user_data) +{ + g_return_if_fail (TERMINAL_IS_SETTINGS_LIST (list)); + g_return_if_fail (callback); + + for (char **p = list->uuids; *p; p++) { + const char *uuid = *p; + gs_unref_object GSettings *child = terminal_settings_list_ref_child_internal (list, uuid); + if (child != NULL) + callback (list, uuid, child, user_data); + } +} + +/** + * terminal_settings_list_foreach_child: + * @list: a #TerminalSettingsList + * + * Returns: the number of children of @list. + */ +guint +terminal_settings_list_get_n_children (TerminalSettingsList *list) +{ + g_return_val_if_fail (TERMINAL_IS_SETTINGS_LIST (list), 0); + + return g_hash_table_size (list->children); +} diff --git a/src/terminal-settings-list.h b/src/terminal-settings-list.h new file mode 100644 index 0000000..ecf8950 --- /dev/null +++ b/src/terminal-settings-list.h @@ -0,0 +1,89 @@ +/* + * Copyright © 2013 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_SETTINGS_LIST_H +#define TERMINAL_SETTINGS_LIST_H + +#include + +#include "terminal-enums.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_SETTINGS_LIST (terminal_settings_list_get_type ()) +#define TERMINAL_SETTINGS_LIST(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_SETTINGS_LIST, TerminalSettingsList)) +#define TERMINAL_SETTINGS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_SETTINGS_LIST, TerminalSettingsListClass)) +#define TERMINAL_IS_SETTINGS_LIST(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_SETTINGS_LIST)) +#define TERMINAL_IS_SETTINGS_LIST_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_SETTINGS_LIST)) +#define TERMINAL_SETTINGS_LIST_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_SETTINGS_LIST, TerminalSettingsListClass)) + +typedef struct _TerminalSettingsList TerminalSettingsList; +typedef struct _TerminalSettingsListClass TerminalSettingsListClass; + +GType terminal_settings_list_get_type (void); + +TerminalSettingsList *terminal_settings_list_new (const char *path, + const char *schema_id, + const char *child_schema_id, + TerminalSettingsListFlags flags); + +char **terminal_settings_list_dupv_children (TerminalSettingsList *list); + +GList *terminal_settings_list_ref_children (TerminalSettingsList *list); + +gboolean terminal_settings_list_has_child (TerminalSettingsList *list, + const char *uuid); + +GSettings *terminal_settings_list_ref_child (TerminalSettingsList *list, + const char *uuid); + +char *terminal_settings_list_add_child (TerminalSettingsList *list, + const char *name); + +char *terminal_settings_list_clone_child (TerminalSettingsList *list, + const char *uuid, + const char *name); + +void terminal_settings_list_remove_child (TerminalSettingsList *list, + const char *uuid); + +char *terminal_settings_list_dup_uuid_from_child (TerminalSettingsList *list, + GSettings *child); + +GSettings *terminal_settings_list_ref_default_child (TerminalSettingsList *list); + +char *terminal_settings_list_dup_default_child (TerminalSettingsList *list); + +void terminal_settings_list_set_default_child (TerminalSettingsList *list, + const char *uuid); + +typedef void (* TerminalSettingsListForeachFunc) (TerminalSettingsList *list, + const char *uuid, + GSettings *child, + gpointer user_data); + +void terminal_settings_list_foreach_child (TerminalSettingsList *list, + TerminalSettingsListForeachFunc callback, + gpointer user_data); + +guint terminal_settings_list_get_n_children (TerminalSettingsList *list); + +gboolean terminal_settings_list_valid_uuid (const char *str); + +G_END_DECLS + +#endif /* TERMINAL_SETTINGS_LIST_H */ diff --git a/src/terminal-tab-label.c b/src/terminal-tab-label.c new file mode 100644 index 0000000..7b4b084 --- /dev/null +++ b/src/terminal-tab-label.c @@ -0,0 +1,391 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2007, 2008 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include + +#include "terminal-intl.h" +#include "terminal-tab-label.h" +#include "terminal-icon-button.h" +#include "terminal-window.h" + +#define TERMINAL_TAB_LABEL_GET_PRIVATE(tab_label)(G_TYPE_INSTANCE_GET_PRIVATE ((tab_label), TERMINAL_TYPE_TAB_LABEL, TerminalTabLabelPrivate)) + +#define SPACING (4) + +struct _TerminalTabLabelPrivate +{ + TerminalScreen *screen; + GtkWidget *label; + GtkWidget *close_button; + gboolean bold; + GtkPositionType tab_pos; +}; + +enum +{ + PROP_0, + PROP_SCREEN +}; + +enum +{ + CLOSE_BUTTON_CLICKED, + LAST_SIGNAL +}; + +static guint signals[LAST_SIGNAL]; + +G_DEFINE_TYPE (TerminalTabLabel, terminal_tab_label, GTK_TYPE_BOX); + +/* helper functions */ + +static void +close_button_clicked_cb (GtkWidget *widget, + TerminalTabLabel *tab_label) +{ + g_signal_emit (tab_label, signals[CLOSE_BUTTON_CLICKED], 0); +} + +static void +sync_tab_label (TerminalScreen *screen, + GParamSpec *pspec, + GtkWidget *label) +{ + GtkWidget *hbox; + const char *title; + TerminalWindow *window; + + title = terminal_screen_get_title (screen); + hbox = gtk_widget_get_parent (label); + + gtk_label_set_text (GTK_LABEL (label), + title && title[0] ? title : _("Terminal")); + + gtk_widget_set_tooltip_text (hbox, title); + + /* This call updates the window size: bug 732588. + * FIXMEchpe: This is probably a GTK+ bug, should get them fix it. + */ + window = TERMINAL_WINDOW (gtk_widget_get_ancestor (GTK_WIDGET (label), + TERMINAL_TYPE_WINDOW)); + if (window != NULL) + terminal_window_update_size (window); +} + +static void +notify_tab_pos_cb (GtkNotebook *notebook, + GParamSpec *pspec G_GNUC_UNUSED, + TerminalTabLabel *label) +{ + TerminalTabLabelPrivate *priv = label->priv; + GtkPositionType pos; + + pos = gtk_notebook_get_tab_pos (notebook); + if (pos == priv->tab_pos) + return; + + priv->tab_pos = pos; + + switch (pos) { + case GTK_POS_LEFT: + case GTK_POS_RIGHT: + gtk_widget_hide (priv->close_button); + break; + case GTK_POS_TOP: + case GTK_POS_BOTTOM: + gtk_widget_show (priv->close_button); + break; + } +} + +/* public functions */ + +/* Class implementation */ + +static void +terminal_tab_label_parent_set (GtkWidget *widget, + GtkWidget *old_parent) +{ + GtkWidget *parent; + void (* parent_set) (GtkWidget *, GtkWidget *) = GTK_WIDGET_CLASS (terminal_tab_label_parent_class)->parent_set; + + if (GTK_IS_NOTEBOOK (old_parent)) { + g_signal_handlers_disconnect_by_func (old_parent, + G_CALLBACK (notify_tab_pos_cb), + widget); + } + + if (parent_set) + parent_set (widget, old_parent); + + parent = gtk_widget_get_parent (widget); + if (GTK_IS_NOTEBOOK (parent)) { + notify_tab_pos_cb (GTK_NOTEBOOK (parent), NULL, TERMINAL_TAB_LABEL (widget)); + g_signal_connect (parent, "notify::tab-pos", + G_CALLBACK (notify_tab_pos_cb), widget); + } +} + +static void +terminal_tab_label_get_preferred_width (GtkWidget *widget, + int *minimum_width, + int *natural_width) +{ + TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (widget); + TerminalTabLabelPrivate *priv = tab_label->priv; + + if (priv->tab_pos == GTK_POS_LEFT || + priv->tab_pos == GTK_POS_RIGHT) { + if (natural_width) + *natural_width = 160; + if (minimum_width) + *minimum_width = 160; + } + else + GTK_WIDGET_CLASS (terminal_tab_label_parent_class)->get_preferred_width (widget, minimum_width, natural_width); +} + +static void +terminal_tab_label_init (TerminalTabLabel *tab_label) +{ + TerminalTabLabelPrivate *priv; + + priv = tab_label->priv = TERMINAL_TAB_LABEL_GET_PRIVATE (tab_label); + + priv->tab_pos = (GtkPositionType) -1; /* invalid */ +} + +static void +terminal_tab_label_constructed (GObject *object) +{ + TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object); + TerminalTabLabelPrivate *priv = tab_label->priv; + GtkWidget *hbox, *label, *close_button; + + G_OBJECT_CLASS (terminal_tab_label_parent_class)->constructed (object); + + hbox = GTK_WIDGET (tab_label); + + g_assert (priv->screen != NULL); + + gtk_box_set_spacing (GTK_BOX (hbox), SPACING); + + priv->label = label = gtk_label_new (NULL); + gtk_widget_set_halign (label, GTK_ALIGN_CENTER); + gtk_widget_set_valign (label, GTK_ALIGN_BASELINE); + gtk_widget_set_margin_start (label, 0); + gtk_widget_set_margin_end (label, 0); + gtk_widget_set_margin_top (label, 0); + gtk_widget_set_margin_bottom (label, 0); + + gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END); + gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE); + + gtk_box_set_center_widget (GTK_BOX (hbox), label); + + priv->close_button = close_button = terminal_close_button_new (); + gtk_widget_set_tooltip_text (close_button, _("Close tab")); + gtk_box_pack_end (GTK_BOX (hbox), close_button, FALSE, FALSE, 0); + + sync_tab_label (priv->screen, NULL, label); + g_signal_connect (priv->screen, "notify::title", + G_CALLBACK (sync_tab_label), label); + + g_signal_connect (close_button, "clicked", + G_CALLBACK (close_button_clicked_cb), tab_label); + + gtk_widget_show_all (hbox); +} + +static void +terminal_tab_label_dispose (GObject *object) +{ + TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object); + TerminalTabLabelPrivate *priv = tab_label->priv; + + if (priv->screen != NULL) { + g_signal_handlers_disconnect_by_func (priv->screen, + G_CALLBACK (sync_tab_label), + priv->label); + g_object_unref (priv->screen); + priv->screen = NULL; + } + + G_OBJECT_CLASS (terminal_tab_label_parent_class)->dispose (object); +} + +static void +terminal_tab_label_finalize (GObject *object) +{ +// TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object); + + G_OBJECT_CLASS (terminal_tab_label_parent_class)->finalize (object); +} + +static void +terminal_tab_label_get_property (GObject *object, + guint prop_id, + GValue *value, + GParamSpec *pspec) +{ + TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object); + + switch (prop_id) { + case PROP_SCREEN: + g_value_set_object (value, terminal_tab_label_get_screen (tab_label)); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_tab_label_set_property (GObject *object, + guint prop_id, + const GValue *value, + GParamSpec *pspec) +{ + TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (object); + TerminalTabLabelPrivate *priv = tab_label->priv; + + switch (prop_id) { + case PROP_SCREEN: + priv->screen = g_value_dup_object (value); + break; + default: + G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec); + break; + } +} + +static void +terminal_tab_label_class_init (TerminalTabLabelClass *klass) +{ + GObjectClass *gobject_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + gobject_class->constructed = terminal_tab_label_constructed; + gobject_class->dispose = terminal_tab_label_dispose; + gobject_class->finalize = terminal_tab_label_finalize; + gobject_class->get_property = terminal_tab_label_get_property; + gobject_class->set_property = terminal_tab_label_set_property; + + widget_class->parent_set = terminal_tab_label_parent_set; + widget_class->get_preferred_width = terminal_tab_label_get_preferred_width; + + signals[CLOSE_BUTTON_CLICKED] = + g_signal_new (I_("close-button-clicked"), + G_OBJECT_CLASS_TYPE (gobject_class), + G_SIGNAL_RUN_LAST, + G_STRUCT_OFFSET (TerminalTabLabelClass, close_button_clicked), + NULL, NULL, + g_cclosure_marshal_VOID__VOID, + G_TYPE_NONE, + 0); + + g_object_class_install_property + (gobject_class, + PROP_SCREEN, + g_param_spec_object ("screen", NULL, NULL, + TERMINAL_TYPE_SCREEN, + G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB | + G_PARAM_CONSTRUCT_ONLY)); + + g_type_class_add_private (gobject_class, sizeof (TerminalTabLabelPrivate)); +} + +/* public API */ + +/** + * terminal_tab_label_new: + * @screen: a #TerminalScreen + * + * Returns: a new #TerminalTabLabel for @screen + */ +GtkWidget * +terminal_tab_label_new (TerminalScreen *screen) +{ + return g_object_new (TERMINAL_TYPE_TAB_LABEL, + "orientation", GTK_ORIENTATION_HORIZONTAL, + "screen", screen, + NULL); +} + +/** + * terminal_tab_label_set_bold: + * @tab_label: a #TerminalTabLabel + * @bold: whether to enable label bolding + * + * Sets the tab label text bold, or unbolds it. + */ +void +terminal_tab_label_set_bold (TerminalTabLabel *tab_label, + gboolean bold) +{ + TerminalTabLabelPrivate *priv = tab_label->priv; + PangoAttrList *attr_list; + PangoAttribute *weight_attr; + gboolean free_list = FALSE; + + bold = bold != FALSE; + if (priv->bold == bold) + return; + + priv->bold = bold; + + attr_list = gtk_label_get_attributes (GTK_LABEL (priv->label)); + if (!attr_list) { + attr_list = pango_attr_list_new (); + free_list = TRUE; + } + + if (bold) + weight_attr = pango_attr_weight_new (PANGO_WEIGHT_BOLD); + else + weight_attr = pango_attr_weight_new (PANGO_WEIGHT_NORMAL); + + /* gtk_label_get_attributes() returns the label's internal list, + * which we're probably not supposed to modify directly. + * It seems to work ok however. + */ + pango_attr_list_change (attr_list, weight_attr); + + gtk_label_set_attributes (GTK_LABEL (priv->label), attr_list); + + if (free_list) + pango_attr_list_unref (attr_list); +} + +/** + * terminal_tab_label_get_screen: + * @tab_label: a #TerminalTabLabel + * + * Returns: (transfer none): the #TerminalScreen for @tab_label + */ +TerminalScreen * +terminal_tab_label_get_screen (TerminalTabLabel *tab_label) +{ + g_return_val_if_fail (TERMINAL_IS_TAB_LABEL (tab_label), NULL); + + return tab_label->priv->screen; +} diff --git a/src/terminal-tab-label.h b/src/terminal-tab-label.h new file mode 100644 index 0000000..20cfbce --- /dev/null +++ b/src/terminal-tab-label.h @@ -0,0 +1,66 @@ +/* + * Copyright © 2008 Christian Persch + * + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_TAB_LABEL_H +#define TERMINAL_TAB_LABEL_H + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_TAB_LABEL (terminal_tab_label_get_type ()) +#define TERMINAL_TAB_LABEL(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_TAB_LABEL, TerminalTabLabel)) +#define TERMINAL_TAB_LABEL_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_TAB_LABEL, TerminalTabLabelClass)) +#define TERMINAL_IS_TAB_LABEL(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_TAB_LABEL)) +#define TERMINAL_IS_TAB_LABEL_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_TAB_LABEL)) +#define TERMINAL_TAB_LABEL_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_TAB_LABEL, TerminalTabLabelClass)) + +typedef struct _TerminalTabLabel TerminalTabLabel; +typedef struct _TerminalTabLabelClass TerminalTabLabelClass; +typedef struct _TerminalTabLabelPrivate TerminalTabLabelPrivate; + +struct _TerminalTabLabel +{ + GtkBox parent_instance; + + /*< private >*/ + TerminalTabLabelPrivate *priv; +}; + +struct _TerminalTabLabelClass +{ + GtkBoxClass parent_class; + + /* Signals */ + void (* close_button_clicked) (TerminalTabLabel *tab_label); +}; + +GType terminal_tab_label_get_type (void); + +GtkWidget * terminal_tab_label_new (TerminalScreen *screen); + +void terminal_tab_label_set_bold (TerminalTabLabel *tab_label, + gboolean bold); + +TerminalScreen *terminal_tab_label_get_screen (TerminalTabLabel *tab_label); + +G_END_DECLS + +#endif /* !TERMINAL_TAB_LABEL_H */ diff --git a/src/terminal-type-builtins.c.template b/src/terminal-type-builtins.c.template new file mode 100644 index 0000000..eb8fe99 --- /dev/null +++ b/src/terminal-type-builtins.c.template @@ -0,0 +1,45 @@ +/*** BEGIN file-header ***/ +#include + +#include "terminal-type-builtins.h" + +/*** END file-header ***/ + +/*** BEGIN file-production ***/ +/* enumerations from "@filename@" */ + +#include "@filename@" + +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType +@enum_name@_get_type (void) +{ + static volatile gsize g_define_type_id__volatile = 0; + + if (g_once_init_enter (&g_define_type_id__volatile)) { + static const G@Type@Value values[] = { +/*** END value-header ***/ + +/*** BEGIN value-production ***/ + { @VALUENAME@, "@VALUENAME@", "@valuenick@" }, +/*** END value-production ***/ + +/*** BEGIN value-tail ***/ + { 0, NULL, NULL } + }; + GType g_define_type_id = \ + g_@type@_register_static (/* g_intern_static_string */ ("@EnumName@"), values); + + g_once_init_leave (&g_define_type_id__volatile, g_define_type_id); + } + + return g_define_type_id__volatile; +} + +/*** END value-tail ***/ + +/*** BEGIN file-tail ***/ + +/*** END file-tail ***/ diff --git a/src/terminal-type-builtins.h.template b/src/terminal-type-builtins.h.template new file mode 100644 index 0000000..c454d05 --- /dev/null +++ b/src/terminal-type-builtins.h.template @@ -0,0 +1,25 @@ +/*** BEGIN file-header ***/ +#ifndef TERMINAL_TYPE_BUILTINS_H +#define TERMINAL_TYPE_BUILTINS_H + +#include + +G_BEGIN_DECLS +/*** END file-header ***/ + +/*** BEGIN file-production ***/ + +/* enumerations from "@filename@" */ +/*** END file-production ***/ + +/*** BEGIN value-header ***/ +GType @enum_name@_get_type (void); +#define TERMINAL_TYPE_@ENUMSHORT@ (@enum_name@_get_type ()) +/*** END value-header ***/ + +/*** BEGIN file-tail ***/ + +G_END_DECLS + +#endif /* !TERMINAL_TYPE_BUILTINS_H */ +/*** END file-tail ***/ diff --git a/src/terminal-util.c b/src/terminal-util.c new file mode 100644 index 0000000..3155e3f --- /dev/null +++ b/src/terminal-util.c @@ -0,0 +1,1580 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008, 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include +#include + +#include +#include + +#include +#include + +#include + +#include "terminal-accels.h" +#include "terminal-app.h" +#include "terminal-intl.h" +#include "terminal-util.h" +#include "terminal-libgsystem.h" + +/** + * terminal_util_show_error_dialog: + * @transient_parent: parent of the future dialog window; + * @weap_ptr: pointer to a #Widget pointer, to control the population. + * @error: a #GError, or %NULL + * @message_format: printf() style format string + * + * Create a #GtkMessageDialog window with the message, and present it, handling its buttons. + * If @weap_ptr is not #NULL, only create the dialog if *weap_ptr is #NULL + * (and in that * case, set @weap_ptr to be a weak pointer to the new dialog), otherwise just + * present *weak_ptr. Note that in this last case, the message will + * be changed. + */ +void +terminal_util_show_error_dialog (GtkWindow *transient_parent, + GtkWidget **weak_ptr, + GError *error, + const char *message_format, + ...) +{ + gs_free char *message; + va_list args; + + if (message_format) + { + va_start (args, message_format); + message = g_strdup_vprintf (message_format, args); + va_end (args); + } + else message = NULL; + + if (weak_ptr == NULL || *weak_ptr == NULL) + { + GtkWidget *dialog; + dialog = gtk_message_dialog_new (transient_parent, + GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_ERROR, + GTK_BUTTONS_OK, + message ? "%s" : NULL, + message); + + if (error != NULL) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", error->message); + + g_signal_connect (G_OBJECT (dialog), "response", G_CALLBACK (gtk_widget_destroy), NULL); + + if (weak_ptr != NULL) + { + *weak_ptr = dialog; + g_object_add_weak_pointer (G_OBJECT (dialog), (void**)weak_ptr); + } + + gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE); + + gtk_widget_show_all (dialog); + } + else + { + g_return_if_fail (GTK_IS_MESSAGE_DIALOG (*weak_ptr)); + + /* Sucks that there's no direct accessor for "text" property */ + g_object_set (G_OBJECT (*weak_ptr), "text", message, NULL); + + gtk_window_present (GTK_WINDOW (*weak_ptr)); + } +} + +static gboolean +open_url (GtkWindow *parent, + const char *uri, + guint32 user_time, + GError **error) +{ + GdkScreen *screen; + gs_free char *uri_fixed; + + if (parent) + screen = gtk_widget_get_screen (GTK_WIDGET (parent)); + else + screen = gdk_screen_get_default (); + + uri_fixed = terminal_util_uri_fixup (uri, error); + if (uri_fixed == NULL) + return FALSE; + + return gtk_show_uri (screen, uri_fixed, user_time, error); +} + +void +terminal_util_show_help (const char *topic) +{ + gs_free_error GError *error = NULL; + gs_free char *uri; + + if (topic) { + uri = g_strdup_printf ("help:gnome-terminal/%s", topic); + } else { + uri = g_strdup ("help:gnome-terminal"); + } + + if (!open_url (NULL, uri, gtk_get_current_event_time (), &error)) + { + terminal_util_show_error_dialog (NULL, NULL, error, + _("There was an error displaying help")); + } +} + +#define ABOUT_GROUP "About" +#define ABOUT_URL "https://wiki.gnome.org/Apps/Terminal" +#define EMAILIFY(string) (g_strdelimit ((string), "%", '@')) + +void +terminal_util_show_about (void) +{ + static const char copyright[] = + "Copyright © 2002–2004 Havoc Pennington\n" + "Copyright © 2003–2004, 2007 Mariano Suárez-Alvarez\n" + "Copyright © 2006 Guilherme de S. Pastore\n" + "Copyright © 2007–2019 Christian Persch\n" + "Copyright © 2013–2019 Egmont Koblinger"; + char *licence_text; + GKeyFile *key_file; + GBytes *bytes; + const guint8 *data; + gsize data_len; + GError *error = NULL; + char **authors, **contributors, **artists, **documenters, **array_strv; + gsize n_authors = 0, n_contributors = 0, n_artists = 0, n_documenters = 0 , i; + GPtrArray *array; + gs_free char *comment; + gs_free char *vte_version; + GtkWindow *dialog; + + bytes = g_resources_lookup_data (TERMINAL_RESOURCES_PATH_PREFIX "/ui/terminal.about", + G_RESOURCE_LOOKUP_FLAGS_NONE, + &error); + g_assert_no_error (error); + + data = g_bytes_get_data (bytes, &data_len); + key_file = g_key_file_new (); + g_key_file_load_from_data (key_file, (const char *) data, data_len, 0, &error); + g_assert_no_error (error); + + authors = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Authors", &n_authors, NULL); + contributors = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Contributors", &n_contributors, NULL); + artists = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Artists", &n_artists, NULL); + documenters = g_key_file_get_string_list (key_file, ABOUT_GROUP, "Documenters", &n_documenters, NULL); + + g_key_file_free (key_file); + g_bytes_unref (bytes); + + array = g_ptr_array_new (); + + for (i = 0; i < n_authors; ++i) + g_ptr_array_add (array, EMAILIFY (authors[i])); + g_free (authors); /* strings are now owned by the array */ + + if (n_contributors > 0) + { + g_ptr_array_add (array, g_strdup ("")); + g_ptr_array_add (array, g_strdup (_("Contributors:"))); + for (i = 0; i < n_contributors; ++i) + g_ptr_array_add (array, EMAILIFY (contributors[i])); + } + g_free (contributors); /* strings are now owned by the array */ + + g_ptr_array_add (array, NULL); + array_strv = (char **) g_ptr_array_free (array, FALSE); + + for (i = 0; i < n_artists; ++i) + artists[i] = EMAILIFY (artists[i]); + for (i = 0; i < n_documenters; ++i) + documenters[i] = EMAILIFY (documenters[i]); + + licence_text = terminal_util_get_licence_text (); + + vte_version = g_strdup_printf (_("Using VTE version %u.%u.%u"), + vte_get_major_version (), + vte_get_minor_version (), + vte_get_micro_version ()); + + comment = g_strdup_printf("%s\n%s %s", + _("A terminal emulator for the GNOME desktop"), + vte_version, + vte_get_features ()); + + dialog = g_object_new (GTK_TYPE_ABOUT_DIALOG, + /* Hold the application while the window is shown */ + "application", terminal_app_get (), + "program-name", _("GNOME Terminal"), + "copyright", copyright, + "comments", comment, + "version", VERSION, + "authors", array_strv, + "artists", artists, + "documenters", documenters, + "license", licence_text, + "wrap-license", TRUE, + "website", ABOUT_URL, + "translator-credits", _("translator-credits"), + "logo-icon-name", GNOME_TERMINAL_ICON_NAME, + NULL); + + g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL); + gtk_window_present (dialog); + + g_strfreev (array_strv); + g_strfreev (artists); + g_strfreev (documenters); + g_free (licence_text); +} + +/* sets accessible name and description for the widget */ + +void +terminal_util_set_atk_name_description (GtkWidget *widget, + const char *name, + const char *desc) +{ + AtkObject *obj; + + obj = gtk_widget_get_accessible (widget); + + if (obj == NULL) + { + g_warning ("%s: for some reason widget has no GtkAccessible", + G_STRFUNC); + return; + } + + if (!GTK_IS_ACCESSIBLE (obj)) + return; /* This means GAIL is not loaded so we have the NoOp accessible */ + + g_return_if_fail (GTK_IS_ACCESSIBLE (obj)); + if (desc) + atk_object_set_description (obj, desc); + if (name) + atk_object_set_name (obj, name); +} + +void +terminal_util_open_url (GtkWidget *parent, + const char *orig_url, + TerminalURLFlavor flavor, + guint32 user_time) +{ + gs_free_error GError *error = NULL; + gs_free char *uri = NULL; + + g_return_if_fail (orig_url != NULL); + + switch (flavor) + { + case FLAVOR_DEFAULT_TO_HTTP: + uri = g_strdup_printf ("http://%s", orig_url); + break; + case FLAVOR_EMAIL: + if (g_ascii_strncasecmp ("mailto:", orig_url, 7) != 0) + uri = g_strdup_printf ("mailto:%s", orig_url); + else + uri = g_strdup (orig_url); + break; + case FLAVOR_VOIP_CALL: + case FLAVOR_AS_IS: + uri = g_strdup (orig_url); + break; + default: + uri = NULL; + g_assert_not_reached (); + } + + if (!open_url (GTK_WINDOW (parent), uri, user_time, &error)) + { + terminal_util_show_error_dialog (GTK_WINDOW (parent), NULL, error, + _("Could not open the address “%s”"), + uri); + } +} + +/** + * terminal_util_transform_uris_to_quoted_fuse_paths: + * @uris: + * + * Transforms those URIs in @uris to shell-quoted paths that point to + * GIO fuse paths. + */ +void +terminal_util_transform_uris_to_quoted_fuse_paths (char **uris) +{ + guint i; + + if (!uris) + return; + + for (i = 0; uris[i]; ++i) + { + gs_unref_object GFile *file; + gs_free char *path; + + file = g_file_new_for_uri (uris[i]); + + path = g_file_get_path (file); + if (path) + { + char *quoted; + + quoted = g_shell_quote (path); + g_free (uris[i]); + + uris[i] = quoted; + } + } +} + +char * +terminal_util_concat_uris (char **uris, + gsize *length) +{ + GString *string; + gsize len; + guint i; + + len = 0; + for (i = 0; uris[i]; ++i) + len += strlen (uris[i]) + 1; + + if (length) + *length = len; + + string = g_string_sized_new (len + 1); + for (i = 0; uris[i]; ++i) + { + g_string_append (string, uris[i]); + g_string_append_c (string, ' '); + } + + return g_string_free (string, FALSE); +} + +char * +terminal_util_get_licence_text (void) +{ + const gchar *license[] = { + N_("GNOME Terminal is free software: you can redistribute it and/or modify " + "it under the terms of the GNU General Public License as published by " + "the Free Software Foundation, either version 3 of the License, or " + "(at your option) any later version."), + N_("GNOME Terminal is distributed in the hope that it will be useful, " + "but WITHOUT ANY WARRANTY; without even the implied warranty of " + "MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the " + "GNU General Public License for more details."), + N_("You should have received a copy of the GNU General Public License " + "along with GNOME Terminal. If not, see .") + }; + + return g_strjoin ("\n\n", _(license[0]), _(license[1]), _(license[2]), NULL); +} + +static void +main_object_destroy_cb (GtkWidget *widget) +{ + g_object_set_data (G_OBJECT (widget), "builder", NULL); +} + +GtkBuilder * +terminal_util_load_widgets_resource (const char *path, + const char *main_object_name, + const char *object_name, + ...) +{ + GtkBuilder *builder; + GError *error = NULL; + va_list args; + + builder = gtk_builder_new (); + gtk_builder_add_from_resource (builder, path, &error); + g_assert_no_error (error); + + va_start (args, object_name); + + while (object_name) { + GObject **objectptr; + + objectptr = va_arg (args, GObject**); + *objectptr = gtk_builder_get_object (builder, object_name); + if (!*objectptr) + g_error ("Failed to fetch object \"%s\" from resource \"%s\"\n", object_name, path); + + object_name = va_arg (args, const char*); + } + + va_end (args); + + if (main_object_name) { + GObject *main_object; + GtkWidget *action_area; + + main_object = gtk_builder_get_object (builder, main_object_name); + g_object_set_data_full (main_object, "builder", g_object_ref (builder), (GDestroyNotify) g_object_unref); + g_signal_connect (main_object, "destroy", G_CALLBACK (main_object_destroy_cb), NULL); + + /* Fixup dialogue padding, #735242 */ + if (GTK_IS_DIALOG (main_object) && + (action_area = (GtkWidget *) gtk_builder_get_object (builder, "dialog-action-area"))) { + gtk_widget_set_margin_start (action_area, 5); + gtk_widget_set_margin_end (action_area, 5); + gtk_widget_set_margin_top (action_area, 5); + gtk_widget_set_margin_bottom (action_area, 5); + } + } + return builder; +} + +void +terminal_util_load_objects_resource (const char *path, + const char *object_name, + ...) +{ + gs_unref_object GtkBuilder *builder; + GError *error = NULL; + va_list args; + + builder = gtk_builder_new (); + gtk_builder_add_from_resource (builder, path, &error); + g_assert_no_error (error); + + va_start (args, object_name); + + while (object_name) { + GObject **objectptr; + + objectptr = va_arg (args, GObject**); + *objectptr = gtk_builder_get_object (builder, object_name); + if (*objectptr) + g_object_ref (*objectptr); + else + g_error ("Failed to fetch object \"%s\" from resource \"%s\"\n", object_name, path); + + object_name = va_arg (args, const char*); + } + + va_end (args); +} + +gboolean +terminal_util_dialog_response_on_delete (GtkWindow *widget) +{ + gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_DELETE_EVENT); + return TRUE; +} + +void +terminal_util_dialog_focus_widget (GtkBuilder *builder, + const char *widget_name) +{ + GtkWidget *widget, *page, *page_parent; + + if (widget_name == NULL) + return; + + widget = GTK_WIDGET (gtk_builder_get_object (builder, widget_name)); + if (widget == NULL) + return; + + page = widget; + while (page != NULL && + (page_parent = gtk_widget_get_parent (page)) != NULL && + !GTK_IS_NOTEBOOK (page_parent)) + page = page_parent; + + page_parent = gtk_widget_get_parent (page); + if (page != NULL && GTK_IS_NOTEBOOK (page_parent)) { + GtkNotebook *notebook; + + notebook = GTK_NOTEBOOK (page_parent); + gtk_notebook_set_current_page (notebook, gtk_notebook_page_num (notebook, page)); + } + + if (gtk_widget_is_sensitive (widget)) + gtk_widget_grab_focus (widget); +} + +/* Proxy stuff */ + +/* + * set_proxy_env: + * @env_table: a #GHashTable + * @key: the env var name + * @value: the env var value + * + * Adds @value for @key to @env_table, taking care to never overwrite an + * existing value for @key. @value is consumed. + */ +static void +set_proxy_env (GHashTable *env_table, + const char *key, + char *value /* consumed */) +{ + char *key1 = NULL, *key2 = NULL; + char *value1 = NULL, *value2 = NULL; + + if (!value) + return; + + if (g_hash_table_lookup (env_table, key) == NULL) + key1 = g_strdup (key); + + key2 = g_ascii_strup (key, -1); + if (g_hash_table_lookup (env_table, key) != NULL) + { + g_free (key2); + key2 = NULL; + } + + if (key1 && key2) + { + value1 = value; + value2 = g_strdup (value); + } + else if (key1) + value1 = value; + else if (key2) + value2 = value; + else + g_free (value); + + if (key1) + g_hash_table_replace (env_table, key1, value1); + if (key2) + g_hash_table_replace (env_table, key2, value2); +} + +static void +setup_proxy_env (GSettings *proxy_settings, + const char *child_schema_id, + const char *proxy_scheme, + const char *env_name, + GHashTable *env_table) +{ + gs_unref_object GSettings *child_settings; + GString *buf; + gs_free char *host; + int port; + gboolean is_http; + + is_http = (strcmp (child_schema_id, "http") == 0); + + child_settings = g_settings_get_child (proxy_settings, child_schema_id); + + host = g_settings_get_string (child_settings, "host"); + port = g_settings_get_int (child_settings, "port"); + if (host[0] == '\0' || port == 0) + return; + + buf = g_string_sized_new (64); + + g_string_append_printf (buf, "%s://", proxy_scheme); + + if (is_http && + g_settings_get_boolean (child_settings, "use-authentication")) + { + gs_free char *user; + + user = g_settings_get_string (child_settings, "authentication-user"); + if (user[0]) + { + gs_free char *password; + + g_string_append_uri_escaped (buf, user, NULL, TRUE); + + password = g_settings_get_string (child_settings, "authentication-password"); + if (password[0]) + { + g_string_append_c (buf, ':'); + g_string_append_uri_escaped (buf, password, NULL, TRUE); + } + g_string_append_c (buf, '@'); + } + } + + g_string_append_printf (buf, "%s:%d/", host, port); + set_proxy_env (env_table, env_name, g_string_free (buf, FALSE)); +} + +static void +setup_autoconfig_proxy_env (GSettings *proxy_settings, + GHashTable *env_table) +{ + /* XXX Not sure what to do with this. See bug #596688. + gs_free char *url; + + url = g_settings_get_string (proxy_settings, "autoconfig-url"); + if (url[0]) + { + char *proxy; + proxy = g_strdup_printf ("pac+%s", url); + set_proxy_env (env_table, "http_proxy", proxy); + } + */ +} + +static void +setup_ignore_proxy_env (GSettings *proxy_settings, + GHashTable *env_table) +{ + GString *buf; + gs_strfreev char **ignore; + int i; + + g_settings_get (proxy_settings, "ignore-hosts", "^as", &ignore); + if (ignore == NULL) + return; + + buf = g_string_sized_new (64); + for (i = 0; ignore[i] != NULL; ++i) + { + if (buf->len) + g_string_append_c (buf, ','); + g_string_append (buf, ignore[i]); + } + + set_proxy_env (env_table, "no_proxy", g_string_free (buf, FALSE)); +} + +/** + * terminal_util_add_proxy_env: + * @env_table: a #GHashTable + * + * Adds the proxy env variables to @env_table. + */ +void +terminal_util_add_proxy_env (GHashTable *env_table) +{ + GSettings *proxy_settings; + GDesktopProxyMode mode; + + proxy_settings = terminal_app_get_proxy_settings (terminal_app_get ()); + mode = g_settings_get_enum (proxy_settings, "mode"); + + if (mode == G_DESKTOP_PROXY_MODE_MANUAL) + { + setup_proxy_env (proxy_settings, "http", "http", "http_proxy", env_table); + /* Even though it's https, the proxy scheme is 'http'. See bug #624440. */ + setup_proxy_env (proxy_settings, "https", "http", "https_proxy", env_table); + /* Even though it's ftp, the proxy scheme is 'http'. See bug #624440. */ + setup_proxy_env (proxy_settings, "ftp", "http", "ftp_proxy", env_table); + setup_proxy_env (proxy_settings, "socks", "socks", "all_proxy", env_table); + setup_ignore_proxy_env (proxy_settings, env_table); + } + else if (mode == G_DESKTOP_PROXY_MODE_AUTO) + { + setup_autoconfig_proxy_env (proxy_settings, env_table); + } +} + +/** + * terminal_util_get_etc_shells: + * + * Returns: (transfer full) the contents of /etc/shells + */ +char ** +terminal_util_get_etc_shells (void) +{ + GError *err = NULL; + gsize len; + gs_free char *contents = NULL; + char *str, *nl, *end; + GPtrArray *arr; + + if (!g_file_get_contents ("/etc/shells", &contents, &len, &err) || len == 0) { + /* Defaults as per man:getusershell(3) */ + char *default_shells[3] = { + (char*) "/bin/sh", + (char*) "/bin/csh", + NULL + }; + return g_strdupv (default_shells); + } + + arr = g_ptr_array_new (); + str = contents; + end = contents + len; + while (str < end && (nl = strchr (str, '\n')) != NULL) { + if (str != nl) /* non-empty? */ + g_ptr_array_add (arr, g_strndup (str, nl - str)); + str = nl + 1; + } + /* Anything non-empty left? */ + if (str < end && str[0]) + g_ptr_array_add (arr, g_strdup (str)); + + g_ptr_array_add (arr, NULL); + return (char **) g_ptr_array_free (arr, FALSE); +} + +/** + * terminal_util_get_is_shell: + * @command: a string + * + * Returns wether @command is a valid shell as defined by the contents of /etc/shells. + * + * Returns: whether @command is a shell + */ +gboolean +terminal_util_get_is_shell (const char *command) +{ + gs_strfreev char **shells; + guint i; + + shells = terminal_util_get_etc_shells (); + if (shells == NULL) + return FALSE; + + for (i = 0; shells[i]; i++) + if (g_str_equal (command, shells[i])) + return TRUE; + + return FALSE; +} + +static gboolean +s_to_rgba (GVariant *variant, + gpointer *result, + gpointer user_data) +{ + GdkRGBA *color = user_data; + const char *str; + + if (variant == NULL) { + /* Fallback */ + *result = NULL; + return TRUE; + } + + g_variant_get (variant, "&s", &str); + if (!gdk_rgba_parse (color, str)) + return FALSE; + + color->alpha = 1.0; + *result = color; + return TRUE; +} + +/** + * terminal_g_settings_new: + * @schema_id: a settings schema ID + * @mandatory_key: the name of a key that must exist in the schema + * @mandatory_key_type: the expected value type of @mandatory_key + * + * Creates a #GSettings for @schema_id, if this schema exists and + * has a key named @mandatory_key (if non-%NULL) with the value type + * @mandatory_key_type. + * + * Returns: (transfer full): a new #GSettings, or %NULL + */ +GSettings * +terminal_g_settings_new (const char *schema_id, + const char *mandatory_key, + const GVariantType *mandatory_key_type) +{ + gs_unref_settings_schema GSettingsSchema *schema; + + schema = g_settings_schema_source_lookup (g_settings_schema_source_get_default (), + schema_id, + TRUE); + if (schema == NULL) + return NULL; + + if (mandatory_key) { + gs_unref_settings_schema_key GSettingsSchemaKey *key; + + key = g_settings_schema_get_key (schema, mandatory_key); + if (key == NULL) + return NULL; + + if (!g_variant_type_equal (g_settings_schema_key_get_value_type (key), + mandatory_key_type)) + return NULL; + } + + return g_settings_new_full (schema, NULL, NULL); +} + +/** + * terminal_g_settings_get_rgba: + * @settings: a #GSettings + * @key: a valid key in @settings of type "s" + * @color: location to store the parsed color + * + * Gets a color from @key in @settings. + * + * Returns: @color if parsing succeeded, or %NULL otherwise + */ +const GdkRGBA * +terminal_g_settings_get_rgba (GSettings *settings, + const char *key, + GdkRGBA *color) +{ + g_return_val_if_fail (color != NULL, FALSE); + + return g_settings_get_mapped (settings, key, + (GSettingsGetMapping) s_to_rgba, + color); +} + +/** + * terminal_g_settings_set_rgba: + * @settings: a #GSettings + * @key: a valid key in @settings of type "s" + * @color: a #GdkRGBA + * + * Sets a color in @key in @settings. + */ +void +terminal_g_settings_set_rgba (GSettings *settings, + const char *key, + const GdkRGBA *color) +{ + gs_free char *str; + + str = gdk_rgba_to_string (color); + g_settings_set_string (settings, key, str); +} + +static gboolean +as_to_rgba_palette (GVariant *variant, + gpointer *result, + gpointer user_data) +{ + gsize *n_colors = user_data; + gs_free GdkRGBA *colors = NULL; + gsize n = 0; + GVariantIter iter; + const char *str; + gsize i; + + /* Fallback */ + if (variant == NULL) + goto out; + + g_variant_iter_init (&iter, variant); + n = g_variant_iter_n_children (&iter); + colors = g_new (GdkRGBA, n); + + i = 0; + while (g_variant_iter_next (&iter, "&s", &str)) { + if (!gdk_rgba_parse (&colors[i++], str)) { + return FALSE; + } + } + + out: + gs_transfer_out_value (result, &colors); + if (n_colors) + *n_colors = n; + + return TRUE; +} + +/** + * terminal_g_settings_get_rgba_palette: + * @settings: a #GSettings + * @key: a valid key in @settings or type "s" + * @n_colors: (allow-none): location to store the number of palette entries, or %NULL + * + * Returns: (transfer full): + */ +GdkRGBA * +terminal_g_settings_get_rgba_palette (GSettings *settings, + const char *key, + gsize *n_colors) +{ + return g_settings_get_mapped (settings, key, + (GSettingsGetMapping) as_to_rgba_palette, + n_colors); +} + +void +terminal_g_settings_set_rgba_palette (GSettings *settings, + const char *key, + const GdkRGBA *colors, + gsize n_colors) +{ + gs_strfreev char **strv; + gsize i; + + strv = g_new (char *, n_colors + 1); + for (i = 0; i < n_colors; ++i) + strv[i] = gdk_rgba_to_string (&colors[i]); + strv[n_colors] = NULL; + + g_settings_set (settings, key, "^as", strv); +} + +static void +mnemonic_label_set_sensitive_cb (GtkWidget *widget, + GParamSpec *pspec, + GtkWidget *label) +{ + gtk_widget_set_sensitive (label, gtk_widget_get_sensitive (widget)); +} + +/** + * terminal_util_bind_mnemonic_label_sensitivity: + * @container: a #GtkContainer + */ +void +terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget) +{ + GList *list, *l; + + list = gtk_widget_list_mnemonic_labels (widget); + for (l = list; l != NULL; l = l->next) { + GtkWidget *label = l->data; + + if (gtk_widget_is_ancestor (label, widget)) + continue; + +#if 0 + g_print ("Widget %s has mnemonic label %s\n", + gtk_buildable_get_name (GTK_BUILDABLE (widget)), + gtk_buildable_get_name (GTK_BUILDABLE (label))); +#endif + + mnemonic_label_set_sensitive_cb (widget, NULL, label); + g_signal_connect (widget, "notify::sensitive", + G_CALLBACK (mnemonic_label_set_sensitive_cb), + label); + } + g_list_free (list); + + if (GTK_IS_CONTAINER (widget)) + gtk_container_foreach (GTK_CONTAINER (widget), + /* See #96 for double casting. */ + (GtkCallback) (GCallback) terminal_util_bind_mnemonic_label_sensitivity, + NULL); +} + +/* + * "1234567", "'", 3 -> "1'234'567" + */ +static char * +add_separators (const char *in, const char *sep, int groupby) +{ + int inlen, outlen, seplen, firstgrouplen; + char *out, *ret; + + if (in[0] == '\0') + return g_strdup(""); + + inlen = strlen(in); + seplen = strlen(sep); + outlen = inlen + (inlen - 1) / groupby * seplen; + ret = out = g_malloc(outlen + 1); + + firstgrouplen = (inlen - 1) % groupby + 1; + memcpy(out, in, firstgrouplen); + in += firstgrouplen; + out += firstgrouplen; + + while (*in != '\0') { + memcpy(out, sep, seplen); + out += seplen; + memcpy(out, in, groupby); + in += groupby; + out += groupby; + } + + g_assert(out - ret == outlen); + *out = '\0'; + return ret; +} + +/** + * terminal_util_number_info: + * @str: a dec or hex number as string + * + * Returns: (transfer full): Useful info about @str, or %NULL if it's too large + */ +char * +terminal_util_number_info (const char *str) +{ + gs_free char *decstr = NULL; + gs_free char *hextmp = NULL; + gs_free char *hexstr = NULL; + gs_free char *magnitudestr = NULL; + unsigned long long num; + gboolean exact = TRUE; + gboolean hex = FALSE; + const char *thousep; + + errno = 0; + /* Deliberately not handle octal */ + if (str[1] == 'x' || str[1] == 'X') { + num = strtoull(str + 2, NULL, 16); + hex = TRUE; + } else { + num = strtoull(str, NULL, 10); + } + if (errno) { + return NULL; + } + + /* No use in dec-hex conversion for so small numbers */ + if (num < 10) { + return NULL; + } + + /* Group the decimal digits */ + thousep = nl_langinfo(THOUSEP); + if (thousep[0] != '\0') { + /* If thousep is nonempty, use printf's magic which can handle + more complex separating logics, e.g. 2+2+2+3 for some locales */ + decstr = g_strdup_printf("%'llu", num); + } else { + /* If, however, thousep is empty, override it with a space so that we + do always group the digits (that's the whole point of this feature; + the choice of space guarantees not conflicting with the decimal separator) */ + gs_free char *tmp = g_strdup_printf("%llu", num); + thousep = " "; + decstr = add_separators(tmp, thousep, 3); + } + + /* Group the hex digits by 4 using the same nonempty separator */ + hextmp = g_strdup_printf("%llx", num); + hexstr = add_separators(hextmp, thousep, 4); + + /* Find out the human-readable magnitude, e.g. 15.99 Mi */ + if (num >= 1024) { + int power = 0; + while (num >= 1024 * 1024) { + power++; + if (num % 1024 != 0) + exact = FALSE; + num /= 1024; + } + /* Show 2 fraction digits, always rounding downwards. Printf rounds floats to the nearest representable value, + so do the calculation with integers until we get 100-fold the desired value, and then switch to float. */ + if (100 * num % 1024 != 0) + exact = FALSE; + num = 100 * num / 1024; + magnitudestr = g_strdup_printf(" %s %.2f %ci", exact ? "=" : "≈", (double) num / 100, "KMGTPE"[power]); + } else { + magnitudestr = g_strdup(""); + } + + return g_strdup_printf(hex ? "0x%2$s = %1$s%3$s" : "%s = 0x%s%s", decstr, hexstr, magnitudestr); +} + +/** + * terminal_util_uri_fixup: + * @uri: The URI to verify and maybe fixup + * @error: a #GError that is returned in case of errors + * + * Checks if gnome-terminal should attempt to handle the given URI, + * and rewrites if necessary. + * + * Currently URIs of "file://some-other-host/..." are refused because + * GIO (e.g. gtk_show_uri()) silently strips off the remote hostname + * and opens the local counterpart which is incorrect and misleading. + * + * Furthermore, once the hostname is verified, it is stripped off to + * avoid potential confusion around short hostname vs. fqdn, and to + * work around bug 781800 (LibreOffice bug 107461). + * + * Returns: The possibly rewritten URI if gnome-terminal should attempt + * to handle it, NULL if it should refuse to handle. + */ +char * +terminal_util_uri_fixup (const char *uri, + GError **error) +{ + gs_free char *filename; + gs_free char *hostname; + + filename = g_filename_from_uri (uri, &hostname, NULL); + if (filename != NULL && + hostname != NULL && + hostname[0] != '\0') { + /* "file" scheme and nonempty hostname */ + if (g_ascii_strcasecmp (hostname, "localhost") == 0 || + g_ascii_strcasecmp (hostname, g_get_host_name()) == 0) { + /* hostname corresponds to localhost */ + char *slash1, *slash2, *slash3; + + /* We shouldn't enter this branch in case of URIs like + * "file:/etc/passwd", but just in case we do, or encounter + * something else unexpected, leave the URI unchanged. */ + slash1 = strchr(uri, '/'); + if (slash1 == NULL) + return g_strdup (uri); + + slash2 = slash1 + 1; + if (*slash2 != '/') + return g_strdup (uri); + + slash3 = strchr(slash2 + 1, '/'); + if (slash3 == NULL) + return g_strdup (uri); + + return g_strdup_printf("%.*s%s", + (int) (slash2 + 1 - uri), + uri, + slash3); + } else { + /* hostname refers to another host (e.g. the OSC 8 escape sequence + * was correctly emitted by a utility inside an ssh session) */ + g_set_error_literal (error, + G_IO_ERROR, + G_IO_ERROR_NOT_SUPPORTED, + _("“file” scheme with remote hostname not supported")); + return NULL; + } + } else { + /* "file" scheme without hostname, or some other scheme */ + return g_strdup (uri); + } +} + +/** + * terminal_util_hyperlink_uri_label: + * @uri: a URI + * + * Formats @uri to be displayed in a tooltip. + * Performs URI-decoding and converts IDN hostname to UTF-8. + * + * Returns: (transfer full): The human readable URI as plain text + */ +char *terminal_util_hyperlink_uri_label (const char *uri) +{ + gs_free char *unesc = NULL; + gboolean replace_hostname; + + if (uri == NULL) + return NULL; + + unesc = g_uri_unescape_string(uri, NULL); + if (unesc == NULL) + unesc = g_strdup(uri); + + if (g_ascii_strncasecmp(unesc, "ftp://", 6) == 0 || + g_ascii_strncasecmp(unesc, "http://", 7) == 0 || + g_ascii_strncasecmp(unesc, "https://", 8) == 0) { + gs_free char *unidn = NULL; + char *hostname = strchr(unesc, '/') + 2; + char *hostname_end = strchrnul(hostname, '/'); + char save = *hostname_end; + *hostname_end = '\0'; + unidn = g_hostname_to_unicode(hostname); + replace_hostname = unidn != NULL && g_ascii_strcasecmp(unidn, hostname) != 0; + *hostname_end = save; + if (replace_hostname) { + char *new_unesc = g_strdup_printf("%.*s%s%s", + (int) (hostname - unesc), + unesc, + unidn, + hostname_end); + g_free(unesc); + unesc = new_unesc; + } + } + + return g_utf8_make_valid (unesc, -1); +} + +#define TERMINAL_CACHE_DIR "gnome-terminal" +#define TERMINAL_PRINT_SETTINGS_FILENAME "print-settings.ini" +#define TERMINAL_PRINT_SETTINGS_GROUP_NAME "Print Settings" +#define TERMINAL_PAGE_SETUP_GROUP_NAME "Page Setup" + +#define KEYFILE_FLAGS_FOR_LOAD (G_KEY_FILE_NONE) +#define KEYFILE_FLAGS_FOR_SAVE (G_KEY_FILE_KEEP_COMMENTS | G_KEY_FILE_KEEP_TRANSLATIONS) + +static char * +get_cache_dir (void) +{ + return g_build_filename (g_get_user_cache_dir (), TERMINAL_CACHE_DIR, NULL); +} + +static gboolean +ensure_cache_dir (void) +{ + gs_free char *cache_dir; + int r; + + cache_dir = get_cache_dir (); + errno = 0; + r = g_mkdir_with_parents (cache_dir, 0700); + if (r == -1 && errno != EEXIST) + g_printerr ("Failed to create cache dir: %m\n"); + return r == 0; +} + +static char * +get_cache_filename (const char *filename) +{ + gs_free char *cache_dir = get_cache_dir (); + return g_build_filename (cache_dir, filename, NULL); +} + +static GKeyFile * +load_cache_keyfile (const char *filename, + GKeyFileFlags flags, + gboolean ignore_error) +{ + gs_free char *path; + GKeyFile *keyfile; + + path = get_cache_filename (filename); + keyfile = g_key_file_new (); + if (g_key_file_load_from_file (keyfile, path, flags, NULL) || ignore_error) + return keyfile; + + g_key_file_unref (keyfile); + return NULL; +} + +static void +save_cache_keyfile (GKeyFile *keyfile, + const char *filename) +{ + gs_free char *path = NULL; + gs_free char *data = NULL; + gsize len = 0; + + if (!ensure_cache_dir ()) + return; + + data = g_key_file_to_data (keyfile, &len, NULL); + if (data == NULL || len == 0) + return; + + path = get_cache_filename (filename); + + /* Ignore errors */ + GError *err = NULL; + if (!g_file_set_contents (path, data, len, &err)) { + g_printerr ("Error saving print settings: %s\n", err->message); + g_error_free (err); + } +} + +static void +keyfile_remove_keys (GKeyFile *keyfile, + const char *group_name, + ...) +{ + va_list args; + const char *key; + + va_start (args, group_name); + while ((key = va_arg (args, const char *)) != NULL) { + g_key_file_remove_key (keyfile, group_name, key, NULL); + } + va_end (args); +} + +/** + * terminal_util_load_print_settings: + * + * Loads the saved print settings, if any. + */ +void +terminal_util_load_print_settings (GtkPrintSettings **settings, + GtkPageSetup **page_setup) +{ + gs_unref_key_file GKeyFile *keyfile = load_cache_keyfile (TERMINAL_PRINT_SETTINGS_FILENAME, + KEYFILE_FLAGS_FOR_LOAD, + FALSE); + if (keyfile == NULL) { + *settings = NULL; + *page_setup = NULL; + return; + } + + /* Ignore errors */ + *settings = gtk_print_settings_new_from_key_file (keyfile, + TERMINAL_PRINT_SETTINGS_GROUP_NAME, + NULL); + *page_setup = gtk_page_setup_new_from_key_file (keyfile, + TERMINAL_PAGE_SETUP_GROUP_NAME, + NULL); +} + +/** + * terminal_util_save_print_settings: + * @settings: (allow-none): a #GtkPrintSettings + * @page_setup: (allow-none): a #GtkPageSetup + * + * Saves the print settings. + */ +void +terminal_util_save_print_settings (GtkPrintSettings *settings, + GtkPageSetup *page_setup) +{ + gs_unref_key_file GKeyFile *keyfile = NULL; + + keyfile = load_cache_keyfile (TERMINAL_PRINT_SETTINGS_FILENAME, + KEYFILE_FLAGS_FOR_SAVE, + TRUE); + g_assert (keyfile != NULL); + + if (settings != NULL) + gtk_print_settings_to_key_file (settings, keyfile, + TERMINAL_PRINT_SETTINGS_GROUP_NAME); + + /* Some keys are not desirable to persist; remove these. + * This list comes from evince. + */ + keyfile_remove_keys (keyfile, + TERMINAL_PRINT_SETTINGS_GROUP_NAME, + GTK_PRINT_SETTINGS_COLLATE, + GTK_PRINT_SETTINGS_NUMBER_UP, + GTK_PRINT_SETTINGS_N_COPIES, + GTK_PRINT_SETTINGS_OUTPUT_URI, + GTK_PRINT_SETTINGS_PAGE_RANGES, + GTK_PRINT_SETTINGS_PAGE_SET, + GTK_PRINT_SETTINGS_PRINT_PAGES, + GTK_PRINT_SETTINGS_REVERSE, + GTK_PRINT_SETTINGS_SCALE, + NULL); + + if (page_setup != NULL) + gtk_page_setup_to_key_file (page_setup, keyfile, + TERMINAL_PAGE_SETUP_GROUP_NAME); + + /* Some keys are not desirable to persist; remove these. + * This list comes from evince. + */ + keyfile_remove_keys (keyfile, + TERMINAL_PAGE_SETUP_GROUP_NAME, + "page-setup-orientation", + "page-setup-margin-bottom", + "page-setup-margin-left", + "page-setup-margin-right", + "page-setup-margin-top", + NULL); + + save_cache_keyfile (keyfile, TERMINAL_PRINT_SETTINGS_FILENAME); +} + +/* + * terminal_util_translate_encoding: + * @encoding: the encoding name + * + * Translates old encoding name to the one supported by ICU, or + * to %NULL if the encoding is not known to ICU. + * + * Returns: (transfer none): the translated encoding, or %NULL if + * not translation was possible. + */ +const char* +terminal_util_translate_encoding (const char *encoding) +{ + if (vte_get_encoding_supported (encoding)) + return encoding; + + /* ICU knows (or has aliases for) most of the old names, except the following */ + struct { + const char *name; + const char *replacement; + } translations[] = { + { "ARMSCII-8", NULL }, /* apparently not supported by ICU */ + { "GEORGIAN-PS", NULL }, /* no idea which charset this even is */ + { "ISO-IR-111", NULL }, /* ISO-IR-111 refers to ECMA-94, but that + * standard does not contain cyrillic letters. + * ECMA-94 refers to ECMA-113 (ISO-IR-144), + * whose assignment differs greatly from ISO-IR-111, + * so it cannot be that either. + */ + /* All the MAC_* charsets appear to be unknown to even glib iconv, so + * why did we have them in our list in the first place? + */ + { "MAC_DEVANAGARI", NULL }, /* apparently not supported by ICU */ + { "MAC_FARSI", NULL }, /* apparently not supported by ICU */ + { "MAC_GREEK", "x-MacGreek" }, + { "MAC_GUJARATI", NULL }, /* apparently not supported by ICU */ + { "MAC_GURMUKHI", NULL }, /* apparently not supported by ICU */ + { "MAC_ICELANDIC", NULL }, /* apparently not supported by ICU */ + { "MAC_ROMANIAN", "x-macroman" }, /* not sure this is the right one */ + { "MAC_TURKISH", "x-MacTurkish" }, + { "MAC_UKRAINIAN", "x-MacUkraine" }, + + { "TCVN", NULL }, /* apparently not supported by ICU */ + { "UHC", "cp949" }, + { "VISCII", NULL }, /* apparently not supported by ICU */ + + /* ISO-2022-* are known to ICU, but they simply cannot work in vte as + * I/O encoding, so don't even try. + */ + { "ISO-2022-JP", NULL }, + { "ISO-2022-KR", NULL }, + }; + + const char *replacement = NULL; + for (guint i = 0; i < G_N_ELEMENTS (translations); ++i) { + if (g_str_equal (encoding, translations[i].name)) { + replacement = translations[i].replacement; + break; + } + } + + return replacement; +} + +/* BEGIN code copied from glib + * + * Copyright (C) 1995-1998 Peter Mattis, Spencer Kimball and Josh MacDonald + * + * Code originally under LGPL2+; used and modified here under GPL3+ + * Changes: + * Remove win32 support. + * Make @program nullable. + * Use @path instead of getenv("PATH"). + * Use strchrnul + */ + +/** + * terminal_util_find_program_in_path: + * @path: (type filename) (nullable): the search path (delimited by G_SEARCHPATH_SEPARATOR) + * @program: (type filename) (nullable): the programme to find in @path + * + * Like g_find_program_in_path(), but uses @path instead of the + * PATH environment variable as the search path. + * + * Returns: (type filename) (transfer full) (nullable): a newly allocated + * string containing the full path to @program, or %NULL if @program + * could not be found in @path. + */ +char * +terminal_util_find_program_in_path (const char *path, + const char *program) +{ + const gchar *p; + gchar *name, *freeme; + gsize len; + gsize pathlen; + + if (program == NULL) + return NULL; + + /* If it is an absolute path, or a relative path including subdirectories, + * don't look in PATH. + */ + if (g_path_is_absolute (program) + || strchr (program, G_DIR_SEPARATOR) != NULL + ) + { + if (g_file_test (program, G_FILE_TEST_IS_EXECUTABLE) && + !g_file_test (program, G_FILE_TEST_IS_DIR)) + return g_strdup (program); + else + return NULL; + } + + if (path == NULL) + { + /* There is no 'PATH' in the environment. The default + * search path in GNU libc is the current directory followed by + * the path 'confstr' returns for '_CS_PATH'. + */ + + /* In GLib we put . last, for security, and don't use the + * unportable confstr(); UNIX98 does not actually specify + * what to search if PATH is unset. POSIX may, dunno. + */ + + path = "/bin:/usr/bin:."; + } + + len = strlen (program) + 1; + pathlen = strlen (path); + freeme = name = g_malloc (pathlen + len + 1); + + /* Copy the file name at the top, including '\0' */ + memcpy (name + pathlen + 1, program, len); + name = name + pathlen; + /* And add the slash before the filename */ + *name = G_DIR_SEPARATOR; + + p = path; + do + { + char *startp; + + path = p; + p = strchrnul (path, G_SEARCHPATH_SEPARATOR); + + if (p == path) + /* Two adjacent colons, or a colon at the beginning or the end + * of 'PATH' means to search the current directory. + */ + startp = name + 1; + else + startp = memcpy (name - (p - path), path, p - path); + + if (g_file_test (startp, G_FILE_TEST_IS_EXECUTABLE) && + !g_file_test (startp, G_FILE_TEST_IS_DIR)) + { + gchar *ret; + ret = g_strdup (startp); + g_free (freeme); + return ret; + } + } + while (*p++ != '\0'); + + g_free (freeme); + return NULL; +} + +/* END code copied from glib */ + +/* + * terminal_util_check_envv: + * @strv: + * + * Validates that each element is of the form 'KEY=VALUE'. + */ +gboolean +terminal_util_check_envv(char const* const* strv) +{ + if (!strv) + return TRUE; + + for (int i = 0; strv[i]; ++i) { + const char *str = strv[i]; + const char *equal = strchr(str, '='); + if (equal == NULL || equal == str) + return FALSE; + } + + return TRUE; +} diff --git a/src/terminal-util.h b/src/terminal-util.h new file mode 100644 index 0000000..0f3e6bf --- /dev/null +++ b/src/terminal-util.h @@ -0,0 +1,117 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2008, 2010 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_UTIL_H +#define TERMINAL_UTIL_H + +#include +#include + +G_BEGIN_DECLS + +void terminal_util_show_error_dialog (GtkWindow *transient_parent, + GtkWidget **weap_ptr, + GError *error, + const char *message_format, ...) G_GNUC_PRINTF(4, 5); + +void terminal_util_show_help (const char *topic); + +void terminal_util_show_about (void); + +void terminal_util_set_labelled_by (GtkWidget *widget, + GtkLabel *label); +void terminal_util_set_atk_name_description (GtkWidget *widget, + const char *name, + const char *desc); + +void terminal_util_open_url (GtkWidget *parent, + const char *orig_url, + TerminalURLFlavor flavor, + guint32 user_time); + +void terminal_util_transform_uris_to_quoted_fuse_paths (char **uris); + +char *terminal_util_concat_uris (char **uris, + gsize *length); + +char *terminal_util_get_licence_text (void); + +GtkBuilder *terminal_util_load_widgets_resource (const char *path, + const char *main_object_name, + const char *object_name, + ...); + +void terminal_util_load_objects_resource (const char *path, + const char *object_name, + ...); + +void terminal_util_dialog_focus_widget (GtkBuilder *builder, + const char *widget_name); + +gboolean terminal_util_dialog_response_on_delete (GtkWindow *widget); + +void terminal_util_add_proxy_env (GHashTable *env_table); + +char **terminal_util_get_etc_shells (void); + +gboolean terminal_util_get_is_shell (const char *command); + +GSettings *terminal_g_settings_new (const char *schema_id, + const char *mandatory_key, + const GVariantType *mandatory_key_type); + +const GdkRGBA *terminal_g_settings_get_rgba (GSettings *settings, + const char *key, + GdkRGBA *rgba); +void terminal_g_settings_set_rgba (GSettings *settings, + const char *key, + const GdkRGBA *rgba); + +GdkRGBA *terminal_g_settings_get_rgba_palette (GSettings *settings, + const char *key, + gsize *n_colors); +void terminal_g_settings_set_rgba_palette (GSettings *settings, + const char *key, + const GdkRGBA *colors, + gsize n_colors); + +void terminal_util_bind_mnemonic_label_sensitivity (GtkWidget *widget); + +char *terminal_util_number_info (const char *str); + +char *terminal_util_uri_fixup (const char *uri, + GError **error); + +char *terminal_util_hyperlink_uri_label (const char *str); + +void terminal_util_load_print_settings (GtkPrintSettings **settings, + GtkPageSetup **page_setup); + +void terminal_util_save_print_settings (GtkPrintSettings *settings, + GtkPageSetup *page_setup); + +const char *terminal_util_translate_encoding (const char *encoding); + +char *terminal_util_find_program_in_path (const char *path, + const char *program); + +gboolean terminal_util_check_envv(char const* const* strv); + +G_END_DECLS + +#endif /* TERMINAL_UTIL_H */ diff --git a/src/terminal-version.h b/src/terminal-version.h new file mode 100644 index 0000000..cc336a4 --- /dev/null +++ b/src/terminal-version.h @@ -0,0 +1,34 @@ +/* + * Copyright © 2009 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if !defined (__TERMINAL_TERMINAL_H_INSIDE__) && !defined (TERMINAL_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef TERMINAL_VERSION_H +#define TERMINAL_VERSION_H + +#define TERMINAL_MAJOR_VERSION (3) +#define TERMINAL_MINOR_VERSION (38) +#define TERMINAL_MICRO_VERSION (3) + +#define TERMINAL_CHECK_VERSION(major,minor,micro) \ + (TERMINAL_MAJOR_VERSION > (major) || \ + (TERMINAL_MAJOR_VERSION == (major) && TERMINAL_MINOR_VERSION > (minor)) || \ + (TERMINAL_MAJOR_VERSION == (major) && TERMINAL_MINOR_VERSION == (minor) && TERMINAL_MICRO_VERSION >= (micro))) + +#endif /* !TERMINAL_VERSION_H */ diff --git a/src/terminal-version.h.in b/src/terminal-version.h.in new file mode 100644 index 0000000..154a3a1 --- /dev/null +++ b/src/terminal-version.h.in @@ -0,0 +1,34 @@ +/* + * Copyright © 2009 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#if !defined (__TERMINAL_TERMINAL_H_INSIDE__) && !defined (TERMINAL_COMPILATION) +#error "Only can be included directly." +#endif + +#ifndef TERMINAL_VERSION_H +#define TERMINAL_VERSION_H + +#define TERMINAL_MAJOR_VERSION (@TERMINAL_MAJOR_VERSION@) +#define TERMINAL_MINOR_VERSION (@TERMINAL_MINOR_VERSION@) +#define TERMINAL_MICRO_VERSION (@TERMINAL_MICRO_VERSION@) + +#define TERMINAL_CHECK_VERSION(major,minor,micro) \ + (TERMINAL_MAJOR_VERSION > (major) || \ + (TERMINAL_MAJOR_VERSION == (major) && TERMINAL_MINOR_VERSION > (minor)) || \ + (TERMINAL_MAJOR_VERSION == (major) && TERMINAL_MINOR_VERSION == (minor) && TERMINAL_MICRO_VERSION >= (micro))) + +#endif /* !TERMINAL_VERSION_H */ diff --git a/src/terminal-window.c b/src/terminal-window.c new file mode 100644 index 0000000..8adb134 --- /dev/null +++ b/src/terminal-window.c @@ -0,0 +1,3259 @@ +/* + * Copyright © 2001 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2007, 2008, 2009, 2011, 2017 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include + +#include +#include + +#include +#include + +#include "terminal-app.h" +#include "terminal-debug.h" +#include "terminal-enums.h" +#include "terminal-headerbar.h" +#include "terminal-icon-button.h" +#include "terminal-intl.h" +#include "terminal-mdi-container.h" +#include "terminal-menu-button.h" +#include "terminal-notebook.h" +#include "terminal-schemas.h" +#include "terminal-screen-container.h" +#include "terminal-search-popover.h" +#include "terminal-tab-label.h" +#include "terminal-util.h" +#include "terminal-window.h" +#include "terminal-libgsystem.h" + +struct _TerminalWindowPrivate +{ + char *uuid; + + GtkClipboard *clipboard; + + TerminalScreenPopupInfo *popup_info; + + GtkWidget *menubar; + TerminalMdiContainer *mdi_container; + GtkWidget *main_vbox; + TerminalScreen *active_screen; + + /* Size of a character cell in pixels */ + int old_char_width; + int old_char_height; + + /* Width and height added to the actual terminal grid by "chrome" inside + * what was traditionally the X11 window: menu bar, title bar, + * style-provided padding. This must be included when resizing the window + * and also included in geometry hints. */ + int old_chrome_width; + int old_chrome_height; + + /* Width and height added to the window by client-side decorations. + * This must be included in geometry hints but must not be included when + * resizing the window. */ + int old_csd_width; + int old_csd_height; + + /* Width and height of the padding around the geometry widget. */ + int old_padding_width; + int old_padding_height; + + void *old_geometry_widget; /* only used for pointer value as it may be freed */ + + GtkWidget *confirm_close_dialog; + TerminalSearchPopover *search_popover; + + guint use_default_menubar_visibility : 1; + + guint disposed : 1; + guint present_on_insert : 1; + + guint realized : 1; +}; + +#define TERMINAL_WINDOW_CSS_NAME "terminal-window" + +#define MIN_WIDTH_CHARS 4 +#define MIN_HEIGHT_CHARS 1 + +#if 1 +/* + * We don't want to enable content saving until vte supports it async. + * So we disable this code for stable versions. + */ +#include "terminal-version.h" + +#if (TERMINAL_MINOR_VERSION & 1) != 0 +#define ENABLE_SAVE +#else +#undef ENABLE_SAVE +#endif +#endif + +/* See bug #789356 */ +#define WINDOW_STATE_TILED (GDK_WINDOW_STATE_TILED | \ + GDK_WINDOW_STATE_LEFT_TILED | \ + GDK_WINDOW_STATE_RIGHT_TILED | \ + GDK_WINDOW_STATE_TOP_TILED | \ + GDK_WINDOW_STATE_BOTTOM_TILED) + +static void terminal_window_dispose (GObject *object); +static void terminal_window_finalize (GObject *object); +static gboolean terminal_window_state_event (GtkWidget *widget, + GdkEventWindowState *event); + +static gboolean terminal_window_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer data); + +static gboolean notebook_button_press_cb (GtkWidget *notebook, + GdkEventButton *event, + TerminalWindow *window); +static gboolean notebook_popup_menu_cb (GtkWidget *notebook, + TerminalWindow *window); +static void mdi_screen_switched_cb (TerminalMdiContainer *container, + TerminalScreen *old_active_screen, + TerminalScreen *screen, + TerminalWindow *window); +static void mdi_screen_added_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window); +static void mdi_screen_removed_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window); +static void mdi_screens_reordered_cb (TerminalMdiContainer *container, + TerminalWindow *window); +static void screen_close_request_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window); + +/* Menu action callbacks */ +static gboolean find_larger_zoom_factor (double *zoom); +static gboolean find_smaller_zoom_factor (double *zoom); +static void terminal_window_update_zoom_sensitivity (TerminalWindow *window); +static void terminal_window_update_search_sensitivity (TerminalScreen *screen, + TerminalWindow *window); +static void terminal_window_update_paste_sensitivity (TerminalWindow *window); + +static void terminal_window_show (GtkWidget *widget); + +static gboolean confirm_close_window_or_tab (TerminalWindow *window, + TerminalScreen *screen); + +G_DEFINE_TYPE (TerminalWindow, terminal_window, GTK_TYPE_APPLICATION_WINDOW) + +/* Zoom helpers */ + +static const double zoom_factors[] = { + TERMINAL_SCALE_MINIMUM, + TERMINAL_SCALE_XXXXX_SMALL, + TERMINAL_SCALE_XXXX_SMALL, + TERMINAL_SCALE_XXX_SMALL, + PANGO_SCALE_XX_SMALL, + PANGO_SCALE_X_SMALL, + PANGO_SCALE_SMALL, + PANGO_SCALE_MEDIUM, + PANGO_SCALE_LARGE, + PANGO_SCALE_X_LARGE, + PANGO_SCALE_XX_LARGE, + TERMINAL_SCALE_XXX_LARGE, + TERMINAL_SCALE_XXXX_LARGE, + TERMINAL_SCALE_XXXXX_LARGE, + TERMINAL_SCALE_MAXIMUM +}; + +static gboolean +find_larger_zoom_factor (double *zoom) +{ + double current = *zoom; + guint i; + + for (i = 0; i < G_N_ELEMENTS (zoom_factors); ++i) + { + /* Find a font that's larger than this one */ + if ((zoom_factors[i] - current) > 1e-6) + { + *zoom = zoom_factors[i]; + return TRUE; + } + } + + return FALSE; +} + +static gboolean +find_smaller_zoom_factor (double *zoom) +{ + double current = *zoom; + int i; + + i = (int) G_N_ELEMENTS (zoom_factors) - 1; + while (i >= 0) + { + /* Find a font that's smaller than this one */ + if ((current - zoom_factors[i]) > 1e-6) + { + *zoom = zoom_factors[i]; + return TRUE; + } + + --i; + } + + return FALSE; +} + +static inline GSimpleAction * +lookup_action (TerminalWindow *window, + const char *name) +{ + GAction *action; + + action = g_action_map_lookup_action (G_ACTION_MAP (window), name); + g_return_val_if_fail (action != NULL, NULL); + + return G_SIMPLE_ACTION (action); +} + +/* Context menu helpers */ + +/* We don't want context menus to show accelerators. + * Setting the menu's accel group and/or accel path to NULL + * unfortunately doesn't hide accelerators; we need to walk + * the menu items and remove the accelerators on each, + * manually. + */ +static void +popup_menu_remove_accelerators (GtkWidget *menu) +{ + gs_free_list GList *menu_items; + GList *l; + + menu_items = gtk_container_get_children (GTK_CONTAINER (menu)); + for (l = menu_items; l != NULL; l = l ->next) { + GtkMenuItem *item = (GtkMenuItem*) (l->data); + GtkWidget *label, *submenu; + + if (!GTK_IS_MENU_ITEM (item)) + continue; + + if (GTK_IS_ACCEL_LABEL ((label = gtk_bin_get_child (GTK_BIN (item))))) + gtk_accel_label_set_accel (GTK_ACCEL_LABEL (label), 0, 0); + + /* Recurse into submenus */ + if ((submenu = gtk_menu_item_get_submenu (item))) + popup_menu_remove_accelerators (submenu); + } +} + +/* Because we're using gtk_menu_attach_to_widget(), the attach + * widget holds a strong reference to the menu, causing it not to + * be automatically destroyed once popped down. So we need to + * detach the menu from the attach widget manually, which will + * cause the menu to be destroyed. We cannot do so in the + * "deactivate" handler however, since that causes the menu + * item activation to be lost. The "selection-done" signal + * appears to be the right place. + */ + +static void +popup_menu_destroy_cb (GtkWidget *menu, + gpointer user_data) +{ + /* g_printerr ("Menu %p destroyed!\n", menu); */ +} + +static void +popup_menu_selection_done_cb (GtkMenu *menu, + gpointer user_data) +{ + g_signal_handlers_disconnect_by_func + (menu, G_CALLBACK (popup_menu_selection_done_cb), user_data); + + /* g_printerr ("selection-done %p\n", menu); */ + + /* This will remove the ref from the attach widget widget, and destroy the menu */ + if (gtk_menu_get_attach_widget (menu) != NULL) + gtk_menu_detach (menu); +} + +static void +popup_menu_detach_cb (GtkWidget *attach_widget, + GtkMenu *menu) +{ + gtk_menu_shell_deactivate (GTK_MENU_SHELL (menu)); +} + +static GtkWidget * +context_menu_new (GMenuModel *menu, + GtkWidget *widget) +{ + GtkWidget *popup_menu; + + popup_menu = gtk_menu_new_from_model (menu); + gtk_style_context_add_class (gtk_widget_get_style_context (popup_menu), + GTK_STYLE_CLASS_CONTEXT_MENU); + gtk_menu_attach_to_widget (GTK_MENU (popup_menu), widget, + (GtkMenuDetachFunc)popup_menu_detach_cb); + + popup_menu_remove_accelerators (popup_menu); + + /* Staggered destruction */ + g_signal_connect (popup_menu, "selection-done", + G_CALLBACK (popup_menu_selection_done_cb), widget); + g_signal_connect (popup_menu, "destroy", + G_CALLBACK (popup_menu_destroy_cb), widget); + + return popup_menu; +} + +/* GAction callbacks */ + +static void +action_new_terminal_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalApp *app; + TerminalSettingsList *profiles_list; + gs_unref_object GSettings *profile = NULL; + gboolean can_toggle = FALSE; + + g_assert (TERMINAL_IS_WINDOW (window)); + + app = terminal_app_get (); + + const char *mode_str, *uuid_str; + g_variant_get (parameter, "(&s&s)", &mode_str, &uuid_str); + + TerminalNewTerminalMode mode; + if (g_str_equal (mode_str, "tab")) + mode = TERMINAL_NEW_TERMINAL_MODE_TAB; + else if (g_str_equal (mode_str, "window")) + mode = TERMINAL_NEW_TERMINAL_MODE_WINDOW; + else if (g_str_equal (mode_str, "tab-default")) { + mode = TERMINAL_NEW_TERMINAL_MODE_TAB; + can_toggle = TRUE; + } else { + mode = g_settings_get_enum (terminal_app_get_global_settings (app), + TERMINAL_SETTING_NEW_TERMINAL_MODE_KEY); + can_toggle = TRUE; + } + + if (can_toggle) { + GdkEvent *event = gtk_get_current_event (); + if (event != NULL) { + GdkModifierType modifiers; + + if ((gdk_event_get_state (event, &modifiers) && + (modifiers & gtk_accelerator_get_default_mod_mask () & GDK_CONTROL_MASK))) { + /* Invert */ + if (mode == TERMINAL_NEW_TERMINAL_MODE_WINDOW) + mode = TERMINAL_NEW_TERMINAL_MODE_TAB; + else + mode = TERMINAL_NEW_TERMINAL_MODE_WINDOW; + } + gdk_event_free (event); + } + } + + TerminalScreen *parent_screen = priv->active_screen; + + profiles_list = terminal_app_get_profiles_list (app); + if (g_str_equal (uuid_str, "current")) + profile = terminal_screen_ref_profile (parent_screen); + else if (g_str_equal (uuid_str, "default")) + profile = terminal_settings_list_ref_default_child (profiles_list); + else + profile = terminal_settings_list_ref_child (profiles_list, uuid_str); + + if (profile == NULL) + return; + + if (mode == TERMINAL_NEW_TERMINAL_MODE_WINDOW) + window = terminal_window_new (G_APPLICATION (app)); + + TerminalScreen *screen = terminal_screen_new (profile, + NULL /* title */, + 1.0); + + /* Now add the new screen to the window */ + terminal_window_add_screen (window, screen, -1); + terminal_window_switch_screen (window, screen); + gtk_widget_grab_focus (GTK_WIDGET (screen)); + + /* Start child process, if possible by using the same args as the parent screen */ + terminal_screen_reexec_from_screen (screen, parent_screen, NULL, NULL); + + if (mode == TERMINAL_NEW_TERMINAL_MODE_WINDOW) + gtk_window_present (GTK_WINDOW (window)); +} + +#ifdef ENABLE_SAVE + +static void +save_contents_dialog_on_response (GtkDialog *dialog, gint response_id, gpointer terminal) +{ + GtkWindow *parent; + gs_free gchar *filename_uri = NULL; + gs_unref_object GFile *file = NULL; + GOutputStream *stream; + gs_free_error GError *error = NULL; + + if (response_id != GTK_RESPONSE_ACCEPT) + { + gtk_widget_destroy (GTK_WIDGET (dialog)); + return; + } + + parent = (GtkWindow*) gtk_widget_get_ancestor (GTK_WIDGET (terminal), GTK_TYPE_WINDOW); + filename_uri = gtk_file_chooser_get_uri (GTK_FILE_CHOOSER (dialog)); + + gtk_widget_destroy (GTK_WIDGET (dialog)); + + if (filename_uri == NULL) + return; + + file = g_file_new_for_uri (filename_uri); + stream = G_OUTPUT_STREAM (g_file_replace (file, NULL, FALSE, G_FILE_CREATE_NONE, NULL, &error)); + + if (stream) + { + /* XXX + * FIXME + * This is a sync operation. + * Should be replaced with the async version when vte implements that. + */ + vte_terminal_write_contents_sync (terminal, stream, + VTE_WRITE_DEFAULT, + NULL, &error); + g_object_unref (stream); + } + + if (error) + { + terminal_util_show_error_dialog (parent, NULL, error, + "%s", _("Could not save contents")); + } +} + +static void +action_save_contents_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + GtkWidget *dialog = NULL; + TerminalWindowPrivate *priv = window->priv; + VteTerminal *terminal; + + if (priv->active_screen == NULL) + return; + + terminal = VTE_TERMINAL (priv->active_screen); + g_return_if_fail (VTE_IS_TERMINAL (terminal)); + + dialog = gtk_file_chooser_dialog_new (_("Save as…"), + GTK_WINDOW(window), + GTK_FILE_CHOOSER_ACTION_SAVE, + _("_Cancel"), GTK_RESPONSE_CANCEL, + _("_Save"), GTK_RESPONSE_ACCEPT, + NULL); + + gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE); + gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_user_special_dir (G_USER_DIRECTORY_DOCUMENTS)); + + gtk_window_set_transient_for (GTK_WINDOW (dialog), GTK_WINDOW (window)); + gtk_window_set_modal (GTK_WINDOW (dialog), TRUE); + gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE); + + g_signal_connect (dialog, "response", G_CALLBACK (save_contents_dialog_on_response), terminal); + g_signal_connect (dialog, "delete_event", G_CALLBACK (terminal_util_dialog_response_on_delete), NULL); + + gtk_window_present (GTK_WINDOW (dialog)); +} + +#endif /* ENABLE_SAVE */ + +#ifdef ENABLE_PRINT + +static void +print_begin_cb (GtkPrintOperation *op, + GtkPrintContext *context, + TerminalApp *app) +{ + GtkPrintSettings *settings; + GtkPageSetup *page_setup; + + /* Don't save if the print dialogue was cancelled */ + if (gtk_print_operation_get_status(op) == GTK_PRINT_STATUS_FINISHED_ABORTED) + return; + + settings = gtk_print_operation_get_print_settings (op); + page_setup = gtk_print_operation_get_default_page_setup (op); + terminal_util_save_print_settings (settings, page_setup); +} + +static void +print_done_cb (GtkPrintOperation *op, + GtkPrintOperationResult result, + TerminalWindow *window) +{ + if (result != GTK_PRINT_OPERATION_RESULT_ERROR) + return; + + /* FIXME: show error */ +} + +static void +action_print_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + gs_unref_object GtkPrintSettings *settings = NULL; + gs_unref_object GtkPageSetup *page_setup = NULL; + gs_unref_object GtkPrintOperation *op = NULL; + gs_free_error GError *error = NULL; + GtkPrintOperationResult result; + + if (priv->active_screen == NULL) + return; + + op = vte_print_operation_new (VTE_TERMINAL (priv->active_screen), + VTE_PRINT_OPERATION_DEFAULT /* flags */); + if (op == NULL) + return; + + terminal_util_load_print_settings (&settings, &page_setup); + if (settings != NULL) + gtk_print_operation_set_print_settings (op, settings); + if (page_setup != NULL) + gtk_print_operation_set_default_page_setup (op, page_setup); + + g_signal_connect (op, "begin-print", G_CALLBACK (print_begin_cb), window); + g_signal_connect (op, "done", G_CALLBACK (print_done_cb), window); + + /* FIXME: show progress better */ + + result = gtk_print_operation_run (op, + /* this is the only supported one: */ + GTK_PRINT_OPERATION_ACTION_PRINT_DIALOG, + GTK_WINDOW (window), + &error); + /* VtePrintOperation always runs async */ + g_assert_cmpint (result, ==, GTK_PRINT_OPERATION_RESULT_IN_PROGRESS); +} + +#endif /* ENABLE_PRINT */ + +#ifdef ENABLE_EXPORT + +static void +action_export_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + gs_unref_object VteExportOperation *op = NULL; + gs_free_error GError *error = NULL; + + if (priv->active_screen == NULL) + return; + + op = vte_export_operation_new (VTE_TERMINAL (priv->active_screen), + TRUE /* interactive */, + VTE_EXPORT_FORMAT_ASK /* allow user to choose export format */, + NULL, NULL /* GSettings & key to load/store default directory from, FIXME */, + NULL, NULL /* progress callback & user data, FIXME */); + if (op == NULL) + return; + + /* FIXME: show progress better */ + + vte_export_operation_run_async (op, GTK_WINDOW (window), NULL /* cancellable */); +} + +#endif /* ENABLE_EXPORT */ + +static void +action_close_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalScreen *screen; + const char *mode_str; + + g_assert_nonnull (parameter); + g_variant_get (parameter, "&s", &mode_str); + + if (g_str_equal (mode_str, "tab")) + screen = priv->active_screen; + else if (g_str_equal (mode_str, "window")) + screen = NULL; + else + return; + + if (confirm_close_window_or_tab (window, screen)) + return; + + if (screen) + terminal_window_remove_screen (window, screen); + else + gtk_widget_destroy (GTK_WIDGET (window)); +} + +static void +action_copy_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + const char *format_str; + VteFormat format; + + if (priv->active_screen == NULL) + return; + + g_assert_nonnull (parameter); + g_variant_get (parameter, "&s", &format_str); + + if (g_str_equal (format_str, "text")) + format = VTE_FORMAT_TEXT; + else if (g_str_equal (format_str, "html")) + format = VTE_FORMAT_HTML; + else + return; + + vte_terminal_copy_clipboard_format (VTE_TERMINAL (priv->active_screen), format); +} + +/* Clipboard helpers */ + +typedef struct { + GWeakRef screen_weak_ref; +} PasteData; + +static void +clipboard_uris_received_cb (GtkClipboard *clipboard, + /* const */ char **uris, + PasteData *data) +{ + gs_unref_object TerminalScreen *screen = NULL; + + if (uris != NULL && uris[0] != NULL && + (screen = g_weak_ref_get (&data->screen_weak_ref))) { + gs_free char *text; + gsize len; + + /* This potentially modifies the strings in |uris| but that's ok */ + terminal_util_transform_uris_to_quoted_fuse_paths (uris); + text = terminal_util_concat_uris (uris, &len); + + vte_terminal_feed_child (VTE_TERMINAL (screen), text, len); + } + + g_weak_ref_clear (&data->screen_weak_ref); + g_slice_free (PasteData, data); +} + +static void +request_clipboard_contents_for_paste (TerminalWindow *window, + gboolean paste_as_uris) +{ + TerminalWindowPrivate *priv = window->priv; + GdkAtom *targets; + int n_targets; + + if (priv->active_screen == NULL) + return; + + targets = terminal_app_get_clipboard_targets (terminal_app_get (), + priv->clipboard, + &n_targets); + if (targets == NULL) + return; + + if (paste_as_uris && gtk_targets_include_uri (targets, n_targets)) { + PasteData *data = g_slice_new (PasteData); + g_weak_ref_init (&data->screen_weak_ref, priv->active_screen); + + gtk_clipboard_request_uris (priv->clipboard, + (GtkClipboardURIReceivedFunc) clipboard_uris_received_cb, + data); + return; + } else if (gtk_targets_include_text (targets, n_targets)) { + vte_terminal_paste_clipboard (VTE_TERMINAL (priv->active_screen)); + } +} + +static void +action_paste_text_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + request_clipboard_contents_for_paste (window, FALSE); +} + +static void +action_paste_uris_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + request_clipboard_contents_for_paste (window, TRUE); +} + +static void +action_select_all_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + vte_terminal_select_all (VTE_TERMINAL (priv->active_screen)); +} + +static void +action_reset_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + g_assert_nonnull (parameter); + + if (priv->active_screen == NULL) + return; + + vte_terminal_reset (VTE_TERMINAL (priv->active_screen), + TRUE, + g_variant_get_boolean (parameter)); +} + +static void +tab_switch_relative (TerminalWindow *window, + int change) +{ + TerminalWindowPrivate *priv = window->priv; + int n_screens, value; + + n_screens = terminal_mdi_container_get_n_screens (priv->mdi_container); + value = terminal_mdi_container_get_active_screen_num (priv->mdi_container) + change; + + gboolean keynav_wrap_around; + g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)), + "gtk-keynav-wrap-around", &keynav_wrap_around, + NULL); + if (keynav_wrap_around) { + if (value < 0) + value += n_screens; + else if (value >= n_screens) + value -= n_screens; + } + + if (value < 0 || value >= n_screens) + return; + + g_action_change_state (G_ACTION (lookup_action (window, "active-tab")), + g_variant_new_int32 (value)); +} + +static void +action_tab_switch_left_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + tab_switch_relative (window, -1); +} + +static void +action_tab_switch_right_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + tab_switch_relative (window, 1); +} + +static void +action_tab_move_left_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + int change; + + if (priv->active_screen == NULL) + return; + + change = gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL ? 1 : -1; + terminal_mdi_container_reorder_screen (priv->mdi_container, + terminal_mdi_container_get_active_screen (priv->mdi_container), + change); +} + +static void +action_tab_move_right_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + int change; + + if (priv->active_screen == NULL) + return; + + change = gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL ? -1 : 1; + terminal_mdi_container_reorder_screen (priv->mdi_container, + terminal_mdi_container_get_active_screen (priv->mdi_container), + change); +} + +static void +action_zoom_in_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + double zoom; + + if (priv->active_screen == NULL) + return; + + zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen)); + if (!find_larger_zoom_factor (&zoom)) + return; + + vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), zoom); + terminal_window_update_zoom_sensitivity (window); +} + +static void +action_zoom_out_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + double zoom; + + if (priv->active_screen == NULL) + return; + + zoom = vte_terminal_get_font_scale (VTE_TERMINAL (priv->active_screen)); + if (!find_smaller_zoom_factor (&zoom)) + return; + + vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), zoom); + terminal_window_update_zoom_sensitivity (window); +} + +static void +action_zoom_normal_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + vte_terminal_set_font_scale (VTE_TERMINAL (priv->active_screen), PANGO_SCALE_MEDIUM); + terminal_window_update_zoom_sensitivity (window); +} + +static void +action_tab_detach_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalApp *app; + TerminalWindow *new_window; + TerminalScreen *screen; + char geometry[32]; + int width, height; + + app = terminal_app_get (); + + screen = priv->active_screen; + + terminal_screen_get_size (screen, &width, &height); + g_snprintf (geometry, sizeof (geometry), "%dx%d", width, height); + + new_window = terminal_window_new (G_APPLICATION (app)); + + terminal_window_move_screen (window, new_window, screen, -1); + + terminal_window_parse_geometry (new_window, geometry); + + gtk_window_present_with_time (GTK_WINDOW (new_window), gtk_get_current_event_time ()); +} + +static void +action_help_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + terminal_util_show_help (NULL); +} + +static void +action_about_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + terminal_util_show_about (); +} + +static void +action_edit_preferences_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + terminal_app_edit_preferences (terminal_app_get (), + terminal_screen_get_profile (priv->active_screen), + NULL); +} + +static void +action_size_to_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + guint width, height; + + g_assert_nonnull (parameter); + + if (priv->active_screen == NULL) + return; + + g_variant_get (parameter, "(uu)", &width, &height); + if (width < MIN_WIDTH_CHARS || height < MIN_HEIGHT_CHARS || + width > 256 || height > 256) + return; + + vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), width, height); + terminal_window_update_size (window); +} + +static void +action_open_match_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalScreenPopupInfo *info = priv->popup_info; + + if (info == NULL) + return; + if (info->url == NULL) + return; + + terminal_util_open_url (GTK_WIDGET (window), info->url, info->url_flavor, + gtk_get_current_event_time ()); +} + +static void +action_copy_match_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalScreenPopupInfo *info = priv->popup_info; + + if (info == NULL) + return; + if (info->url == NULL) + return; + + gtk_clipboard_set_text (priv->clipboard, info->url, -1); +} + +static void +action_open_hyperlink_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalScreenPopupInfo *info = priv->popup_info; + + if (info == NULL) + return; + if (info->hyperlink == NULL) + return; + + terminal_util_open_url (GTK_WIDGET (window), info->hyperlink, FLAVOR_AS_IS, + gtk_get_current_event_time ()); +} + +static void +action_copy_hyperlink_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalScreenPopupInfo *info = priv->popup_info; + + if (info == NULL) + return; + if (info->hyperlink == NULL) + return; + + gtk_clipboard_set_text (priv->clipboard, info->hyperlink, -1); +} + +static void +action_enter_fullscreen_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + g_action_group_change_action_state (G_ACTION_GROUP (window), "fullscreen", + g_variant_new_boolean (TRUE)); +} + +static void +action_leave_fullscreen_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + g_action_group_change_action_state (G_ACTION_GROUP (window), "fullscreen", + g_variant_new_boolean (FALSE)); +} + +static void +action_inspector_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + gtk_window_set_interactive_debugging (TRUE); +} + +static void +search_popover_search_cb (TerminalSearchPopover *popover, + gboolean backward, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (G_UNLIKELY (priv->active_screen == NULL)) + return; + + if (backward) + vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen)); + else + vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen)); +} + +static void +search_popover_notify_regex_cb (TerminalSearchPopover *popover, + GParamSpec *pspec G_GNUC_UNUSED, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + VteRegex *regex; + + if (G_UNLIKELY (priv->active_screen == NULL)) + return; + + regex = terminal_search_popover_get_regex (popover); + vte_terminal_search_set_regex (VTE_TERMINAL (priv->active_screen), regex, 0); + + terminal_window_update_search_sensitivity (priv->active_screen, window); +} + +static void +search_popover_notify_wrap_around_cb (TerminalSearchPopover *popover, + GParamSpec *pspec G_GNUC_UNUSED, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + gboolean wrap; + + if (G_UNLIKELY (priv->active_screen == NULL)) + return; + + wrap = terminal_search_popover_get_wrap_around (popover); + vte_terminal_search_set_wrap_around (VTE_TERMINAL (priv->active_screen), wrap); +} + +static void +action_find_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (G_UNLIKELY(priv->active_screen == NULL)) + return; + + if (priv->search_popover != NULL) { + search_popover_notify_regex_cb (priv->search_popover, NULL, window); + search_popover_notify_wrap_around_cb (priv->search_popover, NULL, window); + + gtk_window_present_with_time (GTK_WINDOW (priv->search_popover), + gtk_get_current_event_time ()); + gtk_widget_grab_focus (GTK_WIDGET (priv->search_popover)); + return; + } + + if (priv->active_screen == NULL) + return; + + priv->search_popover = terminal_search_popover_new (GTK_WIDGET (window)); + + g_signal_connect (priv->search_popover, "search", G_CALLBACK (search_popover_search_cb), window); + + search_popover_notify_regex_cb (priv->search_popover, NULL, window); + g_signal_connect (priv->search_popover, "notify::regex", G_CALLBACK (search_popover_notify_regex_cb), window); + + search_popover_notify_wrap_around_cb (priv->search_popover, NULL, window); + g_signal_connect (priv->search_popover, "notify::wrap-around", G_CALLBACK (search_popover_notify_wrap_around_cb), window); + + g_signal_connect (priv->search_popover, "destroy", G_CALLBACK (gtk_widget_destroyed), &priv->search_popover); + + gtk_window_present_with_time (GTK_WINDOW (priv->search_popover), gtk_get_current_event_time ()); + gtk_widget_grab_focus (GTK_WIDGET (priv->search_popover)); +} + +static void +action_find_forward_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen)); +} + +static void +action_find_backward_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen)); +} + +static void +action_find_clear_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + vte_terminal_search_set_regex (VTE_TERMINAL (priv->active_screen), NULL, 0); + vte_terminal_unselect_all (VTE_TERMINAL (priv->active_screen)); +} + +static void +action_shadow_activate_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + gs_free char *param = g_variant_print(parameter, TRUE); + + _terminal_debug_print (TERMINAL_DEBUG_ACCELS, + "Window %p shadow action activated for %s\n", + window, param); + + /* We make sure in terminal-accels to always install the keybinding + * for the real action first, so that it's first in line for activation. + * That means we can make this here a NOP, instead of forwarding the + * activation to the shadowed action. + */ +} + +static void +action_menubar_visible_state_cb (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + TerminalWindow *window = user_data; + gboolean active; + + active = g_variant_get_boolean (state); + terminal_window_set_menubar_visible (window, active); /* this also sets the action state */ +} + +static void +action_fullscreen_state_cb (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + TerminalWindow *window = user_data; + + if (!gtk_widget_get_realized (GTK_WIDGET (window))) + return; + + if (g_variant_get_boolean (state)) + gtk_window_fullscreen (GTK_WINDOW (window)); + else + gtk_window_unfullscreen (GTK_WINDOW (window)); + + /* The window-state-changed callback will update the action's actual state */ +} + +static void +action_read_only_state_cb (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + g_assert_nonnull (state); + + g_simple_action_set_state (action, state); + + terminal_window_update_paste_sensitivity (window); + + if (priv->active_screen == NULL) + return; + + vte_terminal_set_input_enabled (VTE_TERMINAL (priv->active_screen), + !g_variant_get_boolean (state)); +} + +static void +action_profile_state_cb (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + TerminalSettingsList *profiles_list; + const gchar *uuid; + gs_unref_object GSettings *profile; + + g_assert_nonnull (state); + + uuid = g_variant_get_string (state, NULL); + profiles_list = terminal_app_get_profiles_list (terminal_app_get ()); + profile = terminal_settings_list_ref_child (profiles_list, uuid); + if (profile == NULL) + return; + + g_simple_action_set_state (action, state); + + terminal_screen_set_profile (priv->active_screen, profile); +} + +static void +action_active_tab_set_cb (GSimpleAction *action, + GVariant *parameter, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + int value, n_screens; + + g_assert_nonnull (parameter); + + n_screens = terminal_mdi_container_get_n_screens (priv->mdi_container); + + value = g_variant_get_int32 (parameter); + if (value < 0) + value += n_screens; + if (value < 0 || value >= n_screens) + return; + + g_action_change_state (G_ACTION (action), g_variant_new_int32 (value)); +} + +static void +action_active_tab_state_cb (GSimpleAction *action, + GVariant *state, + gpointer user_data) +{ + TerminalWindow *window = user_data; + TerminalWindowPrivate *priv = window->priv; + + g_assert_nonnull (state); + + g_simple_action_set_state (action, state); + + terminal_mdi_container_set_active_screen_num (priv->mdi_container, g_variant_get_int32 (state)); +} + +/* Menubar mnemonics & accel settings handling */ + +static void +enable_menubar_accel_changed_cb (GSettings *settings, + const char *key, + GtkSettings *gtk_settings) +{ + if (g_settings_get_boolean (settings, key)) + gtk_settings_reset_property (gtk_settings, "gtk-menu-bar-accel"); + else + g_object_set (gtk_settings, "gtk-menu-bar-accel", NULL, NULL); +} + +/* The menubar is shown by the app, and the use of mnemonics (e.g. Alt+F for File) is toggled. + * The mnemonic modifier is per window, so it doesn't affect the Find or Preferences windows. + * If the menubar is shown by the shell, a non-mnemonic variant of the menu is loaded instead + * in terminal-app.c. See over there for further details. */ +static void +enable_mnemonics_changed_cb (GSettings *settings, + const char *key, + TerminalWindow *window) +{ + gboolean enabled = g_settings_get_boolean (settings, key); + + if (enabled) + gtk_window_set_mnemonic_modifier (GTK_WINDOW (window), GDK_MOD1_MASK); + else + gtk_window_set_mnemonic_modifier (GTK_WINDOW (window), GDK_MODIFIER_MASK & ~GDK_RELEASE_MASK); +} + +static void +app_setting_notify_destroy_cb (GtkSettings *gtk_settings) +{ + g_signal_handlers_disconnect_by_func (terminal_app_get_global_settings (terminal_app_get ()), + G_CALLBACK (enable_menubar_accel_changed_cb), + gtk_settings); +} + +/* utility functions */ + +static int +find_tab_num_at_pos (GtkNotebook *notebook, + int screen_x, + int screen_y) +{ + GtkPositionType tab_pos; + int page_num = 0; + GtkNotebook *nb = GTK_NOTEBOOK (notebook); + GtkWidget *page; + GtkAllocation tab_allocation; + + tab_pos = gtk_notebook_get_tab_pos (GTK_NOTEBOOK (notebook)); + + while ((page = gtk_notebook_get_nth_page (nb, page_num))) + { + GtkWidget *tab; + int max_x, max_y, x_root, y_root; + + tab = gtk_notebook_get_tab_label (nb, page); + g_return_val_if_fail (tab != NULL, -1); + + if (!gtk_widget_get_mapped (GTK_WIDGET (tab))) + { + page_num++; + continue; + } + + gdk_window_get_origin (gtk_widget_get_window (tab), &x_root, &y_root); + + gtk_widget_get_allocation (tab, &tab_allocation); + max_x = x_root + tab_allocation.x + tab_allocation.width; + max_y = y_root + tab_allocation.y + tab_allocation.height; + + if ((tab_pos == GTK_POS_TOP || tab_pos == GTK_POS_BOTTOM) && screen_x <= max_x) + return page_num; + + if ((tab_pos == GTK_POS_LEFT || tab_pos == GTK_POS_RIGHT) && screen_y <= max_y) + return page_num; + + page_num++; + } + + return -1; +} + +static void +terminal_window_update_set_profile_menu_active_profile (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + GSettings *new_active_profile; + TerminalSettingsList *profiles_list; + char *uuid; + + if (priv->active_screen == NULL) + return; + + new_active_profile = terminal_screen_get_profile (priv->active_screen); + + profiles_list = terminal_app_get_profiles_list (terminal_app_get ()); + uuid = terminal_settings_list_dup_uuid_from_child (profiles_list, new_active_profile); + + g_simple_action_set_state (lookup_action (window, "profile"), + g_variant_new_take_string (uuid)); +} + +static void +terminal_window_update_terminal_menu (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (priv->active_screen == NULL) + return; + + gboolean read_only = !vte_terminal_get_input_enabled (VTE_TERMINAL (priv->active_screen)); + g_simple_action_set_state (lookup_action (window, "read-only"), + g_variant_new_boolean (read_only)); +} + +/* Actions stuff */ + +static void +terminal_window_update_copy_sensitivity (TerminalScreen *screen, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + gboolean can_copy; + + if (screen != priv->active_screen) + return; + + can_copy = vte_terminal_get_has_selection (VTE_TERMINAL (screen)); + g_simple_action_set_enabled (lookup_action (window, "copy"), can_copy); +} + +static void +terminal_window_update_zoom_sensitivity (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + TerminalScreen *screen; + + screen = priv->active_screen; + if (screen == NULL) + return; + + double v; + double zoom = v = vte_terminal_get_font_scale (VTE_TERMINAL (screen)); + g_simple_action_set_enabled (lookup_action (window, "zoom-in"), + find_larger_zoom_factor (&v)); + + v = zoom; + g_simple_action_set_enabled (lookup_action (window, "zoom-out"), + find_smaller_zoom_factor (&v)); +} + +static void +terminal_window_update_search_sensitivity (TerminalScreen *screen, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (screen != priv->active_screen) + return; + + gboolean can_search = vte_terminal_search_get_regex (VTE_TERMINAL (screen)) != NULL; + + g_simple_action_set_enabled (lookup_action (window, "find-forward"), can_search); + g_simple_action_set_enabled (lookup_action (window, "find-backward"), can_search); + g_simple_action_set_enabled (lookup_action (window, "find-clear"), can_search); +} + +static void +clipboard_targets_changed_cb (TerminalApp *app, + GtkClipboard *clipboard, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (clipboard != priv->clipboard) + return; + + terminal_window_update_paste_sensitivity (window); +} + +static void +terminal_window_update_paste_sensitivity (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + GdkAtom *targets; + int n_targets; + targets = terminal_app_get_clipboard_targets (terminal_app_get(), priv->clipboard, &n_targets); + + gboolean can_paste; + gboolean can_paste_uris; + if (n_targets) { + can_paste = gtk_targets_include_text (targets, n_targets); + can_paste_uris = gtk_targets_include_uri (targets, n_targets); + } else { + can_paste = can_paste_uris = FALSE; + } + + gs_unref_variant GVariant *ro_state = g_action_get_state (g_action_map_lookup_action (G_ACTION_MAP (window), "read-only")); + gboolean read_only = g_variant_get_boolean (ro_state); + + g_simple_action_set_enabled (lookup_action (window, "paste-text"), can_paste && !read_only); + g_simple_action_set_enabled (lookup_action (window, "paste-uris"), can_paste_uris && !read_only); +} + +static void +screen_resize_window_cb (TerminalScreen *screen, + guint columns, + guint rows, + TerminalWindow* window) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *widget = GTK_WIDGET (screen); + + if (gtk_widget_get_realized (widget) && + (gdk_window_get_state (gtk_widget_get_window (widget)) & (GDK_WINDOW_STATE_MAXIMIZED | + GDK_WINDOW_STATE_FULLSCREEN | + WINDOW_STATE_TILED)) != 0) + return; + + vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), columns, rows); + + if (screen == priv->active_screen) + terminal_window_update_size (window); +} + +static void +terminal_window_update_tabs_actions_sensitivity (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (priv->disposed) + return; + + int num_pages = terminal_mdi_container_get_n_screens (priv->mdi_container); + int page_num = terminal_mdi_container_get_active_screen_num (priv->mdi_container); + + gboolean not_only = num_pages > 1; + gboolean not_first = page_num > 0; + gboolean not_last = page_num + 1 < num_pages; + + gboolean not_first_lr, not_last_lr; + if (gtk_widget_get_direction (GTK_WIDGET (window)) == GTK_TEXT_DIR_RTL) { + not_first_lr = not_last; + not_last_lr = not_first; + } else { + not_first_lr = not_first; + not_last_lr = not_last; + } + + /* Hide the tabs menu in single-tab windows */ + g_simple_action_set_enabled (lookup_action (window, "tabs-menu"), not_only); + + /* Disable shadowing of MDI actions in SDI windows */ + g_simple_action_set_enabled (lookup_action (window, "shadow-mdi"), not_only); + + /* Disable tab switching (and all its shortcuts) in SDI windows */ + g_simple_action_set_enabled (lookup_action (window, "active-tab"), not_only); + + /* Set the active tab */ + g_simple_action_set_state (lookup_action (window, "active-tab"), + g_variant_new_int32 (page_num)); + + /* Keynav wraps around? See bug #92139 */ + gboolean keynav_wrap_around; + g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)), + "gtk-keynav-wrap-around", &keynav_wrap_around, + NULL); + + gboolean wrap = keynav_wrap_around && not_only; + g_simple_action_set_enabled (lookup_action (window, "tab-switch-left"), not_first || wrap); + g_simple_action_set_enabled (lookup_action (window, "tab-switch-right"), not_last || wrap); + g_simple_action_set_enabled (lookup_action (window, "tab-move-left"), not_first_lr || wrap); + g_simple_action_set_enabled (lookup_action (window, "tab-move-right"), not_last_lr || wrap); + g_simple_action_set_enabled (lookup_action (window, "tab-detach"), not_only); +} + +static GtkNotebook * +handle_tab_droped_on_desktop (GtkNotebook *source_notebook, + GtkWidget *container, + gint x, + gint y, + gpointer data G_GNUC_UNUSED) +{ + TerminalWindow *source_window; + TerminalWindow *new_window; + TerminalWindowPrivate *new_priv; + + source_window = TERMINAL_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (source_notebook))); + g_return_val_if_fail (TERMINAL_IS_WINDOW (source_window), NULL); + + new_window = terminal_window_new (G_APPLICATION (terminal_app_get ())); + new_priv = new_window->priv; + new_priv->present_on_insert = TRUE; + + return GTK_NOTEBOOK (new_priv->mdi_container); +} + +/* Terminal screen popup menu handling */ + +static void +remove_popup_info (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (priv->popup_info != NULL) + { + terminal_screen_popup_info_unref (priv->popup_info); + priv->popup_info = NULL; + } +} + +static void +screen_popup_menu_selection_done_cb (GtkWidget *popup, + GtkWidget *window) +{ + g_signal_handlers_disconnect_by_func + (popup, G_CALLBACK (screen_popup_menu_selection_done_cb), window); + + GtkWidget *attach_widget = gtk_menu_get_attach_widget (GTK_MENU (popup)); + if (attach_widget != window || !TERMINAL_IS_WINDOW (attach_widget)) + return; + + remove_popup_info (TERMINAL_WINDOW (attach_widget)); +} + +static void +screen_show_popup_menu_cb (TerminalScreen *screen, + TerminalScreenPopupInfo *info, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + TerminalApp *app = terminal_app_get (); + + if (screen != priv->active_screen) + return; + + remove_popup_info (window); + priv->popup_info = terminal_screen_popup_info_ref (info); + + gs_unref_object GMenu *menu = g_menu_new (); + + /* Hyperlink section */ + if (info->hyperlink != NULL) { + gs_unref_object GMenu *section1 = g_menu_new (); + + g_menu_append (section1, _("Open _Hyperlink"), "win.open-hyperlink"); + g_menu_append (section1, _("Copy Hyperlink _Address"), "win.copy-hyperlink"); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section1)); + } + /* Matched link section */ + else if (info->url != NULL) { + gs_unref_object GMenu *section2 = g_menu_new (); + + const char *open_label = NULL, *copy_label = NULL; + switch (info->url_flavor) { + case FLAVOR_EMAIL: + open_label = _("Send Mail _To…"); + copy_label = _("Copy Mail _Address"); + break; + case FLAVOR_VOIP_CALL: + open_label = _("Call _To…"); + copy_label = _("Copy Call _Address "); + break; + case FLAVOR_AS_IS: + case FLAVOR_DEFAULT_TO_HTTP: + default: + open_label = _("_Open Link"); + copy_label = _("Copy _Link"); + break; + } + + g_menu_append (section2, open_label, "win.open-match"); + g_menu_append (section2, copy_label, "win.copy-match"); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section2)); + } + + /* Info section */ + if (info->number_info != NULL) { + gs_unref_object GMenu *section3 = g_menu_new (); + /* Non-existent action will make this item insensitive */ + gs_unref_object GMenuItem *item3 = g_menu_item_new (info->number_info, "win.notexist"); + g_menu_append_item (section3, item3); + g_menu_append_section (menu, NULL, G_MENU_MODEL (section3)); + } + + /* Clipboard section */ + gs_unref_object GMenu *section4 = g_menu_new (); + + g_menu_append (section4, _("_Copy"), "win.copy::text"); + g_menu_append (section4, _("Copy as _HTML"), "win.copy::html"); + g_menu_append (section4, _("_Paste"), "win.paste-text"); + if (g_action_get_enabled (G_ACTION (lookup_action (window, "paste-uris")))) + g_menu_append (section4, _("Paste as _Filenames"), "win.paste-uris"); + + g_menu_append_section (menu, NULL, G_MENU_MODEL (section4)); + + /* Profile and property section */ + gs_unref_object GMenu *section5 = g_menu_new (); + g_menu_append (section5, _("Read-_Only"), "win.read-only"); + + GMenuModel *profiles_menu = terminal_app_get_profile_section (app); + if (profiles_menu != NULL && g_menu_model_get_n_items (profiles_menu) > 1) { + gs_unref_object GMenu *submenu5 = g_menu_new (); + g_menu_append_section (submenu5, NULL, profiles_menu); + + gs_unref_object GMenuItem *item5 = g_menu_item_new (_("P_rofiles"), NULL); + g_menu_item_set_submenu (item5, G_MENU_MODEL (submenu5)); + g_menu_append_item (section5, item5); + } + + g_menu_append (section5, _("_Preferences"), "win.edit-preferences"); + + g_menu_append_section (menu, NULL, G_MENU_MODEL (section5)); + + /* New Terminal section */ + gs_unref_object GMenu *section6 = g_menu_new (); + if (terminal_app_get_menu_unified (app)) { + gs_unref_object GMenuItem *item6 = g_menu_item_new (_("New _Terminal"), NULL); + g_menu_item_set_action_and_target (item6, "win.new-terminal", + "(ss)", "default", "current"); + g_menu_append_item (section6, item6); + } else { + gs_unref_object GMenuItem *item61 = g_menu_item_new (_("New _Window"), NULL); + g_menu_item_set_action_and_target (item61, "win.new-terminal", + "(ss)", "window", "current"); + g_menu_append_item (section6, item61); + gs_unref_object GMenuItem *item62 = g_menu_item_new (_("New _Tab"), NULL); + g_menu_item_set_action_and_target (item62, "win.new-terminal", + "(ss)", "tab", "current"); + g_menu_append_item (section6, item62); + } + g_menu_append_section (menu, NULL, G_MENU_MODEL (section6)); + + /* Window section */ + gs_unref_object GMenu *section7 = g_menu_new (); + + /* Only show this if the WM doesn't show the menubar */ + if (g_action_get_enabled (G_ACTION (lookup_action (window, "menubar-visible")))) + g_menu_append (section7, _("Show _Menubar"), "win.menubar-visible"); + if (g_action_get_enabled (G_ACTION (lookup_action (window, "leave-fullscreen")))) + g_menu_append (section7, _("L_eave Full Screen"), "win.leave-fullscreen"); + + g_menu_append_section (menu, NULL, G_MENU_MODEL (section7)); + + /* Now create the popup menu and show it */ + GtkWidget *popup_menu = context_menu_new (G_MENU_MODEL (menu), GTK_WIDGET (window)); + + /* Remove the popup info after the menu is done */ + g_signal_connect (popup_menu, "selection-done", + G_CALLBACK (screen_popup_menu_selection_done_cb), window); + + gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, + NULL, NULL, + info->button, + info->timestamp); + + if (info->button == 0) + gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE); +} + +static gboolean +screen_match_clicked_cb (TerminalScreen *screen, + const char *url, + int url_flavor, + guint state, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (screen != priv->active_screen) + return FALSE; + + gtk_widget_grab_focus (GTK_WIDGET (screen)); + terminal_util_open_url (GTK_WIDGET (window), url, url_flavor, + gtk_get_current_event_time ()); + + return TRUE; +} + +static void +screen_close_cb (TerminalScreen *screen, + TerminalWindow *window) +{ + terminal_window_remove_screen (window, screen); +} + +static void +notebook_update_tabs_menu_cb (GtkMenuButton *button, + TerminalWindow *window) +{ + gs_unref_object GMenu *menu; + gs_free_list GList *tabs; + GList *t; + int i; + + menu = g_menu_new (); + tabs = terminal_window_list_screen_containers (window); + + for (t = tabs, i = 0; t != NULL; t = t->next, i++) { + TerminalScreenContainer *container = t->data; + TerminalScreen *screen = terminal_screen_container_get_screen (container); + gs_unref_object GMenuItem *item; + const char *title; + + if (t->next == NULL) { + /* Last entry. If it has no dedicated shortcut "Switch to Tab N", + * display the accel of "Switch to Last Tab". */ + GtkApplication *app = GTK_APPLICATION (g_application_get_default ()); + gs_free gchar *detailed_action = g_strdup_printf("win.active-tab(%d)", i); + gs_strfreev gchar **accels = gtk_application_get_accels_for_action (app, detailed_action); + if (accels[0] == NULL) + i = -1; + } + + title = terminal_screen_get_title (screen); + + item = g_menu_item_new (title && title[0] ? title : _("Terminal"), NULL); + g_menu_item_set_action_and_target (item, "win.active-tab", "i", i); + g_menu_append_item (menu, item); + } + + gtk_menu_button_set_menu_model (button, G_MENU_MODEL (menu)); + + /* Need this so the menu is positioned correctly */ + gtk_widget_set_halign (GTK_WIDGET (gtk_menu_button_get_popup (button)), GTK_ALIGN_END); +} + +static void +terminal_window_fill_notebook_action_box (TerminalWindow *window, + gboolean add_new_tab_button) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *box, *new_tab_button, *tabs_menu_button; + + box = terminal_notebook_get_action_box (TERMINAL_NOTEBOOK (priv->mdi_container), GTK_PACK_END); + + /* Create the NewTerminal button */ + if (add_new_tab_button) + { + new_tab_button = terminal_icon_button_new ("tab-new-symbolic"); + gtk_actionable_set_action_name (GTK_ACTIONABLE (new_tab_button), "win.new-terminal"); + gtk_actionable_set_action_target (GTK_ACTIONABLE (new_tab_button), "(ss)", "tab", "current"); + gtk_box_pack_start (GTK_BOX (box), new_tab_button, FALSE, FALSE, 0); + gtk_widget_show (new_tab_button); + } + + /* Create Tabs menu button */ + tabs_menu_button = terminal_menu_button_new (); + g_signal_connect (tabs_menu_button, "update-menu", + G_CALLBACK (notebook_update_tabs_menu_cb), window); + gtk_box_pack_start (GTK_BOX (box), tabs_menu_button, FALSE, FALSE, 0); + gtk_menu_button_set_align_widget (GTK_MENU_BUTTON (tabs_menu_button), box); + gtk_widget_show (tabs_menu_button); +} + +/*****************************************/ + +#ifdef ENABLE_DEBUG +static void +terminal_window_size_request_cb (GtkWidget *widget, + GtkRequisition *req) +{ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] size-request result %d : %d\n", + widget, req->width, req->height); +} + +static void +terminal_window_size_allocate_cb (GtkWidget *widget, + GtkAllocation *allocation) +{ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] size-alloc result %d : %d at (%d, %d)\n", + widget, + allocation->width, allocation->height, + allocation->x, allocation->y); +} +#endif /* ENABLE_DEBUG */ + +static void +terminal_window_realize (GtkWidget *widget) +{ + TerminalWindow *window = TERMINAL_WINDOW (widget); + TerminalWindowPrivate *priv = window->priv; + GtkAllocation widget_allocation; + + gtk_widget_get_allocation (widget, &widget_allocation); + + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] realize, size %d : %d at (%d, %d)\n", + widget, + widget_allocation.width, widget_allocation.height, + widget_allocation.x, widget_allocation.y); + + GTK_WIDGET_CLASS (terminal_window_parent_class)->realize (widget); + + /* Now that we've been realized, we should know precisely how large the + * client-side decorations are going to be. Recalculate the geometry hints, + * export them to the windowing system, and resize the window accordingly. */ + priv->realized = TRUE; + terminal_window_update_size (window); +} + +static gboolean +terminal_window_state_event (GtkWidget *widget, + GdkEventWindowState *event) +{ + gboolean (* window_state_event) (GtkWidget *, GdkEventWindowState *event) = + GTK_WIDGET_CLASS (terminal_window_parent_class)->window_state_event; + + if (event->changed_mask & GDK_WINDOW_STATE_FULLSCREEN) + { + TerminalWindow *window = TERMINAL_WINDOW (widget); + gboolean is_fullscreen; + + is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0; + + g_simple_action_set_state (lookup_action (window, "fullscreen"), + g_variant_new_boolean (is_fullscreen)); + g_simple_action_set_enabled (lookup_action (window, "leave-fullscreen"), + is_fullscreen); + g_simple_action_set_enabled (lookup_action (window, "size-to"), + !is_fullscreen); + } + + if (window_state_event) + return window_state_event (widget, event); + + return FALSE; +} + +static void +terminal_window_screen_update (TerminalWindow *window, + GdkScreen *screen) +{ + GSettings *settings; + GtkSettings *gtk_settings; + + if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (screen), "GT::HasSettingsConnection"))) + return; + + settings = terminal_app_get_global_settings (terminal_app_get ()); + gtk_settings = gtk_settings_get_for_screen (screen); + + g_object_set_data_full (G_OBJECT (screen), "GT::HasSettingsConnection", + gtk_settings, + (GDestroyNotify) app_setting_notify_destroy_cb); + + g_settings_bind (settings, + TERMINAL_SETTING_ENABLE_SHORTCUTS_KEY, + gtk_settings, + "gtk-enable-accels", + G_SETTINGS_BIND_GET); + + enable_menubar_accel_changed_cb (settings, + TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, + gtk_settings); + g_signal_connect (settings, "changed::" TERMINAL_SETTING_ENABLE_MENU_BAR_ACCEL_KEY, + G_CALLBACK (enable_menubar_accel_changed_cb), + gtk_settings); +} + +static void +terminal_window_screen_changed (GtkWidget *widget, + GdkScreen *previous_screen) +{ + TerminalWindow *window = TERMINAL_WINDOW (widget); + void (* screen_changed) (GtkWidget *, GdkScreen *) = + GTK_WIDGET_CLASS (terminal_window_parent_class)->screen_changed; + GdkScreen *screen; + + if (screen_changed) + screen_changed (widget, previous_screen); + + screen = gtk_widget_get_screen (widget); + if (previous_screen == screen) + return; + + if (!screen) + return; + + terminal_window_screen_update (window, screen); +} + +static void +terminal_window_init (TerminalWindow *window) +{ + const GActionEntry action_entries[] = { + /* Actions without state */ + { "about", action_about_cb, NULL, NULL, NULL }, + { "close", action_close_cb, "s", NULL, NULL }, + { "copy", action_copy_cb, "s", NULL, NULL }, + { "copy-hyperlink", action_copy_hyperlink_cb, NULL, NULL, NULL }, + { "copy-match", action_copy_match_cb, NULL, NULL, NULL }, + { "edit-preferences", action_edit_preferences_cb, NULL, NULL, NULL }, + { "enter-fullscreen", action_enter_fullscreen_cb, NULL, NULL, NULL }, + { "find", action_find_cb, NULL, NULL, NULL }, + { "find-backward", action_find_backward_cb, NULL, NULL, NULL }, + { "find-clear", action_find_clear_cb, NULL, NULL, NULL }, + { "find-forward", action_find_forward_cb, NULL, NULL, NULL }, + { "help", action_help_cb, NULL, NULL, NULL }, + { "inspector", action_inspector_cb, NULL, NULL, NULL }, + { "leave-fullscreen", action_leave_fullscreen_cb, NULL, NULL, NULL }, + { "new-terminal", action_new_terminal_cb, "(ss)", NULL, NULL }, + { "open-match", action_open_match_cb, NULL, NULL, NULL }, + { "open-hyperlink", action_open_hyperlink_cb, NULL, NULL, NULL }, + { "paste-text", action_paste_text_cb, NULL, NULL, NULL }, + { "paste-uris", action_paste_uris_cb, NULL, NULL, NULL }, + { "reset", action_reset_cb, "b", NULL, NULL }, + { "select-all", action_select_all_cb, NULL, NULL, NULL }, + { "size-to", action_size_to_cb, "(uu)", NULL, NULL }, + { "tab-detach", action_tab_detach_cb, NULL, NULL, NULL }, + { "tab-move-left", action_tab_move_left_cb, NULL, NULL, NULL }, + { "tab-move-right", action_tab_move_right_cb, NULL, NULL, NULL }, + { "tab-switch-left", action_tab_switch_left_cb, NULL, NULL, NULL }, + { "tab-switch-right", action_tab_switch_right_cb, NULL, NULL, NULL }, + { "tabs-menu", NULL, NULL, NULL, NULL }, + { "zoom-in", action_zoom_in_cb, NULL, NULL, NULL }, + { "zoom-normal", action_zoom_normal_cb, NULL, NULL, NULL }, + { "zoom-out", action_zoom_out_cb, NULL, NULL, NULL }, +#ifdef ENABLE_EXPORT + { "export", action_export_cb, NULL, NULL, NULL }, +#endif +#ifdef ENABLE_PRINT + { "print", action_print_cb, NULL, NULL, NULL }, +#endif +#ifdef ENABLE_SAVE + { "save-contents", action_save_contents_cb, NULL, NULL, NULL }, +#endif + + /* Shadow actions for keybinding comsumption, see comment in terminal-accels.c */ + { "shadow", action_shadow_activate_cb, "s", NULL, NULL }, + { "shadow-mdi", action_shadow_activate_cb, "s", NULL, NULL }, + + /* Actions with state */ + { "active-tab", action_active_tab_set_cb, "i", "@i 0", action_active_tab_state_cb }, + { "header-menu", NULL /* toggles state */, NULL, "false", NULL }, + { "fullscreen", NULL /* toggles state */, NULL, "false", action_fullscreen_state_cb }, + { "menubar-visible", NULL /* toggles state */, NULL, "true", action_menubar_visible_state_cb }, + { "profile", NULL /* changes state */, "s", "''", action_profile_state_cb }, + { "read-only", NULL /* toggles state */, NULL, "false", action_read_only_state_cb }, + }; + TerminalWindowPrivate *priv; + TerminalApp *app; + GSettings *gtk_debug_settings; + GtkWindowGroup *window_group; + // GtkAccelGroup *accel_group; + uuid_t u; + char uuidstr[37], role[64]; + gboolean shell_shows_menubar; + gboolean use_headerbar; + GSimpleAction *action; + + app = terminal_app_get (); + + priv = window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, TERMINAL_TYPE_WINDOW, TerminalWindowPrivate); + + gtk_widget_init_template (GTK_WIDGET (window)); + + uuid_generate (u); + uuid_unparse (u, uuidstr); + priv->uuid = g_strdup (uuidstr); + + g_signal_connect (G_OBJECT (window), "delete_event", + G_CALLBACK(terminal_window_delete_event), + NULL); +#ifdef ENABLE_DEBUG + _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_GEOMETRY) + { + g_signal_connect_after (window, "size-request", G_CALLBACK (terminal_window_size_request_cb), NULL); + g_signal_connect_after (window, "size-allocate", G_CALLBACK (terminal_window_size_allocate_cb), NULL); + } +#endif + + use_headerbar = terminal_app_get_use_headerbar (app); + if (use_headerbar) { + GtkWidget *headerbar; + + headerbar = terminal_headerbar_new (); + gtk_window_set_titlebar (GTK_WINDOW (window), headerbar); + } + + gtk_window_set_title (GTK_WINDOW (window), _("Terminal")); + + priv->active_screen = NULL; + + priv->main_vbox = gtk_bin_get_child (GTK_BIN (window)); + + priv->mdi_container = TERMINAL_MDI_CONTAINER (terminal_notebook_new ()); + + g_signal_connect (priv->mdi_container, "screen-close-request", + G_CALLBACK (screen_close_request_cb), window); + + g_signal_connect_after (priv->mdi_container, "screen-switched", + G_CALLBACK (mdi_screen_switched_cb), window); + g_signal_connect_after (priv->mdi_container, "screen-added", + G_CALLBACK (mdi_screen_added_cb), window); + g_signal_connect_after (priv->mdi_container, "screen-removed", + G_CALLBACK (mdi_screen_removed_cb), window); + g_signal_connect_after (priv->mdi_container, "screens-reordered", + G_CALLBACK (mdi_screens_reordered_cb), window); + + g_signal_connect_swapped (priv->mdi_container, "notify::tab-pos", + G_CALLBACK (terminal_window_update_geometry), window); + g_signal_connect_swapped (priv->mdi_container, "notify::show-tabs", + G_CALLBACK (terminal_window_update_geometry), window); + + /* FIXME hack hack! */ + if (GTK_IS_NOTEBOOK (priv->mdi_container)) { + g_signal_connect (priv->mdi_container, "button-press-event", + G_CALLBACK (notebook_button_press_cb), window); + g_signal_connect (priv->mdi_container, "popup-menu", + G_CALLBACK (notebook_popup_menu_cb), window); + g_signal_connect (priv->mdi_container, "create-window", + G_CALLBACK (handle_tab_droped_on_desktop), window); + } + + gtk_box_pack_end (GTK_BOX (priv->main_vbox), GTK_WIDGET (priv->mdi_container), TRUE, TRUE, 0); + gtk_widget_show (GTK_WIDGET (priv->mdi_container)); + + priv->old_char_width = -1; + priv->old_char_height = -1; + + priv->old_chrome_width = -1; + priv->old_chrome_height = -1; + priv->old_csd_width = -1; + priv->old_csd_height = -1; + priv->old_padding_width = -1; + priv->old_padding_height = -1; + + priv->old_geometry_widget = NULL; + + /* GAction setup */ + g_action_map_add_action_entries (G_ACTION_MAP (window), + action_entries, G_N_ELEMENTS (action_entries), + window); + + g_simple_action_set_enabled (lookup_action (window, "leave-fullscreen"), FALSE); + + GSettings *global_settings = terminal_app_get_global_settings (app); + enable_mnemonics_changed_cb (global_settings, TERMINAL_SETTING_ENABLE_MNEMONICS_KEY, window); + g_signal_connect (global_settings, "changed::" TERMINAL_SETTING_ENABLE_MNEMONICS_KEY, + G_CALLBACK (enable_mnemonics_changed_cb), window); + + /* Hide "menubar-visible" when the menubar is shown by the shell */ + g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)), + "gtk-shell-shows-menubar", &shell_shows_menubar, + NULL); + if (shell_shows_menubar) { + g_simple_action_set_enabled (lookup_action (window, "menubar-visible"), FALSE); + } else { + priv->menubar = gtk_menu_bar_new_from_model (terminal_app_get_menubar (app)); + gtk_box_pack_start (GTK_BOX (priv->main_vbox), + priv->menubar, + FALSE, FALSE, 0); + + terminal_window_set_menubar_visible (window, !use_headerbar); + priv->use_default_menubar_visibility = !use_headerbar; + } + + /* Maybe make Inspector available */ + action = lookup_action (window, "inspector"); + gtk_debug_settings = terminal_app_get_gtk_debug_settings (app); + if (gtk_debug_settings != NULL) + g_settings_bind (gtk_debug_settings, + "enable-inspector-keybinding", + action, + "enabled", + G_SETTINGS_BIND_GET | G_SETTINGS_BIND_NO_SENSITIVITY); + else + g_simple_action_set_enabled (action, FALSE); + + priv->clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD); + clipboard_targets_changed_cb (app, priv->clipboard, window); + g_signal_connect (app, "clipboard-targets-changed", + G_CALLBACK (clipboard_targets_changed_cb), window); + + terminal_window_fill_notebook_action_box (window, !use_headerbar); + + /* We have to explicitly call this, since screen-changed is NOT + * emitted for the toplevel the first time! + */ + terminal_window_screen_update (window, gtk_widget_get_screen (GTK_WIDGET (window))); + + window_group = gtk_window_group_new (); + gtk_window_group_add_window (window_group, GTK_WINDOW (window)); + g_object_unref (window_group); + + g_snprintf (role, sizeof (role), "gnome-terminal-window-%s", uuidstr); + gtk_window_set_role (GTK_WINDOW (window), role); +} + +static void +terminal_window_style_updated (GtkWidget *widget) +{ + TerminalWindow *window = TERMINAL_WINDOW (widget); + + GTK_WIDGET_CLASS (terminal_window_parent_class)->style_updated (widget); + + terminal_window_update_size (window); +} + +static void +terminal_window_class_init (TerminalWindowClass *klass) +{ + GObjectClass *object_class = G_OBJECT_CLASS (klass); + GtkWidgetClass *widget_class = GTK_WIDGET_CLASS (klass); + + object_class->dispose = terminal_window_dispose; + object_class->finalize = terminal_window_finalize; + + widget_class->show = terminal_window_show; + widget_class->realize = terminal_window_realize; + widget_class->window_state_event = terminal_window_state_event; + widget_class->screen_changed = terminal_window_screen_changed; + widget_class->style_updated = terminal_window_style_updated; + + GtkWindowClass *window_klass; + GtkBindingSet *binding_set; + + window_klass = g_type_class_ref (GTK_TYPE_WINDOW); + binding_set = gtk_binding_set_by_class (window_klass); + gtk_binding_entry_skip (binding_set, GDK_KEY_I, GDK_CONTROL_MASK|GDK_SHIFT_MASK); + gtk_binding_entry_skip (binding_set, GDK_KEY_D, GDK_CONTROL_MASK|GDK_SHIFT_MASK); + g_type_class_unref (window_klass); + + g_type_class_add_private (object_class, sizeof (TerminalWindowPrivate)); + + gtk_widget_class_set_template_from_resource (widget_class, "/org/gnome/terminal/ui/window.ui"); + + gtk_widget_class_set_css_name(widget_class, TERMINAL_WINDOW_CSS_NAME); +} + +static void +terminal_window_dispose (GObject *object) +{ + TerminalWindow *window = TERMINAL_WINDOW (object); + TerminalWindowPrivate *priv = window->priv; + TerminalApp *app = terminal_app_get (); + + if (!priv->disposed) { + GSettings *global_settings = terminal_app_get_global_settings (app); + g_signal_handlers_disconnect_by_func (global_settings, + G_CALLBACK (enable_mnemonics_changed_cb), + window); + } + + priv->disposed = TRUE; + + if (priv->clipboard != NULL) { + g_signal_handlers_disconnect_by_func (app, + G_CALLBACK (clipboard_targets_changed_cb), + window); + priv->clipboard = NULL; + } + + remove_popup_info (window); + + if (priv->search_popover != NULL) + { + g_signal_handlers_disconnect_matched (priv->search_popover, G_SIGNAL_MATCH_DATA, + 0, 0, NULL, NULL, window); + gtk_widget_destroy (GTK_WIDGET (priv->search_popover)); + priv->search_popover = NULL; + } + + G_OBJECT_CLASS (terminal_window_parent_class)->dispose (object); +} + +static void +terminal_window_finalize (GObject *object) +{ + TerminalWindow *window = TERMINAL_WINDOW (object); + TerminalWindowPrivate *priv = window->priv; + + if (priv->confirm_close_dialog) + gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog), + GTK_RESPONSE_DELETE_EVENT); + + g_free (priv->uuid); + + G_OBJECT_CLASS (terminal_window_parent_class)->finalize (object); +} + +static gboolean +terminal_window_delete_event (GtkWidget *widget, + GdkEvent *event, + gpointer data) +{ + return confirm_close_window_or_tab (TERMINAL_WINDOW (widget), NULL); +} + +static void +terminal_window_show (GtkWidget *widget) +{ + TerminalWindow *window = TERMINAL_WINDOW (widget); + TerminalWindowPrivate *priv = window->priv; + GtkAllocation widget_allocation; + + gtk_widget_get_allocation (widget, &widget_allocation); + + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] show, size %d : %d at (%d, %d)\n", + widget, + widget_allocation.width, widget_allocation.height, + widget_allocation.x, widget_allocation.y); + + /* Because of the unexpected reentrancy caused by adding the tab to the notebook + * showing the TerminalWindow, we can get here when the first page has been + * added but not yet set current. By setting the page current, we get the + * right size when we first show the window */ + if (GTK_IS_NOTEBOOK (priv->mdi_container) && + gtk_notebook_get_current_page (GTK_NOTEBOOK (priv->mdi_container)) == -1) + gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->mdi_container), 0); + + if (priv->active_screen != NULL) + { + /* At this point, we have our GdkScreen, and hence the right + * font size, so we can go ahead and size the window. */ + terminal_window_update_size (window); + } + + GTK_WIDGET_CLASS (terminal_window_parent_class)->show (widget); +} + +TerminalWindow* +terminal_window_new (GApplication *app) +{ + return g_object_new (TERMINAL_TYPE_WINDOW, + "application", app, + "show-menubar", FALSE, + NULL); +} + +static void +profile_set_cb (TerminalScreen *screen, + GSettings *old_profile, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (!gtk_widget_get_realized (GTK_WIDGET (window))) + return; + + if (screen != priv->active_screen) + return; + + terminal_window_update_set_profile_menu_active_profile (window); +} + +static void +sync_screen_title (TerminalScreen *screen, + GParamSpec *psepc, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + const char *title; + + if (screen != priv->active_screen) + return; + + title = terminal_screen_get_title (screen); + gtk_window_set_title (GTK_WINDOW (window), + title && title[0] ? title : _("Terminal")); +} + +static void +screen_font_any_changed_cb (TerminalScreen *screen, + GParamSpec *psepc, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + if (!gtk_widget_get_realized (GTK_WIDGET (window))) + return; + + if (screen != priv->active_screen) + return; + + terminal_window_update_size (window); +} + +static void +screen_hyperlink_hover_uri_changed (TerminalScreen *screen, + const char *uri, + const GdkRectangle *bbox G_GNUC_UNUSED, + TerminalWindow *window G_GNUC_UNUSED) +{ + gs_free char *label = NULL; + + if (!gtk_widget_get_realized (GTK_WIDGET (screen))) + return; + + label = terminal_util_hyperlink_uri_label (uri); + + gtk_widget_set_tooltip_text (GTK_WIDGET (screen), label); +} + +/* MDI container callbacks */ + +static void +screen_close_request_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window) +{ + if (confirm_close_window_or_tab (window, screen)) + return; + + terminal_window_remove_screen (window, screen); +} + +int +terminal_window_get_active_screen_num (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + return terminal_mdi_container_get_active_screen_num (priv->mdi_container); +} + +void +terminal_window_add_screen (TerminalWindow *window, + TerminalScreen *screen, + int position) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *old_window; + + old_window = gtk_widget_get_toplevel (GTK_WIDGET (screen)); + if (gtk_widget_is_toplevel (old_window) && + TERMINAL_IS_WINDOW (old_window) && + TERMINAL_WINDOW (old_window)== window) + return; + + if (TERMINAL_IS_WINDOW (old_window)) + terminal_window_remove_screen (TERMINAL_WINDOW (old_window), screen); + + if (position == -1) { + GSettings *global_settings = terminal_app_get_global_settings (terminal_app_get ()); + TerminalNewTabPosition position_pref = g_settings_get_enum (global_settings, + TERMINAL_SETTING_NEW_TAB_POSITION_KEY); + switch (position_pref) { + case TERMINAL_NEW_TAB_POSITION_NEXT: + position = terminal_window_get_active_screen_num (window) + 1; + break; + + default: + case TERMINAL_NEW_TAB_POSITION_LAST: + position = -1; + break; + } + } + + terminal_mdi_container_add_screen (priv->mdi_container, screen, position); +} + +void +terminal_window_remove_screen (TerminalWindow *window, + TerminalScreen *screen) +{ + TerminalWindowPrivate *priv = window->priv; + + terminal_mdi_container_remove_screen (priv->mdi_container, screen); +} + +void +terminal_window_move_screen (TerminalWindow *source_window, + TerminalWindow *dest_window, + TerminalScreen *screen, + int dest_position) +{ + TerminalScreenContainer *screen_container; + + g_return_if_fail (TERMINAL_IS_WINDOW (source_window)); + g_return_if_fail (TERMINAL_IS_WINDOW (dest_window)); + g_return_if_fail (TERMINAL_IS_SCREEN (screen)); + g_return_if_fail (gtk_widget_get_toplevel (GTK_WIDGET (screen)) == GTK_WIDGET (source_window)); + g_return_if_fail (dest_position >= -1); + + screen_container = terminal_screen_container_get_from_screen (screen); + g_assert (TERMINAL_IS_SCREEN_CONTAINER (screen_container)); + + /* We have to ref the screen container as well as the screen, + * because otherwise removing the screen container from the source + * window's notebook will cause the container and its containing + * screen to be gtk_widget_destroy()ed! + */ + g_object_ref_sink (screen_container); + g_object_ref_sink (screen); + terminal_window_remove_screen (source_window, screen); + + /* Now we can safely remove the screen from the container and let the container die */ + gtk_container_remove (GTK_CONTAINER (gtk_widget_get_parent (GTK_WIDGET (screen))), GTK_WIDGET (screen)); + g_object_unref (screen_container); + + terminal_window_add_screen (dest_window, screen, dest_position); + terminal_mdi_container_set_active_screen (dest_window->priv->mdi_container, screen); + g_object_unref (screen); +} + +GList* +terminal_window_list_screen_containers (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + return terminal_mdi_container_list_screen_containers (priv->mdi_container); +} + +void +terminal_window_set_menubar_visible (TerminalWindow *window, + gboolean setting) +{ + TerminalWindowPrivate *priv = window->priv; + + if (priv->menubar == NULL) + return; + + /* it's been set now, so don't override when adding a screen. + * this side effect must happen before we short-circuit below. + */ + priv->use_default_menubar_visibility = FALSE; + + g_simple_action_set_state (lookup_action (window, "menubar-visible"), + g_variant_new_boolean (setting)); + + g_object_set (priv->menubar, "visible", setting, NULL); + + /* FIXMEchpe: use gtk_widget_get_realized instead? */ + if (priv->active_screen) + { + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] setting size after toggling menubar visibility\n", + window); + + terminal_window_update_size (window); + } +} + +GtkWidget * +terminal_window_get_mdi_container (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL); + + return GTK_WIDGET (priv->mdi_container); +} + +void +terminal_window_update_size (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + int grid_width, grid_height; + int pixel_width, pixel_height; + GdkWindow *gdk_window; + + gdk_window = gtk_widget_get_window (GTK_WIDGET (window)); + + if (gdk_window != NULL && + (gdk_window_get_state (gdk_window) & + (GDK_WINDOW_STATE_MAXIMIZED | WINDOW_STATE_TILED | GDK_WINDOW_STATE_FULLSCREEN))) + { + /* Don't adjust the size of maximized or tiled (snapped, half-maximized) + * windows: if we do, there will be ugly gaps of up to 1 character cell + * around otherwise tiled windows. */ + return; + } + + /* be sure our geometry is up-to-date */ + terminal_window_update_geometry (window); + + terminal_screen_get_size (priv->active_screen, &grid_width, &grid_height); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] size is %dx%d cells of %dx%d px\n", + window, grid_width, grid_height, + priv->old_char_width, priv->old_char_height); + + /* the "old" struct members were updated by update_geometry */ + pixel_width = priv->old_chrome_width + grid_width * priv->old_char_width; + pixel_height = priv->old_chrome_height + grid_height * priv->old_char_height; + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] %dx%d + %dx%d = %dx%d\n", + window, grid_width * priv->old_char_width, + grid_height * priv->old_char_height, + priv->old_chrome_width, priv->old_chrome_height, + pixel_width, pixel_height); + + gtk_window_resize (GTK_WINDOW (window), pixel_width, pixel_height); +} + +void +terminal_window_switch_screen (TerminalWindow *window, + TerminalScreen *screen) +{ + TerminalWindowPrivate *priv = window->priv; + + terminal_mdi_container_set_active_screen (priv->mdi_container, screen); +} + +TerminalScreen* +terminal_window_get_active (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + + return terminal_mdi_container_get_active_screen (priv->mdi_container); +} + +static void +notebook_show_context_menu (TerminalWindow *window, + GdkEvent *event, + guint button, + guint32 timestamp) +{ + /* Load the UI */ + gs_unref_object GMenu *menu; + terminal_util_load_objects_resource ("/org/gnome/terminal/ui/notebook-menu.ui", + "notebook-popup", &menu, + NULL); + + GtkWidget *popup_menu = context_menu_new (G_MENU_MODEL (menu), GTK_WIDGET (window)); + + gtk_widget_set_halign (popup_menu, GTK_ALIGN_START); + gtk_menu_popup (GTK_MENU (popup_menu), NULL, NULL, + NULL, NULL, + button, timestamp); + + if (button == 0) + gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE); +} + +static gboolean +notebook_button_press_cb (GtkWidget *widget, + GdkEventButton *event, + TerminalWindow *window) +{ + GtkNotebook *notebook = GTK_NOTEBOOK (widget); + int tab_clicked; + + if (event->type != GDK_BUTTON_PRESS || + event->button != GDK_BUTTON_SECONDARY || + (event->state & gtk_accelerator_get_default_mod_mask ()) != 0) + return FALSE; + + tab_clicked = find_tab_num_at_pos (notebook, event->x_root, event->y_root); + if (tab_clicked < 0) + return FALSE; + + /* switch to the page the mouse is over */ + gtk_notebook_set_current_page (notebook, tab_clicked); + + notebook_show_context_menu (window, (GdkEvent*)event, event->button, event->time); + return TRUE; +} + +static gboolean +notebook_popup_menu_cb (GtkWidget *widget, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *focus_widget; + + focus_widget = gtk_window_get_focus (GTK_WINDOW (window)); + /* Only respond if the notebook is the actual focus */ + if (focus_widget != GTK_WIDGET (priv->mdi_container)) + return FALSE; + + notebook_show_context_menu (window, NULL, 0, gtk_get_current_event_time ()); + return TRUE; +} + +static void +mdi_screen_switched_cb (TerminalMdiContainer *container, + TerminalScreen *old_active_screen, + TerminalScreen *screen, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + int old_grid_width, old_grid_height; + + _terminal_debug_print (TERMINAL_DEBUG_MDI, + "[window %p] MDI: screen-switched old %p new %p\n", + window, old_active_screen, screen); + + if (priv->disposed) + return; + + if (screen == NULL || old_active_screen == screen) + return; + + if (priv->search_popover != NULL) + gtk_widget_hide (GTK_WIDGET (priv->search_popover)); + + _terminal_debug_print (TERMINAL_DEBUG_MDI, + "[window %p] MDI: setting active tab to screen %p (old active screen %p)\n", + window, screen, priv->active_screen); + + if (old_active_screen != NULL && screen != NULL) { + terminal_screen_get_size (old_active_screen, &old_grid_width, &old_grid_height); + + /* This is so that we maintain the same grid */ + vte_terminal_set_size (VTE_TERMINAL (screen), old_grid_width, old_grid_height); + } + + priv->active_screen = screen; + + /* Override menubar setting if it wasn't restored from session */ + if (priv->use_default_menubar_visibility) + { + gboolean setting = + g_settings_get_boolean (terminal_app_get_global_settings (terminal_app_get ()), + TERMINAL_SETTING_DEFAULT_SHOW_MENUBAR_KEY); + + terminal_window_set_menubar_visible (window, setting); + } + + sync_screen_title (screen, NULL, window); + + /* set size of window to current grid size */ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] setting size after flipping notebook pages\n", + window); + terminal_window_update_size (window); + + terminal_window_update_tabs_actions_sensitivity (window); + terminal_window_update_terminal_menu (window); + terminal_window_update_set_profile_menu_active_profile (window); + terminal_window_update_copy_sensitivity (screen, window); + terminal_window_update_zoom_sensitivity (window); + terminal_window_update_search_sensitivity (screen, window); + terminal_window_update_paste_sensitivity (window); +} + +static void +mdi_screen_added_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + int pages; + + _terminal_debug_print (TERMINAL_DEBUG_MDI, + "[window %p] MDI: screen %p inserted\n", + window, screen); + + g_signal_connect (G_OBJECT (screen), + "profile-set", + G_CALLBACK (profile_set_cb), + window); + + /* FIXME: only connect on the active screen, not all screens! */ + g_signal_connect (screen, "notify::title", + G_CALLBACK (sync_screen_title), window); + g_signal_connect (screen, "notify::font-desc", + G_CALLBACK (screen_font_any_changed_cb), window); + g_signal_connect (screen, "notify::font-scale", + G_CALLBACK (screen_font_any_changed_cb), window); + g_signal_connect (screen, "notify::cell-height-scale", + G_CALLBACK (screen_font_any_changed_cb), window); + g_signal_connect (screen, "notify::cell-width-scale", + G_CALLBACK (screen_font_any_changed_cb), window); + g_signal_connect (screen, "selection-changed", + G_CALLBACK (terminal_window_update_copy_sensitivity), window); + g_signal_connect (screen, "hyperlink-hover-uri-changed", + G_CALLBACK (screen_hyperlink_hover_uri_changed), window); + + g_signal_connect (screen, "show-popup-menu", + G_CALLBACK (screen_show_popup_menu_cb), window); + g_signal_connect (screen, "match-clicked", + G_CALLBACK (screen_match_clicked_cb), window); + g_signal_connect (screen, "resize-window", + G_CALLBACK (screen_resize_window_cb), window); + + g_signal_connect (screen, "close-screen", + G_CALLBACK (screen_close_cb), window); + + terminal_window_update_tabs_actions_sensitivity (window); + terminal_window_update_search_sensitivity (screen, window); + terminal_window_update_paste_sensitivity (window); + +#if 0 + /* FIXMEchpe: wtf is this doing? */ + + /* If we have an active screen, match its size and zoom */ + if (priv->active_screen) + { + int current_width, current_height; + double scale; + + terminal_screen_get_size (priv->active_screen, ¤t_width, ¤t_height); + vte_terminal_set_size (VTE_TERMINAL (screen), current_width, current_height); + + scale = terminal_screen_get_font_scale (priv->active_screen); + terminal_screen_set_font_scale (screen, scale); + } +#endif + + if (priv->present_on_insert) + { + gtk_window_present_with_time (GTK_WINDOW (window), gtk_get_current_event_time ()); + priv->present_on_insert = FALSE; + } + + pages = terminal_mdi_container_get_n_screens (container); + if (pages == 2) + { + terminal_window_update_size (window); + } +} + +static void +mdi_screen_removed_cb (TerminalMdiContainer *container, + TerminalScreen *screen, + TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + int pages; + + if (priv->disposed) + return; + + _terminal_debug_print (TERMINAL_DEBUG_MDI, + "[window %p] MDI: screen %p removed\n", + window, screen); + + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), + G_CALLBACK (profile_set_cb), + window); + + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), + G_CALLBACK (sync_screen_title), + window); + + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), + G_CALLBACK (screen_font_any_changed_cb), + window); + + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), + G_CALLBACK (terminal_window_update_copy_sensitivity), + window); + + g_signal_handlers_disconnect_by_func (G_OBJECT (screen), + G_CALLBACK (screen_hyperlink_hover_uri_changed), + window); + + g_signal_handlers_disconnect_by_func (screen, + G_CALLBACK (screen_show_popup_menu_cb), + window); + + g_signal_handlers_disconnect_by_func (screen, + G_CALLBACK (screen_match_clicked_cb), + window); + g_signal_handlers_disconnect_by_func (screen, + G_CALLBACK (screen_resize_window_cb), + window); + + g_signal_handlers_disconnect_by_func (screen, + G_CALLBACK (screen_close_cb), + window); + + /* We already got a switch-page signal whose handler sets the active tab to the + * new active tab, unless this screen was the only one in the notebook, so + * priv->active_tab is valid here. + */ + + pages = terminal_mdi_container_get_n_screens (container); + if (pages == 0) + { + priv->active_screen = NULL; + + /* That was the last tab in the window; close it. */ + gtk_widget_destroy (GTK_WIDGET (window)); + return; + } + + terminal_window_update_tabs_actions_sensitivity (window); + terminal_window_update_search_sensitivity (screen, window); + + if (pages == 1) + { + TerminalScreen *active_screen = terminal_mdi_container_get_active_screen (container); + gtk_widget_grab_focus (GTK_WIDGET(active_screen)); /* bug 742422 */ + + terminal_window_update_size (window); + } +} + +static void +mdi_screens_reordered_cb (TerminalMdiContainer *container, + TerminalWindow *window) +{ + terminal_window_update_tabs_actions_sensitivity (window); +} + +gboolean +terminal_window_parse_geometry (TerminalWindow *window, + const char *geometry) +{ + TerminalWindowPrivate *priv = window->priv; + + /* gtk_window_parse_geometry() needs to have the right base size + * and width/height increment to compute the window size from + * the geometry. + */ + terminal_window_update_geometry (window); + + if (!gtk_window_parse_geometry (GTK_WINDOW (window), geometry)) + return FALSE; + + /* We won't actually get allocated at the size parsed out of the + * geometry until the window is shown. If terminal_window_update_size() + * is called between now and then, that could result in us getting + * snapped back to the old grid size. So we need to immediately + * update the size of the active terminal to grid size from the + * geometry. + */ + if (priv->active_screen) + { + int grid_width, grid_height; + + /* After parse_geometry(), the default size is in units of the + * width/height increment, not a pixel size */ + gtk_window_get_default_size (GTK_WINDOW (window), &grid_width, &grid_height); + + vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), + grid_width, grid_height); + } + + return TRUE; +} + +void +terminal_window_update_geometry (TerminalWindow *window) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *widget; + GdkGeometry hints; + GtkBorder padding; + GtkRequisition vbox_request, widget_request; + int grid_width, grid_height; + int char_width, char_height; + int chrome_width, chrome_height; + int csd_width = 0, csd_height = 0; + + if (gtk_widget_in_destruction (GTK_WIDGET (window))) + return; + + if (priv->active_screen == NULL) + return; + + widget = GTK_WIDGET (priv->active_screen); + + /* We set geometry hints from the active term; best thing + * I can think of to do. Other option would be to try to + * get some kind of union of all hints from all terms in the + * window, but that doesn't make too much sense. + */ + terminal_screen_get_cell_size (priv->active_screen, &char_width, &char_height); + + terminal_screen_get_size (priv->active_screen, &grid_width, &grid_height); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "%dx%d cells of %dx%d px = %dx%d px\n", + grid_width, grid_height, char_width, char_height, + char_width * grid_width, char_height * grid_height); + + gtk_style_context_get_padding(gtk_widget_get_style_context(widget), + gtk_widget_get_state_flags(widget), + &padding); + + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "padding = %dx%d px\n", + padding.left + padding.right, + padding.top + padding.bottom); + + gtk_widget_get_preferred_size (priv->main_vbox, NULL, &vbox_request); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "content area requests %dx%d px\n", + vbox_request.width, vbox_request.height); + + + chrome_width = vbox_request.width - (char_width * grid_width); + chrome_height = vbox_request.height - (char_height * grid_height); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "chrome: %dx%d px\n", + chrome_width, chrome_height); + + if (priv->realized) + { + /* Only when having been realize the CSD can be calculated. Do this by + * using the actual allocation rather then the preferred size as the + * the preferred size takes the natural size of e.g. the title bar into + * account which can be far wider then the contents size when using a + * very long title */ + GtkAllocation toplevel_allocation, vbox_allocation; + + gtk_widget_get_allocation (GTK_WIDGET (priv->main_vbox), &vbox_allocation); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "terminal widget allocation %dx%d px\n", + vbox_allocation.width, vbox_allocation.height); + + gtk_widget_get_allocation (GTK_WIDGET (window), &toplevel_allocation); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "window allocation %dx%d px\n", + toplevel_allocation.width, toplevel_allocation.height); + + csd_width = toplevel_allocation.width - vbox_allocation.width; + csd_height = toplevel_allocation.height - vbox_allocation.height; + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "CSDs: %dx%d px\n", + csd_width, csd_height); + } + + gtk_widget_get_preferred_size (widget, NULL, &widget_request); + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "terminal widget requests %dx%d px\n", + widget_request.width, widget_request.height); + + if (!priv->realized) + { + /* Don't actually set the geometry hints until we have been realized, + * because we don't know how large the client-side decorations are going + * to be. We also avoid setting priv->old_csd_width or + * priv->old_csd_height, so that next time through this function we'll + * definitely recalculate the hints. + * + * Similarly, the size request doesn't seem to include the padding + * until we've been redrawn at least once. Don't resize the window + * until we've done that. */ + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, "not realized yet\n"); + } + else if (char_width != priv->old_char_width || + char_height != priv->old_char_height || + padding.left + padding.right != priv->old_padding_width || + padding.top + padding.bottom != priv->old_padding_height || + chrome_width != priv->old_chrome_width || + chrome_height != priv->old_chrome_height || + csd_width != priv->old_csd_width || + csd_height != priv->old_csd_height || + widget != (GtkWidget*) priv->old_geometry_widget) + { + hints.base_width = chrome_width + csd_width; + hints.base_height = chrome_height + csd_height; + + hints.width_inc = char_width; + hints.height_inc = char_height; + + /* min size is min size of the whole window, remember. */ + hints.min_width = hints.base_width + hints.width_inc * MIN_WIDTH_CHARS; + hints.min_height = hints.base_height + hints.height_inc * MIN_HEIGHT_CHARS; + + gtk_window_set_geometry_hints (GTK_WINDOW (window), + NULL, + &hints, + GDK_HINT_RESIZE_INC | + GDK_HINT_MIN_SIZE | + GDK_HINT_BASE_SIZE); + + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] hints: base %dx%d min %dx%d inc %d %d\n", + window, + hints.base_width, + hints.base_height, + hints.min_width, + hints.min_height, + hints.width_inc, + hints.height_inc); + + priv->old_csd_width = csd_width; + priv->old_csd_height = csd_height; + priv->old_geometry_widget = widget; + } + else + { + _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY, + "[window %p] hints: increment unchanged, not setting\n", + window); + } + + /* We need these for the size calculation in terminal_window_update_size() + * (at least under GTK >= 3.19), so we set them unconditionally. */ + priv->old_char_width = char_width; + priv->old_char_height = char_height; + priv->old_chrome_width = chrome_width; + priv->old_chrome_height = chrome_height; + priv->old_padding_width = padding.left + padding.right; + priv->old_padding_height = padding.top + padding.bottom; +} + +static void +confirm_close_response_cb (GtkWidget *dialog, + int response, + TerminalWindow *window) +{ + TerminalScreen *screen; + + screen = g_object_get_data (G_OBJECT (dialog), "close-screen"); + + gtk_widget_destroy (dialog); + + if (response != GTK_RESPONSE_ACCEPT) + return; + + if (screen) + terminal_window_remove_screen (window, screen); + else + gtk_widget_destroy (GTK_WIDGET (window)); +} + +/* Returns: TRUE if closing needs to wait until user confirmation; + * FALSE if the terminal or window can close immediately. + */ +static gboolean +confirm_close_window_or_tab (TerminalWindow *window, + TerminalScreen *screen) +{ + TerminalWindowPrivate *priv = window->priv; + GtkWidget *dialog; + gboolean do_confirm; + int n_tabs; + + if (priv->confirm_close_dialog) + { + /* WTF, already have one? It's modal, so how did that happen? */ + gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog), + GTK_RESPONSE_DELETE_EVENT); + } + + do_confirm = g_settings_get_boolean (terminal_app_get_global_settings (terminal_app_get ()), + TERMINAL_SETTING_CONFIRM_CLOSE_KEY); + if (!do_confirm) + return FALSE; + + if (screen) + { + do_confirm = terminal_screen_has_foreground_process (screen, NULL, NULL); + n_tabs = 1; + } + else + { + GList *tabs, *t; + + do_confirm = FALSE; + + tabs = terminal_window_list_screen_containers (window); + n_tabs = g_list_length (tabs); + + for (t = tabs; t != NULL; t = t->next) + { + TerminalScreen *terminal_screen; + + terminal_screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (t->data)); + if (terminal_screen_has_foreground_process (terminal_screen, NULL, NULL)) + { + do_confirm = TRUE; + break; + } + } + g_list_free (tabs); + } + + if (!do_confirm) + return FALSE; + + dialog = priv->confirm_close_dialog = + gtk_message_dialog_new (GTK_WINDOW (window), + GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT, + GTK_MESSAGE_WARNING, + GTK_BUTTONS_CANCEL, + "%s", n_tabs > 1 ? _("Close this window?") : _("Close this terminal?")); + + if (n_tabs > 1) + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", _("There are still processes running in some terminals in this window. " + "Closing the window will kill all of them.")); + else + gtk_message_dialog_format_secondary_text (GTK_MESSAGE_DIALOG (dialog), + "%s", _("There is still a process running in this terminal. " + "Closing the terminal will kill it.")); + + gtk_window_set_title (GTK_WINDOW (dialog), ""); + + gtk_dialog_add_button (GTK_DIALOG (dialog), n_tabs > 1 ? _("C_lose Window") : _("C_lose Terminal"), GTK_RESPONSE_ACCEPT); + gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT); + + g_object_set_data (G_OBJECT (dialog), "close-screen", screen); + + g_signal_connect (dialog, "destroy", + G_CALLBACK (gtk_widget_destroyed), &priv->confirm_close_dialog); + g_signal_connect (dialog, "response", + G_CALLBACK (confirm_close_response_cb), window); + + gtk_window_present (GTK_WINDOW (dialog)); + + return TRUE; +} + +void +terminal_window_request_close (TerminalWindow *window) +{ + g_return_if_fail (TERMINAL_IS_WINDOW (window)); + + if (confirm_close_window_or_tab (window, NULL)) + return; + + gtk_widget_destroy (GTK_WIDGET (window)); +} + +const char * +terminal_window_get_uuid (TerminalWindow *window) +{ + g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL); + + return window->priv->uuid; +} diff --git a/src/terminal-window.h b/src/terminal-window.h new file mode 100644 index 0000000..7691c5a --- /dev/null +++ b/src/terminal-window.h @@ -0,0 +1,97 @@ +/* + * Copyright © 2001 Havoc Pennington + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#ifndef TERMINAL_WINDOW_H +#define TERMINAL_WINDOW_H + +#include + +#include "terminal-screen.h" + +G_BEGIN_DECLS + +#define TERMINAL_TYPE_WINDOW (terminal_window_get_type ()) +#define TERMINAL_WINDOW(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_WINDOW, TerminalWindow)) +#define TERMINAL_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_WINDOW, TerminalWindowClass)) +#define TERMINAL_IS_WINDOW(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_WINDOW)) +#define TERMINAL_IS_WINDOW_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_WINDOW)) +#define TERMINAL_WINDOW_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_WINDOW, TerminalWindowClass)) + +typedef struct _TerminalWindowClass TerminalWindowClass; +typedef struct _TerminalWindowPrivate TerminalWindowPrivate; + +struct _TerminalWindow +{ + GtkApplicationWindow parent_instance; + + TerminalWindowPrivate *priv; +}; + +struct _TerminalWindowClass +{ + GtkApplicationWindowClass parent_class; +}; + +GType terminal_window_get_type (void) G_GNUC_CONST; + +TerminalWindow* terminal_window_new (GApplication *app); + +GtkUIManager *terminal_window_get_ui_manager (TerminalWindow *window); + +int terminal_window_get_active_screen_num (TerminalWindow *window); + +void terminal_window_add_screen (TerminalWindow *window, + TerminalScreen *screen, + int position); + +void terminal_window_remove_screen (TerminalWindow *window, + TerminalScreen *screen); + +void terminal_window_move_screen (TerminalWindow *source_window, + TerminalWindow *dest_window, + TerminalScreen *screen, + int dest_position); + +/* Menubar visibility is part of session state, except that + * if it isn't restored from session, the window gets the setting + * from the profile of the first screen added to the window + */ +void terminal_window_set_menubar_visible (TerminalWindow *window, + gboolean setting); + +void terminal_window_update_size (TerminalWindow *window); + +void terminal_window_switch_screen (TerminalWindow *window, + TerminalScreen *screen); +TerminalScreen* terminal_window_get_active (TerminalWindow *window); + +GList* terminal_window_list_screen_containers (TerminalWindow *window); + +gboolean terminal_window_parse_geometry (TerminalWindow *window, + const char *geometry); + +void terminal_window_update_geometry (TerminalWindow *window); + +GtkWidget* terminal_window_get_mdi_container (TerminalWindow *window); + +void terminal_window_request_close (TerminalWindow *window); + +const char *terminal_window_get_uuid (TerminalWindow *window); + +G_END_DECLS + +#endif /* TERMINAL_WINDOW_H */ diff --git a/src/terminal-window.ui b/src/terminal-window.ui new file mode 100644 index 0000000..b0f63fd --- /dev/null +++ b/src/terminal-window.ui @@ -0,0 +1,17 @@ + + + + + diff --git a/src/terminal.about b/src/terminal.about new file mode 100644 index 0000000..3b097d5 --- /dev/null +++ b/src/terminal.about @@ -0,0 +1,5 @@ +[About] +Authors=Behdad Esfahbod;Egmont Koblinger;Guilherme de S. Pastore;Havoc Pennington;Christian Persch;Mariano Suárez-Alvarez; +Contributors= +;Artists= +Documenters=GNOME Documentation Team ; diff --git a/src/terminal.c b/src/terminal.c new file mode 100644 index 0000000..ad97539 --- /dev/null +++ b/src/terminal.c @@ -0,0 +1,601 @@ +/* + * Copyright © 2001, 2002 Havoc Pennington + * Copyright © 2002 Red Hat, Inc. + * Copyright © 2002 Sun Microsystems + * Copyright © 2003 Mariano Suarez-Alvarez + * Copyright © 2008, 2010, 2011 Christian Persch + * + * This program is free software: you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation, either version 3 of the License, or + * (at your option) any later version. + * + * This program is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program. If not, see . + */ + +#include "config.h" + +#include +#include +#include +#include +#include +#include + +#include +#include +#include +#include + +#include + +#include "terminal-debug.h" +#include "terminal-defines.h" +#include "terminal-i18n.h" +#include "terminal-options.h" +#include "terminal-gdbus-generated.h" +#include "terminal-defines.h" +#include "terminal-client-utils.h" +#include "terminal-libgsystem.h" + +GS_DEFINE_CLEANUP_FUNCTION0(TerminalOptions*, gs_local_options_free, terminal_options_free) +#define gs_free_options __attribute__ ((cleanup(gs_local_options_free))) + +/* Wait-for-exit helper */ + +typedef struct { + GMainLoop *loop; + int status; +} RunData; + +static void +receiver_child_exited_cb (TerminalReceiver *receiver, + int status, + RunData *data) +{ + data->status = status; + + if (g_main_loop_is_running (data->loop)) + g_main_loop_quit (data->loop); +} + +static void +factory_name_owner_notify_cb (TerminalFactory *factory, + GParamSpec *pspec, + RunData *data) +{ + /* Name owner change to NULL can only mean that the server + * went away before it could send out our child-exited signal. + * Assume the server was killed and thus our child process + * too, and return with the corresponding exit code. + */ + if (g_dbus_proxy_get_name_owner(G_DBUS_PROXY (factory)) != NULL) + return; + + data->status = W_EXITCODE(0, SIGKILL); + + if (g_main_loop_is_running (data->loop)) + g_main_loop_quit (data->loop); +} + +static int +run_receiver (TerminalFactory *factory, + TerminalReceiver *receiver) +{ + RunData data = { g_main_loop_new (NULL, FALSE), 0 }; + gulong receiver_exited_id = g_signal_connect (receiver, "child-exited", + G_CALLBACK (receiver_child_exited_cb), &data); + gulong factory_notify_id = g_signal_connect (factory, "notify::g-name-owner", + G_CALLBACK (factory_name_owner_notify_cb), &data); + g_main_loop_run (data.loop); + g_signal_handler_disconnect (receiver, receiver_exited_id); + g_signal_handler_disconnect (factory, factory_notify_id); + g_main_loop_unref (data.loop); + + /* Mangle the exit status */ + int exit_code; + if (WIFEXITED (data.status)) + exit_code = WEXITSTATUS (data.status); + else if (WIFSIGNALED (data.status)) + exit_code = 128 + (int) WTERMSIG (data.status); + else if (WCOREDUMP (data.status)) + exit_code = 127; + else + exit_code = 127; + + return exit_code; +} + +/* Factory helpers */ + +static gboolean +get_factory_exit_status (const char *service_name, + const char *message, + int *exit_status) +{ + gs_free char *pattern = NULL, *number = NULL; + gs_unref_regex GRegex *regex = NULL; + gs_free_match_info GMatchInfo *match_info = NULL; + gint64 v; + char *end; + GError *err = NULL; + + pattern = g_strdup_printf ("org.freedesktop.DBus.Error.Spawn.ChildExited: Process %s exited with status (\\d+)$", + service_name); + regex = g_regex_new (pattern, 0, 0, &err); + g_assert_no_error (err); + + if (!g_regex_match (regex, message, 0, &match_info)) + return FALSE; + + number = g_match_info_fetch (match_info, 1); + g_assert_nonnull (number); + + errno = 0; + v = g_ascii_strtoll (number, &end, 10); + if (errno || end == number || *end != '\0' || v < 0 || v > G_MAXINT) + return FALSE; + + *exit_status = (int)v; + return TRUE; +} + +static gboolean +handle_factory_error (const char *service_name, + GError *error) +{ + int exit_status; + + if (!g_dbus_error_is_remote_error (error) || + !g_error_matches (error, G_DBUS_ERROR, G_DBUS_ERROR_SPAWN_CHILD_EXITED) || + !get_factory_exit_status (service_name, error->message, &exit_status)) + return FALSE; + + g_dbus_error_strip_remote_error (error); + terminal_printerr ("%s\n\n", error->message); + + switch (exit_status) { + case _EXIT_FAILURE_WRONG_ID: + terminal_printerr ("You tried to run gnome-terminal-server with elevated privileged. This is not supported.\n"); + break; + case _EXIT_FAILURE_NO_UTF8: + terminal_printerr ("The environment that gnome-terminal-server was launched with specified a non-UTF-8 locale. This is not supported.\n"); + break; + case _EXIT_FAILURE_UNSUPPORTED_LOCALE: + terminal_printerr ("The environment that gnome-terminal-server was launched with specified an unsupported locale.\n"); + break; + case _EXIT_FAILURE_GTK_INIT: + terminal_printerr ("The environment that gnome-terminal-server was launched with most likely contained an incorrect or unset \"DISPLAY\" variable.\n"); + break; + default: + break; + } + terminal_printerr ("See https://wiki.gnome.org/Apps/Terminal/FAQ#Exit_status_%d for more information.\n", exit_status); + + return TRUE; +} + +static gboolean +handle_create_instance_error (const char *service_name, + GError *error) +{ + if (handle_factory_error (service_name, error)) + return TRUE; + + g_dbus_error_strip_remote_error (error); + terminal_printerr ("Error creating terminal: %s\n", error->message); + return FALSE; /* don't abort */ +} + +static gboolean +handle_create_receiver_proxy_error (const char *service_name, + GError *error) +{ + if (handle_factory_error (service_name, error)) + return TRUE; + + g_dbus_error_strip_remote_error (error); + terminal_printerr ("Failed to create proxy for terminal: %s\n", error->message); + return FALSE; /* don't abort */ +} + +static gboolean +handle_exec_error (const char *service_name, + GError *error) +{ + if (handle_factory_error (service_name, error)) + return TRUE; + + g_dbus_error_strip_remote_error (error); + terminal_printerr ("Error: %s\n", error->message); + return FALSE; /* don't abort */ +} + +static gboolean +factory_proxy_new_for_service_name (const char *service_name, + gboolean ping_server, + gboolean connect_signals, + TerminalFactory **factory_ptr, + char **service_name_ptr, + GError **error) +{ + if (service_name == NULL) + service_name = TERMINAL_APPLICATION_ID; + + gs_free_error GError *err = NULL; + gs_unref_object TerminalFactory *factory = + terminal_factory_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + connect_signals ? 0 : G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS, + service_name, + TERMINAL_FACTORY_OBJECT_PATH, + NULL /* cancellable */, + &err); + if (factory == NULL) { + if (!handle_factory_error (service_name, err)) + terminal_printerr ("Error constructing proxy for %s:%s: %s\n", + service_name, TERMINAL_FACTORY_OBJECT_PATH, err->message); + g_propagate_error (error, err); + err = NULL; + return FALSE; + } + + if (ping_server) { + /* If we try to use the environment specified server, we need to make + * sure it actually exists so we can later fall back to the default name. + * There doesn't appear to a way to fail proxy creation above if the + * unique name doesn't exist; so we do it this way. + */ + gs_unref_variant GVariant *v = g_dbus_proxy_call_sync (G_DBUS_PROXY (factory), + "org.freedesktop.DBus.Peer.Ping", + g_variant_new ("()"), + G_DBUS_CALL_FLAGS_NONE, + 1000 /* 1s */, + NULL /* cancelleable */, + &err); + if (v == NULL) { + g_propagate_error (error, err); + err = NULL; + return FALSE; + } + } + + gs_transfer_out_value (factory_ptr, &factory); + *service_name_ptr = g_strdup (service_name); + return TRUE; +} + +static gboolean +factory_proxy_new (TerminalOptions *options, + TerminalFactory **factory_ptr, + char **service_name_ptr, + char **parent_screen_object_path_ptr, + GError **error) +{ + const char *service_name = options->server_app_id; + + /* If --app-id was specified, or the environment does not specify + * the server to use, create the factory proxy from the given (or default) + * name, with no fallback. + * + * If the server specified by the environment doesn't exist, fall back to the + * default server, and ignore the environment-specified parent screen. + */ + if (options->server_app_id == NULL && + options->server_unique_name != NULL) { + gs_free_error GError *err = NULL; + if (factory_proxy_new_for_service_name (options->server_unique_name, + TRUE, + options->wait, + factory_ptr, + service_name_ptr, + &err)) { + *parent_screen_object_path_ptr = g_strdup (options->parent_screen_object_path); + return TRUE; + } + + terminal_printerr ("Failed to use specified server: %s\n", + err->message); + terminal_printerr ("Falling back to default server.\n"); + + /* Fall back to the default */ + service_name = NULL; + } + + *parent_screen_object_path_ptr = NULL; + + return factory_proxy_new_for_service_name (service_name, + FALSE, + options->wait, + factory_ptr, + service_name_ptr, + error); +} + +static void +handle_show_preferences (TerminalOptions *options, + const char *service_name) +{ + gs_free_error GError *error = NULL; + gs_unref_object GDBusConnection *bus = NULL; + gs_free char *object_path = NULL; + GVariantBuilder builder; + + bus = g_bus_get_sync (G_BUS_TYPE_SESSION, NULL, &error); + if (bus == NULL) { + terminal_printerr ("Failed to get session bus: %s\n", error->message); + return; + } + + /* For reasons (!?), the org.gtk.Actions interface's object path + * is derived from the service name, i.e. for service name + * "foo.bar.baz" the object path is "/foo/bar/baz". + * This means that without the name (like when given only the unique name), + * we cannot activate the action. + */ + if (g_dbus_is_unique_name(service_name)) { + terminal_printerr ("Cannot call this function from within gnome-terminal.\n"); + return; + } + + object_path = g_strdelimit (g_strdup_printf (".%s", service_name), ".", '/'); + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("(sava{sv})")); + g_variant_builder_add (&builder, "s", "preferences"); + g_variant_builder_open (&builder, G_VARIANT_TYPE ("av")); + g_variant_builder_close (&builder); + g_variant_builder_open (&builder, G_VARIANT_TYPE ("a{sv}")); + if (options->startup_id) + g_variant_builder_add (&builder, "{sv}", + "desktop-startup-id", g_variant_new_string (options->startup_id)); + g_variant_builder_close (&builder); + + if (!g_dbus_connection_call_sync (bus, + service_name, + object_path, + "org.gtk.Actions", + "Activate", + g_variant_builder_end (&builder), + G_VARIANT_TYPE ("()"), + G_DBUS_CALL_FLAGS_NO_AUTO_START, + 30 * 1000 /* ms timeout */, + NULL /* cancelleable */, + &error)) { + terminal_printerr ("Activate call failed: %s\n", error->message); + return; + } +} + +/** + * handle_options: + * @app: + * @options: a #TerminalOptions + * @allow_resume: whether to merge the terminal configuration from the + * saved session on resume + * @wait_for_receiver: location to store the #TerminalReceiver to wait for + * + * Processes @options. It loads or saves the terminal configuration, or + * opens the specified windows and tabs. + * + * Returns: %TRUE if @options could be successfully handled, or %FALSE on + * error + */ +static gboolean +handle_options (TerminalOptions *options, + TerminalFactory *factory, + const char *service_name, + const char *parent_screen_object_path, + TerminalReceiver **wait_for_receiver) +{ + /* We need to forward the locale encoding to the server, see bug #732128 */ + const char *encoding; + g_get_charset (&encoding); + + if (options->show_preferences) { + handle_show_preferences (options, service_name); + } else { + /* Make sure we open at least one window */ + terminal_options_ensure_window (options); + } + + const char *factory_unique_name = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (factory)); + + for (GList *lw = options->initial_windows; lw != NULL; lw = lw->next) + { + InitialWindow *iw = lw->data; + + g_assert_nonnull (iw); + + guint window_id = 0; + + gs_free char *previous_screen_object_path = NULL; + if (iw->implicit_first_window) + previous_screen_object_path = g_strdup (parent_screen_object_path); + + /* Now add the tabs */ + for (GList *lt = iw->tabs; lt != NULL; lt = lt->next) + { + InitialTab *it = lt->data; + g_assert_nonnull (it); + + GVariantBuilder builder; + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + terminal_client_append_create_instance_options (&builder, + options->display_name, + options->startup_id, + iw->geometry, + iw->role, + it->profile ? it->profile : options->default_profile, + encoding, + it->title ? it->title : options->default_title, + it->active, + iw->start_maximized, + iw->start_fullscreen); + + /* This will be used to apply missing defaults */ + if (parent_screen_object_path != NULL) + g_variant_builder_add (&builder, "{sv}", + "parent-screen", g_variant_new_object_path (parent_screen_object_path)); + + /* This will be used to get the parent window */ + if (previous_screen_object_path) + g_variant_builder_add (&builder, "{sv}", + "window-from-screen", g_variant_new_object_path (previous_screen_object_path)); + if (window_id) + g_variant_builder_add (&builder, "{sv}", + "window-id", g_variant_new_uint32 (window_id)); + /* Restored windows shouldn't demand attention; see bug #586308. */ + if (iw->source_tag == SOURCE_SESSION) + g_variant_builder_add (&builder, "{sv}", + "present-window", g_variant_new_boolean (FALSE)); + if (options->zoom_set || it->zoom_set) + g_variant_builder_add (&builder, "{sv}", + "zoom", g_variant_new_double (it->zoom_set ? it->zoom : options->zoom)); + if (iw->force_menubar_state) + g_variant_builder_add (&builder, "{sv}", + "show-menubar", g_variant_new_boolean (iw->menubar_state)); + + gs_free_error GError *err = NULL; + gs_free char *object_path = NULL; + if (!terminal_factory_call_create_instance_sync + (factory, + g_variant_builder_end (&builder), + &object_path, + NULL /* cancellable */, + &err)) { + if (handle_create_instance_error (service_name, err)) + return FALSE; + else + continue; /* Continue processing the remaining options! */ + } + + /* Deprecated and not working on new server anymore */ + char *p = strstr (object_path, "/window/"); + if (p) { + char *end = NULL; + guint64 value; + + errno = 0; + p += strlen ("/window/"); + value = g_ascii_strtoull (p, &end, 10); + if (errno == 0 && end != p && *end == '/') + window_id = (guint) value; + } + + g_free (previous_screen_object_path); + previous_screen_object_path = g_strdup (object_path); + + gs_unref_object TerminalReceiver *receiver = + terminal_receiver_proxy_new_for_bus_sync (G_BUS_TYPE_SESSION, + G_DBUS_PROXY_FLAGS_DO_NOT_LOAD_PROPERTIES | + (it->wait ? 0 : G_DBUS_PROXY_FLAGS_DO_NOT_CONNECT_SIGNALS), + factory_unique_name, + object_path, + NULL /* cancellable */, + &err); + if (receiver == NULL) { + if (handle_create_receiver_proxy_error (service_name, err)) + return FALSE; + else + continue; /* Continue processing the remaining options! */ + } + + g_variant_builder_init (&builder, G_VARIANT_TYPE ("a{sv}")); + + char **argv = it->exec_argv ? it->exec_argv : options->exec_argv; + int argc = argv ? g_strv_length (argv) : 0; + + PassFdElement *fd_array = it->fd_array ? (PassFdElement*)it->fd_array->data : NULL; + gsize fd_array_len = it->fd_array ? it->fd_array->len : 0; + + terminal_client_append_exec_options (&builder, + !options->no_environment, + it->working_dir ? it->working_dir + : options->default_working_dir, + fd_array, fd_array_len, + argc == 0); + + if (!terminal_receiver_call_exec_sync (receiver, + g_variant_builder_end (&builder), + g_variant_new_bytestring_array ((const char * const *) argv, argc), + it->fd_list, NULL /* outfdlist */, + NULL /* cancellable */, + &err)) { + if (handle_exec_error (service_name, err)) + return FALSE; + else + continue; /* Continue processing the remaining options! */ + } + + if (it->wait) + gs_transfer_out_value (wait_for_receiver, &receiver); + + if (options->print_environment) + g_print ("%s=%s\n", TERMINAL_ENV_SCREEN, object_path); + } + } + + return TRUE; +} + +int +main (int argc, char **argv) +{ + int exit_code = EXIT_FAILURE; + + g_log_set_writer_func (terminal_log_writer, NULL, NULL); + + g_set_prgname ("gnome-terminal"); + + setlocale (LC_ALL, ""); + + terminal_i18n_init (TRUE); + + _terminal_debug_init (); + + gs_free_error GError *error = NULL; + gs_free_options TerminalOptions *options = terminal_options_parse (&argc, &argv, &error); + if (options == NULL) { + terminal_printerr (_("Failed to parse arguments: %s\n"), error->message); + return exit_code; + } + + g_set_application_name (_("Terminal")); + + gs_unref_object TerminalFactory *factory = NULL; + gs_free char *service_name = NULL; + gs_free char *parent_screen_object_path = NULL; + if (!factory_proxy_new (options, + &factory, + &service_name, + &parent_screen_object_path, + &error)) + return exit_code; + + if (options->print_environment) { + const char *name_owner = g_dbus_proxy_get_name_owner (G_DBUS_PROXY (factory)); + if (name_owner != NULL) + g_print ("%s=%s\n", TERMINAL_ENV_SERVICE_NAME, name_owner); + else + return exit_code; + } + + TerminalReceiver *receiver = NULL; + if (!handle_options (options, factory, service_name, parent_screen_object_path, &receiver)) + return exit_code; + + if (receiver != NULL) { + exit_code = run_receiver (factory, receiver); + g_object_unref (receiver); + } else + exit_code = EXIT_SUCCESS; + + return exit_code; +} diff --git a/src/terminal.common.css b/src/terminal.common.css new file mode 100644 index 0000000..4c57726 --- /dev/null +++ b/src/terminal.common.css @@ -0,0 +1,22 @@ +/* Generic theme-independent CSS file */ + +terminal-window scrolledwindow undershoot.top, +terminal-window scrolledwindow undershoot.bottom, +terminal-window scrolledwindow overshoot.top, +terminal-window scrolledwindow overshoot.bottom +{ + background: none; +} + +popover button.model +{ + padding-left: 16px; + padding-right: 16px; +} + +.disclosure-button +{ + padding-left: 4px; + padding-right: 4px; + min-width: 0; +} diff --git a/src/terminal.gresource.xml b/src/terminal.gresource.xml new file mode 100644 index 0000000..8fd5040 --- /dev/null +++ b/src/terminal.gresource.xml @@ -0,0 +1,31 @@ + + + + + terminal.common.css + terminal-headerbar.ui + terminal-headermenu.ui + terminal-menubar-with-mnemonics.ui + terminal-menubar-without-mnemonics.ui + terminal-notebook-menu.ui + preferences.ui + search-popover.ui + terminal.about + terminal-window.ui + + -- cgit v1.2.3