summaryrefslogtreecommitdiff
path: root/src
diff options
context:
space:
mode:
Diffstat (limited to 'src')
-rw-r--r--src/Makefile.am205
-rw-r--r--src/Makefile.in1473
-rw-r--r--src/eggdesktopfile.c1510
-rw-r--r--src/eggdesktopfile.h160
-rw-r--r--src/eggshell.c114
-rw-r--r--src/eggshell.h40
-rw-r--r--src/eggsmclient-osx.c235
-rw-r--r--src/eggsmclient-private.h53
-rw-r--r--src/eggsmclient-win32.c353
-rw-r--r--src/eggsmclient-xsmp.c1405
-rw-r--r--src/eggsmclient.c610
-rw-r--r--src/eggsmclient.h123
-rw-r--r--src/encodings-dialog.glade296
-rw-r--r--src/extra-strings.c73
-rw-r--r--src/find-dialog.glade236
-rw-r--r--src/keybinding-editor.glade194
-rw-r--r--src/mate-terminal.schemas.in1302
-rw-r--r--src/profile-editor.c921
-rw-r--r--src/profile-editor.h34
-rw-r--r--src/profile-manager.glade213
-rw-r--r--src/profile-new-dialog.glade261
-rw-r--r--src/profile-preferences.glade2814
-rw-r--r--src/skey-challenge.glade198
-rw-r--r--src/skey-popup.c228
-rw-r--r--src/skey-popup.h35
-rw-r--r--src/skey/Makefile.am60
-rw-r--r--src/skey/Makefile.in777
-rw-r--r--src/skey/btoe.c304
-rw-r--r--src/skey/btoe.h2
-rw-r--r--src/skey/md4.c335
-rw-r--r--src/skey/md4.h19
-rw-r--r--src/skey/md5.c67
-rw-r--r--src/skey/md5.h9
-rw-r--r--src/skey/sha1.c112
-rw-r--r--src/skey/sha1.h9
-rw-r--r--src/skey/skey.c37
-rw-r--r--src/skey/skey.h10
-rw-r--r--src/skey/skeyutil.c24
-rw-r--r--src/skey/skeyutil.h3
-rw-r--r--src/skey/test.c99
-rw-r--r--src/terminal-accels.c1012
-rw-r--r--src/terminal-accels.h35
-rw-r--r--src/terminal-app.c2116
-rw-r--r--src/terminal-app.h159
-rw-r--r--src/terminal-debug.c45
-rw-r--r--src/terminal-debug.h74
-rw-r--r--src/terminal-encoding.c614
-rw-r--r--src/terminal-encoding.h61
-rw-r--r--src/terminal-info-bar.c119
-rw-r--r--src/terminal-info-bar.h62
-rw-r--r--src/terminal-intl.h27
-rw-r--r--src/terminal-marshal.list1
-rw-r--r--src/terminal-options.c1396
-rw-r--r--src/terminal-options.h118
-rw-r--r--src/terminal-profile.c1690
-rw-r--r--src/terminal-profile.h191
-rw-r--r--src/terminal-screen-container.c409
-rw-r--r--src/terminal-screen-container.h69
-rw-r--r--src/terminal-screen.c2343
-rw-r--r--src/terminal-screen.h160
-rw-r--r--src/terminal-search-dialog.c378
-rw-r--r--src/terminal-search-dialog.h49
-rw-r--r--src/terminal-tab-label.c289
-rw-r--r--src/terminal-tab-label.h64
-rw-r--r--src/terminal-tabs-menu.c487
-rw-r--r--src/terminal-tabs-menu.h56
-rw-r--r--src/terminal-type-builtins.c.template45
-rw-r--r--src/terminal-type-builtins.h.template25
-rw-r--r--src/terminal-util.c1213
-rw-r--r--src/terminal-util.h112
-rw-r--r--src/terminal-version.h.in35
-rw-r--r--src/terminal-window.c4026
-rw-r--r--src/terminal-window.h106
-rw-r--r--src/terminal.about5
-rw-r--r--src/terminal.c619
-rw-r--r--src/terminal.xml116
76 files changed, 33279 insertions, 0 deletions
diff --git a/src/Makefile.am b/src/Makefile.am
new file mode 100644
index 0000000..9e34a8b
--- /dev/null
+++ b/src/Makefile.am
@@ -0,0 +1,205 @@
+NULL =
+
+if ENABLE_SKEY
+SUBDIRS = skey
+endif
+
+bin_PROGRAMS = mate-terminal
+
+BUILT_SOURCES = \
+ terminal-marshal.c \
+ terminal-marshal.h \
+ terminal-type-builtins.c \
+ terminal-type-builtins.h \
+ $(NULL)
+
+mate_terminal_SOURCES= \
+ eggshell.c \
+ eggshell.h \
+ profile-editor.c \
+ profile-editor.h \
+ terminal.c \
+ terminal-accels.c \
+ terminal-accels.h \
+ terminal-app.c \
+ terminal-app.h \
+ terminal-debug.c \
+ terminal-debug.h \
+ terminal-encoding.c \
+ terminal-encoding.h \
+ terminal-info-bar.c \
+ terminal-info-bar.h \
+ terminal-intl.h \
+ terminal-options.c \
+ terminal-options.h \
+ terminal-profile.c \
+ terminal-profile.h \
+ terminal-screen.c \
+ terminal-screen.h \
+ terminal-screen-container.c \
+ terminal-screen-container.h \
+ terminal-search-dialog.c \
+ terminal-search-dialog.h \
+ terminal-tab-label.c \
+ terminal-tab-label.h \
+ terminal-tabs-menu.c \
+ terminal-tabs-menu.h \
+ terminal-util.c \
+ terminal-util.h \
+ terminal-version.h \
+ terminal-window.c \
+ terminal-window.h \
+ $(NULL)
+
+if ENABLE_SKEY
+mate_terminal_SOURCES += \
+ skey-popup.c \
+ skey-popup.h \
+ $(NULL)
+endif
+
+nodist_mate_terminal_SOURCES= $(BUILT_SOURCES)
+
+mate_terminal_CPPFLAGS = \
+ -DTERMINAL_COMPILATION \
+ -DEXECUTABLE_NAME=\"mate-terminal\" \
+ -DTERM_DATADIR="\"$(datadir)\"" \
+ -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \
+ -DTERM_PKGDATADIR="\"$(pkgdatadir)\"" \
+ -DTERM_HELPDIR="\"$(HELP_DIR)\"" \
+ -DSN_API_NOT_YET_FROZEN \
+ -DGDK_MULTIHEAD_SAFE \
+ -DG_DISABLE_SINGLE_INCLUDES \
+ -DPANGO_DISABLE_SINGLE_INCLUDES \
+ -DATK_DISABLE_SINGLE_INCLUDES \
+ -DGDK_DISABLE_SINGLE_INCLUDES \
+ -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
+ -DGTK_DISABLE_SINGLE_INCLUDES \
+ $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS)
+
+mate_terminal_CFLAGS = \
+ $(TERM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLAGS)
+
+mate_terminal_LDFLAGS =
+
+mate_terminal_LDADD = \
+ skey/libskey.la \
+ $(TERM_LIBS)
+
+if WITH_SMCLIENT
+mate_terminal_SOURCES += \
+ eggsmclient.c \
+ eggsmclient.h \
+ eggsmclient-private.h \
+ $(NULL)
+mate_terminal_CFLAGS += $(SMCLIENT_CFLAGS)
+mate_terminal_LDADD += $(SMCLIENT_LIBS)
+
+if WITH_SMCLIENT_XSMP
+mate_terminal_SOURCES += \
+ eggdesktopfile.c \
+ eggdesktopfile.h \
+ eggsmclient-xsmp.c \
+ $(NULL)
+mate_terminal_CPPFLAGS += -DEGG_SM_CLIENT_BACKEND_XSMP
+endif
+if WITH_SMCLIENT_WIN32
+mate_terminal_SOURCES += eggsmclient-win32.c
+endif
+if WITH_SMCLIENT_QUARTZ
+mate_terminal_SOURCES += eggsmclient-osx.c
+endif
+endif
+
+TYPES_H_FILES = \
+ terminal-profile.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) ( $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \
+ --header \
+ --body \
+ --internal > terminal-marshal.c.tmp \
+ && mv terminal-marshal.c.tmp terminal-marshal.c ) \
+ || ( rm -f terminal-marshal.c.tmp && exit 1 )
+
+schemadir = $(MATECONF_SCHEMA_FILE_DIR)
+schema_in_files = mate-terminal.schemas.in
+schema_DATA = mate-terminal.schemas
+
+aboutdir = $(pkgdatadir)
+about_DATA = \
+ terminal.about \
+ $(NULL)
+
+uimanagerdir = $(pkgdatadir)
+uimanager_DATA = \
+ terminal.xml \
+ $(NULL)
+
+builder_in_files = \
+ encodings-dialog.glade \
+ find-dialog.glade \
+ keybinding-editor.glade \
+ profile-manager.glade \
+ profile-new-dialog.glade \
+ profile-preferences.glade \
+ skey-challenge.glade \
+ $(NULL)
+
+builderdir = $(pkgdatadir)
+builder_DATA = $(builder_in_files:.glade=.ui)
+
+CLEANFILES = \
+ stamp-terminal-type-builtins.h \
+ mate-terminal.schemas \
+ stamp-terminal-type-builtins.h \
+ $(builder_DATA) \
+ $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ terminal-marshal.list \
+ terminal-type-builtins.c.template \
+ terminal-type-builtins.h.template \
+ extra-strings.c \
+ $(about_DATA) \
+ $(schema_in_files) \
+ $(uimanager_DATA) \
+ $(builder_in_files) \
+ $(NULL)
+
+@INTLTOOL_SCHEMAS_RULE@
+
+if MATECONF_SCHEMAS_INSTALL
+install-data-local:
+ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/src/$(schema_DATA)
+endif
+
+%.ui: %.glade
+ $(AM_V_GEN) $(GTK_BUILDER_CONVERT) $< $@
+
+-include $(top_srcdir)/git.mk
diff --git a/src/Makefile.in b/src/Makefile.in
new file mode 100644
index 0000000..6007afc
--- /dev/null
+++ b/src/Makefile.in
@@ -0,0 +1,1473 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
+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 = mate-terminal$(EXEEXT)
+@ENABLE_SKEY_TRUE@am__append_1 = \
+@ENABLE_SKEY_TRUE@ skey-popup.c \
+@ENABLE_SKEY_TRUE@ skey-popup.h \
+@ENABLE_SKEY_TRUE@ $(NULL)
+
+@WITH_SMCLIENT_TRUE@am__append_2 = \
+@WITH_SMCLIENT_TRUE@ eggsmclient.c \
+@WITH_SMCLIENT_TRUE@ eggsmclient.h \
+@WITH_SMCLIENT_TRUE@ eggsmclient-private.h \
+@WITH_SMCLIENT_TRUE@ $(NULL)
+
+@WITH_SMCLIENT_TRUE@am__append_3 = $(SMCLIENT_CFLAGS)
+@WITH_SMCLIENT_TRUE@am__append_4 = $(SMCLIENT_LIBS)
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@am__append_5 = \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ eggdesktopfile.c \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ eggdesktopfile.h \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ eggsmclient-xsmp.c \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ $(NULL)
+
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@am__append_6 = -DEGG_SM_CLIENT_BACKEND_XSMP
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_WIN32_TRUE@am__append_7 = eggsmclient-win32.c
+@WITH_SMCLIENT_QUARTZ_TRUE@@WITH_SMCLIENT_TRUE@am__append_8 = eggsmclient-osx.c
+subdir = src
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in \
+ $(srcdir)/terminal-version.h.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES = terminal-version.h
+CONFIG_CLEAN_VPATH_FILES =
+am__installdirs = "$(DESTDIR)$(bindir)" "$(DESTDIR)$(aboutdir)" \
+ "$(DESTDIR)$(builderdir)" "$(DESTDIR)$(schemadir)" \
+ "$(DESTDIR)$(uimanagerdir)"
+PROGRAMS = $(bin_PROGRAMS)
+am__mate_terminal_SOURCES_DIST = eggshell.c eggshell.h \
+ profile-editor.c profile-editor.h terminal.c terminal-accels.c \
+ terminal-accels.h terminal-app.c terminal-app.h \
+ terminal-debug.c terminal-debug.h terminal-encoding.c \
+ terminal-encoding.h terminal-info-bar.c terminal-info-bar.h \
+ terminal-intl.h terminal-options.c terminal-options.h \
+ terminal-profile.c terminal-profile.h terminal-screen.c \
+ terminal-screen.h terminal-screen-container.c \
+ terminal-screen-container.h terminal-search-dialog.c \
+ terminal-search-dialog.h terminal-tab-label.c \
+ terminal-tab-label.h terminal-tabs-menu.c terminal-tabs-menu.h \
+ terminal-util.c terminal-util.h terminal-version.h \
+ terminal-window.c terminal-window.h skey-popup.c skey-popup.h \
+ eggsmclient.c eggsmclient.h eggsmclient-private.h \
+ eggdesktopfile.c eggdesktopfile.h eggsmclient-xsmp.c \
+ eggsmclient-win32.c eggsmclient-osx.c
+am__objects_1 =
+@ENABLE_SKEY_TRUE@am__objects_2 = mate_terminal-skey-popup.$(OBJEXT) \
+@ENABLE_SKEY_TRUE@ $(am__objects_1)
+@WITH_SMCLIENT_TRUE@am__objects_3 = \
+@WITH_SMCLIENT_TRUE@ mate_terminal-eggsmclient.$(OBJEXT) \
+@WITH_SMCLIENT_TRUE@ $(am__objects_1)
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@am__objects_4 = mate_terminal-eggdesktopfile.$(OBJEXT) \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ mate_terminal-eggsmclient-xsmp.$(OBJEXT) \
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_XSMP_TRUE@ $(am__objects_1)
+@WITH_SMCLIENT_TRUE@@WITH_SMCLIENT_WIN32_TRUE@am__objects_5 = mate_terminal-eggsmclient-win32.$(OBJEXT)
+@WITH_SMCLIENT_QUARTZ_TRUE@@WITH_SMCLIENT_TRUE@am__objects_6 = mate_terminal-eggsmclient-osx.$(OBJEXT)
+am_mate_terminal_OBJECTS = mate_terminal-eggshell.$(OBJEXT) \
+ mate_terminal-profile-editor.$(OBJEXT) \
+ mate_terminal-terminal.$(OBJEXT) \
+ mate_terminal-terminal-accels.$(OBJEXT) \
+ mate_terminal-terminal-app.$(OBJEXT) \
+ mate_terminal-terminal-debug.$(OBJEXT) \
+ mate_terminal-terminal-encoding.$(OBJEXT) \
+ mate_terminal-terminal-info-bar.$(OBJEXT) \
+ mate_terminal-terminal-options.$(OBJEXT) \
+ mate_terminal-terminal-profile.$(OBJEXT) \
+ mate_terminal-terminal-screen.$(OBJEXT) \
+ mate_terminal-terminal-screen-container.$(OBJEXT) \
+ mate_terminal-terminal-search-dialog.$(OBJEXT) \
+ mate_terminal-terminal-tab-label.$(OBJEXT) \
+ mate_terminal-terminal-tabs-menu.$(OBJEXT) \
+ mate_terminal-terminal-util.$(OBJEXT) \
+ mate_terminal-terminal-window.$(OBJEXT) $(am__objects_1) \
+ $(am__objects_2) $(am__objects_3) $(am__objects_4) \
+ $(am__objects_5) $(am__objects_6)
+am__objects_7 = mate_terminal-terminal-marshal.$(OBJEXT) \
+ mate_terminal-terminal-type-builtins.$(OBJEXT) \
+ $(am__objects_1)
+nodist_mate_terminal_OBJECTS = $(am__objects_7)
+mate_terminal_OBJECTS = $(am_mate_terminal_OBJECTS) \
+ $(nodist_mate_terminal_OBJECTS)
+am__DEPENDENCIES_1 =
+@WITH_SMCLIENT_TRUE@am__DEPENDENCIES_2 = $(am__DEPENDENCIES_1)
+mate_terminal_DEPENDENCIES = skey/libskey.la $(am__DEPENDENCIES_1) \
+ $(am__DEPENDENCIES_2)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+mate_terminal_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(mate_terminal_CFLAGS) \
+ $(CFLAGS) $(mate_terminal_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+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_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+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_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(mate_terminal_SOURCES) $(nodist_mate_terminal_SOURCES)
+DIST_SOURCES = $(am__mate_terminal_SOURCES_DIST)
+RECURSIVE_TARGETS = all-recursive check-recursive dvi-recursive \
+ html-recursive info-recursive install-data-recursive \
+ install-dvi-recursive install-exec-recursive \
+ install-html-recursive install-info-recursive \
+ install-pdf-recursive install-ps-recursive install-recursive \
+ installcheck-recursive installdirs-recursive pdf-recursive \
+ ps-recursive uninstall-recursive
+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'
+DATA = $(about_DATA) $(builder_DATA) $(schema_DATA) $(uimanager_DATA)
+RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive \
+ distclean-recursive maintainer-clean-recursive
+AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
+ $(RECURSIVE_CLEAN_TARGETS:-recursive=) tags TAGS ctags CTAGS \
+ distdir
+ETAGS = etags
+CTAGS = ctags
+DIST_SUBDIRS = skey
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+am__relativize = \
+ dir0=`pwd`; \
+ sed_first='s,^\([^/]*\)/.*$$,\1,'; \
+ sed_rest='s,^[^/]*/*,,'; \
+ sed_last='s,^.*/\([^/]*\)$$,\1,'; \
+ sed_butlast='s,/*[^/]*$$,,'; \
+ while test -n "$$dir1"; do \
+ first=`echo "$$dir1" | sed -e "$$sed_first"`; \
+ if test "$$first" != "."; then \
+ if test "$$first" = ".."; then \
+ dir2=`echo "$$dir0" | sed -e "$$sed_last"`/"$$dir2"; \
+ dir0=`echo "$$dir0" | sed -e "$$sed_butlast"`; \
+ else \
+ first2=`echo "$$dir2" | sed -e "$$sed_first"`; \
+ if test "$$first2" = "$$first"; then \
+ dir2=`echo "$$dir2" | sed -e "$$sed_rest"`; \
+ else \
+ dir2="../$$dir2"; \
+ fi; \
+ dir0="$$dir0"/"$$first"; \
+ fi; \
+ fi; \
+ dir1=`echo "$$dir1" | sed -e "$$sed_rest"`; \
+ done; \
+ reldir="$$dir2"
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOC_USER_FORMATS = @DOC_USER_FORMATS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GTK_BUILDER_CONVERT = @GTK_BUILDER_CONVERT@
+HELP_DIR = @HELP_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OMF_DIR = @OMF_DIR@
+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@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SMCLIENT_CFLAGS = @SMCLIENT_CFLAGS@
+SMCLIENT_LIBS = @SMCLIENT_LIBS@
+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@
+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@
+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@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+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@
+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 =
+@ENABLE_SKEY_TRUE@SUBDIRS = skey
+BUILT_SOURCES = \
+ terminal-marshal.c \
+ terminal-marshal.h \
+ terminal-type-builtins.c \
+ terminal-type-builtins.h \
+ $(NULL)
+
+mate_terminal_SOURCES = eggshell.c eggshell.h profile-editor.c \
+ profile-editor.h terminal.c terminal-accels.c \
+ terminal-accels.h terminal-app.c terminal-app.h \
+ terminal-debug.c terminal-debug.h terminal-encoding.c \
+ terminal-encoding.h terminal-info-bar.c terminal-info-bar.h \
+ terminal-intl.h terminal-options.c terminal-options.h \
+ terminal-profile.c terminal-profile.h terminal-screen.c \
+ terminal-screen.h terminal-screen-container.c \
+ terminal-screen-container.h terminal-search-dialog.c \
+ terminal-search-dialog.h terminal-tab-label.c \
+ terminal-tab-label.h terminal-tabs-menu.c terminal-tabs-menu.h \
+ terminal-util.c terminal-util.h terminal-version.h \
+ terminal-window.c terminal-window.h $(NULL) $(am__append_1) \
+ $(am__append_2) $(am__append_5) $(am__append_7) \
+ $(am__append_8)
+nodist_mate_terminal_SOURCES = $(BUILT_SOURCES)
+mate_terminal_CPPFLAGS = -DTERMINAL_COMPILATION \
+ -DEXECUTABLE_NAME=\"mate-terminal\" \
+ -DTERM_DATADIR="\"$(datadir)\"" \
+ -DTERM_LOCALEDIR="\"$(datadir)/locale\"" \
+ -DTERM_PKGDATADIR="\"$(pkgdatadir)\"" \
+ -DTERM_HELPDIR="\"$(HELP_DIR)\"" -DSN_API_NOT_YET_FROZEN \
+ -DGDK_MULTIHEAD_SAFE -DG_DISABLE_SINGLE_INCLUDES \
+ -DPANGO_DISABLE_SINGLE_INCLUDES -DATK_DISABLE_SINGLE_INCLUDES \
+ -DGDK_DISABLE_SINGLE_INCLUDES \
+ -DGDK_PIXBUF_DISABLE_SINGLE_INCLUDES \
+ -DGTK_DISABLE_SINGLE_INCLUDES $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS) $(am__append_6)
+mate_terminal_CFLAGS = $(TERM_CFLAGS) $(WARN_CFLAGS) $(AM_CFLAGS) \
+ $(am__append_3)
+mate_terminal_LDFLAGS =
+mate_terminal_LDADD = skey/libskey.la $(TERM_LIBS) $(am__append_4)
+TYPES_H_FILES = \
+ terminal-profile.h \
+ $(NULL)
+
+schemadir = $(MATECONF_SCHEMA_FILE_DIR)
+schema_in_files = mate-terminal.schemas.in
+schema_DATA = mate-terminal.schemas
+aboutdir = $(pkgdatadir)
+about_DATA = \
+ terminal.about \
+ $(NULL)
+
+uimanagerdir = $(pkgdatadir)
+uimanager_DATA = \
+ terminal.xml \
+ $(NULL)
+
+builder_in_files = \
+ encodings-dialog.glade \
+ find-dialog.glade \
+ keybinding-editor.glade \
+ profile-manager.glade \
+ profile-new-dialog.glade \
+ profile-preferences.glade \
+ skey-challenge.glade \
+ $(NULL)
+
+builderdir = $(pkgdatadir)
+builder_DATA = $(builder_in_files:.glade=.ui)
+CLEANFILES = \
+ stamp-terminal-type-builtins.h \
+ mate-terminal.schemas \
+ stamp-terminal-type-builtins.h \
+ $(builder_DATA) \
+ $(BUILT_SOURCES)
+
+EXTRA_DIST = \
+ terminal-marshal.list \
+ terminal-type-builtins.c.template \
+ terminal-type-builtins.h.template \
+ extra-strings.c \
+ $(about_DATA) \
+ $(schema_in_files) \
+ $(uimanager_DATA) \
+ $(builder_in_files) \
+ $(NULL)
+
+all: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) all-recursive
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(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
+.PRECIOUS: 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__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ 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)
+ test -z "$(bindir)" || $(MKDIR_P) "$(DESTDIR)$(bindir)"
+ @list='$(bin_PROGRAMS)'; test -n "$(bindir)" || list=; \
+ 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
+mate-terminal$(EXEEXT): $(mate_terminal_OBJECTS) $(mate_terminal_DEPENDENCIES)
+ @rm -f mate-terminal$(EXEEXT)
+ $(AM_V_CCLD)$(mate_terminal_LINK) $(mate_terminal_OBJECTS) $(mate_terminal_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggdesktopfile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggshell.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggsmclient-osx.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggsmclient-win32.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggsmclient-xsmp.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-eggsmclient.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-profile-editor.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-skey-popup.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-accels.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-app.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-debug.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-encoding.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-info-bar.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-marshal.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-options.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-profile.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-screen-container.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-screen.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-search-dialog.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-tab-label.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-tabs-menu.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-type-builtins.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-util.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal-window.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mate_terminal-terminal.Po@am__quote@
+
+.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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+mate_terminal-eggshell.o: eggshell.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggshell.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggshell.Tpo -c -o mate_terminal-eggshell.o `test -f 'eggshell.c' || echo '$(srcdir)/'`eggshell.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggshell.Tpo $(DEPDIR)/mate_terminal-eggshell.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggshell.c' object='mate_terminal-eggshell.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggshell.o `test -f 'eggshell.c' || echo '$(srcdir)/'`eggshell.c
+
+mate_terminal-eggshell.obj: eggshell.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggshell.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggshell.Tpo -c -o mate_terminal-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)/mate_terminal-eggshell.Tpo $(DEPDIR)/mate_terminal-eggshell.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggshell.c' object='mate_terminal-eggshell.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggshell.obj `if test -f 'eggshell.c'; then $(CYGPATH_W) 'eggshell.c'; else $(CYGPATH_W) '$(srcdir)/eggshell.c'; fi`
+
+mate_terminal-profile-editor.o: profile-editor.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-profile-editor.o -MD -MP -MF $(DEPDIR)/mate_terminal-profile-editor.Tpo -c -o mate_terminal-profile-editor.o `test -f 'profile-editor.c' || echo '$(srcdir)/'`profile-editor.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-profile-editor.Tpo $(DEPDIR)/mate_terminal-profile-editor.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='profile-editor.c' object='mate_terminal-profile-editor.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-profile-editor.o `test -f 'profile-editor.c' || echo '$(srcdir)/'`profile-editor.c
+
+mate_terminal-profile-editor.obj: profile-editor.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-profile-editor.obj -MD -MP -MF $(DEPDIR)/mate_terminal-profile-editor.Tpo -c -o mate_terminal-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)/mate_terminal-profile-editor.Tpo $(DEPDIR)/mate_terminal-profile-editor.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='profile-editor.c' object='mate_terminal-profile-editor.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-profile-editor.obj `if test -f 'profile-editor.c'; then $(CYGPATH_W) 'profile-editor.c'; else $(CYGPATH_W) '$(srcdir)/profile-editor.c'; fi`
+
+mate_terminal-terminal.o: terminal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal.Tpo -c -o mate_terminal-terminal.o `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal.Tpo $(DEPDIR)/mate_terminal-terminal.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal.c' object='mate_terminal-terminal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal.o `test -f 'terminal.c' || echo '$(srcdir)/'`terminal.c
+
+mate_terminal-terminal.obj: terminal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal.Tpo -c -o mate_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)/mate_terminal-terminal.Tpo $(DEPDIR)/mate_terminal-terminal.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal.c' object='mate_terminal-terminal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal.obj `if test -f 'terminal.c'; then $(CYGPATH_W) 'terminal.c'; else $(CYGPATH_W) '$(srcdir)/terminal.c'; fi`
+
+mate_terminal-terminal-accels.o: terminal-accels.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-accels.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-accels.Tpo -c -o mate_terminal-terminal-accels.o `test -f 'terminal-accels.c' || echo '$(srcdir)/'`terminal-accels.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-accels.Tpo $(DEPDIR)/mate_terminal-terminal-accels.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-accels.c' object='mate_terminal-terminal-accels.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-accels.o `test -f 'terminal-accels.c' || echo '$(srcdir)/'`terminal-accels.c
+
+mate_terminal-terminal-accels.obj: terminal-accels.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-accels.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-accels.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-accels.Tpo $(DEPDIR)/mate_terminal-terminal-accels.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-accels.c' object='mate_terminal-terminal-accels.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-accels.obj `if test -f 'terminal-accels.c'; then $(CYGPATH_W) 'terminal-accels.c'; else $(CYGPATH_W) '$(srcdir)/terminal-accels.c'; fi`
+
+mate_terminal-terminal-app.o: terminal-app.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-app.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-app.Tpo -c -o mate_terminal-terminal-app.o `test -f 'terminal-app.c' || echo '$(srcdir)/'`terminal-app.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-app.Tpo $(DEPDIR)/mate_terminal-terminal-app.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-app.c' object='mate_terminal-terminal-app.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-app.o `test -f 'terminal-app.c' || echo '$(srcdir)/'`terminal-app.c
+
+mate_terminal-terminal-app.obj: terminal-app.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-app.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-app.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-app.Tpo $(DEPDIR)/mate_terminal-terminal-app.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-app.c' object='mate_terminal-terminal-app.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-app.obj `if test -f 'terminal-app.c'; then $(CYGPATH_W) 'terminal-app.c'; else $(CYGPATH_W) '$(srcdir)/terminal-app.c'; fi`
+
+mate_terminal-terminal-debug.o: terminal-debug.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-debug.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-debug.Tpo -c -o mate_terminal-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-debug.Tpo $(DEPDIR)/mate_terminal-terminal-debug.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-debug.c' object='mate_terminal-terminal-debug.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-debug.o `test -f 'terminal-debug.c' || echo '$(srcdir)/'`terminal-debug.c
+
+mate_terminal-terminal-debug.obj: terminal-debug.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-debug.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-debug.Tpo -c -o mate_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)/mate_terminal-terminal-debug.Tpo $(DEPDIR)/mate_terminal-terminal-debug.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-debug.c' object='mate_terminal-terminal-debug.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-debug.obj `if test -f 'terminal-debug.c'; then $(CYGPATH_W) 'terminal-debug.c'; else $(CYGPATH_W) '$(srcdir)/terminal-debug.c'; fi`
+
+mate_terminal-terminal-encoding.o: terminal-encoding.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-encoding.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-encoding.Tpo -c -o mate_terminal-terminal-encoding.o `test -f 'terminal-encoding.c' || echo '$(srcdir)/'`terminal-encoding.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-encoding.Tpo $(DEPDIR)/mate_terminal-terminal-encoding.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-encoding.c' object='mate_terminal-terminal-encoding.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-encoding.o `test -f 'terminal-encoding.c' || echo '$(srcdir)/'`terminal-encoding.c
+
+mate_terminal-terminal-encoding.obj: terminal-encoding.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-encoding.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-encoding.Tpo -c -o mate_terminal-terminal-encoding.obj `if test -f 'terminal-encoding.c'; then $(CYGPATH_W) 'terminal-encoding.c'; else $(CYGPATH_W) '$(srcdir)/terminal-encoding.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-encoding.Tpo $(DEPDIR)/mate_terminal-terminal-encoding.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-encoding.c' object='mate_terminal-terminal-encoding.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-encoding.obj `if test -f 'terminal-encoding.c'; then $(CYGPATH_W) 'terminal-encoding.c'; else $(CYGPATH_W) '$(srcdir)/terminal-encoding.c'; fi`
+
+mate_terminal-terminal-info-bar.o: terminal-info-bar.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-info-bar.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-info-bar.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-info-bar.Tpo $(DEPDIR)/mate_terminal-terminal-info-bar.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-info-bar.c' object='mate_terminal-terminal-info-bar.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-info-bar.o `test -f 'terminal-info-bar.c' || echo '$(srcdir)/'`terminal-info-bar.c
+
+mate_terminal-terminal-info-bar.obj: terminal-info-bar.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-info-bar.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-info-bar.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-info-bar.Tpo $(DEPDIR)/mate_terminal-terminal-info-bar.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-info-bar.c' object='mate_terminal-terminal-info-bar.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-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`
+
+mate_terminal-terminal-options.o: terminal-options.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-options.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-options.Tpo -c -o mate_terminal-terminal-options.o `test -f 'terminal-options.c' || echo '$(srcdir)/'`terminal-options.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-options.Tpo $(DEPDIR)/mate_terminal-terminal-options.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-options.c' object='mate_terminal-terminal-options.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-options.o `test -f 'terminal-options.c' || echo '$(srcdir)/'`terminal-options.c
+
+mate_terminal-terminal-options.obj: terminal-options.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-options.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-options.Tpo -c -o mate_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)/mate_terminal-terminal-options.Tpo $(DEPDIR)/mate_terminal-terminal-options.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-options.c' object='mate_terminal-terminal-options.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-options.obj `if test -f 'terminal-options.c'; then $(CYGPATH_W) 'terminal-options.c'; else $(CYGPATH_W) '$(srcdir)/terminal-options.c'; fi`
+
+mate_terminal-terminal-profile.o: terminal-profile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-profile.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-profile.Tpo -c -o mate_terminal-terminal-profile.o `test -f 'terminal-profile.c' || echo '$(srcdir)/'`terminal-profile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-profile.Tpo $(DEPDIR)/mate_terminal-terminal-profile.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-profile.c' object='mate_terminal-terminal-profile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-profile.o `test -f 'terminal-profile.c' || echo '$(srcdir)/'`terminal-profile.c
+
+mate_terminal-terminal-profile.obj: terminal-profile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-profile.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-profile.Tpo -c -o mate_terminal-terminal-profile.obj `if test -f 'terminal-profile.c'; then $(CYGPATH_W) 'terminal-profile.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-profile.Tpo $(DEPDIR)/mate_terminal-terminal-profile.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-profile.c' object='mate_terminal-terminal-profile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-profile.obj `if test -f 'terminal-profile.c'; then $(CYGPATH_W) 'terminal-profile.c'; else $(CYGPATH_W) '$(srcdir)/terminal-profile.c'; fi`
+
+mate_terminal-terminal-screen.o: terminal-screen.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-screen.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-screen.Tpo -c -o mate_terminal-terminal-screen.o `test -f 'terminal-screen.c' || echo '$(srcdir)/'`terminal-screen.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-screen.Tpo $(DEPDIR)/mate_terminal-terminal-screen.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-screen.c' object='mate_terminal-terminal-screen.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-screen.o `test -f 'terminal-screen.c' || echo '$(srcdir)/'`terminal-screen.c
+
+mate_terminal-terminal-screen.obj: terminal-screen.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-screen.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-screen.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-screen.Tpo $(DEPDIR)/mate_terminal-terminal-screen.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-screen.c' object='mate_terminal-terminal-screen.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-screen.obj `if test -f 'terminal-screen.c'; then $(CYGPATH_W) 'terminal-screen.c'; else $(CYGPATH_W) '$(srcdir)/terminal-screen.c'; fi`
+
+mate_terminal-terminal-screen-container.o: terminal-screen-container.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-screen-container.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-screen-container.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-screen-container.Tpo $(DEPDIR)/mate_terminal-terminal-screen-container.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-screen-container.c' object='mate_terminal-terminal-screen-container.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-screen-container.o `test -f 'terminal-screen-container.c' || echo '$(srcdir)/'`terminal-screen-container.c
+
+mate_terminal-terminal-screen-container.obj: terminal-screen-container.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-screen-container.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-screen-container.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-screen-container.Tpo $(DEPDIR)/mate_terminal-terminal-screen-container.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-screen-container.c' object='mate_terminal-terminal-screen-container.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-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`
+
+mate_terminal-terminal-search-dialog.o: terminal-search-dialog.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-search-dialog.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-search-dialog.Tpo -c -o mate_terminal-terminal-search-dialog.o `test -f 'terminal-search-dialog.c' || echo '$(srcdir)/'`terminal-search-dialog.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-search-dialog.Tpo $(DEPDIR)/mate_terminal-terminal-search-dialog.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-search-dialog.c' object='mate_terminal-terminal-search-dialog.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-search-dialog.o `test -f 'terminal-search-dialog.c' || echo '$(srcdir)/'`terminal-search-dialog.c
+
+mate_terminal-terminal-search-dialog.obj: terminal-search-dialog.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-search-dialog.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-search-dialog.Tpo -c -o mate_terminal-terminal-search-dialog.obj `if test -f 'terminal-search-dialog.c'; then $(CYGPATH_W) 'terminal-search-dialog.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-dialog.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-search-dialog.Tpo $(DEPDIR)/mate_terminal-terminal-search-dialog.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-search-dialog.c' object='mate_terminal-terminal-search-dialog.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-search-dialog.obj `if test -f 'terminal-search-dialog.c'; then $(CYGPATH_W) 'terminal-search-dialog.c'; else $(CYGPATH_W) '$(srcdir)/terminal-search-dialog.c'; fi`
+
+mate_terminal-terminal-tab-label.o: terminal-tab-label.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-tab-label.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-tab-label.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-tab-label.Tpo $(DEPDIR)/mate_terminal-terminal-tab-label.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-tab-label.c' object='mate_terminal-terminal-tab-label.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-tab-label.o `test -f 'terminal-tab-label.c' || echo '$(srcdir)/'`terminal-tab-label.c
+
+mate_terminal-terminal-tab-label.obj: terminal-tab-label.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-tab-label.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-tab-label.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-tab-label.Tpo $(DEPDIR)/mate_terminal-terminal-tab-label.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-tab-label.c' object='mate_terminal-terminal-tab-label.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-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`
+
+mate_terminal-terminal-tabs-menu.o: terminal-tabs-menu.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-tabs-menu.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-tabs-menu.Tpo -c -o mate_terminal-terminal-tabs-menu.o `test -f 'terminal-tabs-menu.c' || echo '$(srcdir)/'`terminal-tabs-menu.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-tabs-menu.Tpo $(DEPDIR)/mate_terminal-terminal-tabs-menu.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-tabs-menu.c' object='mate_terminal-terminal-tabs-menu.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-tabs-menu.o `test -f 'terminal-tabs-menu.c' || echo '$(srcdir)/'`terminal-tabs-menu.c
+
+mate_terminal-terminal-tabs-menu.obj: terminal-tabs-menu.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-tabs-menu.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-tabs-menu.Tpo -c -o mate_terminal-terminal-tabs-menu.obj `if test -f 'terminal-tabs-menu.c'; then $(CYGPATH_W) 'terminal-tabs-menu.c'; else $(CYGPATH_W) '$(srcdir)/terminal-tabs-menu.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-tabs-menu.Tpo $(DEPDIR)/mate_terminal-terminal-tabs-menu.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-tabs-menu.c' object='mate_terminal-terminal-tabs-menu.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-tabs-menu.obj `if test -f 'terminal-tabs-menu.c'; then $(CYGPATH_W) 'terminal-tabs-menu.c'; else $(CYGPATH_W) '$(srcdir)/terminal-tabs-menu.c'; fi`
+
+mate_terminal-terminal-util.o: terminal-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-util.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-util.Tpo -c -o mate_terminal-terminal-util.o `test -f 'terminal-util.c' || echo '$(srcdir)/'`terminal-util.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-util.Tpo $(DEPDIR)/mate_terminal-terminal-util.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-util.c' object='mate_terminal-terminal-util.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-util.o `test -f 'terminal-util.c' || echo '$(srcdir)/'`terminal-util.c
+
+mate_terminal-terminal-util.obj: terminal-util.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-util.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-util.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-util.Tpo $(DEPDIR)/mate_terminal-terminal-util.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-util.c' object='mate_terminal-terminal-util.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-util.obj `if test -f 'terminal-util.c'; then $(CYGPATH_W) 'terminal-util.c'; else $(CYGPATH_W) '$(srcdir)/terminal-util.c'; fi`
+
+mate_terminal-terminal-window.o: terminal-window.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-window.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-window.Tpo -c -o mate_terminal-terminal-window.o `test -f 'terminal-window.c' || echo '$(srcdir)/'`terminal-window.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-window.Tpo $(DEPDIR)/mate_terminal-terminal-window.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-window.c' object='mate_terminal-terminal-window.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-window.o `test -f 'terminal-window.c' || echo '$(srcdir)/'`terminal-window.c
+
+mate_terminal-terminal-window.obj: terminal-window.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-window.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-window.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-window.Tpo $(DEPDIR)/mate_terminal-terminal-window.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-window.c' object='mate_terminal-terminal-window.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-window.obj `if test -f 'terminal-window.c'; then $(CYGPATH_W) 'terminal-window.c'; else $(CYGPATH_W) '$(srcdir)/terminal-window.c'; fi`
+
+mate_terminal-skey-popup.o: skey-popup.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-skey-popup.o -MD -MP -MF $(DEPDIR)/mate_terminal-skey-popup.Tpo -c -o mate_terminal-skey-popup.o `test -f 'skey-popup.c' || echo '$(srcdir)/'`skey-popup.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-skey-popup.Tpo $(DEPDIR)/mate_terminal-skey-popup.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='skey-popup.c' object='mate_terminal-skey-popup.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-skey-popup.o `test -f 'skey-popup.c' || echo '$(srcdir)/'`skey-popup.c
+
+mate_terminal-skey-popup.obj: skey-popup.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-skey-popup.obj -MD -MP -MF $(DEPDIR)/mate_terminal-skey-popup.Tpo -c -o mate_terminal-skey-popup.obj `if test -f 'skey-popup.c'; then $(CYGPATH_W) 'skey-popup.c'; else $(CYGPATH_W) '$(srcdir)/skey-popup.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-skey-popup.Tpo $(DEPDIR)/mate_terminal-skey-popup.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='skey-popup.c' object='mate_terminal-skey-popup.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-skey-popup.obj `if test -f 'skey-popup.c'; then $(CYGPATH_W) 'skey-popup.c'; else $(CYGPATH_W) '$(srcdir)/skey-popup.c'; fi`
+
+mate_terminal-eggsmclient.o: eggsmclient.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient.Tpo -c -o mate_terminal-eggsmclient.o `test -f 'eggsmclient.c' || echo '$(srcdir)/'`eggsmclient.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient.Tpo $(DEPDIR)/mate_terminal-eggsmclient.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient.c' object='mate_terminal-eggsmclient.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient.o `test -f 'eggsmclient.c' || echo '$(srcdir)/'`eggsmclient.c
+
+mate_terminal-eggsmclient.obj: eggsmclient.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient.Tpo -c -o mate_terminal-eggsmclient.obj `if test -f 'eggsmclient.c'; then $(CYGPATH_W) 'eggsmclient.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient.Tpo $(DEPDIR)/mate_terminal-eggsmclient.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient.c' object='mate_terminal-eggsmclient.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient.obj `if test -f 'eggsmclient.c'; then $(CYGPATH_W) 'eggsmclient.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient.c'; fi`
+
+mate_terminal-eggdesktopfile.o: eggdesktopfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggdesktopfile.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggdesktopfile.Tpo -c -o mate_terminal-eggdesktopfile.o `test -f 'eggdesktopfile.c' || echo '$(srcdir)/'`eggdesktopfile.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggdesktopfile.Tpo $(DEPDIR)/mate_terminal-eggdesktopfile.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggdesktopfile.c' object='mate_terminal-eggdesktopfile.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggdesktopfile.o `test -f 'eggdesktopfile.c' || echo '$(srcdir)/'`eggdesktopfile.c
+
+mate_terminal-eggdesktopfile.obj: eggdesktopfile.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggdesktopfile.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggdesktopfile.Tpo -c -o mate_terminal-eggdesktopfile.obj `if test -f 'eggdesktopfile.c'; then $(CYGPATH_W) 'eggdesktopfile.c'; else $(CYGPATH_W) '$(srcdir)/eggdesktopfile.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggdesktopfile.Tpo $(DEPDIR)/mate_terminal-eggdesktopfile.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggdesktopfile.c' object='mate_terminal-eggdesktopfile.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggdesktopfile.obj `if test -f 'eggdesktopfile.c'; then $(CYGPATH_W) 'eggdesktopfile.c'; else $(CYGPATH_W) '$(srcdir)/eggdesktopfile.c'; fi`
+
+mate_terminal-eggsmclient-xsmp.o: eggsmclient-xsmp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-xsmp.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Tpo -c -o mate_terminal-eggsmclient-xsmp.o `test -f 'eggsmclient-xsmp.c' || echo '$(srcdir)/'`eggsmclient-xsmp.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Tpo $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-xsmp.c' object='mate_terminal-eggsmclient-xsmp.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-xsmp.o `test -f 'eggsmclient-xsmp.c' || echo '$(srcdir)/'`eggsmclient-xsmp.c
+
+mate_terminal-eggsmclient-xsmp.obj: eggsmclient-xsmp.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-xsmp.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Tpo -c -o mate_terminal-eggsmclient-xsmp.obj `if test -f 'eggsmclient-xsmp.c'; then $(CYGPATH_W) 'eggsmclient-xsmp.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-xsmp.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Tpo $(DEPDIR)/mate_terminal-eggsmclient-xsmp.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-xsmp.c' object='mate_terminal-eggsmclient-xsmp.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-xsmp.obj `if test -f 'eggsmclient-xsmp.c'; then $(CYGPATH_W) 'eggsmclient-xsmp.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-xsmp.c'; fi`
+
+mate_terminal-eggsmclient-win32.o: eggsmclient-win32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-win32.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-win32.Tpo -c -o mate_terminal-eggsmclient-win32.o `test -f 'eggsmclient-win32.c' || echo '$(srcdir)/'`eggsmclient-win32.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-win32.Tpo $(DEPDIR)/mate_terminal-eggsmclient-win32.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-win32.c' object='mate_terminal-eggsmclient-win32.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-win32.o `test -f 'eggsmclient-win32.c' || echo '$(srcdir)/'`eggsmclient-win32.c
+
+mate_terminal-eggsmclient-win32.obj: eggsmclient-win32.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-win32.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-win32.Tpo -c -o mate_terminal-eggsmclient-win32.obj `if test -f 'eggsmclient-win32.c'; then $(CYGPATH_W) 'eggsmclient-win32.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-win32.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-win32.Tpo $(DEPDIR)/mate_terminal-eggsmclient-win32.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-win32.c' object='mate_terminal-eggsmclient-win32.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-win32.obj `if test -f 'eggsmclient-win32.c'; then $(CYGPATH_W) 'eggsmclient-win32.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-win32.c'; fi`
+
+mate_terminal-eggsmclient-osx.o: eggsmclient-osx.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-osx.o -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-osx.Tpo -c -o mate_terminal-eggsmclient-osx.o `test -f 'eggsmclient-osx.c' || echo '$(srcdir)/'`eggsmclient-osx.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-osx.Tpo $(DEPDIR)/mate_terminal-eggsmclient-osx.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-osx.c' object='mate_terminal-eggsmclient-osx.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-osx.o `test -f 'eggsmclient-osx.c' || echo '$(srcdir)/'`eggsmclient-osx.c
+
+mate_terminal-eggsmclient-osx.obj: eggsmclient-osx.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-eggsmclient-osx.obj -MD -MP -MF $(DEPDIR)/mate_terminal-eggsmclient-osx.Tpo -c -o mate_terminal-eggsmclient-osx.obj `if test -f 'eggsmclient-osx.c'; then $(CYGPATH_W) 'eggsmclient-osx.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-osx.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-eggsmclient-osx.Tpo $(DEPDIR)/mate_terminal-eggsmclient-osx.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='eggsmclient-osx.c' object='mate_terminal-eggsmclient-osx.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-eggsmclient-osx.obj `if test -f 'eggsmclient-osx.c'; then $(CYGPATH_W) 'eggsmclient-osx.c'; else $(CYGPATH_W) '$(srcdir)/eggsmclient-osx.c'; fi`
+
+mate_terminal-terminal-marshal.o: terminal-marshal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-marshal.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-marshal.Tpo -c -o mate_terminal-terminal-marshal.o `test -f 'terminal-marshal.c' || echo '$(srcdir)/'`terminal-marshal.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/mate_terminal-terminal-marshal.Tpo $(DEPDIR)/mate_terminal-terminal-marshal.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-marshal.c' object='mate_terminal-terminal-marshal.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-marshal.o `test -f 'terminal-marshal.c' || echo '$(srcdir)/'`terminal-marshal.c
+
+mate_terminal-terminal-marshal.obj: terminal-marshal.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-marshal.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-marshal.Tpo -c -o mate_terminal-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)/mate_terminal-terminal-marshal.Tpo $(DEPDIR)/mate_terminal-terminal-marshal.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-marshal.c' object='mate_terminal-terminal-marshal.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-marshal.obj `if test -f 'terminal-marshal.c'; then $(CYGPATH_W) 'terminal-marshal.c'; else $(CYGPATH_W) '$(srcdir)/terminal-marshal.c'; fi`
+
+mate_terminal-terminal-type-builtins.o: terminal-type-builtins.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-type-builtins.o -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-type-builtins.Tpo -c -o mate_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)/mate_terminal-terminal-type-builtins.Tpo $(DEPDIR)/mate_terminal-terminal-type-builtins.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-type-builtins.c' object='mate_terminal-terminal-type-builtins.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_terminal-terminal-type-builtins.o `test -f 'terminal-type-builtins.c' || echo '$(srcdir)/'`terminal-type-builtins.c
+
+mate_terminal-terminal-type-builtins.obj: terminal-type-builtins.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -MT mate_terminal-terminal-type-builtins.obj -MD -MP -MF $(DEPDIR)/mate_terminal-terminal-type-builtins.Tpo -c -o mate_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)/mate_terminal-terminal-type-builtins.Tpo $(DEPDIR)/mate_terminal-terminal-type-builtins.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='terminal-type-builtins.c' object='mate_terminal-terminal-type-builtins.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(mate_terminal_CPPFLAGS) $(CPPFLAGS) $(mate_terminal_CFLAGS) $(CFLAGS) -c -o mate_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`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+install-aboutDATA: $(about_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(aboutdir)" || $(MKDIR_P) "$(DESTDIR)$(aboutdir)"
+ @list='$(about_DATA)'; test -n "$(aboutdir)" || list=; \
+ 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)$(aboutdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(aboutdir)" || exit $$?; \
+ done
+
+uninstall-aboutDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(about_DATA)'; test -n "$(aboutdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(aboutdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(aboutdir)" && rm -f $$files
+install-builderDATA: $(builder_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(builderdir)" || $(MKDIR_P) "$(DESTDIR)$(builderdir)"
+ @list='$(builder_DATA)'; test -n "$(builderdir)" || list=; \
+ 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)$(builderdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(builderdir)" || exit $$?; \
+ done
+
+uninstall-builderDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(builder_DATA)'; test -n "$(builderdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(builderdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(builderdir)" && rm -f $$files
+install-schemaDATA: $(schema_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(schemadir)" || $(MKDIR_P) "$(DESTDIR)$(schemadir)"
+ @list='$(schema_DATA)'; test -n "$(schemadir)" || list=; \
+ 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)$(schemadir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(schemadir)" || exit $$?; \
+ done
+
+uninstall-schemaDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(schema_DATA)'; test -n "$(schemadir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(schemadir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(schemadir)" && rm -f $$files
+install-uimanagerDATA: $(uimanager_DATA)
+ @$(NORMAL_INSTALL)
+ test -z "$(uimanagerdir)" || $(MKDIR_P) "$(DESTDIR)$(uimanagerdir)"
+ @list='$(uimanager_DATA)'; test -n "$(uimanagerdir)" || list=; \
+ 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)$(uimanagerdir)'"; \
+ $(INSTALL_DATA) $$files "$(DESTDIR)$(uimanagerdir)" || exit $$?; \
+ done
+
+uninstall-uimanagerDATA:
+ @$(NORMAL_UNINSTALL)
+ @list='$(uimanager_DATA)'; test -n "$(uimanagerdir)" || list=; \
+ files=`for p in $$list; do echo $$p; done | sed -e 's|^.*/||'`; \
+ test -n "$$files" || exit 0; \
+ echo " ( cd '$(DESTDIR)$(uimanagerdir)' && rm -f" $$files ")"; \
+ cd "$(DESTDIR)$(uimanagerdir)" && rm -f $$files
+
+# This directory's subdirectories are mostly independent; you can cd
+# into them and run `make' without going through this Makefile.
+# To change the values of `make' variables: instead of editing Makefiles,
+# (1) if the variable is set in `config.status', edit `config.status'
+# (which will cause the Makefiles to be regenerated when you run `make');
+# (2) otherwise, pass the desired values on the `make' command line.
+$(RECURSIVE_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ target=`echo $@ | sed s/-recursive//`; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ dot_seen=yes; \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done; \
+ if test "$$dot_seen" = "no"; then \
+ $(MAKE) $(AM_MAKEFLAGS) "$$target-am" || exit 1; \
+ fi; test -z "$$fail"
+
+$(RECURSIVE_CLEAN_TARGETS):
+ @fail= failcom='exit 1'; \
+ for f in x $$MAKEFLAGS; do \
+ case $$f in \
+ *=* | --[!k]*);; \
+ *k*) failcom='fail=yes';; \
+ esac; \
+ done; \
+ dot_seen=no; \
+ case "$@" in \
+ distclean-* | maintainer-clean-*) list='$(DIST_SUBDIRS)' ;; \
+ *) list='$(SUBDIRS)' ;; \
+ esac; \
+ rev=''; for subdir in $$list; do \
+ if test "$$subdir" = "."; then :; else \
+ rev="$$subdir $$rev"; \
+ fi; \
+ done; \
+ rev="$$rev ."; \
+ target=`echo $@ | sed s/-recursive//`; \
+ for subdir in $$rev; do \
+ echo "Making $$target in $$subdir"; \
+ if test "$$subdir" = "."; then \
+ local_target="$$target-am"; \
+ else \
+ local_target="$$target"; \
+ fi; \
+ ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) $$local_target) \
+ || eval $$failcom; \
+ done && test -z "$$fail"
+tags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) tags); \
+ done
+ctags-recursive:
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ test "$$subdir" = . || ($(am__cd) $$subdir && $(MAKE) $(AM_MAKEFLAGS) ctags); \
+ done
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: tags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ if ($(ETAGS) --etags-include --version) >/dev/null 2>&1; then \
+ include_option=--etags-include; \
+ empty_fix=.; \
+ else \
+ include_option=--include; \
+ empty_fix=; \
+ fi; \
+ list='$(SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test ! -f $$subdir/TAGS || \
+ set "$$@" "$$include_option=$$here/$$subdir/TAGS"; \
+ fi; \
+ done; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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
+CTAGS: ctags-recursive $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+distdir: $(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
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ test -d "$(distdir)/$$subdir" \
+ || $(MKDIR_P) "$(distdir)/$$subdir" \
+ || exit 1; \
+ fi; \
+ done
+ @list='$(DIST_SUBDIRS)'; for subdir in $$list; do \
+ if test "$$subdir" = .; then :; else \
+ dir1=$$subdir; dir2="$(distdir)/$$subdir"; \
+ $(am__relativize); \
+ new_distdir=$$reldir; \
+ dir1=$$subdir; dir2="$(top_distdir)"; \
+ $(am__relativize); \
+ new_top_distdir=$$reldir; \
+ echo " (cd $$subdir && $(MAKE) $(AM_MAKEFLAGS) top_distdir="$$new_top_distdir" distdir="$$new_distdir" \\"; \
+ echo " am__remove_distdir=: am__skip_length_check=: am__skip_mode_fix=: distdir)"; \
+ ($(am__cd) $$subdir && \
+ $(MAKE) $(AM_MAKEFLAGS) \
+ top_distdir="$$new_top_distdir" \
+ distdir="$$new_distdir" \
+ am__remove_distdir=: \
+ am__skip_length_check=: \
+ am__skip_mode_fix=: \
+ distdir) \
+ || exit 1; \
+ fi; \
+ done
+check-am: all-am
+check: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) check-recursive
+all-am: Makefile $(PROGRAMS) $(DATA)
+installdirs: installdirs-recursive
+installdirs-am:
+ for dir in "$(DESTDIR)$(bindir)" "$(DESTDIR)$(aboutdir)" "$(DESTDIR)$(builderdir)" "$(DESTDIR)$(schemadir)" "$(DESTDIR)$(uimanagerdir)"; do \
+ test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+ done
+install: $(BUILT_SOURCES)
+ $(MAKE) $(AM_MAKEFLAGS) install-recursive
+install-exec: install-exec-recursive
+install-data: install-data-recursive
+uninstall: uninstall-recursive
+
+install-am: all-am
+ @$(MAKE) $(AM_MAKEFLAGS) install-exec-am install-data-am
+
+installcheck: installcheck-recursive
+install-strip:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+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)
+@MATECONF_SCHEMAS_INSTALL_FALSE@install-data-local:
+clean: clean-recursive
+
+clean-am: clean-binPROGRAMS clean-generic clean-libtool mostlyclean-am
+
+distclean: distclean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+distclean-am: clean-am distclean-compile distclean-generic \
+ distclean-tags
+
+dvi: dvi-recursive
+
+dvi-am:
+
+html: html-recursive
+
+html-am:
+
+info: info-recursive
+
+info-am:
+
+install-data-am: install-aboutDATA install-builderDATA \
+ install-data-local install-schemaDATA install-uimanagerDATA
+
+install-dvi: install-dvi-recursive
+
+install-dvi-am:
+
+install-exec-am: install-binPROGRAMS
+
+install-html: install-html-recursive
+
+install-html-am:
+
+install-info: install-info-recursive
+
+install-info-am:
+
+install-man:
+
+install-pdf: install-pdf-recursive
+
+install-pdf-am:
+
+install-ps: install-ps-recursive
+
+install-ps-am:
+
+installcheck-am:
+
+maintainer-clean: maintainer-clean-recursive
+ -rm -rf ./$(DEPDIR)
+ -rm -f Makefile
+maintainer-clean-am: distclean-am maintainer-clean-generic
+
+mostlyclean: mostlyclean-recursive
+
+mostlyclean-am: mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool
+
+pdf: pdf-recursive
+
+pdf-am:
+
+ps: ps-recursive
+
+ps-am:
+
+uninstall-am: uninstall-aboutDATA uninstall-binPROGRAMS \
+ uninstall-builderDATA uninstall-schemaDATA \
+ uninstall-uimanagerDATA
+
+.MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all check \
+ ctags-recursive install install-am install-strip \
+ tags-recursive
+
+.PHONY: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) CTAGS GTAGS \
+ all all-am check check-am clean clean-binPROGRAMS \
+ clean-generic clean-libtool ctags ctags-recursive distclean \
+ distclean-compile distclean-generic distclean-libtool \
+ distclean-tags distdir dvi dvi-am html html-am info info-am \
+ install install-aboutDATA install-am install-binPROGRAMS \
+ install-builderDATA install-data install-data-am \
+ install-data-local install-dvi install-dvi-am install-exec \
+ install-exec-am install-html install-html-am install-info \
+ install-info-am install-man install-pdf install-pdf-am \
+ install-ps install-ps-am install-schemaDATA install-strip \
+ install-uimanagerDATA installcheck installcheck-am installdirs \
+ installdirs-am maintainer-clean maintainer-clean-generic \
+ mostlyclean mostlyclean-compile mostlyclean-generic \
+ mostlyclean-libtool pdf pdf-am ps ps-am tags tags-recursive \
+ uninstall uninstall-aboutDATA uninstall-am \
+ uninstall-binPROGRAMS uninstall-builderDATA \
+ uninstall-schemaDATA uninstall-uimanagerDATA
+
+
+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) ( $(GLIB_GENMARSHAL) --prefix=_terminal_marshal $(srcdir)/terminal-marshal.list \
+ --header \
+ --body \
+ --internal > terminal-marshal.c.tmp \
+ && mv terminal-marshal.c.tmp terminal-marshal.c ) \
+ || ( rm -f terminal-marshal.c.tmp && exit 1 )
+
+@INTLTOOL_SCHEMAS_RULE@
+
+@MATECONF_SCHEMAS_INSTALL_TRUE@install-data-local:
+@MATECONF_SCHEMAS_INSTALL_TRUE@ MATECONF_CONFIG_SOURCE=$(MATECONF_SCHEMA_CONFIG_SOURCE) $(MATECONFTOOL) --makefile-install-rule $(top_builddir)/src/$(schema_DATA)
+
+%.ui: %.glade
+ $(AM_V_GEN) $(GTK_BUILDER_CONVERT) $< $@
+
+-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/eggdesktopfile.c b/src/eggdesktopfile.c
new file mode 100644
index 0000000..e38d867
--- /dev/null
+++ b/src/eggdesktopfile.c
@@ -0,0 +1,1510 @@
+/* eggdesktopfile.c - Freedesktop.Org Desktop Files
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * Based on mate-desktop-item.c
+ * Copyright (C) 1999, 2000 Red Hat Inc.
+ * Copyright (C) 2001 George Lebl
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "eggdesktopfile.h"
+
+#include <string.h>
+#include <unistd.h>
+
+#include <glib/gi18n.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+struct EggDesktopFile {
+ GKeyFile *key_file;
+ char *source;
+
+ char *name, *icon;
+ EggDesktopFileType type;
+ char document_code;
+};
+
+/**
+ * egg_desktop_file_new:
+ * @desktop_file_path: path to a Freedesktop-style Desktop file
+ * @error: error pointer
+ *
+ * Creates a new #EggDesktopFile for @desktop_file.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new (const char *desktop_file_path, GError **error)
+{
+ GKeyFile *key_file;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (key_file, desktop_file_path, 0, error))
+ {
+ g_key_file_free (key_file);
+ return NULL;
+ }
+
+ return egg_desktop_file_new_from_key_file (key_file, desktop_file_path,
+ error);
+}
+
+/**
+ * egg_desktop_file_new_from_data_dirs:
+ * @desktop_file_path: relative path to a Freedesktop-style Desktop file
+ * @error: error pointer
+ *
+ * Looks for @desktop_file_path in the paths returned from
+ * g_get_user_data_dir() and g_get_system_data_dirs(), and creates
+ * a new #EggDesktopFile from it.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
+ GError **error)
+{
+ EggDesktopFile *desktop_file;
+ GKeyFile *key_file;
+ char *full_path;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_data_dirs (key_file, desktop_file_path,
+ &full_path, 0, error))
+ {
+ g_key_file_free (key_file);
+ return NULL;
+ }
+
+ desktop_file = egg_desktop_file_new_from_key_file (key_file,
+ full_path,
+ error);
+ g_free (full_path);
+ return desktop_file;
+}
+
+/**
+ * egg_desktop_file_new_from_dirs:
+ * @desktop_file_path: relative path to a Freedesktop-style Desktop file
+ * @search_dirs: NULL-terminated array of directories to search
+ * @error: error pointer
+ *
+ * Looks for @desktop_file_path in the paths returned from
+ * g_get_user_data_dir() and g_get_system_data_dirs(), and creates
+ * a new #EggDesktopFile from it.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error)
+{
+ EggDesktopFile *desktop_file;
+ GKeyFile *key_file;
+ char *full_path;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_dirs (key_file, desktop_file_path, search_dirs,
+ &full_path, 0, error))
+ {
+ g_key_file_free (key_file);
+ return NULL;
+ }
+
+ desktop_file = egg_desktop_file_new_from_key_file (key_file,
+ full_path,
+ error);
+ g_free (full_path);
+ return desktop_file;
+}
+
+/**
+ * egg_desktop_file_new_from_key_file:
+ * @key_file: a #GKeyFile representing a desktop file
+ * @source: the path or URI that @key_file was loaded from, or %NULL
+ * @error: error pointer
+ *
+ * Creates a new #EggDesktopFile for @key_file. Assumes ownership of
+ * @key_file (on success or failure); you should consider @key_file to
+ * be freed after calling this function.
+ *
+ * Return value: the new #EggDesktopFile, or %NULL on error.
+ **/
+EggDesktopFile *
+egg_desktop_file_new_from_key_file (GKeyFile *key_file,
+ const char *source,
+ GError **error)
+{
+ EggDesktopFile *desktop_file;
+ char *version, *type;
+
+ if (!g_key_file_has_group (key_file, EGG_DESKTOP_FILE_GROUP))
+ {
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_INVALID,
+ _("File is not a valid .desktop file"));
+ g_key_file_free (key_file);
+ return NULL;
+ }
+
+ version = g_key_file_get_value (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_VERSION,
+ NULL);
+ if (version)
+ {
+ double version_num;
+ char *end;
+
+ version_num = g_ascii_strtod (version, &end);
+ if (*end)
+ {
+ g_warning ("Invalid Version string '%s' in %s",
+ version, source ? source : "(unknown)");
+ }
+ else if (version_num > 1.0)
+ {
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_INVALID,
+ _("Unrecognized desktop file Version '%s'"), version);
+ g_free (version);
+ g_key_file_free (key_file);
+ return NULL;
+ }
+ g_free (version);
+ }
+
+ desktop_file = g_new0 (EggDesktopFile, 1);
+ desktop_file->key_file = key_file;
+
+ if (g_path_is_absolute (source))
+ desktop_file->source = g_filename_to_uri (source, NULL, NULL);
+ else
+ desktop_file->source = g_strdup (source);
+
+ desktop_file->name = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_NAME, error);
+ if (!desktop_file->name)
+ {
+ egg_desktop_file_free (desktop_file);
+ return NULL;
+ }
+
+ type = g_key_file_get_string (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_TYPE, error);
+ if (!type)
+ {
+ egg_desktop_file_free (desktop_file);
+ return NULL;
+ }
+
+ if (!strcmp (type, "Application"))
+ {
+ char *exec, *p;
+
+ desktop_file->type = EGG_DESKTOP_FILE_TYPE_APPLICATION;
+
+ exec = g_key_file_get_string (key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_EXEC,
+ error);
+ if (!exec)
+ {
+ egg_desktop_file_free (desktop_file);
+ g_free (type);
+ return NULL;
+ }
+
+ /* See if it takes paths or URIs or neither */
+ for (p = exec; *p; p++)
+ {
+ if (*p == '%')
+ {
+ if (p[1] == '\0' || strchr ("FfUu", p[1]))
+ {
+ desktop_file->document_code = p[1];
+ break;
+ }
+ p++;
+ }
+ }
+
+ g_free (exec);
+ }
+ else if (!strcmp (type, "Link"))
+ {
+ char *url;
+
+ desktop_file->type = EGG_DESKTOP_FILE_TYPE_LINK;
+
+ url = g_key_file_get_string (key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_URL,
+ error);
+ if (!url)
+ {
+ egg_desktop_file_free (desktop_file);
+ g_free (type);
+ return NULL;
+ }
+ g_free (url);
+ }
+ else if (!strcmp (type, "Directory"))
+ desktop_file->type = EGG_DESKTOP_FILE_TYPE_DIRECTORY;
+ else
+ desktop_file->type = EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED;
+
+ g_free (type);
+
+ /* Check the Icon key */
+ desktop_file->icon = g_key_file_get_string (key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_ICON,
+ NULL);
+ if (desktop_file->icon && !g_path_is_absolute (desktop_file->icon))
+ {
+ char *ext;
+
+ /* Lots of .desktop files still get this wrong */
+ ext = strrchr (desktop_file->icon, '.');
+ if (ext && (!strcmp (ext, ".png") ||
+ !strcmp (ext, ".xpm") ||
+ !strcmp (ext, ".svg")))
+ {
+ g_warning ("Desktop file '%s' has malformed Icon key '%s'"
+ "(should not include extension)",
+ source ? source : "(unknown)",
+ desktop_file->icon);
+ *ext = '\0';
+ }
+ }
+
+ return desktop_file;
+}
+
+/**
+ * egg_desktop_file_free:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Frees @desktop_file.
+ **/
+void
+egg_desktop_file_free (EggDesktopFile *desktop_file)
+{
+ g_key_file_free (desktop_file->key_file);
+ g_free (desktop_file->source);
+ g_free (desktop_file->name);
+ g_free (desktop_file->icon);
+ g_free (desktop_file);
+}
+
+/**
+ * egg_desktop_file_get_source:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Gets the URI that @desktop_file was loaded from.
+ *
+ * Return value: @desktop_file's source URI
+ **/
+const char *
+egg_desktop_file_get_source (EggDesktopFile *desktop_file)
+{
+ return desktop_file->source;
+}
+
+/**
+ * egg_desktop_file_get_desktop_file_type:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Gets the desktop file type of @desktop_file.
+ *
+ * Return value: @desktop_file's type
+ **/
+EggDesktopFileType
+egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file)
+{
+ return desktop_file->type;
+}
+
+/**
+ * egg_desktop_file_get_name:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Gets the (localized) value of @desktop_file's "Name" key.
+ *
+ * Return value: the application/link name
+ **/
+const char *
+egg_desktop_file_get_name (EggDesktopFile *desktop_file)
+{
+ return desktop_file->name;
+}
+
+/**
+ * egg_desktop_file_get_icon:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Gets the value of @desktop_file's "Icon" key.
+ *
+ * If the icon string is a full path (that is, if g_path_is_absolute()
+ * returns %TRUE when called on it), it points to a file containing an
+ * unthemed icon. If the icon string is not a full path, it is the
+ * name of a themed icon, which can be looked up with %GtkIconTheme,
+ * or passed directly to a theme-aware widget like %GtkImage or
+ * %GtkCellRendererPixbuf.
+ *
+ * Return value: the icon path or name
+ **/
+const char *
+egg_desktop_file_get_icon (EggDesktopFile *desktop_file)
+{
+ return desktop_file->icon;
+}
+
+gboolean
+egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_has_key (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char *
+egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error)
+{
+ return g_key_file_get_locale_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, locale,
+ error);
+}
+
+gboolean
+egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_boolean (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+double
+egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error)
+{
+ return g_key_file_get_double (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ error);
+}
+
+char **
+egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key, length,
+ error);
+}
+
+char **
+egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error)
+{
+ return g_key_file_get_locale_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP, key,
+ locale, length,
+ error);
+}
+
+/**
+ * egg_desktop_file_can_launch:
+ * @desktop_file: an #EggDesktopFile
+ * @desktop_environment: the name of the running desktop environment,
+ * or %NULL
+ *
+ * Tests if @desktop_file can/should be launched in the current
+ * environment. If @desktop_environment is non-%NULL, @desktop_file's
+ * "OnlyShowIn" and "NotShowIn" keys are checked to make sure that
+ * this desktop_file is appropriate for the named environment.
+ *
+ * Furthermore, if @desktop_file has type
+ * %EGG_DESKTOP_FILE_TYPE_APPLICATION, its "TryExec" key (if any) is
+ * also checked, to make sure the binary it points to exists.
+ *
+ * egg_desktop_file_can_launch() does NOT check the value of the
+ * "Hidden" key.
+ *
+ * Return value: %TRUE if @desktop_file can be launched
+ **/
+gboolean
+egg_desktop_file_can_launch (EggDesktopFile *desktop_file,
+ const char *desktop_environment)
+{
+ char *try_exec, *found_program;
+ char **only_show_in, **not_show_in;
+ gboolean found;
+ int i;
+
+ if (desktop_file->type != EGG_DESKTOP_FILE_TYPE_APPLICATION &&
+ desktop_file->type != EGG_DESKTOP_FILE_TYPE_LINK)
+ return FALSE;
+
+ if (desktop_environment)
+ {
+ only_show_in = g_key_file_get_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN,
+ NULL, NULL);
+ if (only_show_in)
+ {
+ for (i = 0, found = FALSE; only_show_in[i] && !found; i++)
+ {
+ if (!strcmp (only_show_in[i], desktop_environment))
+ found = TRUE;
+ }
+
+ g_strfreev (only_show_in);
+
+ if (!found)
+ return FALSE;
+ }
+
+ not_show_in = g_key_file_get_string_list (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN,
+ NULL, NULL);
+ if (not_show_in)
+ {
+ for (i = 0, found = FALSE; not_show_in[i] && !found; i++)
+ {
+ if (!strcmp (not_show_in[i], desktop_environment))
+ found = TRUE;
+ }
+
+ g_strfreev (not_show_in);
+
+ if (found)
+ return FALSE;
+ }
+ }
+
+ if (desktop_file->type == EGG_DESKTOP_FILE_TYPE_APPLICATION)
+ {
+ try_exec = g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_TRY_EXEC,
+ NULL);
+ if (try_exec)
+ {
+ found_program = g_find_program_in_path (try_exec);
+ g_free (try_exec);
+
+ if (!found_program)
+ return FALSE;
+ g_free (found_program);
+ }
+ }
+
+ return TRUE;
+}
+
+/**
+ * egg_desktop_file_accepts_documents:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Tests if @desktop_file represents an application that can accept
+ * documents on the command line.
+ *
+ * Return value: %TRUE or %FALSE
+ **/
+gboolean
+egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file)
+{
+ return desktop_file->document_code != 0;
+}
+
+/**
+ * egg_desktop_file_accepts_multiple:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Tests if @desktop_file can accept multiple documents at once.
+ *
+ * If this returns %FALSE, you can still pass multiple documents to
+ * egg_desktop_file_launch(), but that will result in multiple copies
+ * of the application being launched. See egg_desktop_file_launch()
+ * for more details.
+ *
+ * Return value: %TRUE or %FALSE
+ **/
+gboolean
+egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file)
+{
+ return (desktop_file->document_code == 'F' ||
+ desktop_file->document_code == 'U');
+}
+
+/**
+ * egg_desktop_file_accepts_uris:
+ * @desktop_file: an #EggDesktopFile
+ *
+ * Tests if @desktop_file can accept (non-"file:") URIs as documents to
+ * open.
+ *
+ * Return value: %TRUE or %FALSE
+ **/
+gboolean
+egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file)
+{
+ return (desktop_file->document_code == 'U' ||
+ desktop_file->document_code == 'u');
+}
+
+static void
+append_quoted_word (GString *str,
+ const char *s,
+ gboolean in_single_quotes,
+ gboolean in_double_quotes)
+{
+ const char *p;
+
+ if (!in_single_quotes && !in_double_quotes)
+ g_string_append_c (str, '\'');
+ else if (!in_single_quotes && in_double_quotes)
+ g_string_append (str, "\"'");
+
+ if (!strchr (s, '\''))
+ g_string_append (str, s);
+ else
+ {
+ for (p = s; *p != '\0'; p++)
+ {
+ if (*p == '\'')
+ g_string_append (str, "'\\''");
+ else
+ g_string_append_c (str, *p);
+ }
+ }
+
+ if (!in_single_quotes && !in_double_quotes)
+ g_string_append_c (str, '\'');
+ else if (!in_single_quotes && in_double_quotes)
+ g_string_append (str, "'\"");
+}
+
+static void
+do_percent_subst (EggDesktopFile *desktop_file,
+ char code,
+ GString *str,
+ GSList **documents,
+ gboolean in_single_quotes,
+ gboolean in_double_quotes)
+{
+ GSList *d;
+ char *doc;
+
+ switch (code)
+ {
+ case '%':
+ g_string_append_c (str, '%');
+ break;
+
+ case 'F':
+ case 'U':
+ for (d = *documents; d; d = d->next)
+ {
+ doc = d->data;
+ g_string_append (str, " ");
+ append_quoted_word (str, doc, in_single_quotes, in_double_quotes);
+ }
+ *documents = NULL;
+ break;
+
+ case 'f':
+ case 'u':
+ if (*documents)
+ {
+ doc = (*documents)->data;
+ g_string_append (str, " ");
+ append_quoted_word (str, doc, in_single_quotes, in_double_quotes);
+ *documents = (*documents)->next;
+ }
+ break;
+
+ case 'i':
+ if (desktop_file->icon)
+ {
+ g_string_append (str, "--icon ");
+ append_quoted_word (str, desktop_file->icon,
+ in_single_quotes, in_double_quotes);
+ }
+ break;
+
+ case 'c':
+ if (desktop_file->name)
+ {
+ append_quoted_word (str, desktop_file->name,
+ in_single_quotes, in_double_quotes);
+ }
+ break;
+
+ case 'k':
+ if (desktop_file->source)
+ {
+ append_quoted_word (str, desktop_file->source,
+ in_single_quotes, in_double_quotes);
+ }
+ break;
+
+ case 'D':
+ case 'N':
+ case 'd':
+ case 'n':
+ case 'v':
+ case 'm':
+ /* Deprecated; skip */
+ break;
+
+ default:
+ g_warning ("Unrecognized %%-code '%%%c' in Exec", code);
+ break;
+ }
+}
+
+static char *
+parse_exec (EggDesktopFile *desktop_file,
+ GSList **documents,
+ GError **error)
+{
+ char *exec, *p, *command;
+ gboolean escape, single_quot, double_quot;
+ GString *gs;
+
+ exec = g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_EXEC,
+ error);
+ if (!exec)
+ return NULL;
+
+ /* Build the command */
+ gs = g_string_new (NULL);
+ escape = single_quot = double_quot = FALSE;
+
+ for (p = exec; *p != '\0'; p++)
+ {
+ if (escape)
+ {
+ escape = FALSE;
+ g_string_append_c (gs, *p);
+ }
+ else if (*p == '\\')
+ {
+ if (!single_quot)
+ escape = TRUE;
+ g_string_append_c (gs, *p);
+ }
+ else if (*p == '\'')
+ {
+ g_string_append_c (gs, *p);
+ if (!single_quot && !double_quot)
+ single_quot = TRUE;
+ else if (single_quot)
+ single_quot = FALSE;
+ }
+ else if (*p == '"')
+ {
+ g_string_append_c (gs, *p);
+ if (!single_quot && !double_quot)
+ double_quot = TRUE;
+ else if (double_quot)
+ double_quot = FALSE;
+ }
+ else if (*p == '%' && p[1])
+ {
+ do_percent_subst (desktop_file, p[1], gs, documents,
+ single_quot, double_quot);
+ p++;
+ }
+ else
+ g_string_append_c (gs, *p);
+ }
+
+ g_free (exec);
+ command = g_string_free (gs, FALSE);
+
+ /* Prepend "xdg-terminal " if needed (FIXME: use gvfs) */
+ if (g_key_file_has_key (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_TERMINAL,
+ NULL))
+ {
+ GError *terminal_error = NULL;
+ gboolean use_terminal =
+ g_key_file_get_boolean (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_TERMINAL,
+ &terminal_error);
+ if (terminal_error)
+ {
+ g_free (command);
+ g_propagate_error (error, terminal_error);
+ return NULL;
+ }
+
+ if (use_terminal)
+ {
+ gs = g_string_new ("xdg-terminal ");
+ append_quoted_word (gs, command, FALSE, FALSE);
+ g_free (command);
+ command = g_string_free (gs, FALSE);
+ }
+ }
+
+ return command;
+}
+
+static GSList *
+translate_document_list (EggDesktopFile *desktop_file, GSList *documents)
+{
+ gboolean accepts_uris = egg_desktop_file_accepts_uris (desktop_file);
+ GSList *ret, *d;
+
+ for (d = documents, ret = NULL; d; d = d->next)
+ {
+ const char *document = d->data;
+ gboolean is_uri = !g_path_is_absolute (document);
+ char *translated;
+
+ if (accepts_uris)
+ {
+ if (is_uri)
+ translated = g_strdup (document);
+ else
+ translated = g_filename_to_uri (document, NULL, NULL);
+ }
+ else
+ {
+ if (is_uri)
+ translated = g_filename_from_uri (document, NULL, NULL);
+ else
+ translated = g_strdup (document);
+ }
+
+ if (translated)
+ ret = g_slist_prepend (ret, translated);
+ }
+
+ return g_slist_reverse (ret);
+}
+
+static void
+free_document_list (GSList *documents)
+{
+ GSList *d;
+
+ for (d = documents; d; d = d->next)
+ g_free (d->data);
+ g_slist_free (documents);
+}
+
+/**
+ * egg_desktop_file_parse_exec:
+ * @desktop_file: a #EggDesktopFile
+ * @documents: a list of document paths or URIs
+ * @error: error pointer
+ *
+ * Parses @desktop_file's Exec key, inserting @documents into it, and
+ * returns the result.
+ *
+ * If @documents contains non-file: URIs and @desktop_file does not
+ * accept URIs, those URIs will be ignored. Likewise, if @documents
+ * contains more elements than @desktop_file accepts, the extra
+ * documents will be ignored.
+ *
+ * Return value: the parsed Exec string
+ **/
+char *
+egg_desktop_file_parse_exec (EggDesktopFile *desktop_file,
+ GSList *documents,
+ GError **error)
+{
+ GSList *translated, *docs;
+ char *command;
+
+ docs = translated = translate_document_list (desktop_file, documents);
+ command = parse_exec (desktop_file, &docs, error);
+ free_document_list (translated);
+
+ return command;
+}
+
+static gboolean
+parse_link (EggDesktopFile *desktop_file,
+ EggDesktopFile **app_desktop_file,
+ GSList **documents,
+ GError **error)
+{
+ char *url;
+ GKeyFile *key_file;
+
+ url = g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_URL,
+ error);
+ if (!url)
+ return FALSE;
+ *documents = g_slist_prepend (NULL, url);
+
+ /* FIXME: use gvfs */
+ key_file = g_key_file_new ();
+ g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_NAME,
+ "xdg-open");
+ g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_TYPE,
+ "Application");
+ g_key_file_set_string (key_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_EXEC,
+ "xdg-open %u");
+ *app_desktop_file = egg_desktop_file_new_from_key_file (key_file, NULL, NULL);
+ return TRUE;
+}
+
+#if GTK_CHECK_VERSION (2, 12, 0)
+static char *
+start_startup_notification (GdkDisplay *display,
+ EggDesktopFile *desktop_file,
+ const char *argv0,
+ int screen,
+ int workspace,
+ guint32 launch_time)
+{
+ static int sequence = 0;
+ char *startup_id;
+ char *description, *wmclass;
+ char *screen_str, *workspace_str;
+
+ if (g_key_file_has_key (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY,
+ NULL))
+ {
+ if (!g_key_file_get_boolean (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY,
+ NULL))
+ return NULL;
+ wmclass = NULL;
+ }
+ else
+ {
+ wmclass = g_key_file_get_string (desktop_file->key_file,
+ EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS,
+ NULL);
+ if (!wmclass)
+ return NULL;
+ }
+
+ if (launch_time == (guint32)-1)
+ launch_time = gdk_x11_display_get_user_time (display);
+ startup_id = g_strdup_printf ("%s-%lu-%s-%s-%d_TIME%lu",
+ g_get_prgname (),
+ (unsigned long)getpid (),
+ g_get_host_name (),
+ argv0,
+ sequence++,
+ (unsigned long)launch_time);
+
+ description = g_strdup_printf (_("Starting %s"), desktop_file->name);
+ screen_str = g_strdup_printf ("%d", screen);
+ workspace_str = workspace == -1 ? NULL : g_strdup_printf ("%d", workspace);
+
+ gdk_x11_display_broadcast_startup_message (display, "new",
+ "ID", startup_id,
+ "NAME", desktop_file->name,
+ "SCREEN", screen_str,
+ "BIN", argv0,
+ "ICON", desktop_file->icon,
+ "DESKTOP", workspace_str,
+ "DESCRIPTION", description,
+ "WMCLASS", wmclass,
+ NULL);
+
+ g_free (description);
+ g_free (wmclass);
+ g_free (screen_str);
+ g_free (workspace_str);
+
+ return startup_id;
+}
+
+static void
+end_startup_notification (GdkDisplay *display,
+ const char *startup_id)
+{
+ gdk_x11_display_broadcast_startup_message (display, "remove",
+ "ID", startup_id,
+ NULL);
+}
+
+#define EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH (30 /* seconds */)
+
+typedef struct {
+ GdkDisplay *display;
+ char *startup_id;
+} StartupNotificationData;
+
+static gboolean
+startup_notification_timeout (gpointer data)
+{
+ StartupNotificationData *sn_data = data;
+
+ end_startup_notification (sn_data->display, sn_data->startup_id);
+ g_object_unref (sn_data->display);
+ g_free (sn_data->startup_id);
+ g_free (sn_data);
+
+ return FALSE;
+}
+
+static void
+set_startup_notification_timeout (GdkDisplay *display,
+ const char *startup_id)
+{
+ StartupNotificationData *sn_data;
+
+ sn_data = g_new (StartupNotificationData, 1);
+ sn_data->display = g_object_ref (display);
+ sn_data->startup_id = g_strdup (startup_id);
+
+ g_timeout_add_seconds (EGG_DESKTOP_FILE_SN_TIMEOUT_LENGTH,
+ startup_notification_timeout, sn_data);
+}
+#endif /* GTK 2.12 */
+
+static GPtrArray *
+array_putenv (GPtrArray *env, char *variable)
+{
+ guint i, keylen;
+
+ if (!env)
+ {
+ char **envp;
+
+ env = g_ptr_array_new ();
+
+ envp = g_listenv ();
+ for (i = 0; envp[i]; i++)
+ {
+ const char *value;
+
+ value = g_getenv (envp[i]);
+ g_ptr_array_add (env, g_strdup_printf ("%s=%s", envp[i],
+ value ? value : ""));
+ }
+ g_strfreev (envp);
+ }
+
+ keylen = strcspn (variable, "=");
+
+ /* Remove old value of key */
+ for (i = 0; i < env->len; i++)
+ {
+ char *envvar = env->pdata[i];
+
+ if (!strncmp (envvar, variable, keylen) && envvar[keylen] == '=')
+ {
+ g_free (envvar);
+ g_ptr_array_remove_index_fast (env, i);
+ break;
+ }
+ }
+
+ /* Add new value */
+ g_ptr_array_add (env, g_strdup (variable));
+
+ return env;
+}
+
+static gboolean
+egg_desktop_file_launchv (EggDesktopFile *desktop_file,
+ GSList *documents, va_list args,
+ GError **error)
+{
+ EggDesktopFileLaunchOption option;
+ GSList *translated_documents = NULL, *docs = NULL;
+ char *command, **argv;
+ int argc, i, screen_num;
+ gboolean success, current_success;
+ GdkDisplay *display;
+ char *startup_id;
+
+ GPtrArray *env = NULL;
+ char **variables = NULL;
+ GdkScreen *screen = NULL;
+ int workspace = -1;
+ const char *directory = NULL;
+ guint32 launch_time = (guint32)-1;
+ GSpawnFlags flags = G_SPAWN_SEARCH_PATH;
+ GSpawnChildSetupFunc setup_func = NULL;
+ gpointer setup_data = NULL;
+
+ GPid *ret_pid = NULL;
+ int *ret_stdin = NULL, *ret_stdout = NULL, *ret_stderr = NULL;
+ char **ret_startup_id = NULL;
+
+ if (documents && desktop_file->document_code == 0)
+ {
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
+ _("Application does not accept documents on command line"));
+ return FALSE;
+ }
+
+ /* Read the options: technically it's incorrect for the caller to
+ * NULL-terminate the list of options (rather than 0-terminating
+ * it), but NULL-terminating lets us use G_GNUC_NULL_TERMINATED,
+ * it's more consistent with other glib/gtk methods, and it will
+ * work as long as sizeof (int) <= sizeof (NULL), and NULL is
+ * represented as 0. (Which is true everywhere we care about.)
+ */
+ while ((option = va_arg (args, EggDesktopFileLaunchOption)))
+ {
+ switch (option)
+ {
+ case EGG_DESKTOP_FILE_LAUNCH_CLEARENV:
+ if (env)
+ g_ptr_array_free (env, TRUE);
+ env = g_ptr_array_new ();
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_PUTENV:
+ variables = va_arg (args, char **);
+ for (i = 0; variables[i]; i++)
+ env = array_putenv (env, variables[i]);
+ break;
+
+ case EGG_DESKTOP_FILE_LAUNCH_SCREEN:
+ screen = va_arg (args, GdkScreen *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_WORKSPACE:
+ workspace = va_arg (args, int);
+ break;
+
+ case EGG_DESKTOP_FILE_LAUNCH_DIRECTORY:
+ directory = va_arg (args, const char *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_TIME:
+ launch_time = va_arg (args, guint32);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_FLAGS:
+ flags |= va_arg (args, GSpawnFlags);
+ /* Make sure they didn't set any flags that don't make sense. */
+ flags &= ~G_SPAWN_FILE_AND_ARGV_ZERO;
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC:
+ setup_func = va_arg (args, GSpawnChildSetupFunc);
+ setup_data = va_arg (args, gpointer);
+ break;
+
+ case EGG_DESKTOP_FILE_LAUNCH_RETURN_PID:
+ ret_pid = va_arg (args, GPid *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE:
+ ret_stdin = va_arg (args, int *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE:
+ ret_stdout = va_arg (args, int *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE:
+ ret_stderr = va_arg (args, int *);
+ break;
+ case EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID:
+ ret_startup_id = va_arg (args, char **);
+ break;
+
+ default:
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION,
+ _("Unrecognized launch option: %d"),
+ GPOINTER_TO_INT (option));
+ success = FALSE;
+ goto out;
+ }
+ }
+
+ if (screen)
+ {
+ char *display_name = gdk_screen_make_display_name (screen);
+ char *display_env = g_strdup_printf ("DISPLAY=%s", display_name);
+ env = array_putenv (env, display_env);
+ g_free (display_name);
+ g_free (display_env);
+
+ display = gdk_screen_get_display (screen);
+ }
+ else
+ {
+ display = gdk_display_get_default ();
+ screen = gdk_display_get_default_screen (display);
+ }
+ screen_num = gdk_screen_get_number (screen);
+
+ translated_documents = translate_document_list (desktop_file, documents);
+ docs = translated_documents;
+
+ success = FALSE;
+
+ do
+ {
+ command = parse_exec (desktop_file, &docs, error);
+ if (!command)
+ goto out;
+
+ if (!g_shell_parse_argv (command, &argc, &argv, error))
+ {
+ g_free (command);
+ goto out;
+ }
+ g_free (command);
+
+#if GTK_CHECK_VERSION (2, 12, 0)
+ startup_id = start_startup_notification (display, desktop_file,
+ argv[0], screen_num,
+ workspace, launch_time);
+ if (startup_id)
+ {
+ char *startup_id_env = g_strdup_printf ("DESKTOP_STARTUP_ID=%s",
+ startup_id);
+ env = array_putenv (env, startup_id_env);
+ g_free (startup_id_env);
+ }
+#else
+ startup_id = NULL;
+#endif /* GTK 2.12 */
+
+ if (env != NULL)
+ g_ptr_array_add (env, NULL);
+
+ current_success =
+ g_spawn_async_with_pipes (directory,
+ argv,
+ env ? (char **)(env->pdata) : NULL,
+ flags,
+ setup_func, setup_data,
+ ret_pid,
+ ret_stdin, ret_stdout, ret_stderr,
+ error);
+ g_strfreev (argv);
+
+ if (startup_id)
+ {
+#if GTK_CHECK_VERSION (2, 12, 0)
+ if (current_success)
+ {
+ set_startup_notification_timeout (display, startup_id);
+
+ if (ret_startup_id)
+ *ret_startup_id = startup_id;
+ else
+ g_free (startup_id);
+ }
+ else
+#endif /* GTK 2.12 */
+ g_free (startup_id);
+ }
+ else if (ret_startup_id)
+ *ret_startup_id = NULL;
+
+ if (current_success)
+ {
+ /* If we successfully launch any instances of the app, make
+ * sure we return TRUE and don't set @error.
+ */
+ success = TRUE;
+ error = NULL;
+
+ /* Also, only set the output params on the first one */
+ ret_pid = NULL;
+ ret_stdin = ret_stdout = ret_stderr = NULL;
+ ret_startup_id = NULL;
+ }
+ }
+ while (docs && current_success);
+
+ out:
+ if (env)
+ {
+ g_ptr_array_foreach (env, (GFunc)g_free, NULL);
+ g_ptr_array_free (env, TRUE);
+ }
+ free_document_list (translated_documents);
+
+ return success;
+}
+
+/**
+ * egg_desktop_file_launch:
+ * @desktop_file: an #EggDesktopFile
+ * @documents: a list of URIs or paths to documents to open
+ * @error: error pointer
+ * @...: additional options
+ *
+ * Launches @desktop_file with the given arguments. Additional options
+ * can be specified as follows:
+ *
+ * %EGG_DESKTOP_FILE_LAUNCH_CLEARENV: (no arguments)
+ * clears the environment in the child process
+ * %EGG_DESKTOP_FILE_LAUNCH_PUTENV: (char **variables)
+ * adds the NAME=VALUE strings in the given %NULL-terminated
+ * array to the child process's environment
+ * %EGG_DESKTOP_FILE_LAUNCH_SCREEN: (GdkScreen *screen)
+ * causes the application to be launched on the given screen
+ * %EGG_DESKTOP_FILE_LAUNCH_WORKSPACE: (int workspace)
+ * causes the application to be launched on the given workspace
+ * %EGG_DESKTOP_FILE_LAUNCH_DIRECTORY: (char *dir)
+ * causes the application to be launched in the given directory
+ * %EGG_DESKTOP_FILE_LAUNCH_TIME: (guint32 launch_time)
+ * sets the "launch time" for the application. If the user
+ * interacts with another window after @launch_time but before
+ * the launched application creates its first window, the window
+ * manager may choose to not give focus to the new application.
+ * Passing 0 for @launch_time will explicitly request that the
+ * application not receive focus.
+ * %EGG_DESKTOP_FILE_LAUNCH_FLAGS (GSpawnFlags flags)
+ * Sets additional #GSpawnFlags to use. See g_spawn_async() for
+ * more details.
+ * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC (GSpawnChildSetupFunc, gpointer)
+ * Sets the child setup callback and the data to pass to it.
+ * (See g_spawn_async() for more details.)
+ *
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID (GPid **pid)
+ * On a successful launch, sets *@pid to the PID of the launched
+ * application.
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID (char **startup_id)
+ * On a successful launch, sets *@startup_id to the Startup
+ * Notification "startup id" of the launched application.
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE (int *fd)
+ * On a successful launch, sets *@fd to the file descriptor of
+ * a pipe connected to the application's stdin.
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE (int *fd)
+ * On a successful launch, sets *@fd to the file descriptor of
+ * a pipe connected to the application's stdout.
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE (int *fd)
+ * On a successful launch, sets *@fd to the file descriptor of
+ * a pipe connected to the application's stderr.
+ *
+ * The options should be terminated with a single %NULL.
+ *
+ * If @documents contains multiple documents, but
+ * egg_desktop_file_accepts_multiple() returns %FALSE for
+ * @desktop_file, then egg_desktop_file_launch() will actually launch
+ * multiple instances of the application. In that case, the return
+ * value (as well as any values passed via
+ * %EGG_DESKTOP_FILE_LAUNCH_RETURN_PID, etc) will only reflect the
+ * first instance of the application that was launched (but the
+ * %EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC will be called for each
+ * instance).
+ *
+ * Return value: %TRUE if the application was successfully launched.
+ **/
+gboolean
+egg_desktop_file_launch (EggDesktopFile *desktop_file,
+ GSList *documents, GError **error,
+ ...)
+{
+ va_list args;
+ gboolean success;
+ EggDesktopFile *app_desktop_file;
+
+ switch (desktop_file->type)
+ {
+ case EGG_DESKTOP_FILE_TYPE_APPLICATION:
+ va_start (args, error);
+ success = egg_desktop_file_launchv (desktop_file, documents,
+ args, error);
+ va_end (args);
+ break;
+
+ case EGG_DESKTOP_FILE_TYPE_LINK:
+ if (documents)
+ {
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
+ _("Can't pass document URIs to a 'Type=Link' desktop entry"));
+ return FALSE;
+ }
+
+ if (!parse_link (desktop_file, &app_desktop_file, &documents, error))
+ return FALSE;
+
+ va_start (args, error);
+ success = egg_desktop_file_launchv (app_desktop_file, documents,
+ args, error);
+ va_end (args);
+
+ egg_desktop_file_free (app_desktop_file);
+ free_document_list (documents);
+ break;
+
+ case EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED:
+ case EGG_DESKTOP_FILE_TYPE_DIRECTORY:
+ default:
+ g_set_error (error, EGG_DESKTOP_FILE_ERROR,
+ EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
+ _("Not a launchable item"));
+ success = FALSE;
+ break;
+ }
+
+ return success;
+}
+
+
+GQuark
+egg_desktop_file_error_quark (void)
+{
+ return g_quark_from_static_string ("egg-desktop_file-error-quark");
+}
+
+
+G_LOCK_DEFINE_STATIC (egg_desktop_file);
+static EggDesktopFile *egg_desktop_file;
+
+static void
+egg_set_desktop_file_internal (const char *desktop_file_path,
+ gboolean set_defaults)
+{
+ GError *error = NULL;
+
+ G_LOCK (egg_desktop_file);
+ if (egg_desktop_file)
+ egg_desktop_file_free (egg_desktop_file);
+
+ egg_desktop_file = egg_desktop_file_new (desktop_file_path, &error);
+ if (error)
+ {
+ g_warning ("Could not load desktop file '%s': %s",
+ desktop_file_path, error->message);
+ g_error_free (error);
+ }
+
+ if (set_defaults && egg_desktop_file != NULL) {
+ /* Set localized application name and default window icon */
+ if (egg_desktop_file->name)
+ g_set_application_name (egg_desktop_file->name);
+ if (egg_desktop_file->icon)
+ {
+ if (g_path_is_absolute (egg_desktop_file->icon))
+ gtk_window_set_default_icon_from_file (egg_desktop_file->icon, NULL);
+ else
+ gtk_window_set_default_icon_name (egg_desktop_file->icon);
+ }
+ }
+
+ G_UNLOCK (egg_desktop_file);
+}
+
+/**
+ * egg_set_desktop_file:
+ * @desktop_file_path: path to the application's desktop file
+ *
+ * Creates an #EggDesktopFile for the application from the data at
+ * @desktop_file_path. This will also call g_set_application_name()
+ * with the localized application name from the desktop file, and
+ * gtk_window_set_default_icon_name() or
+ * gtk_window_set_default_icon_from_file() with the application's
+ * icon. Other code may use additional information from the desktop
+ * file.
+ * See egg_set_desktop_file_without_defaults() for a variant of this
+ * function that does not set the application name and default window
+ * icon.
+ *
+ * Note that for thread safety reasons, this function can only
+ * be called once, and is mutually exclusive with calling
+ * egg_set_desktop_file_without_defaults().
+ **/
+void
+egg_set_desktop_file (const char *desktop_file_path)
+{
+ egg_set_desktop_file_internal (desktop_file_path, TRUE);
+}
+
+/**
+ * egg_set_desktop_file_without_defaults:
+ * @desktop_file_path: path to the application's desktop file
+ *
+ * Creates an #EggDesktopFile for the application from the data at
+ * @desktop_file_path.
+ * See egg_set_desktop_file() for a variant of this function that
+ * sets the application name and default window icon from the information
+ * in the desktop file.
+ *
+ * Note that for thread safety reasons, this function can only
+ * be called once, and is mutually exclusive with calling
+ * egg_set_desktop_file().
+ **/
+void
+egg_set_desktop_file_without_defaults (const char *desktop_file_path)
+{
+ egg_set_desktop_file_internal (desktop_file_path, FALSE);
+}
+
+/**
+ * egg_get_desktop_file:
+ *
+ * Gets the application's #EggDesktopFile, as set by
+ * egg_set_desktop_file().
+ *
+ * Return value: the #EggDesktopFile, or %NULL if it hasn't been set.
+ **/
+EggDesktopFile *
+egg_get_desktop_file (void)
+{
+ EggDesktopFile *retval;
+
+ G_LOCK (egg_desktop_file);
+ retval = egg_desktop_file;
+ G_UNLOCK (egg_desktop_file);
+
+ return retval;
+}
diff --git a/src/eggdesktopfile.h b/src/eggdesktopfile.h
new file mode 100644
index 0000000..17bd96e
--- /dev/null
+++ b/src/eggdesktopfile.h
@@ -0,0 +1,160 @@
+/* eggdesktopfile.h - Freedesktop.Org Desktop Files
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public License
+ * as published by the Free Software Foundation; either version 3 of
+ * the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place -
+ * Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_DESKTOP_FILE_H__
+#define __EGG_DESKTOP_FILE_H__
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct EggDesktopFile EggDesktopFile;
+
+typedef enum {
+ EGG_DESKTOP_FILE_TYPE_UNRECOGNIZED,
+
+ EGG_DESKTOP_FILE_TYPE_APPLICATION,
+ EGG_DESKTOP_FILE_TYPE_LINK,
+ EGG_DESKTOP_FILE_TYPE_DIRECTORY
+} EggDesktopFileType;
+
+EggDesktopFile *egg_desktop_file_new (const char *desktop_file_path,
+ GError **error);
+
+EggDesktopFile *egg_desktop_file_new_from_data_dirs (const char *desktop_file_path,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_dirs (const char *desktop_file_path,
+ const char **search_dirs,
+ GError **error);
+EggDesktopFile *egg_desktop_file_new_from_key_file (GKeyFile *key_file,
+ const char *source,
+ GError **error);
+
+void egg_desktop_file_free (EggDesktopFile *desktop_file);
+
+const char *egg_desktop_file_get_source (EggDesktopFile *desktop_file);
+
+EggDesktopFileType egg_desktop_file_get_desktop_file_type (EggDesktopFile *desktop_file);
+
+const char *egg_desktop_file_get_name (EggDesktopFile *desktop_file);
+const char *egg_desktop_file_get_icon (EggDesktopFile *desktop_file);
+
+gboolean egg_desktop_file_can_launch (EggDesktopFile *desktop_file,
+ const char *desktop_environment);
+
+gboolean egg_desktop_file_accepts_documents (EggDesktopFile *desktop_file);
+gboolean egg_desktop_file_accepts_multiple (EggDesktopFile *desktop_file);
+gboolean egg_desktop_file_accepts_uris (EggDesktopFile *desktop_file);
+
+char *egg_desktop_file_parse_exec (EggDesktopFile *desktop_file,
+ GSList *documents,
+ GError **error);
+
+gboolean egg_desktop_file_launch (EggDesktopFile *desktop_file,
+ GSList *documents,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+typedef enum {
+ EGG_DESKTOP_FILE_LAUNCH_CLEARENV = 1,
+ EGG_DESKTOP_FILE_LAUNCH_PUTENV,
+ EGG_DESKTOP_FILE_LAUNCH_SCREEN,
+ EGG_DESKTOP_FILE_LAUNCH_WORKSPACE,
+ EGG_DESKTOP_FILE_LAUNCH_DIRECTORY,
+ EGG_DESKTOP_FILE_LAUNCH_TIME,
+ EGG_DESKTOP_FILE_LAUNCH_FLAGS,
+ EGG_DESKTOP_FILE_LAUNCH_SETUP_FUNC,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_PID,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_STDIN_PIPE,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_STDOUT_PIPE,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_STDERR_PIPE,
+ EGG_DESKTOP_FILE_LAUNCH_RETURN_STARTUP_ID
+} EggDesktopFileLaunchOption;
+
+/* Standard Keys */
+#define EGG_DESKTOP_FILE_GROUP "Desktop Entry"
+
+#define EGG_DESKTOP_FILE_KEY_TYPE "Type"
+#define EGG_DESKTOP_FILE_KEY_VERSION "Version"
+#define EGG_DESKTOP_FILE_KEY_NAME "Name"
+#define EGG_DESKTOP_FILE_KEY_GENERIC_NAME "GenericName"
+#define EGG_DESKTOP_FILE_KEY_NO_DISPLAY "NoDisplay"
+#define EGG_DESKTOP_FILE_KEY_COMMENT "Comment"
+#define EGG_DESKTOP_FILE_KEY_ICON "Icon"
+#define EGG_DESKTOP_FILE_KEY_HIDDEN "Hidden"
+#define EGG_DESKTOP_FILE_KEY_ONLY_SHOW_IN "OnlyShowIn"
+#define EGG_DESKTOP_FILE_KEY_NOT_SHOW_IN "NotShowIn"
+#define EGG_DESKTOP_FILE_KEY_TRY_EXEC "TryExec"
+#define EGG_DESKTOP_FILE_KEY_EXEC "Exec"
+#define EGG_DESKTOP_FILE_KEY_PATH "Path"
+#define EGG_DESKTOP_FILE_KEY_TERMINAL "Terminal"
+#define EGG_DESKTOP_FILE_KEY_MIME_TYPE "MimeType"
+#define EGG_DESKTOP_FILE_KEY_CATEGORIES "Categories"
+#define EGG_DESKTOP_FILE_KEY_STARTUP_NOTIFY "StartupNotify"
+#define EGG_DESKTOP_FILE_KEY_STARTUP_WM_CLASS "StartupWMClass"
+#define EGG_DESKTOP_FILE_KEY_URL "URL"
+
+/* Accessors */
+gboolean egg_desktop_file_has_key (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char *egg_desktop_file_get_string (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error) G_GNUC_MALLOC;
+char *egg_desktop_file_get_locale_string (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ GError **error) G_GNUC_MALLOC;
+gboolean egg_desktop_file_get_boolean (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+double egg_desktop_file_get_numeric (EggDesktopFile *desktop_file,
+ const char *key,
+ GError **error);
+char **egg_desktop_file_get_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+char **egg_desktop_file_get_locale_string_list (EggDesktopFile *desktop_file,
+ const char *key,
+ const char *locale,
+ gsize *length,
+ GError **error) G_GNUC_MALLOC;
+
+
+/* Errors */
+#define EGG_DESKTOP_FILE_ERROR egg_desktop_file_error_quark()
+
+GQuark egg_desktop_file_error_quark (void);
+
+typedef enum {
+ EGG_DESKTOP_FILE_ERROR_INVALID,
+ EGG_DESKTOP_FILE_ERROR_NOT_LAUNCHABLE,
+ EGG_DESKTOP_FILE_ERROR_UNRECOGNIZED_OPTION
+} EggDesktopFileError;
+
+/* Global application desktop file */
+void egg_set_desktop_file (const char *desktop_file_path);
+void egg_set_desktop_file_without_defaults (const char *desktop_file_path);
+EggDesktopFile *egg_get_desktop_file (void);
+
+
+G_END_DECLS
+
+#endif /* __EGG_DESKTOP_FILE_H__ */
diff --git a/src/eggshell.c b/src/eggshell.c
new file mode 100644
index 0000000..ff4d2ce
--- /dev/null
+++ b/src/eggshell.c
@@ -0,0 +1,114 @@
+/*
+ * 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 Mate Library.
+ *
+ * The Mate Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * The Mate Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Mate Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+/*
+ *
+ * Mate utility routines.
+ * (C) 1997, 1998, 1999 the Free Software Foundation.
+ *
+ * Author: Miguel de Icaza,
+ */
+
+#include <config.h>
+
+#include "eggshell.h"
+
+#include <stdlib.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#ifndef G_OS_WIN32
+#include <pwd.h>
+#endif
+
+#include <glib.h>
+
+/**
+ * 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..a4d4c4b
--- /dev/null
+++ b/src/eggshell.h
@@ -0,0 +1,40 @@
+/*
+ * 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 Mate Library.
+ *
+ * The Mate Library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public License as
+ * published by the Free Software Foundation; either version 3 of the
+ * License, or (at your option) any later version.
+ *
+ * The Mate Library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with the Mate Library; see the file COPYING.LIB. If not,
+ * write to the Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+/*
+ @NOTATION@
+ */
+
+#ifndef __EGG_USER_SHELL_H__
+#define __EGG_USER_SHELL_H__
+
+#include <stdlib.h>
+#include <glib.h>
+
+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/eggsmclient-osx.c b/src/eggsmclient-osx.c
new file mode 100644
index 0000000..e6fa376
--- /dev/null
+++ b/src/eggsmclient-osx.c
@@ -0,0 +1,235 @@
+/*
+ * Copyright (C) 2007 Novell, Inc.
+ * Copyright (C) 2008 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* EggSMClientOSX
+ *
+ * For details on the OS X logout process, see:
+ * http://developer.apple.com/documentation/MacOSX/Conceptual/BPSystemStartup/Articles/BootProcess.html#//apple_ref/doc/uid/20002130-114618
+ *
+ * EggSMClientOSX registers for the kAEQuitApplication AppleEvent; the
+ * handler we register (quit_requested()) will be invoked from inside
+ * the quartz event-handling code (specifically, from inside
+ * [NSApplication nextEventMatchingMask]) when an AppleEvent arrives.
+ * We use AESuspendTheCurrentEvent() and AEResumeTheCurrentEvent() to
+ * allow asynchronous / non-main-loop-reentering processing of the
+ * quit request. (These are part of the Carbon framework; it doesn't
+ * seem to be possible to handle AppleEvents asynchronously from
+ * Cocoa.)
+ */
+
+#include "config.h"
+
+#include "eggsmclient-private.h"
+#include <gdk/gdkquartz.h>
+#include <Carbon/Carbon.h>
+#include <CoreServices/CoreServices.h>
+
+#define EGG_TYPE_SM_CLIENT_OSX (egg_sm_client_osx_get_type ())
+#define EGG_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSX))
+#define EGG_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
+#define EGG_IS_SM_CLIENT_OSX(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_OSX))
+#define EGG_IS_SM_CLIENT_OSX_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_OSX))
+#define EGG_SM_CLIENT_OSX_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_OSX, EggSMClientOSXClass))
+
+typedef struct _EggSMClientOSX EggSMClientOSX;
+typedef struct _EggSMClientOSXClass EggSMClientOSXClass;
+
+struct _EggSMClientOSX {
+ EggSMClient parent;
+
+ AppleEvent quit_event, quit_reply;
+ gboolean quit_requested, quitting;
+};
+
+struct _EggSMClientOSXClass
+{
+ EggSMClientClass parent_class;
+
+};
+
+static void sm_client_osx_startup (EggSMClient *client,
+ const char *client_id);
+static void sm_client_osx_will_quit (EggSMClient *client,
+ gboolean will_quit);
+static gboolean sm_client_osx_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation);
+
+static pascal OSErr quit_requested (const AppleEvent *, AppleEvent *, long);
+
+G_DEFINE_TYPE (EggSMClientOSX, egg_sm_client_osx, EGG_TYPE_SM_CLIENT)
+
+static void
+egg_sm_client_osx_init (EggSMClientOSX *osx)
+{
+ ;
+}
+
+static void
+egg_sm_client_osx_class_init (EggSMClientOSXClass *klass)
+{
+ EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
+
+ sm_client_class->startup = sm_client_osx_startup;
+ sm_client_class->will_quit = sm_client_osx_will_quit;
+ sm_client_class->end_session = sm_client_osx_end_session;
+}
+
+EggSMClient *
+egg_sm_client_osx_new (void)
+{
+ return g_object_new (EGG_TYPE_SM_CLIENT_OSX, NULL);
+}
+
+static void
+sm_client_osx_startup (EggSMClient *client,
+ const char *client_id)
+{
+ AEInstallEventHandler (kCoreEventClass, kAEQuitApplication,
+ NewAEEventHandlerUPP (quit_requested),
+ (long)GPOINTER_TO_SIZE (client), false);
+}
+
+static gboolean
+idle_quit_requested (gpointer client)
+{
+ egg_sm_client_quit_requested (client);
+ return FALSE;
+}
+
+static pascal OSErr
+quit_requested (const AppleEvent *aevt, AppleEvent *reply, long refcon)
+{
+ EggSMClient *client = GSIZE_TO_POINTER ((gsize)refcon);
+ EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
+
+ g_return_val_if_fail (!osx->quit_requested, userCanceledErr);
+
+ /* FIXME AEInteractWithUser? */
+
+ osx->quit_requested = TRUE;
+ AEDuplicateDesc (aevt, &osx->quit_event);
+ AEDuplicateDesc (reply, &osx->quit_reply);
+ AESuspendTheCurrentEvent (aevt);
+
+ /* Don't emit the "quit_requested" signal immediately, since we're
+ * called from a weird point in the guts of gdkeventloop-quartz.c
+ */
+ g_idle_add (idle_quit_requested, client);
+ return noErr;
+}
+
+static pascal OSErr
+quit_requested_resumed (const AppleEvent *aevt, AppleEvent *reply, long refcon)
+{
+ EggSMClientOSX *osx = GSIZE_TO_POINTER ((gsize)refcon);
+
+ osx->quit_requested = FALSE;
+ return osx->quitting ? noErr : userCanceledErr;
+}
+
+static gboolean
+idle_will_quit (gpointer client)
+{
+ EggSMClientOSX *osx = (EggSMClientOSX *)client;
+
+ /* Resume the event with a new handler that will return a value to
+ * the system.
+ */
+ AEResumeTheCurrentEvent (&osx->quit_event, &osx->quit_reply,
+ NewAEEventHandlerUPP (quit_requested_resumed),
+ (long)GPOINTER_TO_SIZE (client));
+ AEDisposeDesc (&osx->quit_event);
+ AEDisposeDesc (&osx->quit_reply);
+
+ if (osx->quitting)
+ egg_sm_client_quit (client);
+ return FALSE;
+}
+
+static void
+sm_client_osx_will_quit (EggSMClient *client,
+ gboolean will_quit)
+{
+ EggSMClientOSX *osx = (EggSMClientOSX *)client;
+
+ g_return_if_fail (osx->quit_requested);
+
+ osx->quitting = will_quit;
+
+ /* Finish in an idle handler since the caller might have called
+ * egg_sm_client_will_quit() from inside the "quit_requested" signal
+ * handler, but may not expect the "quit" signal to arrive during
+ * the _will_quit() call.
+ */
+ g_idle_add (idle_will_quit, client);
+}
+
+static gboolean
+sm_client_osx_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation)
+{
+ static const ProcessSerialNumber loginwindow_psn = { 0, kSystemProcess };
+ AppleEvent event = { typeNull, NULL }, reply = { typeNull, NULL };
+ AEAddressDesc target;
+ AEEventID id;
+ OSErr err;
+
+ switch (style)
+ {
+ case EGG_SM_CLIENT_END_SESSION_DEFAULT:
+ case EGG_SM_CLIENT_LOGOUT:
+ id = request_confirmation ? kAELogOut : kAEReallyLogOut;
+ break;
+ case EGG_SM_CLIENT_REBOOT:
+ id = request_confirmation ? kAEShowRestartDialog : kAERestart;
+ break;
+ case EGG_SM_CLIENT_SHUTDOWN:
+ id = request_confirmation ? kAEShowShutdownDialog : kAEShutDown;
+ break;
+ }
+
+ err = AECreateDesc (typeProcessSerialNumber, &loginwindow_psn,
+ sizeof (loginwindow_psn), &target);
+ if (err != noErr)
+ {
+ g_warning ("Could not create descriptor for loginwindow: %d", err);
+ return FALSE;
+ }
+
+ err = AECreateAppleEvent (kCoreEventClass, id, &target,
+ kAutoGenerateReturnID, kAnyTransactionID,
+ &event);
+ AEDisposeDesc (&target);
+ if (err != noErr)
+ {
+ g_warning ("Could not create logout AppleEvent: %d", err);
+ return FALSE;
+ }
+
+ err = AESend (&event, &reply, kAENoReply, kAENormalPriority,
+ kAEDefaultTimeout, NULL, NULL);
+ AEDisposeDesc (&event);
+ if (err == noErr)
+ AEDisposeDesc (&reply);
+
+ return err == noErr;
+}
diff --git a/src/eggsmclient-private.h b/src/eggsmclient-private.h
new file mode 100644
index 0000000..d1e39cb
--- /dev/null
+++ b/src/eggsmclient-private.h
@@ -0,0 +1,53 @@
+/* eggsmclient-private.h
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_SM_CLIENT_PRIVATE_H__
+#define __EGG_SM_CLIENT_PRIVATE_H__
+
+#include <gdkconfig.h>
+#include "eggsmclient.h"
+
+G_BEGIN_DECLS
+
+GKeyFile *egg_sm_client_save_state (EggSMClient *client);
+void egg_sm_client_quit_requested (EggSMClient *client);
+void egg_sm_client_quit_cancelled (EggSMClient *client);
+void egg_sm_client_quit (EggSMClient *client);
+
+#if defined (GDK_WINDOWING_X11)
+# ifdef EGG_SM_CLIENT_BACKEND_XSMP
+GType egg_sm_client_xsmp_get_type (void);
+EggSMClient *egg_sm_client_xsmp_new (void);
+# endif
+# ifdef EGG_SM_CLIENT_BACKEND_DBUS
+GType egg_sm_client_dbus_get_type (void);
+EggSMClient *egg_sm_client_dbus_new (void);
+# endif
+#elif defined (GDK_WINDOWING_WIN32)
+GType egg_sm_client_win32_get_type (void);
+EggSMClient *egg_sm_client_win32_new (void);
+#elif defined (GDK_WINDOWING_QUARTZ)
+GType egg_sm_client_osx_get_type (void);
+EggSMClient *egg_sm_client_osx_new (void);
+#endif
+
+G_END_DECLS
+
+
+#endif /* __EGG_SM_CLIENT_PRIVATE_H__ */
diff --git a/src/eggsmclient-win32.c b/src/eggsmclient-win32.c
new file mode 100644
index 0000000..a762c6c
--- /dev/null
+++ b/src/eggsmclient-win32.c
@@ -0,0 +1,353 @@
+/*
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/* EggSMClientWin32
+ *
+ * For details on the Windows XP logout process, see:
+ * http://msdn.microsoft.com/en-us/library/aa376876.aspx.
+ *
+ * Vista adds some new APIs which EggSMClient does not make use of; see
+ * http://msdn.microsoft.com/en-us/library/ms700677(VS.85).aspx
+ *
+ * When shutting down, Windows sends every top-level window a
+ * WM_QUERYENDSESSION event, which the application must respond to
+ * synchronously, saying whether or not it will quit. To avoid main
+ * loop re-entrancy problems (and to avoid having to muck about too
+ * much with the guts of the gdk-win32 main loop), we watch for this
+ * event in a separate thread, which then signals the main thread and
+ * waits for the main thread to handle the event. Since we don't want
+ * to require g_thread_init() to be called, we do this all using
+ * Windows-specific thread methods.
+ *
+ * After the application handles the WM_QUERYENDSESSION event,
+ * Windows then sends it a WM_ENDSESSION event with a TRUE or FALSE
+ * parameter indicating whether the session is or is not actually
+ * going to end now. We handle this from the other thread as well.
+ *
+ * As mentioned above, Vista introduces several additional new APIs
+ * that don't fit into the (current) EggSMClient API. Windows also has
+ * an entirely separate shutdown-notification scheme for non-GUI apps,
+ * which we also don't handle here.
+ */
+
+#include "config.h"
+
+#include "eggsmclient-private.h"
+#include <gdk/gdk.h>
+
+#define WIN32_LEAN_AND_MEAN
+#define UNICODE
+#include <windows.h>
+#include <process.h>
+
+#define EGG_TYPE_SM_CLIENT_WIN32 (egg_sm_client_win32_get_type ())
+#define EGG_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32))
+#define EGG_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
+#define EGG_IS_SM_CLIENT_WIN32(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_WIN32))
+#define EGG_IS_SM_CLIENT_WIN32_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_WIN32))
+#define EGG_SM_CLIENT_WIN32_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_WIN32, EggSMClientWin32Class))
+
+typedef struct _EggSMClientWin32 EggSMClientWin32;
+typedef struct _EggSMClientWin32Class EggSMClientWin32Class;
+
+struct _EggSMClientWin32 {
+ EggSMClient parent;
+
+ HANDLE message_event, response_event;
+
+ volatile GSourceFunc event;
+ volatile gboolean will_quit;
+};
+
+struct _EggSMClientWin32Class
+{
+ EggSMClientClass parent_class;
+
+};
+
+static void sm_client_win32_startup (EggSMClient *client,
+ const char *client_id);
+static void sm_client_win32_will_quit (EggSMClient *client,
+ gboolean will_quit);
+static gboolean sm_client_win32_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation);
+
+static GSource *g_win32_handle_source_add (HANDLE handle, GSourceFunc callback,
+ gpointer user_data);
+static gboolean got_message (gpointer user_data);
+static void sm_client_thread (gpointer data);
+
+G_DEFINE_TYPE (EggSMClientWin32, egg_sm_client_win32, EGG_TYPE_SM_CLIENT)
+
+static void
+egg_sm_client_win32_init (EggSMClientWin32 *win32)
+{
+ ;
+}
+
+static void
+egg_sm_client_win32_class_init (EggSMClientWin32Class *klass)
+{
+ EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
+
+ sm_client_class->startup = sm_client_win32_startup;
+ sm_client_class->will_quit = sm_client_win32_will_quit;
+ sm_client_class->end_session = sm_client_win32_end_session;
+}
+
+EggSMClient *
+egg_sm_client_win32_new (void)
+{
+ return g_object_new (EGG_TYPE_SM_CLIENT_WIN32, NULL);
+}
+
+static void
+sm_client_win32_startup (EggSMClient *client,
+ const char *client_id)
+{
+ EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
+
+ win32->message_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ win32->response_event = CreateEvent (NULL, FALSE, FALSE, NULL);
+ g_win32_handle_source_add (win32->message_event, got_message, win32);
+ _beginthread (sm_client_thread, 0, client);
+}
+
+static void
+sm_client_win32_will_quit (EggSMClient *client,
+ gboolean will_quit)
+{
+ EggSMClientWin32 *win32 = (EggSMClientWin32 *)client;
+
+ win32->will_quit = will_quit;
+ SetEvent (win32->response_event);
+}
+
+static gboolean
+sm_client_win32_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation)
+{
+ UINT uFlags = EWX_LOGOFF;
+
+ switch (style)
+ {
+ case EGG_SM_CLIENT_END_SESSION_DEFAULT:
+ case EGG_SM_CLIENT_LOGOUT:
+ uFlags = EWX_LOGOFF;
+ break;
+ case EGG_SM_CLIENT_REBOOT:
+ uFlags = EWX_REBOOT;
+ break;
+ case EGG_SM_CLIENT_SHUTDOWN:
+ uFlags = EWX_POWEROFF;
+ break;
+ }
+
+ /* There's no way to make ExitWindowsEx() show a logout dialog, so
+ * we ignore @request_confirmation.
+ */
+
+#ifdef SHTDN_REASON_FLAG_PLANNED
+ ExitWindowsEx (uFlags, SHTDN_REASON_FLAG_PLANNED);
+#else
+ ExitWindowsEx (uFlags, 0);
+#endif
+
+ return TRUE;
+}
+
+
+/* callbacks from logout-listener thread */
+
+static gboolean
+emit_quit_requested (gpointer smclient)
+{
+ gdk_threads_enter ();
+ egg_sm_client_quit_requested (smclient);
+ gdk_threads_leave ();
+
+ return FALSE;
+}
+
+static gboolean
+emit_quit (gpointer smclient)
+{
+ EggSMClientWin32 *win32 = smclient;
+
+ gdk_threads_enter ();
+ egg_sm_client_quit (smclient);
+ gdk_threads_leave ();
+
+ SetEvent (win32->response_event);
+ return FALSE;
+}
+
+static gboolean
+emit_quit_cancelled (gpointer smclient)
+{
+ EggSMClientWin32 *win32 = smclient;
+
+ gdk_threads_enter ();
+ egg_sm_client_quit_cancelled (smclient);
+ gdk_threads_leave ();
+
+ SetEvent (win32->response_event);
+ return FALSE;
+}
+
+static gboolean
+got_message (gpointer smclient)
+{
+ EggSMClientWin32 *win32 = smclient;
+
+ win32->event (win32);
+ return TRUE;
+}
+
+/* Windows HANDLE GSource */
+
+typedef struct {
+ GSource source;
+ GPollFD pollfd;
+} GWin32HandleSource;
+
+static gboolean
+g_win32_handle_source_prepare (GSource *source, gint *timeout)
+{
+ *timeout = -1;
+ return FALSE;
+}
+
+static gboolean
+g_win32_handle_source_check (GSource *source)
+{
+ GWin32HandleSource *hsource = (GWin32HandleSource *)source;
+
+ return hsource->pollfd.revents;
+}
+
+static gboolean
+g_win32_handle_source_dispatch (GSource *source, GSourceFunc callback, gpointer user_data)
+{
+ return (*callback) (user_data);
+}
+
+static void
+g_win32_handle_source_finalize (GSource *source)
+{
+ ;
+}
+
+GSourceFuncs g_win32_handle_source_funcs = {
+ g_win32_handle_source_prepare,
+ g_win32_handle_source_check,
+ g_win32_handle_source_dispatch,
+ g_win32_handle_source_finalize
+};
+
+static GSource *
+g_win32_handle_source_add (HANDLE handle, GSourceFunc callback, gpointer user_data)
+{
+ GWin32HandleSource *hsource;
+ GSource *source;
+
+ source = g_source_new (&g_win32_handle_source_funcs, sizeof (GWin32HandleSource));
+ hsource = (GWin32HandleSource *)source;
+ hsource->pollfd.fd = (int)handle;
+ hsource->pollfd.events = G_IO_IN;
+ hsource->pollfd.revents = 0;
+ g_source_add_poll (source, &hsource->pollfd);
+
+ g_source_set_callback (source, callback, user_data, NULL);
+ g_source_attach (source, NULL);
+ return source;
+}
+
+/* logout-listener thread */
+
+LRESULT CALLBACK
+sm_client_win32_window_procedure (HWND hwnd,
+ UINT message,
+ WPARAM wParam,
+ LPARAM lParam)
+{
+ EggSMClientWin32 *win32 =
+ (EggSMClientWin32 *)GetWindowLongPtr (hwnd, GWLP_USERDATA);
+
+ switch (message)
+ {
+ case WM_QUERYENDSESSION:
+ win32->event = emit_quit_requested;
+ SetEvent (win32->message_event);
+
+ WaitForSingleObject (win32->response_event, INFINITE);
+ return win32->will_quit;
+
+ case WM_ENDSESSION:
+ if (wParam)
+ {
+ /* The session is ending */
+ win32->event = emit_quit;
+ }
+ else
+ {
+ /* Nope, the session *isn't* ending */
+ win32->event = emit_quit_cancelled;
+ }
+
+ SetEvent (win32->message_event);
+ WaitForSingleObject (win32->response_event, INFINITE);
+
+ return 0;
+
+ default:
+ return DefWindowProc (hwnd, message, wParam, lParam);
+ }
+}
+
+static void
+sm_client_thread (gpointer smclient)
+{
+ HINSTANCE instance;
+ WNDCLASSEXW wcl;
+ ATOM klass;
+ HWND window;
+ MSG msg;
+
+ instance = GetModuleHandle (NULL);
+
+ memset (&wcl, 0, sizeof (WNDCLASSEX));
+ wcl.cbSize = sizeof (WNDCLASSEX);
+ wcl.lpfnWndProc = sm_client_win32_window_procedure;
+ wcl.hInstance = instance;
+ wcl.lpszClassName = L"EggSmClientWindow";
+ klass = RegisterClassEx (&wcl);
+
+ window = CreateWindowEx (0, MAKEINTRESOURCE (klass),
+ L"EggSmClientWindow", 0,
+ 10, 10, 50, 50, GetDesktopWindow (),
+ NULL, instance, NULL);
+ SetWindowLongPtr (window, GWLP_USERDATA, (LONG_PTR)smclient);
+
+ /* main loop */
+ while (GetMessage (&msg, NULL, 0, 0))
+ DispatchMessage (&msg);
+}
diff --git a/src/eggsmclient-xsmp.c b/src/eggsmclient-xsmp.c
new file mode 100644
index 0000000..9cf343b
--- /dev/null
+++ b/src/eggsmclient-xsmp.c
@@ -0,0 +1,1405 @@
+/*
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * Inspired by various other pieces of code including GsmClient (C)
+ * 2001 Havoc Pennington, MateClient (C) 1998 Carsten Schaar, and twm
+ * session code (C) 1998 The Open Group.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include "eggsmclient.h"
+#include "eggsmclient-private.h"
+
+#include "eggdesktopfile.h"
+
+#include <errno.h>
+#include <fcntl.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+#include <X11/SM/SMlib.h>
+
+#include <gdk/gdk.h>
+
+#define EGG_TYPE_SM_CLIENT_XSMP (egg_sm_client_xsmp_get_type ())
+#define EGG_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMP))
+#define EGG_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass))
+#define EGG_IS_SM_CLIENT_XSMP(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT_XSMP))
+#define EGG_IS_SM_CLIENT_XSMP_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT_XSMP))
+#define EGG_SM_CLIENT_XSMP_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT_XSMP, EggSMClientXSMPClass))
+
+typedef struct _EggSMClientXSMP EggSMClientXSMP;
+typedef struct _EggSMClientXSMPClass EggSMClientXSMPClass;
+
+/* These mostly correspond to the similarly-named states in section
+ * 9.1 of the XSMP spec. Some of the states there aren't represented
+ * here, because we don't need them. SHUTDOWN_CANCELLED is slightly
+ * different from the spec; we use it when the client is IDLE after a
+ * ShutdownCancelled message, but the application is still interacting
+ * and doesn't know the shutdown has been cancelled yet.
+ */
+typedef enum
+{
+ XSMP_STATE_IDLE,
+ XSMP_STATE_SAVE_YOURSELF,
+ XSMP_STATE_INTERACT_REQUEST,
+ XSMP_STATE_INTERACT,
+ XSMP_STATE_SAVE_YOURSELF_DONE,
+ XSMP_STATE_SHUTDOWN_CANCELLED,
+ XSMP_STATE_CONNECTION_CLOSED
+} EggSMClientXSMPState;
+
+static const char *state_names[] = {
+ "idle",
+ "save-yourself",
+ "interact-request",
+ "interact",
+ "save-yourself-done",
+ "shutdown-cancelled",
+ "connection-closed"
+};
+
+#define EGG_SM_CLIENT_XSMP_STATE(xsmp) (state_names[(xsmp)->state])
+
+struct _EggSMClientXSMP
+{
+ EggSMClient parent;
+
+ SmcConn connection;
+ char *client_id;
+
+ EggSMClientXSMPState state;
+ char **restart_command;
+ gboolean set_restart_command;
+ int restart_style;
+ char **discard_command;
+ gboolean set_discard_command;
+
+ guint idle;
+
+ /* Current SaveYourself state */
+ guint expecting_initial_save_yourself : 1;
+ guint need_save_state : 1;
+ guint need_quit_requested : 1;
+ guint interact_errors : 1;
+ guint shutting_down : 1;
+
+ /* Todo list */
+ guint waiting_to_set_initial_properties : 1;
+ guint waiting_to_emit_quit : 1;
+ guint waiting_to_emit_quit_cancelled : 1;
+ guint waiting_to_save_myself : 1;
+
+};
+
+struct _EggSMClientXSMPClass
+{
+ EggSMClientClass parent_class;
+
+};
+
+static void sm_client_xsmp_startup (EggSMClient *client,
+ const char *client_id);
+static void sm_client_xsmp_set_restart_command (EggSMClient *client,
+ int argc,
+ const char **argv);
+static void sm_client_xsmp_set_discard_command (EggSMClient *client,
+ int argc,
+ const char **argv);
+static void sm_client_xsmp_will_quit (EggSMClient *client,
+ gboolean will_quit);
+static gboolean sm_client_xsmp_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation);
+
+static void xsmp_save_yourself (SmcConn smc_conn,
+ SmPointer client_data,
+ int save_style,
+ Bool shutdown,
+ int interact_style,
+ Bool fast);
+static void xsmp_die (SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_save_complete (SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_shutdown_cancelled (SmcConn smc_conn,
+ SmPointer client_data);
+static void xsmp_interact (SmcConn smc_conn,
+ SmPointer client_data);
+
+static SmProp *array_prop (const char *name,
+ ...);
+static SmProp *ptrarray_prop (const char *name,
+ GPtrArray *values);
+static SmProp *string_prop (const char *name,
+ const char *value);
+static SmProp *card8_prop (const char *name,
+ unsigned char value);
+
+static void set_properties (EggSMClientXSMP *xsmp, ...);
+static void delete_properties (EggSMClientXSMP *xsmp, ...);
+
+static GPtrArray *generate_command (char **argv,
+ const char *client_id,
+ const char *state_file);
+
+static void save_state (EggSMClientXSMP *xsmp);
+static void do_save_yourself (EggSMClientXSMP *xsmp);
+static void update_pending_events (EggSMClientXSMP *xsmp);
+
+static void ice_init (void);
+static gboolean process_ice_messages (IceConn ice_conn);
+static void smc_error_handler (SmcConn smc_conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence,
+ int error_class,
+ int severity,
+ SmPointer values);
+
+G_DEFINE_TYPE (EggSMClientXSMP, egg_sm_client_xsmp, EGG_TYPE_SM_CLIENT)
+
+static void
+egg_sm_client_xsmp_init (EggSMClientXSMP *xsmp)
+{
+ xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
+ xsmp->connection = NULL;
+ xsmp->restart_style = SmRestartIfRunning;
+}
+
+static void
+egg_sm_client_xsmp_class_init (EggSMClientXSMPClass *klass)
+{
+ EggSMClientClass *sm_client_class = EGG_SM_CLIENT_CLASS (klass);
+
+ sm_client_class->startup = sm_client_xsmp_startup;
+ sm_client_class->set_restart_command = sm_client_xsmp_set_restart_command;
+ sm_client_class->set_discard_command = sm_client_xsmp_set_discard_command;
+ sm_client_class->will_quit = sm_client_xsmp_will_quit;
+ sm_client_class->end_session = sm_client_xsmp_end_session;
+}
+
+EggSMClient *
+egg_sm_client_xsmp_new (void)
+{
+ if (!g_getenv ("SESSION_MANAGER"))
+ return NULL;
+
+ return g_object_new (EGG_TYPE_SM_CLIENT_XSMP, NULL);
+}
+
+static gboolean
+sm_client_xsmp_set_initial_properties (gpointer user_data)
+{
+ EggSMClientXSMP *xsmp = user_data;
+ EggDesktopFile *desktop_file;
+ GPtrArray *clone, *restart;
+ char pid_str[64];
+
+ if (xsmp->idle)
+ {
+ g_source_remove (xsmp->idle);
+ xsmp->idle = 0;
+ }
+ xsmp->waiting_to_set_initial_properties = FALSE;
+
+ if (egg_sm_client_get_mode () == EGG_SM_CLIENT_MODE_NO_RESTART)
+ xsmp->restart_style = SmRestartNever;
+
+ /* Parse info out of desktop file */
+ desktop_file = egg_get_desktop_file ();
+ if (desktop_file)
+ {
+ GError *err = NULL;
+ char *cmdline, **argv;
+ int argc;
+
+ if (xsmp->restart_style == SmRestartIfRunning)
+ {
+ if (egg_desktop_file_get_boolean (desktop_file,
+ "X-MATE-AutoRestart", NULL))
+ xsmp->restart_style = SmRestartImmediately;
+ }
+
+ if (!xsmp->set_restart_command)
+ {
+ cmdline = egg_desktop_file_parse_exec (desktop_file, NULL, &err);
+ if (cmdline && g_shell_parse_argv (cmdline, &argc, &argv, &err))
+ {
+ egg_sm_client_set_restart_command (EGG_SM_CLIENT (xsmp),
+ argc, (const char **)argv);
+ g_strfreev (argv);
+ }
+ else
+ {
+ g_warning ("Could not parse Exec line in desktop file: %s",
+ err->message);
+ g_error_free (err);
+ }
+ g_free (cmdline);
+ }
+ }
+
+ if (!xsmp->set_restart_command)
+ xsmp->restart_command = g_strsplit (g_get_prgname (), " ", -1);
+
+ clone = generate_command (xsmp->restart_command, NULL, NULL);
+ restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL);
+
+ g_debug ("Setting initial properties");
+
+ /* Program, CloneCommand, RestartCommand, and UserID are required.
+ * ProcessID isn't required, but the SM may be able to do something
+ * useful with it.
+ */
+ g_snprintf (pid_str, sizeof (pid_str), "%lu", (gulong) getpid ());
+ set_properties (xsmp,
+ string_prop (SmProgram, g_get_prgname ()),
+ ptrarray_prop (SmCloneCommand, clone),
+ ptrarray_prop (SmRestartCommand, restart),
+ string_prop (SmUserID, g_get_user_name ()),
+ string_prop (SmProcessID, pid_str),
+ card8_prop (SmRestartStyleHint, xsmp->restart_style),
+ NULL);
+ g_ptr_array_free (clone, TRUE);
+ g_ptr_array_free (restart, TRUE);
+
+ if (desktop_file)
+ {
+ set_properties (xsmp,
+ string_prop ("_GSM_DesktopFile", egg_desktop_file_get_source (desktop_file)),
+ NULL);
+ }
+
+ update_pending_events (xsmp);
+ return FALSE;
+}
+
+/* This gets called from two different places: xsmp_die() (when the
+ * server asks us to disconnect) and process_ice_messages() (when the
+ * server disconnects unexpectedly).
+ */
+static void
+sm_client_xsmp_disconnect (EggSMClientXSMP *xsmp)
+{
+ SmcConn connection;
+
+ if (!xsmp->connection)
+ return;
+
+ g_debug ("Disconnecting");
+
+ connection = xsmp->connection;
+ xsmp->connection = NULL;
+ SmcCloseConnection (connection, 0, NULL);
+ xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
+
+ xsmp->waiting_to_save_myself = FALSE;
+ update_pending_events (xsmp);
+}
+
+static void
+sm_client_xsmp_startup (EggSMClient *client,
+ const char *client_id)
+{
+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
+ SmcCallbacks callbacks;
+ char *ret_client_id;
+ char error_string_ret[256];
+
+ xsmp->client_id = g_strdup (client_id);
+
+ ice_init ();
+ SmcSetErrorHandler (smc_error_handler);
+
+ callbacks.save_yourself.callback = xsmp_save_yourself;
+ callbacks.die.callback = xsmp_die;
+ callbacks.save_complete.callback = xsmp_save_complete;
+ callbacks.shutdown_cancelled.callback = xsmp_shutdown_cancelled;
+
+ callbacks.save_yourself.client_data = xsmp;
+ callbacks.die.client_data = xsmp;
+ callbacks.save_complete.client_data = xsmp;
+ callbacks.shutdown_cancelled.client_data = xsmp;
+
+ client_id = NULL;
+ error_string_ret[0] = '\0';
+ xsmp->connection =
+ SmcOpenConnection (NULL, xsmp, SmProtoMajor, SmProtoMinor,
+ SmcSaveYourselfProcMask | SmcDieProcMask |
+ SmcSaveCompleteProcMask |
+ SmcShutdownCancelledProcMask,
+ &callbacks,
+ xsmp->client_id, &ret_client_id,
+ sizeof (error_string_ret), error_string_ret);
+
+ if (!xsmp->connection)
+ {
+ g_warning ("Failed to connect to the session manager: %s\n",
+ error_string_ret[0] ?
+ error_string_ret : "no error message given");
+ xsmp->state = XSMP_STATE_CONNECTION_CLOSED;
+ return;
+ }
+
+ /* We expect a pointless initial SaveYourself if either (a) we
+ * didn't have an initial client ID, or (b) we DID have an initial
+ * client ID, but the server rejected it and gave us a new one.
+ */
+ if (!xsmp->client_id ||
+ (ret_client_id && strcmp (xsmp->client_id, ret_client_id) != 0))
+ xsmp->expecting_initial_save_yourself = TRUE;
+
+ if (ret_client_id)
+ {
+ g_free (xsmp->client_id);
+ xsmp->client_id = g_strdup (ret_client_id);
+ free (ret_client_id);
+
+ gdk_threads_enter ();
+ gdk_set_sm_client_id (xsmp->client_id);
+ gdk_threads_leave ();
+
+ g_debug ("Got client ID \"%s\"", xsmp->client_id);
+ }
+
+ xsmp->state = XSMP_STATE_IDLE;
+
+ /* Do not set the initial properties until we reach the main loop,
+ * so that the application has a chance to call
+ * egg_set_desktop_file(). (This may also help the session manager
+ * have a better idea of when the application is fully up and
+ * running.)
+ */
+ xsmp->waiting_to_set_initial_properties = TRUE;
+ xsmp->idle = g_idle_add (sm_client_xsmp_set_initial_properties, client);
+}
+
+static void
+sm_client_xsmp_set_restart_command (EggSMClient *client,
+ int argc,
+ const char **argv)
+{
+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
+ int i;
+
+ g_strfreev (xsmp->restart_command);
+
+ xsmp->restart_command = g_new (char *, argc + 1);
+ for (i = 0; i < argc; i++)
+ xsmp->restart_command[i] = g_strdup (argv[i]);
+ xsmp->restart_command[i] = NULL;
+
+ xsmp->set_restart_command = TRUE;
+}
+
+static void
+sm_client_xsmp_set_discard_command (EggSMClient *client,
+ int argc,
+ const char **argv)
+{
+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
+ int i;
+
+ g_strfreev (xsmp->discard_command);
+
+ xsmp->discard_command = g_new (char *, argc + 1);
+ for (i = 0; i < argc; i++)
+ xsmp->discard_command[i] = g_strdup (argv[i]);
+ xsmp->discard_command[i] = NULL;
+
+ xsmp->set_discard_command = TRUE;
+}
+
+static void
+sm_client_xsmp_will_quit (EggSMClient *client,
+ gboolean will_quit)
+{
+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
+
+ if (xsmp->state == XSMP_STATE_CONNECTION_CLOSED)
+ {
+ /* The session manager has already exited! Schedule a quit
+ * signal.
+ */
+ xsmp->waiting_to_emit_quit = TRUE;
+ update_pending_events (xsmp);
+ return;
+ }
+ else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
+ {
+ /* We received a ShutdownCancelled message while the application
+ * was interacting; Schedule a quit_cancelled signal.
+ */
+ xsmp->waiting_to_emit_quit_cancelled = TRUE;
+ update_pending_events (xsmp);
+ return;
+ }
+
+ g_return_if_fail (xsmp->state == XSMP_STATE_INTERACT);
+
+ g_debug ("Sending InteractDone(%s)", will_quit ? "False" : "True");
+ SmcInteractDone (xsmp->connection, !will_quit);
+
+ if (will_quit && xsmp->need_save_state)
+ save_state (xsmp);
+
+ g_debug ("Sending SaveYourselfDone(%s)", will_quit ? "True" : "False");
+ SmcSaveYourselfDone (xsmp->connection, will_quit);
+ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
+}
+
+static gboolean
+sm_client_xsmp_end_session (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation)
+{
+ EggSMClientXSMP *xsmp = (EggSMClientXSMP *)client;
+ int save_type;
+
+ /* To end the session via XSMP, we have to send a
+ * SaveYourselfRequest. We aren't allowed to do that if anything
+ * else is going on, but we don't want to expose this fact to the
+ * application. So we do our best to patch things up here...
+ *
+ * In the worst case, this method might block for some length of
+ * time in process_ice_messages, but the only time that code path is
+ * honestly likely to get hit is if the application tries to end the
+ * session as the very first thing it does, in which case it
+ * probably won't actually block anyway. It's not worth gunking up
+ * the API to try to deal nicely with the other 0.01% of cases where
+ * this happens.
+ */
+
+ while (xsmp->state != XSMP_STATE_IDLE ||
+ xsmp->expecting_initial_save_yourself)
+ {
+ /* If we're already shutting down, we don't need to do anything. */
+ if (xsmp->shutting_down)
+ return TRUE;
+
+ switch (xsmp->state)
+ {
+ case XSMP_STATE_CONNECTION_CLOSED:
+ return FALSE;
+
+ case XSMP_STATE_SAVE_YOURSELF:
+ /* Trying to log out from the save_state callback? Whatever.
+ * Abort the save_state.
+ */
+ SmcSaveYourselfDone (xsmp->connection, FALSE);
+ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
+ break;
+
+ case XSMP_STATE_INTERACT_REQUEST:
+ case XSMP_STATE_INTERACT:
+ case XSMP_STATE_SHUTDOWN_CANCELLED:
+ /* Already in a shutdown-related state, just ignore
+ * the new shutdown request...
+ */
+ return TRUE;
+
+ case XSMP_STATE_IDLE:
+ if (xsmp->waiting_to_set_initial_properties)
+ sm_client_xsmp_set_initial_properties (xsmp);
+
+ if (!xsmp->expecting_initial_save_yourself)
+ break;
+ /* else fall through */
+
+ case XSMP_STATE_SAVE_YOURSELF_DONE:
+ /* We need to wait for some response from the server.*/
+ process_ice_messages (SmcGetIceConnection (xsmp->connection));
+ break;
+
+ default:
+ /* Hm... shouldn't happen */
+ return FALSE;
+ }
+ }
+
+ /* xfce4-session will do the wrong thing if we pass SmSaveGlobal and
+ * the user chooses to save the session. But mate-session will do
+ * the wrong thing if we pass SmSaveBoth and the user chooses NOT to
+ * save the session... Sigh.
+ */
+ if (!strcmp (SmcVendor (xsmp->connection), "xfce4-session"))
+ save_type = SmSaveBoth;
+ else
+ save_type = SmSaveGlobal;
+
+ g_debug ("Sending SaveYourselfRequest(SmSaveGlobal, Shutdown, SmInteractStyleAny, %sFast)", request_confirmation ? "!" : "");
+ SmcRequestSaveYourself (xsmp->connection,
+ save_type,
+ True, /* shutdown */
+ SmInteractStyleAny,
+ !request_confirmation, /* fast */
+ True /* global */);
+ return TRUE;
+}
+
+static gboolean
+idle_do_pending_events (gpointer data)
+{
+ EggSMClientXSMP *xsmp = data;
+ EggSMClient *client = data;
+
+ gdk_threads_enter ();
+
+ xsmp->idle = 0;
+
+ if (xsmp->waiting_to_emit_quit)
+ {
+ xsmp->waiting_to_emit_quit = FALSE;
+ egg_sm_client_quit (client);
+ goto out;
+ }
+
+ if (xsmp->waiting_to_emit_quit_cancelled)
+ {
+ xsmp->waiting_to_emit_quit_cancelled = FALSE;
+ egg_sm_client_quit_cancelled (client);
+ xsmp->state = XSMP_STATE_IDLE;
+ }
+
+ if (xsmp->waiting_to_save_myself)
+ {
+ xsmp->waiting_to_save_myself = FALSE;
+ do_save_yourself (xsmp);
+ }
+
+ out:
+ gdk_threads_leave ();
+ return FALSE;
+}
+
+static void
+update_pending_events (EggSMClientXSMP *xsmp)
+{
+ gboolean want_idle =
+ xsmp->waiting_to_emit_quit ||
+ xsmp->waiting_to_emit_quit_cancelled ||
+ xsmp->waiting_to_save_myself;
+
+ if (want_idle)
+ {
+ if (xsmp->idle == 0)
+ xsmp->idle = g_idle_add (idle_do_pending_events, xsmp);
+ }
+ else
+ {
+ if (xsmp->idle != 0)
+ g_source_remove (xsmp->idle);
+ xsmp->idle = 0;
+ }
+}
+
+static void
+fix_broken_state (EggSMClientXSMP *xsmp, const char *message,
+ gboolean send_interact_done,
+ gboolean send_save_yourself_done)
+{
+ g_warning ("Received XSMP %s message in state %s: client or server error",
+ message, EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ /* Forget any pending SaveYourself plans we had */
+ xsmp->waiting_to_save_myself = FALSE;
+ update_pending_events (xsmp);
+
+ if (send_interact_done)
+ SmcInteractDone (xsmp->connection, False);
+ if (send_save_yourself_done)
+ SmcSaveYourselfDone (xsmp->connection, True);
+
+ xsmp->state = send_save_yourself_done ? XSMP_STATE_SAVE_YOURSELF_DONE : XSMP_STATE_IDLE;
+}
+
+/* SM callbacks */
+
+static void
+xsmp_save_yourself (SmcConn smc_conn,
+ SmPointer client_data,
+ int save_type,
+ Bool shutdown,
+ int interact_style,
+ Bool fast)
+{
+ EggSMClientXSMP *xsmp = client_data;
+ gboolean wants_quit_requested;
+
+ g_debug ("Received SaveYourself(%s, %s, %s, %s) in state %s",
+ save_type == SmSaveLocal ? "SmSaveLocal" :
+ save_type == SmSaveGlobal ? "SmSaveGlobal" : "SmSaveBoth",
+ shutdown ? "Shutdown" : "!Shutdown",
+ interact_style == SmInteractStyleAny ? "SmInteractStyleAny" :
+ interact_style == SmInteractStyleErrors ? "SmInteractStyleErrors" :
+ "SmInteractStyleNone", fast ? "Fast" : "!Fast",
+ EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ if (xsmp->state != XSMP_STATE_IDLE &&
+ xsmp->state != XSMP_STATE_SHUTDOWN_CANCELLED)
+ {
+ fix_broken_state (xsmp, "SaveYourself", FALSE, TRUE);
+ return;
+ }
+
+ if (xsmp->waiting_to_set_initial_properties)
+ sm_client_xsmp_set_initial_properties (xsmp);
+
+ /* If this is the initial SaveYourself, ignore it; we've already set
+ * properties and there's no reason to actually save state too.
+ */
+ if (xsmp->expecting_initial_save_yourself)
+ {
+ xsmp->expecting_initial_save_yourself = FALSE;
+
+ if (save_type == SmSaveLocal &&
+ interact_style == SmInteractStyleNone &&
+ !shutdown && !fast)
+ {
+ g_debug ("Sending SaveYourselfDone(True) for initial SaveYourself");
+ SmcSaveYourselfDone (xsmp->connection, True);
+ /* As explained in the comment at the end of
+ * do_save_yourself(), SAVE_YOURSELF_DONE is the correct
+ * state here, not IDLE.
+ */
+ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
+ return;
+ }
+ else
+ g_warning ("First SaveYourself was not the expected one!");
+ }
+
+ /* Even ignoring the "fast" flag completely, there are still 18
+ * different combinations of save_type, shutdown and interact_style.
+ * We interpret them as follows:
+ *
+ * Type Shutdown Interact Interpretation
+ * G F A/E/N do nothing (1)
+ * G T N do nothing (1)*
+ * G T A/E quit_requested (2)
+ * L/B F A/E/N save_state (3)
+ * L/B T N save_state (3)*
+ * L/B T A/E quit_requested, then save_state (4)
+ *
+ * 1. Do nothing, because the SM asked us to do something
+ * uninteresting (save open files, but then don't quit
+ * afterward) or rude (save open files without asking the user
+ * for confirmation).
+ *
+ * 2. Request interaction and then emit ::quit_requested. This
+ * perhaps isn't quite correct for the SmInteractStyleErrors
+ * case, but we don't care.
+ *
+ * 3. Emit ::save_state. The SmSaveBoth SaveYourselfs in these
+ * rows essentially get demoted to SmSaveLocal, because their
+ * Global halves correspond to "do nothing".
+ *
+ * 4. Request interaction, emit ::quit_requested, and then emit
+ * ::save_state after interacting. This is the SmSaveBoth
+ * equivalent of #2, but we also promote SmSaveLocal shutdown
+ * SaveYourselfs to SmSaveBoth here, because we want to give
+ * the user a chance to save open files before quitting.
+ *
+ * (* It would be nice if we could do something useful when the
+ * session manager sends a SaveYourself with shutdown True and
+ * SmInteractStyleNone. But we can't, so we just pretend it didn't
+ * even tell us it was shutting down. The docs for ::quit mention
+ * that it might not always be preceded by ::quit_requested.)
+ */
+
+ /* As an optimization, we don't actually request interaction and
+ * emit ::quit_requested if the application isn't listening to the
+ * signal.
+ */
+ wants_quit_requested = g_signal_has_handler_pending (xsmp, g_signal_lookup ("quit_requested", EGG_TYPE_SM_CLIENT), 0, FALSE);
+
+ xsmp->need_save_state = (save_type != SmSaveGlobal);
+ xsmp->need_quit_requested = (shutdown && wants_quit_requested &&
+ interact_style != SmInteractStyleNone);
+ xsmp->interact_errors = (interact_style == SmInteractStyleErrors);
+
+ xsmp->shutting_down = shutdown;
+
+ do_save_yourself (xsmp);
+}
+
+static void
+do_save_yourself (EggSMClientXSMP *xsmp)
+{
+ if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
+ {
+ /* The SM cancelled a previous SaveYourself, but we haven't yet
+ * had a chance to tell the application, so we can't start
+ * processing this SaveYourself yet.
+ */
+ xsmp->waiting_to_save_myself = TRUE;
+ update_pending_events (xsmp);
+ return;
+ }
+
+ if (xsmp->need_quit_requested)
+ {
+ xsmp->state = XSMP_STATE_INTERACT_REQUEST;
+
+ g_debug ("Sending InteractRequest(%s)",
+ xsmp->interact_errors ? "Error" : "Normal");
+ SmcInteractRequest (xsmp->connection,
+ xsmp->interact_errors ? SmDialogError : SmDialogNormal,
+ xsmp_interact,
+ xsmp);
+ return;
+ }
+
+ if (xsmp->need_save_state)
+ {
+ save_state (xsmp);
+
+ /* Though unlikely, the client could have been disconnected
+ * while the application was saving its state.
+ */
+ if (!xsmp->connection)
+ return;
+ }
+
+ g_debug ("Sending SaveYourselfDone(True)");
+ SmcSaveYourselfDone (xsmp->connection, True);
+
+ /* The client state diagram in the XSMP spec says that after a
+ * non-shutdown SaveYourself, we go directly back to "idle". But
+ * everything else in both the XSMP spec and the libSM docs
+ * disagrees.
+ */
+ xsmp->state = XSMP_STATE_SAVE_YOURSELF_DONE;
+}
+
+static void
+save_state (EggSMClientXSMP *xsmp)
+{
+ GKeyFile *state_file;
+ char *state_file_path, *data;
+ EggDesktopFile *desktop_file;
+ GPtrArray *restart, *discard;
+ int offset, fd;
+
+ /* We set xsmp->state before emitting save_state, but our caller is
+ * responsible for setting it back afterward.
+ */
+ xsmp->state = XSMP_STATE_SAVE_YOURSELF;
+
+ state_file = egg_sm_client_save_state ((EggSMClient *)xsmp);
+ if (!state_file)
+ {
+ restart = generate_command (xsmp->restart_command, xsmp->client_id, NULL);
+ set_properties (xsmp,
+ ptrarray_prop (SmRestartCommand, restart),
+ NULL);
+ g_ptr_array_free (restart, TRUE);
+
+ if (xsmp->set_discard_command)
+ {
+ discard = generate_command (xsmp->discard_command, NULL, NULL);
+ set_properties (xsmp,
+ ptrarray_prop (SmDiscardCommand, discard),
+ NULL);
+ g_ptr_array_free (discard, TRUE);
+ }
+ else
+ delete_properties (xsmp, SmDiscardCommand, NULL);
+
+ return;
+ }
+
+ desktop_file = egg_get_desktop_file ();
+ if (desktop_file)
+ {
+ GKeyFile *merged_file;
+ char *desktop_file_path;
+
+ merged_file = g_key_file_new ();
+ desktop_file_path =
+ g_filename_from_uri (egg_desktop_file_get_source (desktop_file),
+ NULL, NULL);
+ if (desktop_file_path &&
+ g_key_file_load_from_file (merged_file, desktop_file_path,
+ G_KEY_FILE_KEEP_COMMENTS |
+ G_KEY_FILE_KEEP_TRANSLATIONS, NULL))
+ {
+ guint g, k, i;
+ char **groups, **keys, *value, *exec;
+
+ groups = g_key_file_get_groups (state_file, NULL);
+ for (g = 0; groups[g]; g++)
+ {
+ keys = g_key_file_get_keys (state_file, groups[g], NULL, NULL);
+ for (k = 0; keys[k]; k++)
+ {
+ value = g_key_file_get_value (state_file, groups[g],
+ keys[k], NULL);
+ if (value)
+ {
+ g_key_file_set_value (merged_file, groups[g],
+ keys[k], value);
+ g_free (value);
+ }
+ }
+ g_strfreev (keys);
+ }
+ g_strfreev (groups);
+
+ g_key_file_free (state_file);
+ state_file = merged_file;
+
+ /* Update Exec key using "--sm-client-state-file %k" */
+ restart = generate_command (xsmp->restart_command,
+ NULL, "%k");
+ for (i = 0; i < restart->len; i++)
+ restart->pdata[i] = g_shell_quote (restart->pdata[i]);
+ g_ptr_array_add (restart, NULL);
+ exec = g_strjoinv (" ", (char **)restart->pdata);
+ g_strfreev ((char **)restart->pdata);
+ g_ptr_array_free (restart, FALSE);
+
+ g_key_file_set_string (state_file, EGG_DESKTOP_FILE_GROUP,
+ EGG_DESKTOP_FILE_KEY_EXEC,
+ exec);
+ g_free (exec);
+ }
+ else
+ desktop_file = NULL;
+
+ g_free (desktop_file_path);
+ }
+
+ /* Now write state_file to disk. (We can't use mktemp(), because
+ * that requires the filename to end with "XXXXXX", and we want
+ * it to end with ".desktop".)
+ */
+
+ data = g_key_file_to_data (state_file, NULL, NULL);
+ g_key_file_free (state_file);
+
+ offset = 0;
+ while (1)
+ {
+ state_file_path = g_strdup_printf ("%s%csession-state%c%s-%ld.%s",
+ g_get_user_config_dir (),
+ G_DIR_SEPARATOR, G_DIR_SEPARATOR,
+ g_get_prgname (),
+ (long)time (NULL) + offset,
+ desktop_file ? "desktop" : "state");
+
+ fd = open (state_file_path, O_WRONLY | O_CREAT | O_EXCL, 0644);
+ if (fd == -1)
+ {
+ if (errno == EEXIST)
+ {
+ offset++;
+ g_free (state_file_path);
+ continue;
+ }
+ else if (errno == ENOTDIR || errno == ENOENT)
+ {
+ char *sep = strrchr (state_file_path, G_DIR_SEPARATOR);
+
+ *sep = '\0';
+ if (g_mkdir_with_parents (state_file_path, 0755) != 0)
+ {
+ g_warning ("Could not create directory '%s'",
+ state_file_path);
+ g_free (state_file_path);
+ state_file_path = NULL;
+ break;
+ }
+
+ continue;
+ }
+
+ g_warning ("Could not create file '%s': %s",
+ state_file_path, g_strerror (errno));
+ g_free (state_file_path);
+ state_file_path = NULL;
+ break;
+ }
+
+ close (fd);
+ g_file_set_contents (state_file_path, data, -1, NULL);
+ break;
+ }
+ g_free (data);
+
+ restart = generate_command (xsmp->restart_command, xsmp->client_id,
+ state_file_path);
+ set_properties (xsmp,
+ ptrarray_prop (SmRestartCommand, restart),
+ NULL);
+ g_ptr_array_free (restart, TRUE);
+
+ if (state_file_path)
+ {
+ set_properties (xsmp,
+ array_prop (SmDiscardCommand,
+ "/bin/rm", "-rf", state_file_path,
+ NULL),
+ NULL);
+ g_free (state_file_path);
+ }
+}
+
+static void
+xsmp_interact (SmcConn smc_conn,
+ SmPointer client_data)
+{
+ EggSMClientXSMP *xsmp = client_data;
+ EggSMClient *client = client_data;
+
+ g_debug ("Received Interact message in state %s",
+ EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ if (xsmp->state != XSMP_STATE_INTERACT_REQUEST)
+ {
+ fix_broken_state (xsmp, "Interact", TRUE, TRUE);
+ return;
+ }
+
+ xsmp->state = XSMP_STATE_INTERACT;
+ egg_sm_client_quit_requested (client);
+}
+
+static void
+xsmp_die (SmcConn smc_conn,
+ SmPointer client_data)
+{
+ EggSMClientXSMP *xsmp = client_data;
+ EggSMClient *client = client_data;
+
+ g_debug ("Received Die message in state %s",
+ EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ sm_client_xsmp_disconnect (xsmp);
+ egg_sm_client_quit (client);
+}
+
+static void
+xsmp_save_complete (SmcConn smc_conn,
+ SmPointer client_data)
+{
+ EggSMClientXSMP *xsmp = client_data;
+
+ g_debug ("Received SaveComplete message in state %s",
+ EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
+ xsmp->state = XSMP_STATE_IDLE;
+ else
+ fix_broken_state (xsmp, "SaveComplete", FALSE, FALSE);
+}
+
+static void
+xsmp_shutdown_cancelled (SmcConn smc_conn,
+ SmPointer client_data)
+{
+ EggSMClientXSMP *xsmp = client_data;
+ EggSMClient *client = client_data;
+
+ g_debug ("Received ShutdownCancelled message in state %s",
+ EGG_SM_CLIENT_XSMP_STATE (xsmp));
+
+ xsmp->shutting_down = FALSE;
+
+ if (xsmp->state == XSMP_STATE_SAVE_YOURSELF_DONE)
+ {
+ /* We've finished interacting and now the SM has agreed to
+ * cancel the shutdown.
+ */
+ xsmp->state = XSMP_STATE_IDLE;
+ egg_sm_client_quit_cancelled (client);
+ }
+ else if (xsmp->state == XSMP_STATE_SHUTDOWN_CANCELLED)
+ {
+ /* Hm... ok, so we got a shutdown SaveYourself, which got
+ * cancelled, but the application was still interacting, so we
+ * didn't tell it yet, and then *another* SaveYourself arrived,
+ * which we must still be waiting to tell the app about, except
+ * that now that SaveYourself has been cancelled too! Dizzy yet?
+ */
+ xsmp->waiting_to_save_myself = FALSE;
+ update_pending_events (xsmp);
+ }
+ else
+ {
+ g_debug ("Sending SaveYourselfDone(False)");
+ SmcSaveYourselfDone (xsmp->connection, False);
+
+ if (xsmp->state == XSMP_STATE_INTERACT)
+ {
+ /* The application is currently interacting, so we can't
+ * tell it about the cancellation yet; we will wait until
+ * after it calls egg_sm_client_will_quit().
+ */
+ xsmp->state = XSMP_STATE_SHUTDOWN_CANCELLED;
+ }
+ else
+ {
+ /* The shutdown was cancelled before the application got a
+ * chance to interact.
+ */
+ xsmp->state = XSMP_STATE_IDLE;
+ }
+ }
+}
+
+/* Utilities */
+
+/* Create a restart/clone/Exec command based on @restart_command.
+ * If @client_id is non-%NULL, add "--sm-client-id @client_id".
+ * If @state_file is non-%NULL, add "--sm-client-state-file @state_file".
+ *
+ * None of the input strings are g_strdup()ed; the caller must keep
+ * them around until it is done with the returned GPtrArray, and must
+ * then free the array, but not its contents.
+ */
+static GPtrArray *
+generate_command (char **argv, const char *client_id,
+ const char *state_file)
+{
+ GPtrArray *cmd;
+ int i;
+
+ cmd = g_ptr_array_new ();
+ g_ptr_array_add (cmd, argv[0]);
+
+ if (client_id)
+ {
+ g_ptr_array_add (cmd, (char *)"--sm-client-id");
+ g_ptr_array_add (cmd, (char *)client_id);
+ }
+
+ if (state_file)
+ {
+ g_ptr_array_add (cmd, (char *)"--sm-client-state-file");
+ g_ptr_array_add (cmd, (char *)state_file);
+ }
+
+ for (i = 1; argv[i]; i++)
+ g_ptr_array_add (cmd, argv[i]);
+
+ return cmd;
+}
+
+/* Takes a NULL-terminated list of SmProp * values, created by
+ * array_prop, ptrarray_prop, string_prop, card8_prop, sets them, and
+ * frees them.
+ */
+static void
+set_properties (EggSMClientXSMP *xsmp, ...)
+{
+ GPtrArray *props;
+ SmProp *prop;
+ va_list ap;
+ guint i;
+
+ props = g_ptr_array_new ();
+
+ va_start (ap, xsmp);
+ while ((prop = va_arg (ap, SmProp *)))
+ g_ptr_array_add (props, prop);
+ va_end (ap);
+
+ if (xsmp->connection)
+ {
+ SmcSetProperties (xsmp->connection, props->len,
+ (SmProp **)props->pdata);
+ }
+
+ for (i = 0; i < props->len; i++)
+ {
+ prop = props->pdata[i];
+ g_free (prop->vals);
+ g_free (prop);
+ }
+ g_ptr_array_free (props, TRUE);
+}
+
+/* Takes a NULL-terminated list of property names and deletes them. */
+static void
+delete_properties (EggSMClientXSMP *xsmp, ...)
+{
+ GPtrArray *props;
+ char *prop;
+ va_list ap;
+
+ if (!xsmp->connection)
+ return;
+
+ props = g_ptr_array_new ();
+
+ va_start (ap, xsmp);
+ while ((prop = va_arg (ap, char *)))
+ g_ptr_array_add (props, prop);
+ va_end (ap);
+
+ SmcDeleteProperties (xsmp->connection, props->len,
+ (char **)props->pdata);
+
+ g_ptr_array_free (props, TRUE);
+}
+
+/* Takes an array of strings and creates a LISTofARRAY8 property. The
+ * strings are neither dupped nor freed; they need to remain valid
+ * until you're done with the SmProp.
+ */
+static SmProp *
+array_prop (const char *name, ...)
+{
+ SmProp *prop;
+ SmPropValue pv;
+ GArray *vals;
+ char *value;
+ va_list ap;
+
+ prop = g_new (SmProp, 1);
+ prop->name = (char *)name;
+ prop->type = (char *)SmLISTofARRAY8;
+
+ vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
+
+ va_start (ap, name);
+ while ((value = va_arg (ap, char *)))
+ {
+ pv.length = strlen (value);
+ pv.value = value;
+ g_array_append_val (vals, pv);
+ }
+
+ prop->num_vals = vals->len;
+ prop->vals = (SmPropValue *)vals->data;
+
+ g_array_free (vals, FALSE);
+
+ return prop;
+}
+
+/* Takes a GPtrArray of strings and creates a LISTofARRAY8 property.
+ * The array contents are neither dupped nor freed; they need to
+ * remain valid until you're done with the SmProp.
+ */
+static SmProp *
+ptrarray_prop (const char *name, GPtrArray *values)
+{
+ SmProp *prop;
+ SmPropValue pv;
+ GArray *vals;
+ guint i;
+
+ prop = g_new (SmProp, 1);
+ prop->name = (char *)name;
+ prop->type = (char *)SmLISTofARRAY8;
+
+ vals = g_array_new (FALSE, FALSE, sizeof (SmPropValue));
+
+ for (i = 0; i < values->len; i++)
+ {
+ pv.length = strlen (values->pdata[i]);
+ pv.value = values->pdata[i];
+ g_array_append_val (vals, pv);
+ }
+
+ prop->num_vals = vals->len;
+ prop->vals = (SmPropValue *)vals->data;
+
+ g_array_free (vals, FALSE);
+
+ return prop;
+}
+
+/* Takes a string and creates an ARRAY8 property. The string is
+ * neither dupped nor freed; it needs to remain valid until you're
+ * done with the SmProp.
+ */
+static SmProp *
+string_prop (const char *name, const char *value)
+{
+ SmProp *prop;
+
+ prop = g_new (SmProp, 1);
+ prop->name = (char *)name;
+ prop->type = (char *)SmARRAY8;
+
+ prop->num_vals = 1;
+ prop->vals = g_new (SmPropValue, 1);
+
+ prop->vals[0].length = strlen (value);
+ prop->vals[0].value = (char *)value;
+
+ return prop;
+}
+
+/* Takes a char and creates a CARD8 property. */
+static SmProp *
+card8_prop (const char *name, unsigned char value)
+{
+ SmProp *prop;
+ char *card8val;
+
+ /* To avoid having to allocate and free prop->vals[0], we cheat and
+ * make vals a 2-element-long array and then use the second element
+ * to store value.
+ */
+
+ prop = g_new (SmProp, 1);
+ prop->name = (char *)name;
+ prop->type = (char *)SmCARD8;
+
+ prop->num_vals = 1;
+ prop->vals = g_new (SmPropValue, 2);
+ card8val = (char *)(&prop->vals[1]);
+ card8val[0] = value;
+
+ prop->vals[0].length = 1;
+ prop->vals[0].value = card8val;
+
+ return prop;
+}
+
+/* ICE code. This makes no effort to play nice with anyone else trying
+ * to use libICE. Fortunately, no one uses libICE for anything other
+ * than SM. (DCOP uses ICE, but it has its own private copy of
+ * libICE.)
+ *
+ * When this moves to gtk, it will need to be cleverer, to avoid
+ * tripping over old apps that use MateClient or that use libSM
+ * directly.
+ */
+
+#include <X11/ICE/ICElib.h>
+#include <fcntl.h>
+
+static void ice_error_handler (IceConn ice_conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence,
+ int error_class,
+ int severity,
+ IcePointer values);
+static void ice_io_error_handler (IceConn ice_conn);
+static void ice_connection_watch (IceConn ice_conn,
+ IcePointer client_data,
+ Bool opening,
+ IcePointer *watch_data);
+
+static void
+ice_init (void)
+{
+ IceSetIOErrorHandler (ice_io_error_handler);
+ IceSetErrorHandler (ice_error_handler);
+ IceAddConnectionWatch (ice_connection_watch, NULL);
+}
+
+static gboolean
+process_ice_messages (IceConn ice_conn)
+{
+ IceProcessMessagesStatus status;
+
+ gdk_threads_enter ();
+ status = IceProcessMessages (ice_conn, NULL, NULL);
+ gdk_threads_leave ();
+
+ switch (status)
+ {
+ case IceProcessMessagesSuccess:
+ return TRUE;
+
+ case IceProcessMessagesIOError:
+ sm_client_xsmp_disconnect (IceGetConnectionContext (ice_conn));
+ return FALSE;
+
+ case IceProcessMessagesConnectionClosed:
+ return FALSE;
+
+ default:
+ g_assert_not_reached ();
+ }
+}
+
+static gboolean
+ice_iochannel_watch (GIOChannel *channel,
+ GIOCondition condition,
+ gpointer client_data)
+{
+ return process_ice_messages (client_data);
+}
+
+static void
+ice_connection_watch (IceConn ice_conn,
+ IcePointer client_data,
+ Bool opening,
+ IcePointer *watch_data)
+{
+ guint watch_id;
+
+ if (opening)
+ {
+ GIOChannel *channel;
+ int fd = IceConnectionNumber (ice_conn);
+
+ fcntl (fd, F_SETFD, fcntl (fd, F_GETFD, 0) | FD_CLOEXEC);
+ channel = g_io_channel_unix_new (fd);
+ watch_id = g_io_add_watch (channel, G_IO_IN | G_IO_ERR,
+ ice_iochannel_watch, ice_conn);
+ g_io_channel_unref (channel);
+
+ *watch_data = GUINT_TO_POINTER (watch_id);
+ }
+ else
+ {
+ watch_id = GPOINTER_TO_UINT (*watch_data);
+ g_source_remove (watch_id);
+ }
+}
+
+static void
+ice_error_handler (IceConn ice_conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence,
+ int error_class,
+ int severity,
+ IcePointer values)
+{
+ /* Do nothing */
+}
+
+static void
+ice_io_error_handler (IceConn ice_conn)
+{
+ /* Do nothing */
+}
+
+static void
+smc_error_handler (SmcConn smc_conn,
+ Bool swap,
+ int offending_minor_opcode,
+ unsigned long offending_sequence,
+ int error_class,
+ int severity,
+ SmPointer values)
+{
+ /* Do nothing */
+}
diff --git a/src/eggsmclient.c b/src/eggsmclient.c
new file mode 100644
index 0000000..31906b6
--- /dev/null
+++ b/src/eggsmclient.c
@@ -0,0 +1,610 @@
+/*
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+#include <glib/gi18n.h>
+
+#include "eggsmclient.h"
+#include "eggsmclient-private.h"
+
+static void egg_sm_client_debug_handler (const char *log_domain,
+ GLogLevelFlags log_level,
+ const char *message,
+ gpointer user_data);
+
+enum {
+ SAVE_STATE,
+ QUIT_REQUESTED,
+ QUIT_CANCELLED,
+ QUIT,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+struct _EggSMClientPrivate {
+ GKeyFile *state_file;
+};
+
+#define EGG_SM_CLIENT_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), EGG_TYPE_SM_CLIENT, EggSMClientPrivate))
+
+G_DEFINE_TYPE (EggSMClient, egg_sm_client, G_TYPE_OBJECT)
+
+static EggSMClient *global_client;
+static EggSMClientMode global_client_mode = EGG_SM_CLIENT_MODE_NORMAL;
+
+static void
+egg_sm_client_init (EggSMClient *client)
+{
+ ;
+}
+
+static void
+egg_sm_client_class_init (EggSMClientClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ g_type_class_add_private (klass, sizeof (EggSMClientPrivate));
+
+ /**
+ * EggSMClient::save_state:
+ * @client: the client
+ * @state_file: a #GKeyFile to save state information into
+ *
+ * Emitted when the session manager has requested that the
+ * application save information about its current state. The
+ * application should save its state into @state_file, and then the
+ * session manager may then restart the application in a future
+ * session and tell it to initialize itself from that state.
+ *
+ * You should not save any data into @state_file's "start group"
+ * (ie, the %NULL group). Instead, applications should save their
+ * data into groups with names that start with the application name,
+ * and libraries that connect to this signal should save their data
+ * into groups with names that start with the library name.
+ *
+ * Alternatively, rather than (or in addition to) using @state_file,
+ * the application can save its state by calling
+ * egg_sm_client_set_restart_command() during the processing of this
+ * signal (eg, to include a list of files to open).
+ **/
+ signals[SAVE_STATE] =
+ g_signal_new ("save_state",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggSMClientClass, save_state),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__POINTER,
+ G_TYPE_NONE,
+ 1, G_TYPE_POINTER);
+
+ /**
+ * EggSMClient::quit_requested:
+ * @client: the client
+ *
+ * Emitted when the session manager requests that the application
+ * exit (generally because the user is logging out). The application
+ * should decide whether or not it is willing to quit (perhaps after
+ * asking the user what to do with documents that have unsaved
+ * changes) and then call egg_sm_client_will_quit(), passing %TRUE
+ * or %FALSE to give its answer to the session manager. (It does not
+ * need to give an answer before returning from the signal handler;
+ * it can interact with the user asynchronously and then give its
+ * answer later on.) If the application does not connect to this
+ * signal, then #EggSMClient will automatically return %TRUE on its
+ * behalf.
+ *
+ * The application should not save its session state as part of
+ * handling this signal; if the user has requested that the session
+ * be saved when logging out, then ::save_state will be emitted
+ * separately.
+ *
+ * If the application agrees to quit, it should then wait for either
+ * the ::quit_cancelled or ::quit signals to be emitted.
+ **/
+ signals[QUIT_REQUESTED] =
+ g_signal_new ("quit_requested",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggSMClientClass, quit_requested),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ /**
+ * EggSMClient::quit_cancelled:
+ * @client: the client
+ *
+ * Emitted when the session manager decides to cancel a logout after
+ * the application has already agreed to quit. After receiving this
+ * signal, the application can go back to what it was doing before
+ * receiving the ::quit_requested signal.
+ **/
+ signals[QUIT_CANCELLED] =
+ g_signal_new ("quit_cancelled",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggSMClientClass, quit_cancelled),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+
+ /**
+ * EggSMClient::quit:
+ * @client: the client
+ *
+ * Emitted when the session manager wants the application to quit
+ * (generally because the user is logging out). The application
+ * should exit as soon as possible after receiving this signal; if
+ * it does not, the session manager may choose to forcibly kill it.
+ *
+ * Normally a GUI application would only be sent a ::quit if it
+ * agreed to quit in response to a ::quit_requested signal. However,
+ * this is not guaranteed; in some situations the session manager
+ * may decide to end the session without giving applications a
+ * chance to object.
+ **/
+ signals[QUIT] =
+ g_signal_new ("quit",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (EggSMClientClass, quit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE,
+ 0);
+}
+
+static gboolean sm_client_disable = FALSE;
+static char *sm_client_state_file = NULL;
+static char *sm_client_id = NULL;
+static char *sm_config_prefix = NULL;
+
+static gboolean
+sm_client_post_parse_func (GOptionContext *context,
+ GOptionGroup *group,
+ gpointer data,
+ GError **error)
+{
+ EggSMClient *client = egg_sm_client_get ();
+
+ if (sm_client_id == NULL)
+ {
+ const gchar *desktop_autostart_id;
+
+ desktop_autostart_id = g_getenv ("DESKTOP_AUTOSTART_ID");
+
+ if (desktop_autostart_id != NULL)
+ sm_client_id = g_strdup (desktop_autostart_id);
+ }
+
+ /* Unset DESKTOP_AUTOSTART_ID in order to avoid child processes to
+ * use the same client id. */
+ g_unsetenv ("DESKTOP_AUTOSTART_ID");
+
+ if (EGG_SM_CLIENT_GET_CLASS (client)->startup)
+ EGG_SM_CLIENT_GET_CLASS (client)->startup (client, sm_client_id);
+ return TRUE;
+}
+
+/**
+ * egg_sm_client_get_option_group:
+ *
+ * Creates a %GOptionGroup containing the session-management-related
+ * options. You should add this group to the application's
+ * %GOptionContext if you want to use #EggSMClient.
+ *
+ * Return value: the %GOptionGroup
+ **/
+GOptionGroup *
+egg_sm_client_get_option_group (void)
+{
+ const GOptionEntry entries[] = {
+ { "sm-client-disable", 0, 0,
+ G_OPTION_ARG_NONE, &sm_client_disable,
+ N_("Disable connection to session manager"), NULL },
+ { "sm-client-state-file", 0, 0,
+ G_OPTION_ARG_FILENAME, &sm_client_state_file,
+ N_("Specify file containing saved configuration"), N_("FILE") },
+ { "sm-client-id", 0, 0,
+ G_OPTION_ARG_STRING, &sm_client_id,
+ N_("Specify session management ID"), N_("ID") },
+ /* MateClient compatibility option */
+ { "sm-disable", 0, G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_NONE, &sm_client_disable,
+ NULL, NULL },
+ /* MateClient compatibility option. This is a dummy option that only
+ * exists so that sessions saved by apps with MateClient can be restored
+ * later when they've switched to EggSMClient. See bug #575308.
+ */
+ { "sm-config-prefix", 0, G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING, &sm_config_prefix,
+ NULL, NULL },
+ { NULL }
+ };
+ GOptionGroup *group;
+
+ /* Use our own debug handler for the "EggSMClient" domain. */
+ g_log_set_handler (G_LOG_DOMAIN, G_LOG_LEVEL_DEBUG,
+ egg_sm_client_debug_handler, NULL);
+
+ group = g_option_group_new ("sm-client",
+ _("Session management options:"),
+ _("Show session management options"),
+ NULL, NULL);
+ g_option_group_add_entries (group, entries);
+ g_option_group_set_parse_hooks (group, NULL, sm_client_post_parse_func);
+
+ return group;
+}
+
+/**
+ * egg_sm_client_set_mode:
+ * @mode: an #EggSMClient mode
+ *
+ * Sets the "mode" of #EggSMClient as follows:
+ *
+ * %EGG_SM_CLIENT_MODE_DISABLED: Session management is completely
+ * disabled. The application will not even connect to the session
+ * manager. (egg_sm_client_get() will still return an #EggSMClient,
+ * but it will just be a dummy object.)
+ *
+ * %EGG_SM_CLIENT_MODE_NO_RESTART: The application will connect to
+ * the session manager (and thus will receive notification when the
+ * user is logging out, etc), but will request to not be
+ * automatically restarted with saved state in future sessions.
+ *
+ * %EGG_SM_CLIENT_MODE_NORMAL: The default. #EggSMCLient will
+ * function normally.
+ *
+ * This must be called before the application's main loop begins.
+ **/
+void
+egg_sm_client_set_mode (EggSMClientMode mode)
+{
+ global_client_mode = mode;
+}
+
+/**
+ * egg_sm_client_get_mode:
+ *
+ * Gets the global #EggSMClientMode. See egg_sm_client_set_mode()
+ * for details.
+ *
+ * Return value: the global #EggSMClientMode
+ **/
+EggSMClientMode
+egg_sm_client_get_mode (void)
+{
+ return global_client_mode;
+}
+
+/**
+ * egg_sm_client_get:
+ *
+ * Returns the master #EggSMClient for the application.
+ *
+ * On platforms that support saved sessions (ie, POSIX/X11), the
+ * application will only request to be restarted by the session
+ * manager if you call egg_set_desktop_file() to set an application
+ * desktop file. In particular, if the desktop file contains the key
+ * "X
+ *
+ * Return value: the master #EggSMClient.
+ **/
+EggSMClient *
+egg_sm_client_get (void)
+{
+ if (!global_client)
+ {
+ if (global_client_mode != EGG_SM_CLIENT_MODE_DISABLED &&
+ !sm_client_disable)
+ {
+#if defined (GDK_WINDOWING_WIN32)
+ global_client = egg_sm_client_win32_new ();
+#elif defined (GDK_WINDOWING_QUARTZ)
+ global_client = egg_sm_client_osx_new ();
+#else
+ /* If both D-Bus and XSMP are compiled in, try XSMP first
+ * (since it supports state saving) and fall back to D-Bus
+ * if XSMP isn't available.
+ */
+# ifdef EGG_SM_CLIENT_BACKEND_XSMP
+ global_client = egg_sm_client_xsmp_new ();
+# endif
+# ifdef EGG_SM_CLIENT_BACKEND_DBUS
+ if (!global_client)
+ global_client = egg_sm_client_dbus_new ();
+# endif
+#endif
+ }
+
+ /* Fallback: create a dummy client, so that callers don't have
+ * to worry about a %NULL return value.
+ */
+ if (!global_client)
+ global_client = g_object_new (EGG_TYPE_SM_CLIENT, NULL);
+ }
+
+ return global_client;
+}
+
+/**
+ * egg_sm_client_is_resumed:
+ * @client: the client
+ *
+ * Checks whether or not the current session has been resumed from
+ * a previous saved session. If so, the application should call
+ * egg_sm_client_get_state_file() and restore its state from the
+ * returned #GKeyFile.
+ *
+ * Return value: %TRUE if the session has been resumed
+ **/
+gboolean
+egg_sm_client_is_resumed (EggSMClient *client)
+{
+ g_return_val_if_fail (client == global_client, FALSE);
+
+ return sm_client_state_file != NULL;
+}
+
+/**
+ * egg_sm_client_get_state_file:
+ * @client: the client
+ *
+ * If the application was resumed by the session manager, this will
+ * return the #GKeyFile containing its state from the previous
+ * session.
+ *
+ * Note that other libraries and #EggSMClient itself may also store
+ * state in the key file, so if you call egg_sm_client_get_groups(),
+ * on it, the return value will likely include groups that you did not
+ * put there yourself. (It is also not guaranteed that the first
+ * group created by the application will still be the "start group"
+ * when it is resumed.)
+ *
+ * Return value: the #GKeyFile containing the application's earlier
+ * state, or %NULL on error. You should not free this key file; it
+ * is owned by @client.
+ **/
+GKeyFile *
+egg_sm_client_get_state_file (EggSMClient *client)
+{
+ EggSMClientPrivate *priv = EGG_SM_CLIENT_GET_PRIVATE (client);
+ char *state_file_path;
+ GError *err = NULL;
+
+ g_return_val_if_fail (client == global_client, NULL);
+
+ if (!sm_client_state_file)
+ return NULL;
+ if (priv->state_file)
+ return priv->state_file;
+
+ if (!strncmp (sm_client_state_file, "file://", 7))
+ state_file_path = g_filename_from_uri (sm_client_state_file, NULL, NULL);
+ else
+ state_file_path = g_strdup (sm_client_state_file);
+
+ priv->state_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (priv->state_file, state_file_path, 0, &err))
+ {
+ g_warning ("Could not load SM state file '%s': %s",
+ sm_client_state_file, err->message);
+ g_clear_error (&err);
+ g_key_file_free (priv->state_file);
+ priv->state_file = NULL;
+ }
+
+ g_free (state_file_path);
+ return priv->state_file;
+}
+
+/**
+ * egg_sm_client_set_restart_command:
+ * @client: the client
+ * @argc: the length of @argv
+ * @argv: argument vector
+ *
+ * Sets the command used to restart @client if it does not have a
+ * .desktop file that can be used to find its restart command.
+ *
+ * This can also be used when handling the ::save_state signal, to
+ * save the current state via an updated command line. (Eg, providing
+ * a list of filenames to open when the application is resumed.)
+ **/
+void
+egg_sm_client_set_restart_command (EggSMClient *client,
+ int argc,
+ const char **argv)
+{
+ g_return_if_fail (EGG_IS_SM_CLIENT (client));
+
+ if (EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command)
+ EGG_SM_CLIENT_GET_CLASS (client)->set_restart_command (client, argc, argv);
+}
+
+/**
+ * egg_sm_client_set_discard_command:
+ * @client: the client
+ * @argc: the length of @argv
+ * @argv: argument vector
+ *
+ * Sets the command used to discard a custom state file if using
+ * egg_sm_client_set_restart_command(), which must be called before
+ * using this function.
+ **/
+void
+egg_sm_client_set_discard_command (EggSMClient *client,
+ int argc,
+ const char **argv)
+{
+ g_return_if_fail (EGG_IS_SM_CLIENT (client));
+
+ if (EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command)
+ EGG_SM_CLIENT_GET_CLASS (client)->set_discard_command (client, argc, argv);
+}
+
+/**
+ * egg_sm_client_will_quit:
+ * @client: the client
+ * @will_quit: whether or not the application is willing to quit
+ *
+ * This MUST be called in response to the ::quit_requested signal, to
+ * indicate whether or not the application is willing to quit. The
+ * application may call it either directly from the signal handler, or
+ * at some later point (eg, after asynchronously interacting with the
+ * user).
+ *
+ * If the application does not connect to ::quit_requested,
+ * #EggSMClient will call this method on its behalf (passing %TRUE
+ * for @will_quit).
+ *
+ * After calling this method, the application should wait to receive
+ * either ::quit_cancelled or ::quit.
+ **/
+void
+egg_sm_client_will_quit (EggSMClient *client,
+ gboolean will_quit)
+{
+ g_return_if_fail (EGG_IS_SM_CLIENT (client));
+
+ if (EGG_SM_CLIENT_GET_CLASS (client)->will_quit)
+ EGG_SM_CLIENT_GET_CLASS (client)->will_quit (client, will_quit);
+}
+
+/**
+ * egg_sm_client_end_session:
+ * @style: a hint at how to end the session
+ * @request_confirmation: whether or not the user should get a chance
+ * to confirm the action
+ *
+ * Requests that the session manager end the current session. @style
+ * indicates how the session should be ended, and
+ * @request_confirmation indicates whether or not the user should be
+ * given a chance to confirm the logout/reboot/shutdown. Both of these
+ * flags are merely hints though; the session manager may choose to
+ * ignore them.
+ *
+ * Return value: %TRUE if the request was sent; %FALSE if it could not
+ * be (eg, because it could not connect to the session manager).
+ **/
+gboolean
+egg_sm_client_end_session (EggSMClientEndStyle style,
+ gboolean request_confirmation)
+{
+ EggSMClient *client = egg_sm_client_get ();
+
+ g_return_val_if_fail (EGG_IS_SM_CLIENT (client), FALSE);
+
+ if (EGG_SM_CLIENT_GET_CLASS (client)->end_session)
+ {
+ return EGG_SM_CLIENT_GET_CLASS (client)->end_session (client, style,
+ request_confirmation);
+ }
+ else
+ return FALSE;
+}
+
+/* Signal-emitting callbacks from platform-specific code */
+
+GKeyFile *
+egg_sm_client_save_state (EggSMClient *client)
+{
+ GKeyFile *state_file;
+ char *group;
+
+ g_return_val_if_fail (client == global_client, NULL);
+
+ state_file = g_key_file_new ();
+
+ g_debug ("Emitting save_state");
+ g_signal_emit (client, signals[SAVE_STATE], 0, state_file);
+ g_debug ("Done emitting save_state");
+
+ group = g_key_file_get_start_group (state_file);
+ if (group)
+ {
+ g_free (group);
+ return state_file;
+ }
+ else
+ {
+ g_key_file_free (state_file);
+ return NULL;
+ }
+}
+
+void
+egg_sm_client_quit_requested (EggSMClient *client)
+{
+ g_return_if_fail (client == global_client);
+
+ if (!g_signal_has_handler_pending (client, signals[QUIT_REQUESTED], 0, FALSE))
+ {
+ g_debug ("Not emitting quit_requested because no one is listening");
+ egg_sm_client_will_quit (client, TRUE);
+ return;
+ }
+
+ g_debug ("Emitting quit_requested");
+ g_signal_emit (client, signals[QUIT_REQUESTED], 0);
+ g_debug ("Done emitting quit_requested");
+}
+
+void
+egg_sm_client_quit_cancelled (EggSMClient *client)
+{
+ g_return_if_fail (client == global_client);
+
+ g_debug ("Emitting quit_cancelled");
+ g_signal_emit (client, signals[QUIT_CANCELLED], 0);
+ g_debug ("Done emitting quit_cancelled");
+}
+
+void
+egg_sm_client_quit (EggSMClient *client)
+{
+ g_return_if_fail (client == global_client);
+
+ g_debug ("Emitting quit");
+ g_signal_emit (client, signals[QUIT], 0);
+ g_debug ("Done emitting quit");
+
+ /* FIXME: should we just call gtk_main_quit() here? */
+}
+
+static void
+egg_sm_client_debug_handler (const char *log_domain,
+ GLogLevelFlags log_level,
+ const char *message,
+ gpointer user_data)
+{
+ static int debug = -1;
+
+ if (debug < 0)
+ debug = (g_getenv ("EGG_SM_CLIENT_DEBUG") != NULL);
+
+ if (debug)
+ g_log_default_handler (log_domain, log_level, message, NULL);
+}
diff --git a/src/eggsmclient.h b/src/eggsmclient.h
new file mode 100644
index 0000000..6de47b6
--- /dev/null
+++ b/src/eggsmclient.h
@@ -0,0 +1,123 @@
+/* eggsmclient.h
+ * Copyright (C) 2007 Novell, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Lesser General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Lesser General Public License for more details.
+ *
+ * You should have received a copy of the GNU Lesser General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef __EGG_SM_CLIENT_H__
+#define __EGG_SM_CLIENT_H__
+
+#include <glib-object.h>
+
+G_BEGIN_DECLS
+
+#define EGG_TYPE_SM_CLIENT (egg_sm_client_get_type ())
+#define EGG_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_CAST ((obj), EGG_TYPE_SM_CLIENT, EggSMClient))
+#define EGG_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), EGG_TYPE_SM_CLIENT, EggSMClientClass))
+#define EGG_IS_SM_CLIENT(obj) (G_TYPE_CHECK_INSTANCE_TYPE ((obj), EGG_TYPE_SM_CLIENT))
+#define EGG_IS_SM_CLIENT_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), EGG_TYPE_SM_CLIENT))
+#define EGG_SM_CLIENT_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), EGG_TYPE_SM_CLIENT, EggSMClientClass))
+
+typedef struct _EggSMClient EggSMClient;
+typedef struct _EggSMClientClass EggSMClientClass;
+typedef struct _EggSMClientPrivate EggSMClientPrivate;
+
+typedef enum {
+ EGG_SM_CLIENT_END_SESSION_DEFAULT,
+ EGG_SM_CLIENT_LOGOUT,
+ EGG_SM_CLIENT_REBOOT,
+ EGG_SM_CLIENT_SHUTDOWN
+} EggSMClientEndStyle;
+
+typedef enum {
+ EGG_SM_CLIENT_MODE_DISABLED,
+ EGG_SM_CLIENT_MODE_NO_RESTART,
+ EGG_SM_CLIENT_MODE_NORMAL
+} EggSMClientMode;
+
+struct _EggSMClient
+{
+ GObject parent;
+
+};
+
+struct _EggSMClientClass
+{
+ GObjectClass parent_class;
+
+ /* signals */
+ void (*save_state) (EggSMClient *client,
+ GKeyFile *state_file);
+
+ void (*quit_requested) (EggSMClient *client);
+ void (*quit_cancelled) (EggSMClient *client);
+ void (*quit) (EggSMClient *client);
+
+ /* virtual methods */
+ void (*startup) (EggSMClient *client,
+ const char *client_id);
+ void (*set_restart_command) (EggSMClient *client,
+ int argc,
+ const char **argv);
+ void (*set_discard_command) (EggSMClient *client,
+ int argc,
+ const char **argv);
+ void (*will_quit) (EggSMClient *client,
+ gboolean will_quit);
+ gboolean (*end_session) (EggSMClient *client,
+ EggSMClientEndStyle style,
+ gboolean request_confirmation);
+
+ /* Padding for future expansion */
+ void (*_egg_reserved1) (void);
+ void (*_egg_reserved2) (void);
+ void (*_egg_reserved3) (void);
+ void (*_egg_reserved4) (void);
+};
+
+GType egg_sm_client_get_type (void) G_GNUC_CONST;
+
+GOptionGroup *egg_sm_client_get_option_group (void);
+
+/* Initialization */
+void egg_sm_client_set_mode (EggSMClientMode mode);
+EggSMClientMode egg_sm_client_get_mode (void);
+EggSMClient *egg_sm_client_get (void);
+
+/* Resuming a saved session */
+gboolean egg_sm_client_is_resumed (EggSMClient *client);
+GKeyFile *egg_sm_client_get_state_file (EggSMClient *client);
+
+/* Alternate means of saving state */
+void egg_sm_client_set_restart_command (EggSMClient *client,
+ int argc,
+ const char **argv);
+void egg_sm_client_set_discard_command (EggSMClient *client,
+ int argc,
+ const char **argv);
+
+/* Handling "quit_requested" signal */
+void egg_sm_client_will_quit (EggSMClient *client,
+ gboolean will_quit);
+
+/* Initiate a logout/reboot/shutdown */
+gboolean egg_sm_client_end_session (EggSMClientEndStyle style,
+ gboolean request_confirmation);
+
+G_END_DECLS
+
+
+#endif /* __EGG_SM_CLIENT_H__ */
diff --git a/src/encodings-dialog.glade b/src/encodings-dialog.glade
new file mode 100644
index 0000000..f86a0f0
--- /dev/null
+++ b/src/encodings-dialog.glade
@@ -0,0 +1,296 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="encodings-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Add or Remove Terminal Encodings</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_height">325</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox3">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area3">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="helpbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-help</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-11</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="closebutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table33">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow2">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="available-treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ <accessibility>
+ <atkrelation target="available-label" type="labelled-by"/>
+ </accessibility>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox27">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox87">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="add-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image3">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-forward</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="remove-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+
+ <child>
+ <widget class="GtkImage" id="image4">
+ <property name="visible">True</property>
+ <property name="stock">gtk-go-back</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="available-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">A_vailable encodings:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">available-treeview</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ <accessibility>
+ <atkrelation target="available-treeview" type="label-for"/>
+ </accessibility>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="displayed-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">E_ncodings shown in menu:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">displayed-treeview</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow3">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="displayed-treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">False</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/extra-strings.c b/src/extra-strings.c
new file mode 100644
index 0000000..0a24c60
--- /dev/null
+++ b/src/extra-strings.c
@@ -0,0 +1,73 @@
+/*
+ * Copyright © 2009 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+/* This file contains extra strings that need to be translated, but
+ * can't be extracted by intltool since the ui files aren't in git, and
+ * the glade files don't contain them in the right form. See bug #553357.
+ */
+
+/* Translators: This refers to the Delete keybinding option */
+N_("Automatic")
+/* Translators: This refers to the Delete keybinding option */
+N_("Control-H")
+/* Translators: This refers to the Delete keybinding option */
+N_("ASCII DEL")
+/* Translators: This refers to the Delete keybinding option */
+N_("Escape sequence")
+/* Translators: This refers to the Delete keybinding option */
+N_("TTY Erase")
+
+/* Translators: Cursor shape: ... */
+N_("Block")
+/* Translators: Cursor shape: ... */
+N_("I-Beam")
+/* Translators: Cursor shape: ... */
+N_("Underline")
+
+/* Translators: When command exits: ... */
+N_("Exit the terminal")
+/* Translators: When command exits: ... */
+N_("Restart the command")
+/* Translators: When command exits: ... */
+N_("Hold the terminal open")
+
+/* Translators: Scrollbar is: ... */
+N_("On the left side")
+/* Translators: Scrollbar is: ... */
+N_("On the right side")
+/* Translators: Scrollbar is: ... */
+N_("Disabled")
+
+/* Translators: When terminal commands set their own titles: ... */
+N_("Replace initial title")
+/* Translators: When terminal commands set their own titles: ... */
+N_("Append initial title")
+/* Translators: When terminal commands set their own titles: ... */
+N_("Prepend initial title")
+/* Translators: When terminal commands set their own titles: ... */
+N_("Keep initial title")
+
+/* Translators: This is the name of a colour scheme */
+N_("Tango")
+/* Translators: This is the name of a colour scheme */
+N_("Linux console")
+/* Translators: This is the name of a colour scheme */
+N_("XTerm")
+/* Translators: This is the name of a colour scheme */
+N_("Rxvt")
+/* Translators: This is the name of a colour scheme */
+N_("Custom")
diff --git a/src/find-dialog.glade b/src/find-dialog.glade
new file mode 100644
index 0000000..71f8b78
--- /dev/null
+++ b/src/find-dialog.glade
@@ -0,0 +1,236 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="mate"/>
+
+<widget class="GtkDialog" id="find-dialog">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Find</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="icon_name">gtk-find</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="hbuttonbox2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="button-close">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button-find">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-find</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-3</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox2">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="search-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Search for:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">search-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBoxEntry" id="search-entry">
+ <property name="visible">True</property>
+ <property name="add_tearoffs">False</property>
+ <property name="has_frame">True</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="match-case-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Match case</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="entire-word-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match _entire word only</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="regex-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Match as _regular expression</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="search-backwards-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Search _backwards</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="wrap-around-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Wrap around</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">False</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/keybinding-editor.glade b/src/keybinding-editor.glade
new file mode 100644
index 0000000..bdc121f
--- /dev/null
+++ b/src/keybinding-editor.glade
@@ -0,0 +1,194 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="keybindings-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">Keyboard Shortcuts</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="role">mate-terminal-accels</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area2">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="close_button1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="button1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-help</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-11</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table32">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="n_rows">4</property>
+ <property name="n_columns">1</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="disable-mnemonics-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Enable menu access keys (such as Alt+F to open the File menu)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="scrolledwindow1">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <widget class="GtkTreeView" id="accelerators-treeview">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="headers_visible">True</property>
+ <property name="rules_hint">True</property>
+ <property name="reorderable">False</property>
+ <property name="enable_search">True</property>
+ <property name="fixed_height_mode">False</property>
+ <property name="hover_selection">False</property>
+ <property name="hover_expand">False</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="disable-menu-accel-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Enable the _menu shortcut key (F10 by default)</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label59">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Shortcut keys:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">accelerators-treeview</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/mate-terminal.schemas.in b/src/mate-terminal.schemas.in
new file mode 100644
index 0000000..5eb5573
--- /dev/null
+++ b/src/mate-terminal.schemas.in
@@ -0,0 +1,1302 @@
+<mateconfschemafile>
+ <schemalist>
+
+
+
+ <!-- Global settings -->
+
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/profile_list</key>
+ <applyto>/apps/mate-terminal/global/profile_list</applyto>
+ <owner>mate-terminal</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <default>[Default]</default>
+ <locale name="C">
+ <short>List of profiles</short>
+ <long>
+ List of profiles known to mate-terminal. The list contains
+ strings naming subdirectories relative to
+ /apps/mate-terminal/profiles.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/default_profile</key>
+ <applyto>/apps/mate-terminal/global/default_profile</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>Default</default>
+ <locale name="C">
+ <short>Profile to use for new terminals</short>
+ <long>
+ Profile to be used when opening a new window or tab.
+ Must be in profile_list.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/use_mnemonics</key>
+ <applyto>/apps/mate-terminal/global/use_mnemonics</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether the menubar has access keys</short>
+ <long>
+ 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.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/use_menu_accelerators</key>
+ <applyto>/apps/mate-terminal/global/use_menu_accelerators</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether the standard GTK shortcut for menubar access is enabled</short>
+ <long>
+ 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.
+ </long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/active_encodings</key>
+ <applyto>/apps/mate-terminal/global/active_encodings</applyto>
+ <owner>mate-terminal</owner>
+ <type>list</type>
+ <list_type>string</list_type>
+ <locale name="C">
+ <default><!-- Translators: Please note that this has to be a list of
+ valid encodings (which are to be taken from the list in src/encoding.c).
+ It has to include UTF-8 and the word 'current', which is not to be
+ translated. This is provided for customization of the default encoding
+ menu; see bug 144810 for an use case. In most cases, this should be
+ left alone. -->[UTF-8,current]</default>
+ <short>List of available encodings</short>
+ <long>
+ A subset of possible encodings are presented in
+ the Encoding submenu. This is a list of encodings
+ to appear there. The special encoding name "current"
+ means to display the encoding of the current locale.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/global/confirm_window_close</key>
+ <applyto>/apps/mate-terminal/global/confirm_window_close</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to ask for confirmation when closing terminal windows</short>
+ <long>
+ Whether to ask for confirmation when closing a terminal window which has
+ more than one open tab.
+ </long>
+ </locale>
+ </schema>
+
+
+
+
+ <!-- Per-profile settings -->
+
+
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/visible_name</key>
+ <applyto>/apps/mate-terminal/profiles/Default/visible_name</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>Default</default>
+ <short>Human-readable name of the profile</short>
+ <long>
+ Human-readable name of the profile.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/default_show_menubar</key>
+ <applyto>/apps/mate-terminal/profiles/Default/default_show_menubar</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to show menubar in new windows/tabs</short>
+ <long>
+ True if the menubar should be shown in new windows,
+ for windows/tabs with this profile.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/foreground_color</key>
+ <applyto>/apps/mate-terminal/profiles/Default/foreground_color</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>#000000</default>
+ <locale name="C">
+ <short>Default color of text in the terminal</short>
+ <long>
+ Default color of text in the terminal, as a color
+ specification (can be HTML-style hex digits, or
+ a color name such as "red").
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/background_color</key>
+ <applyto>/apps/mate-terminal/profiles/Default/background_color</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>#FFFFDD</default>
+ <locale name="C">
+ <short>Default color of terminal background</short>
+ <long>
+ Default color of terminal background, as a color
+ specification (can be HTML-style hex digits, or
+ a color name such as "red").
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/bold_color</key>
+ <applyto>/apps/mate-terminal/profiles/Default/bold_color</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>#000000</default>
+ <locale name="C">
+ <short>Default color of bold text in the terminal</short>
+ <long>
+ 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.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/bold_color_same_as_fg</key>
+ <applyto>/apps/mate-terminal/profiles/Default/bold_color_same_as_fg</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether bold text should use the same color as normal text</short>
+ <long>
+ If true, boldface text will be rendered using the same color as
+ normal text.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/title_mode</key>
+ <applyto>/apps/mate-terminal/profiles/Default/title_mode</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>replace</default>
+ <locale name="C">
+ <short>What to do with dynamic title</short>
+ <long>
+ If the application in the terminal sets the title
+ (most typically people have their shell set up to
+ do this), the dynamically-set title can
+ erase the configured title, go before it, go after it,
+ or replace it. The possible values are "replace",
+ "before", "after", and "ignore".
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/title</key>
+ <applyto>/apps/mate-terminal/profiles/Default/title</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <default>Terminal</default>
+ <short>Title for terminal</short>
+ <long>
+ Title to display for the terminal window or tab.
+ This title may be replaced by or combined with
+ the title set by the application inside the terminal,
+ depending on the title_mode setting.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/allow_bold</key>
+ <applyto>/apps/mate-terminal/profiles/Default/allow_bold</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to allow bold text</short>
+ <long>
+ If true, allow applications in the terminal to make
+ text boldface.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/silent_bell</key>
+ <applyto>/apps/mate-terminal/profiles/Default/silent_bell</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to silence terminal bell</short>
+ <long>
+ If true, don't make a noise when applications send the
+ escape sequence for the terminal bell.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/word_chars</key>
+ <applyto>/apps/mate-terminal/profiles/Default/word_chars</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>-A-Za-z0-9,./?%&amp;#:_=+@~</default>
+ <locale name="C">
+ <short>Characters that are considered "part of a word"</short>
+ <long>
+ When selecting text by word, sequences of these characters
+ are considered single words. Ranges can be given as
+ "A-Z". Literal hyphen (not expressing a range) should be
+ the first character given.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/use_custom_default_size</key>
+ <applyto>/apps/mate-terminal/profiles/Default/use_custom_default_size</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to use custom terminal size for new windows</short>
+ <long>
+ If true, newly created terminal windows will have custom
+ size specified by default_size_columns and default_size_rows.
+ </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/default_size_columns</key>
+ <applyto>/apps/mate-terminal/profiles/Default/default_size_columns</applyto>
+ <owner>mate-terminal</owner>
+ <type>int</type>
+ <default>80</default>
+ <locale name="C">
+ <short>Default number of columns</short>
+ <long>
+ Number of columns in newly created terminal windows.
+ Has no effect if use_custom_default_size is not enabled.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/default_size_rows</key>
+ <applyto>/apps/mate-terminal/profiles/Default/default_size_rows</applyto>
+ <owner>mate-terminal</owner>
+ <type>int</type>
+ <default>24</default>
+ <locale name="C">
+ <short>Default number of rows</short>
+ <long>
+ Number of rows in newly created terminal windows.
+ Has no effect if use_custom_default_size is not enabled.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scrollbar_position</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scrollbar_position</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>right</default>
+ <locale name="C">
+ <short>Position of the scrollbar</short>
+ <long>
+ Where to put the terminal scrollbar. Possibilities are
+ "left", "right", and "hidden".
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scrollback_lines</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scrollback_lines</applyto>
+ <owner>mate-terminal</owner>
+ <type>int</type>
+ <default>512</default>
+ <locale name="C">
+ <short>Number of lines to keep in scrollback</short>
+ <long>
+ 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.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scrollback_unlimited</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scrollback_unlimited</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether an unlimited number of lines should be kept in scrollback</short>
+ <long>
+ 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.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scroll_on_keystroke</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scroll_on_keystroke</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to scroll to the bottom when a key is pressed</short>
+ <long>
+ If true, pressing a key jumps the scrollbar to the bottom.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scroll_on_output</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scroll_on_output</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to scroll to the bottom when there's new output</short>
+ <long>
+ If true, whenever there's new output the terminal will scroll
+ to the bottom.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/exit_action</key>
+ <applyto>/apps/mate-terminal/profiles/Default/exit_action</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>close</default>
+ <locale name="C">
+ <short>What to do with the terminal when the child command exits</short>
+ <long>
+ Possible values are "close" to close the terminal, and
+ "restart" to restart the command.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/login_shell</key>
+ <applyto>/apps/mate-terminal/profiles/Default/login_shell</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to launch the command in the terminal as a login shell</short>
+ <long>
+ If true, the command inside the terminal will be launched as
+ a login shell. (argv[0] will have a hyphen in front of it.)
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/update_records</key>
+ <applyto>/apps/mate-terminal/profiles/Default/update_records</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to update login records when launching terminal command</short>
+ <long>
+ If true, the system login records utmp and wtmp will be updated when the command inside the terminal
+ is launched.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/use_custom_command</key>
+ <applyto>/apps/mate-terminal/profiles/Default/use_custom_command</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>false</default>
+ <locale name="C">
+ <short>Whether to run a custom command instead of the shell</short>
+ <long>
+ If true, the value of the custom_command setting will
+ be used in place of running a shell.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/cursor_blink_mode</key>
+ <applyto>/apps/mate-terminal/profiles/Default/cursor_blink_mode</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>system</default>
+ <locale name="C">
+ <short>Whether to blink the cursor</short>
+ <long>
+ The possible values are "system" to use the global cursor blinking
+ settings, or "on" or "off" to set the mode explicitly.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/cursor_shape</key>
+ <applyto>/apps/mate-terminal/profiles/Default/cursor_shape</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>block</default>
+ <locale name="C">
+ <short>The cursor appearance</short>
+ <long>
+ The possible values are "block" to use a block cursor, "ibeam" to
+ use a vertical line cursor, or "underline" to use an underline cursor.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/custom_command</key>
+ <applyto>/apps/mate-terminal/profiles/Default/custom_command</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Custom command to use instead of the shell</short>
+ <long>
+ Run this command in place of the shell, if
+ use_custom_command is true.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/icon</key>
+ <applyto>/apps/mate-terminal/profiles/Default/icon</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Icon for terminal window</short>
+ <long>
+ Icon to use for tabs/windows containing this profile.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/palette</key>
+ <applyto>/apps/mate-terminal/profiles/Default/palette</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>#2E2E34343636:#CCCC00000000:#4E4E9A9A0606:#C4C4A0A00000:#34346565A4A4:#757550507B7B:#060698209A9A:#D3D3D7D7CFCF:#555557575353:#EFEF29292929:#8A8AE2E23434:#FCFCE9E94F4F:#72729F9FCFCF:#ADAD7F7FA8A8:#3434E2E2E2E2:#EEEEEEEEECEC</default>
+ <locale name="C">
+ <short>Palette for terminal applications</short>
+ <long>
+ Terminals have a 16-color palette that applications inside
+ the terminal can use. This is that palette, in the form
+ of a colon-separated list of color names. Color names
+ should be in hex format e.g. "#FF00FF"
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/font</key>
+ <applyto>/apps/mate-terminal/profiles/Default/font</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>Monospace 12</default>
+ <locale name="C">
+ <short>Font</short>
+ <long>
+ An Pango font name. Examples are "Sans 12" or "Monospace Bold 14".
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/background_type</key>
+ <applyto>/apps/mate-terminal/profiles/Default/background_type</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>solid</default>
+ <locale name="C">
+ <short>Background type</short>
+ <long>
+ Type of terminal background. May be "solid" for a solid color,
+ "image" for an image, or "transparent" for either real transparency if
+ a compositing window manager is running, or pseudo-transparency
+ otherwise.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/background_image</key>
+ <applyto>/apps/mate-terminal/profiles/Default/background_image</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default></default>
+ <locale name="C">
+ <short>Background image</short>
+ <long>
+ Filename of a background image.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/scroll_background</key>
+ <applyto>/apps/mate-terminal/profiles/Default/scroll_background</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to scroll background image</short>
+ <long>
+ If true, scroll the background image with the foreground
+ text; if false, keep the image in a fixed position and
+ scroll the text above it.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/background_darkness</key>
+ <applyto>/apps/mate-terminal/profiles/Default/background_darkness</applyto>
+ <owner>mate-terminal</owner>
+ <type>float</type>
+ <default>0.5</default>
+ <locale name="C">
+ <short>How much to darken the background image</short>
+ <long>
+ A value between 0.0 and 1.0 indicating how much to darken
+ the background image. 0.0 means no darkness, 1.0 means fully
+ dark. In the current implementation, there are only two levels of
+ darkness possible, so the setting behaves as a boolean,
+ where 0.0 disables the darkening effect.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/backspace_binding</key>
+ <applyto>/apps/mate-terminal/profiles/Default/backspace_binding</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>ascii-del</default>
+ <locale name="C">
+ <short>Effect of the Backspace key</short>
+ <long>
+ Sets what code the backspace key generates. Possible values
+ are "ascii-del" for the ASCII DEL character,
+ "control-h" for Control-H (AKA the ASCII BS character),
+ "escape-sequence" for the escape sequence typically
+ bound to backspace or delete. "ascii-del" is normally
+ considered the correct setting for the Backspace key.
+ </long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/delete_binding</key>
+ <applyto>/apps/mate-terminal/profiles/Default/delete_binding</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>escape-sequence</default>
+ <locale name="C">
+ <short>Effect of the Delete key</short>
+ <long>
+ Sets what code the delete key generates. Possible values
+ are "ascii-del" for the ASCII DEL character,
+ "control-h" for Control-H (AKA the ASCII BS character),
+ "escape-sequence" for the escape sequence typically
+ bound to backspace or delete. "escape-sequence" is normally
+ considered the correct setting for the Delete key.
+ </long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/use_theme_colors</key>
+ <applyto>/apps/mate-terminal/profiles/Default/use_theme_colors</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to use the colors from the theme for the terminal widget</short>
+ <long>
+ If true, the theme color scheme used for text entry boxes will
+ be used for the terminal, instead of colors provided by the user.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/use_system_font</key>
+ <applyto>/apps/mate-terminal/profiles/Default/use_system_font</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short>Whether to use the system font</short>
+ <long>
+ If true, the terminal will use the desktop-global standard
+ font if it's monospace (and the most similar font it can
+ come up with otherwise).
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/profiles/Default/use_skey</key>
+ <applyto>/apps/mate-terminal/profiles/Default/use_skey</applyto>
+ <owner>mate-terminal</owner>
+ <type>bool</type>
+ <default>true</default>
+ <locale name="C">
+ <short><!-- Translators: S/Key is the name of an application, so it should
+ not be translated. -->Highlight S/Key challenges</short>
+ <long><!-- Translators: S/Key is the name of an application, so it should
+ not be translated. -->Popup a dialog when an S/Key challenge response query is
+ detected and clicked on. Typing a password into the dialog
+ will send it to the terminal.
+ </long>
+ </locale>
+ </schema>
+
+ <!-- Keybindings -->
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/new_tab</key>
+ <applyto>/apps/mate-terminal/keybindings/new_tab</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;t</default>
+ <locale name="C">
+ <short>Keyboard shortcut to open a new tab</short>
+ <long>
+ Keyboard shortcut key for opening a new tab. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/new_window</key>
+ <applyto>/apps/mate-terminal/keybindings/new_window</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;n</default>
+ <locale name="C">
+ <short>Keyboard shortcut to open a new window</short>
+ <long>
+ Keyboard shortcut key for opening a new window. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/new_profile</key>
+ <applyto>/apps/mate-terminal/keybindings/new_profile</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Keyboard shortcut to create a new profile</short>
+ <long>
+ Keyboard shortcut key for bringing up the dialog for profile
+ creation. Expressed as a string in the same format used for
+ GTK+ resource files. If you set the option to the special
+ string "disabled", then there will be no keyboard shortcut for this
+ action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/save_contents</key>
+ <applyto>/apps/mate-terminal/keybindings/save_contents</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>disabled</default>
+ <locale name="C">
+ <short>Keyboard shortcut to save the current tab contents to file</short>
+ <long>
+ Keyboard shortcut key to save the current tab contents to a file. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/close_tab</key>
+ <applyto>/apps/mate-terminal/keybindings/close_tab</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;w</default>
+ <locale name="C">
+ <short>Keyboard shortcut to close a tab</short>
+ <long>
+ Keyboard shortcut key for closing a tab. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/close_window</key>
+ <applyto>/apps/mate-terminal/keybindings/close_window</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;q</default>
+ <locale name="C">
+ <short>Keyboard shortcut to close a window</short>
+ <long>
+ Keyboard shortcut key for closing a window. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/copy</key>
+ <applyto>/apps/mate-terminal/keybindings/copy</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;c</default>
+ <locale name="C">
+ <short>Keyboard shortcut to copy text</short>
+ <long>
+ Keyboard shortcut key for copying selected text to the
+ clipboard. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/paste</key>
+ <applyto>/apps/mate-terminal/keybindings/paste</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;v</default>
+ <locale name="C">
+ <short>Keyboard shortcut to paste text</short>
+ <long>
+ Keyboard shortcut key for pasting the contents of the
+ clipboard into the terminal. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/full_screen</key>
+ <applyto>/apps/mate-terminal/keybindings/full_screen</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>F11</default>
+ <locale name="C">
+ <short>Keyboard shortcut to toggle full screen mode</short>
+ <long>
+ Keyboard shortcut key for toggling full screen mode. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/toggle_menubar</key>
+ <applyto>/apps/mate-terminal/keybindings/toggle_menubar</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Keyboard shortcut to toggle the visibility of the menubar</short>
+ <long>
+ Keyboard shortcut key to toggle the visibility of the menubar. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/set_terminal_title</key>
+ <applyto>/apps/mate-terminal/keybindings/set_terminal_title</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Keyboard shortcut to set the terminal title</short>
+ <long>
+ Keyboard shortcut key to set the terminal title. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/reset</key>
+ <applyto>/apps/mate-terminal/keybindings/reset</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Keyboard shortcut to reset the terminal</short>
+ <long>
+ Keyboard shortcut key to reset the terminal. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/reset_and_clear</key>
+ <applyto>/apps/mate-terminal/keybindings/reset_and_clear</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Keyboard shortcut to reset and clear the terminal</short>
+ <long>
+ Keyboard shortcut key to reset and clear the terminal. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/prev_tab</key>
+ <applyto>/apps/mate-terminal/keybindings/prev_tab</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Control&gt;Page_Up</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to the previous tab</short>
+ <long>
+ Keyboard shortcut key to switch to the previous tab. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/next_tab</key>
+ <applyto>/apps/mate-terminal/keybindings/next_tab</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Control&gt;Page_Down</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to the next tab</short>
+ <long>
+ Keyboard shortcut key to switch to the next tab. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/move_tab_left</key>
+ <applyto>/apps/mate-terminal/keybindings/move_tab_left</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;Page_Up</default>
+ <locale name="C">
+ <short>Accelerator to move the current tab to the left.</short>
+ <long>
+ Accelerator key to move the current tab to the left. Expressed as a
+ string in the same format used for GTK+ resource files. If you set
+ the option to the special string "disabled", then there will be no
+ keybinding for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/move_tab_right</key>
+ <applyto>/apps/mate-terminal/keybindings/move_tab_right</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;&lt;Shift&gt;Page_Down</default>
+ <locale name="C">
+ <short>Accelerator to move the current tab to the right.</short>
+ <long>
+ Accelerator key to move the current tab to the right. Expressed as a
+ string in the same format used for GTK+ resource files. If you set
+ the option to the special string "disabled", then there will be no
+ keybinding for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/detach_tab</key>
+ <applyto>/apps/mate-terminal/keybindings/detach_tab</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <locale name="C">
+ <short>Accelerator to detach current tab.</short>
+ <long>
+ Accelerator key to detach current tab. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keybinding for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_1</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_1</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;1</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 1</short>
+ <long>
+ Keyboard shortcut key for switch to tab 1. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_2</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_2</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;2</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 2</short>
+ <long>
+ Keyboard shortcut key for switch to tab 2. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_3</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_3</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;3</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 3</short>
+ <long>
+ Keyboard shortcut key for switch to tab 3. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_4</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_4</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;4</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 4</short>
+ <long>
+ Keyboard shortcut key for switch to tab 4. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_5</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_5</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;5</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 5</short>
+ <long>
+ Keyboard shortcut key for switch to tab 5. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_6</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_6</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;6</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 6</short>
+ <long>
+ Keyboard shortcut key for switch to tab 6. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_7</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_7</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;7</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 7</short>
+ <long>
+ Keyboard shortcut key for switch to tab 7. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_8</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_8</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;8</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 8</short>
+ <long>
+ Keyboard shortcut key for switch to tab 8. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_9</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_9</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;9</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 9</short>
+ <long>
+ Keyboard shortcut key for switch to tab 9. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_10</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_10</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Alt&gt;0</default>
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 10</short>
+ <long>
+ Keyboard shortcut key for switch to tab 10. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_11</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_11</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+<!-- no default -->
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 11</short>
+ <long>
+ Keyboard shortcut key for switch to tab 11. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/switch_to_tab_12</key>
+ <applyto>/apps/mate-terminal/keybindings/switch_to_tab_12</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+<!-- no default -->
+ <locale name="C">
+ <short>Keyboard shortcut to switch to tab 12</short>
+ <long>
+ Keyboard shortcut key for switch to tab 12. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/help</key>
+ <applyto>/apps/mate-terminal/keybindings/help</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>F1</default>
+ <locale name="C">
+ <short>Keyboard shortcut to launch help</short>
+ <long>
+ Keyboard shortcut key for launching help. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/zoom_in</key>
+ <applyto>/apps/mate-terminal/keybindings/zoom_in</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;plus</default>
+ <locale name="C">
+ <short>Keyboard shortcut to make font larger</short>
+ <long>
+ Keyboard shortcut key for making font larger. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/zoom_out</key>
+ <applyto>/apps/mate-terminal/keybindings/zoom_out</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;minus</default>
+ <locale name="C">
+ <short>Keyboard shortcut to make font smaller</short>
+ <long>
+ Keyboard shortcut key for making font smaller. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ <schema>
+ <key>/schemas/apps/mate-terminal/keybindings/zoom_normal</key>
+ <applyto>/apps/mate-terminal/keybindings/zoom_normal</applyto>
+ <owner>mate-terminal</owner>
+ <type>string</type>
+ <default>&lt;Ctrl&gt;0</default>
+ <locale name="C">
+ <short>Keyboard shortcut to make font normal-size</short>
+ <long>
+ Keyboard shortcut key for making font the normal size. Expressed as a string
+ in the same format used for GTK+ resource files.
+ If you set the option to the special string "disabled", then there
+ will be no keyboard shortcut for this action.
+ </long>
+ </locale>
+ </schema>
+
+ </schemalist>
+</mateconfschemafile>
diff --git a/src/profile-editor.c b/src/profile-editor.c
new file mode 100644
index 0000000..6ac0b34
--- /dev/null
+++ b/src/profile-editor.c
@@ -0,0 +1,921 @@
+/*
+ * Copyright © 2002 Havoc Pennington
+ * Copyright © 2002 Mathias Hasselmann
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <math.h>
+
+#include <glib.h>
+#include <gio/gio.h>
+
+#include "terminal-intl.h"
+#include "profile-editor.h"
+#include "terminal-util.h"
+
+typedef struct _TerminalColorScheme TerminalColorScheme;
+
+struct _TerminalColorScheme
+{
+ const char *name;
+ const GdkColor foreground;
+ const GdkColor background;
+};
+
+static const TerminalColorScheme color_schemes[] = {
+ { N_("Black on light yellow"),
+ { 0, 0x0000, 0x0000, 0x0000 }, { 0, 0xFFFF, 0xFFFF, 0xDDDD } },
+ { N_("Black on white"),
+ { 0, 0x0000, 0x0000, 0x0000 }, { 0, 0xFFFF, 0xFFFF, 0xFFFF } },
+ { N_("Gray on black"),
+ { 0, 0xAAAA, 0xAAAA, 0xAAAA }, { 0, 0x0000, 0x0000, 0x0000 } },
+ { N_("Green on black"),
+ { 0, 0x0000, 0xFFFF, 0x0000 }, { 0, 0x0000, 0x0000, 0x0000 } },
+ { N_("White on black"),
+ { 0, 0xFFFF, 0xFFFF, 0xFFFF }, { 0, 0x0000, 0x0000, 0x0000 } }
+};
+
+static void profile_forgotten_cb (TerminalProfile *profile,
+ GtkWidget *editor);
+
+static void profile_notify_sensitivity_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkWidget *editor);
+
+static void profile_colors_notify_scheme_combo_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkComboBox *combo);
+
+static void profile_palette_notify_scheme_combo_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkComboBox *combo);
+
+static void profile_palette_notify_colorpickers_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkWidget *editor);
+
+static GtkWidget*
+profile_editor_get_widget (GtkWidget *editor,
+ const char *widget_name)
+{
+ GtkBuilder *builder;
+
+ builder = g_object_get_data (G_OBJECT (editor), "builder");
+ g_assert (builder != NULL);
+
+ return (GtkWidget *) gtk_builder_get_object (builder, widget_name);
+}
+
+static void
+widget_and_labels_set_sensitive (GtkWidget *widget, gboolean sensitive)
+{
+ GList *labels, *i;
+
+ labels = gtk_widget_list_mnemonic_labels (widget);
+ for (i = labels; i; i = i->next)
+ {
+ gtk_widget_set_sensitive (GTK_WIDGET (i->data), sensitive);
+ }
+ g_list_free (labels);
+
+ gtk_widget_set_sensitive (widget, sensitive);
+}
+
+static void
+profile_forgotten_cb (TerminalProfile *profile,
+ GtkWidget *editor)
+{
+ gtk_widget_destroy (editor);
+}
+
+static void
+profile_notify_sensitivity_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkWidget *editor)
+{
+ TerminalBackgroundType bg_type;
+ const char *prop_name;
+
+ if (pspec)
+ prop_name = pspec->name;
+ else
+ prop_name = NULL;
+
+#define SET_SENSITIVE(name, setting) widget_and_labels_set_sensitive (profile_editor_get_widget (editor, name), setting)
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_USE_CUSTOM_COMMAND) ||
+ prop_name == I_(TERMINAL_PROFILE_CUSTOM_COMMAND))
+ {
+ gboolean use_custom_command_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND);
+ SET_SENSITIVE ("use-custom-command-checkbutton", !use_custom_command_locked);
+ SET_SENSITIVE ("custom-command-box",
+ terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND) &&
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_CUSTOM_COMMAND));
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKGROUND_TYPE))
+ {
+ gboolean bg_type_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
+ SET_SENSITIVE ("solid-radiobutton", !bg_type_locked);
+ SET_SENSITIVE ("image-radiobutton", !bg_type_locked);
+ SET_SENSITIVE ("transparent-radiobutton", !bg_type_locked);
+
+ bg_type = terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
+ if (bg_type == TERMINAL_BACKGROUND_IMAGE)
+ {
+ SET_SENSITIVE ("background-image-filechooser", !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE));
+ SET_SENSITIVE ("scroll-background-checkbutton", !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLL_BACKGROUND));
+ SET_SENSITIVE ("darken-background-vbox", !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS));
+ }
+ else if (bg_type == TERMINAL_BACKGROUND_TRANSPARENT)
+ {
+ SET_SENSITIVE ("background-image-filechooser", FALSE);
+ SET_SENSITIVE ("scroll-background-checkbutton", FALSE);
+ SET_SENSITIVE ("darken-background-vbox", !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS));
+ }
+ else
+ {
+ SET_SENSITIVE ("background-image-filechooser", FALSE);
+ SET_SENSITIVE ("scroll-background-checkbutton", FALSE);
+ SET_SENSITIVE ("darken-background-vbox", FALSE);
+ }
+ }
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT) ||
+ prop_name == I_(TERMINAL_PROFILE_FONT))
+ {
+ SET_SENSITIVE ("font-hbox",
+ !terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT) &&
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_FONT));
+ SET_SENSITIVE ("system-font-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT));
+ }
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_FOREGROUND_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BACKGROUND_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
+ prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
+ {
+ gboolean bg_locked, use_theme_colors, fg_locked;
+
+ use_theme_colors = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS);
+ fg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
+ bg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
+
+ SET_SENSITIVE ("foreground-colorpicker", !use_theme_colors && !fg_locked);
+ SET_SENSITIVE ("foreground-colorpicker-label", !use_theme_colors && !fg_locked);
+ SET_SENSITIVE ("background-colorpicker", !use_theme_colors && !bg_locked);
+ SET_SENSITIVE ("background-colorpicker-label", !use_theme_colors && !bg_locked);
+ SET_SENSITIVE ("color-scheme-combobox", !use_theme_colors && !fg_locked && !bg_locked);
+ SET_SENSITIVE ("color-scheme-combobox-label", !use_theme_colors && !fg_locked && !bg_locked);
+ }
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
+ prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
+ {
+ gboolean bold_locked, bold_same_as_fg_locked, bold_same_as_fg, use_theme_colors;
+
+ use_theme_colors = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS);
+ bold_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BOLD_COLOR);
+ bold_same_as_fg_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
+ bold_same_as_fg = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
+
+ SET_SENSITIVE ("bold-color-same-as-fg-checkbox", !use_theme_colors && !bold_same_as_fg_locked);
+ SET_SENSITIVE ("bold-colorpicker", !use_theme_colors && !bold_locked && !bold_same_as_fg);
+ SET_SENSITIVE ("bold-colorpicker-label", !use_theme_colors && ((!bold_same_as_fg && !bold_locked) || !bold_same_as_fg_locked));
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_VISIBLE_NAME))
+ SET_SENSITIVE ("profile-name-entry",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_VISIBLE_NAME));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR))
+ SET_SENSITIVE ("show-menubar-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_TITLE))
+ SET_SENSITIVE ("title-entry",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_TITLE));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_TITLE_MODE))
+ SET_SENSITIVE ("title-mode-combobox",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_TITLE_MODE));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ALLOW_BOLD))
+ SET_SENSITIVE ("allow-bold-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_ALLOW_BOLD));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SILENT_BELL))
+ SET_SENSITIVE ("bell-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SILENT_BELL));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_WORD_CHARS))
+ SET_SENSITIVE ("word-chars-entry",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_WORD_CHARS));
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE) ||
+ prop_name == I_(TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS) ||
+ prop_name == I_(TERMINAL_PROFILE_DEFAULT_SIZE_ROWS))
+ {
+ gboolean use_custom_default_size_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
+ gboolean use_custom_default_size = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
+ gboolean columns_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS);
+ gboolean rows_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS);
+
+ SET_SENSITIVE ("use-custom-default-size-checkbutton", !use_custom_default_size_locked);
+ SET_SENSITIVE ("default-size-hbox", use_custom_default_size);
+ SET_SENSITIVE ("default-size-label", (!columns_locked || !rows_locked));
+ SET_SENSITIVE ("default-size-columns-label", !columns_locked);
+ SET_SENSITIVE ("default-size-columns-spinbutton", !columns_locked);
+ SET_SENSITIVE ("default-size-rows-label", !rows_locked);
+ SET_SENSITIVE ("default-size-rows-spinbutton", !rows_locked);
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLLBAR_POSITION))
+ SET_SENSITIVE ("scrollbar-position-combobox",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBAR_POSITION));
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_LINES) ||
+ prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_UNLIMITED))
+ {
+ gboolean scrollback_lines_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBACK_LINES);
+ gboolean scrollback_unlimited_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
+ gboolean scrollback_unlimited = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
+
+ SET_SENSITIVE ("scrollback-label", !scrollback_lines_locked);
+ SET_SENSITIVE ("scrollback-box", !scrollback_lines_locked && !scrollback_unlimited);
+ SET_SENSITIVE ("scrollback-unlimited-checkbutton", !scrollback_lines_locked && !scrollback_unlimited_locked);
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE))
+ SET_SENSITIVE ("scroll-on-keystroke-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_OUTPUT))
+ SET_SENSITIVE ("scroll-on-output-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_EXIT_ACTION))
+ SET_SENSITIVE ("exit-action-combobox",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_EXIT_ACTION));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_LOGIN_SHELL))
+ SET_SENSITIVE ("login-shell-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_LOGIN_SHELL));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_UPDATE_RECORDS))
+ SET_SENSITIVE ("update-records-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_UPDATE_RECORDS));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_PALETTE))
+ {
+ gboolean palette_locked = terminal_profile_property_locked (profile, TERMINAL_PROFILE_PALETTE);
+ SET_SENSITIVE ("palette-combobox", !palette_locked);
+ SET_SENSITIVE ("palette-table", !palette_locked);
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING))
+ SET_SENSITIVE ("backspace-binding-combobox",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_BACKSPACE_BINDING));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING))
+ SET_SENSITIVE ("delete-binding-combobox",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_DELETE_BINDING));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS))
+ SET_SENSITIVE ("use-theme-colors-checkbutton",
+ !terminal_profile_property_locked (profile, TERMINAL_PROFILE_USE_THEME_COLORS));
+
+#undef SET_INSENSITIVE
+}
+
+static void
+color_scheme_combo_changed_cb (GtkWidget *combo,
+ GParamSpec *pspec,
+ TerminalProfile *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);
+ g_object_set (profile,
+ TERMINAL_PROFILE_FOREGROUND_COLOR, &color_schemes[i].foreground,
+ TERMINAL_PROFILE_BACKGROUND_COLOR, &color_schemes[i].background,
+ NULL);
+ 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 (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkComboBox *combo)
+{
+ const GdkColor *fg, *bg;
+ guint i;
+
+ fg = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
+ bg = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
+
+ if (fg && bg)
+ {
+ for (i = 0; i < G_N_ELEMENTS (color_schemes); ++i)
+ {
+ if (gdk_color_equal (fg, &color_schemes[i].foreground) &&
+ gdk_color_equal (bg, &color_schemes[i].background))
+ break;
+ }
+ }
+ else
+ {
+ i = G_N_ELEMENTS (color_schemes);
+ }
+ /* 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,
+ TerminalProfile *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_profile_set_palette_builtin (profile, i);
+ 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 (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkComboBox *combo)
+{
+ guint i;
+
+ if (!terminal_profile_get_palette_is_builtin (profile, &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,
+ TerminalProfile *profile)
+{
+ GtkWidget *editor;
+ GdkColor color;
+ guint i;
+
+ gtk_color_button_get_color (button, &color);
+ i = GPOINTER_TO_UINT (g_object_get_data (G_OBJECT (button), "palette-entry-index"));
+
+ editor = gtk_widget_get_toplevel (GTK_WIDGET (button));
+ g_signal_handlers_block_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), editor);
+ terminal_profile_modify_palette_entry (profile, i, &color);
+ g_signal_handlers_unblock_by_func (profile, G_CALLBACK (profile_palette_notify_colorpickers_cb), editor);
+}
+
+static void
+profile_palette_notify_colorpickers_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkWidget *editor)
+{
+ GtkWidget *w;
+ GdkColor colors[TERMINAL_PALETTE_SIZE];
+ guint n_colors, i;
+
+ n_colors = G_N_ELEMENTS (colors);
+ terminal_profile_get_palette (profile, colors, &n_colors);
+
+ n_colors = MIN (n_colors, TERMINAL_PALETTE_SIZE);
+ for (i = 0; i < n_colors; i++)
+ {
+ char name[32];
+ GdkColor old_color;
+
+ g_snprintf (name, sizeof (name), "palette-colorpicker-%d", i + 1);
+ w = profile_editor_get_widget (editor, name);
+
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (w), &old_color);
+ if (!gdk_color_equal (&old_color, &colors[i]))
+ {
+ g_signal_handlers_block_by_func (w, G_CALLBACK (palette_color_notify_cb), profile);
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (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)
+{
+#if GTK_CHECK_VERSION (2, 16, 0)
+ const char *command;
+ GError *error = NULL;
+
+ command = gtk_entry_get_text (entry);
+
+ if (g_shell_parse_argv (command, NULL, NULL, &error))
+ {
+ gtk_entry_set_icon_from_stock (entry, GTK_PACK_END, NULL);
+ }
+ else
+ {
+ char *tooltip;
+
+ gtk_entry_set_icon_from_stock (entry, GTK_PACK_END, GTK_STOCK_DIALOG_WARNING);
+
+ tooltip = g_strdup_printf (_("Error parsing command: %s"), error->message);
+ gtk_entry_set_icon_tooltip_text (entry, GTK_PACK_END, tooltip);
+ g_free (tooltip);
+
+ g_error_free (error);
+ }
+#endif /* GTK+ >= 2.16.0 */
+}
+
+static void
+visible_name_entry_changed_cb (GtkEntry *entry,
+ GtkWindow *window)
+{
+ const char *visible_name;
+ char *text;
+
+ visible_name = gtk_entry_get_text (entry);
+
+ text = g_strdup_printf (_("Editing Profile “%s”"), visible_name);
+ gtk_window_set_title (window, text);
+ g_free (text);
+}
+
+static void
+reset_compat_defaults_cb (GtkWidget *button,
+ TerminalProfile *profile)
+{
+ terminal_profile_reset_property (profile, TERMINAL_PROFILE_DELETE_BINDING);
+ terminal_profile_reset_property (profile, TERMINAL_PROFILE_BACKSPACE_BINDING);
+}
+
+/*
+ * initialize widgets
+ */
+
+static void
+init_color_scheme_menu (GtkWidget *combo_box)
+{
+ int i;
+
+ i = G_N_ELEMENTS (color_schemes);
+ while (i > 0)
+ {
+ gtk_combo_box_prepend_text (GTK_COMBO_BOX (combo_box),
+ _(color_schemes[--i].name));
+ }
+}
+
+static char*
+format_percent_value (GtkScale *scale,
+ double val,
+ void *data)
+{
+ return g_strdup_printf ("%d%%", (int) (val * 100.0 + 0.5));
+}
+
+static void
+init_background_darkness_scale (GtkWidget *scale)
+{
+ g_signal_connect (scale, "format-value",
+ G_CALLBACK (format_percent_value),
+ NULL);
+}
+
+
+static void
+editor_response_cb (GtkWidget *editor,
+ int response,
+ gpointer use_data)
+{
+ if (response == GTK_RESPONSE_HELP)
+ {
+ terminal_util_show_help ("mate-terminal-prefs", GTK_WINDOW (editor));
+ return;
+ }
+
+ gtk_widget_destroy (editor);
+}
+
+#if 0
+static GdkPixbuf *
+create_preview_pixbuf (const gchar *filename)
+{
+ GdkPixbuf *pixbuf = NULL;
+ MateThumbnailFactory *thumbs;
+ const char *mime_type = NULL;
+ GFile *gfile;
+ GFileInfo *file_info;
+
+ if (filename == NULL)
+ return NULL;
+
+ gfile = g_file_new_for_uri (filename);
+ file_info = g_file_query_info (gfile,
+ G_FILE_ATTRIBUTE_STANDARD_CONTENT_TYPE,
+ 0, NULL, NULL);
+ if (file_info != NULL)
+ mime_type = g_file_info_get_content_type (file_info);
+
+ g_object_unref (gfile);
+
+ if (mime_type != NULL)
+ {
+ thumbs = mate_thumbnail_factory_new (MATE_THUMBNAIL_SIZE_NORMAL);
+
+ pixbuf = mate_thumbnail_factory_generate_thumbnail (thumbs,
+ filename,
+ mime_type);
+ g_object_unref (thumbs);
+ }
+
+ if (file_info != NULL)
+ g_object_unref (file_info);
+
+ return pixbuf;
+}
+
+static void
+update_image_preview (GtkFileChooser *chooser)
+{
+ GtkWidget *image;
+ gchar *file;
+
+ image = gtk_file_chooser_get_preview_widget (GTK_FILE_CHOOSER (chooser));
+ file = gtk_file_chooser_get_preview_uri (chooser);
+
+ if (file != NULL) {
+
+ GdkPixbuf *pixbuf = NULL;
+
+ pixbuf = create_preview_pixbuf (file);
+ g_free (file);
+
+ if (pixbuf != NULL) {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image), pixbuf);
+ g_object_unref (pixbuf);
+ }
+ else {
+ gtk_image_set_from_stock (GTK_IMAGE (image),
+ "gtk-dialog-question",
+ GTK_ICON_SIZE_DIALOG);
+ }
+ }
+ gtk_file_chooser_set_preview_widget_active (chooser, file != NULL);
+}
+#endif
+
+static void
+setup_background_filechooser (GtkWidget *filechooser,
+ TerminalProfile *profile)
+{
+ GtkFileFilter *filter;
+ const char *home_dir;
+
+ filter = gtk_file_filter_new ();
+ gtk_file_filter_add_pixbuf_formats (filter);
+ gtk_file_filter_set_name (filter, _("Images"));
+ gtk_file_chooser_set_filter (GTK_FILE_CHOOSER (filechooser), filter);
+
+ gtk_file_chooser_set_local_only (GTK_FILE_CHOOSER (filechooser), TRUE);
+
+ /* Start filechooser in $HOME instead of the current dir of the factory which is "/" */
+ home_dir = g_get_home_dir ();
+ if (home_dir)
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (filechooser), home_dir);
+
+#if 0
+ GtkWidget *image_preview;
+ GdkPixbuf *pixbuf = NULL;
+
+ image_preview = gtk_image_new ();
+ /* FIXMchpe this is bogus */
+ pixbuf = create_preview_pixbuf (terminal_profile_get_property_string (profile, TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE));
+ if (pixbuf != NULL)
+ {
+ gtk_image_set_from_pixbuf (GTK_IMAGE (image_preview), pixbuf);
+ g_object_unref (pixbuf);
+ }
+ else
+ {
+ gtk_image_set_from_stock (GTK_IMAGE (image_preview),
+ "gtk-dialog-question",
+ GTK_ICON_SIZE_DIALOG);
+ }
+
+ gtk_file_chooser_set_preview_widget (GTK_FILE_CHOOSER (filechooser),
+ image_preview);
+ gtk_file_chooser_set_use_preview_label (GTK_FILE_CHOOSER (filechooser),
+ FALSE);
+ gtk_widget_set_size_request (image_preview, 128, -1);
+ gtk_widget_show (image_preview);
+
+ g_signal_connect (filechooser, "update-preview",
+ G_CALLBACK (update_image_preview), NULL);
+#endif
+}
+
+static void
+profile_editor_destroyed (GtkWidget *editor,
+ TerminalProfile *profile)
+{
+ g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_forgotten_cb), editor);
+ g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_notify_sensitivity_cb), editor);
+ g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ G_CALLBACK (profile_colors_notify_scheme_combo_cb), NULL);
+ g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ G_CALLBACK (profile_palette_notify_scheme_combo_cb), NULL);
+ g_signal_handlers_disconnect_matched (profile, G_SIGNAL_MATCH_FUNC, 0, 0, NULL,
+ G_CALLBACK (profile_palette_notify_colorpickers_cb), NULL);
+
+ g_object_set_data (G_OBJECT (profile), "editor-window", NULL);
+ g_object_set_data (G_OBJECT (editor), "builder", NULL);
+}
+
+static void
+terminal_profile_editor_focus_widget (GtkWidget *editor,
+ const char *widget_name)
+{
+ GtkBuilder *builder;
+ GtkWidget *widget, *page, *page_parent;
+
+ if (widget_name == NULL)
+ return;
+
+ builder = g_object_get_data (G_OBJECT (editor), "builder");
+ 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);
+}
+
+/**
+ * terminal_profile_edit:
+ * @profile: a #TerminalProfile
+ * @transient_parent: a #GtkWindow, or %NULL
+ * @widget_name: a widget name in the profile editor's UI, or %NULL
+ *
+ * Shows the profile editor with @profile, anchored to @transient_parent.
+ * If @widget_name is non-%NULL, focuses the corresponding widget and
+ * switches the notebook to its containing page.
+ */
+void
+terminal_profile_edit (TerminalProfile *profile,
+ GtkWindow *transient_parent,
+ const char *widget_name)
+{
+ char *path;
+ GtkBuilder *builder;
+ GError *error = NULL;
+ GtkWidget *editor, *w;
+ guint i;
+
+ editor = g_object_get_data (G_OBJECT (profile), "editor-window");
+ if (editor)
+ {
+ terminal_profile_editor_focus_widget (editor, widget_name);
+
+ gtk_window_set_transient_for (GTK_WINDOW (editor),
+ GTK_WINDOW (transient_parent));
+ gtk_window_present (GTK_WINDOW (editor));
+ return;
+ }
+
+ path = g_build_filename (TERM_PKGDATADIR, "profile-preferences.ui", NULL);
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_file (builder, path, &error)) {
+ g_warning ("Failed to load %s: %s\n", path, error->message);
+ g_error_free (error);
+ g_free (path);
+ g_object_unref (builder);
+ return;
+ }
+ g_free (path);
+
+ editor = (GtkWidget *) gtk_builder_get_object (builder, "profile-editor-dialog");
+ g_object_set_data_full (G_OBJECT (editor), "builder",
+ builder, (GDestroyNotify) g_object_unref);
+
+ /* Store the dialogue on the profile, so we can acccess it above to check if
+ * there's already a profile editor for this profile.
+ */
+ g_object_set_data (G_OBJECT (profile), "editor-window", editor);
+
+ g_signal_connect (editor, "destroy",
+ G_CALLBACK (profile_editor_destroyed),
+ profile);
+
+ g_signal_connect (editor, "response",
+ G_CALLBACK (editor_response_cb),
+ NULL);
+
+ w = (GtkWidget *) gtk_builder_get_object (builder, "color-scheme-combobox");
+ init_color_scheme_menu (w);
+
+ w = (GtkWidget *) gtk_builder_get_object (builder, "darken-background-scale");
+ init_background_darkness_scale (w);
+
+ w = (GtkWidget *) gtk_builder_get_object (builder, "background-image-filechooser");
+ setup_background_filechooser (w, 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 + 1);
+ 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 %d"), i + 1);
+ gtk_color_button_set_title (GTK_COLOR_BUTTON (w), text);
+ g_free (text);
+
+ text = g_strdup_printf (_("Palette entry %d"), i + 1);
+ gtk_widget_set_tooltip_text (w, text);
+ g_free (text);
+
+ g_signal_connect (w, "notify::color",
+ G_CALLBACK (palette_color_notify_cb),
+ profile);
+ }
+
+ profile_palette_notify_colorpickers_cb (profile, NULL, editor);
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_PALETTE,
+ G_CALLBACK (profile_palette_notify_colorpickers_cb),
+ editor);
+
+ w = (GtkWidget *) gtk_builder_get_object (builder, "palette-combobox");
+ g_signal_connect (w, "notify::active",
+ G_CALLBACK (palette_scheme_combo_changed_cb),
+ profile);
+
+ profile_palette_notify_scheme_combo_cb (profile, NULL, GTK_COMBO_BOX (w));
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_PALETTE,
+ 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");
+ g_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));
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_FOREGROUND_COLOR,
+ G_CALLBACK (profile_colors_notify_scheme_combo_cb),
+ w);
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_BACKGROUND_COLOR,
+ G_CALLBACK (profile_colors_notify_scheme_combo_cb),
+ w);
+
+#define CONNECT_WITH_FLAGS(name, prop, flags) terminal_util_bind_object_property_to_widget (G_OBJECT (profile), prop, (GtkWidget *) gtk_builder_get_object (builder, name), flags)
+#define CONNECT(name, prop) CONNECT_WITH_FLAGS (name, prop, 0)
+#define SET_ENUM_VALUE(name, value) g_object_set_data (gtk_builder_get_object (builder, name), "enum-value", GINT_TO_POINTER (value))
+
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "custom-command-entry"));
+ custom_command_entry_changed_cb (GTK_ENTRY (w));
+ g_signal_connect (w, "changed",
+ G_CALLBACK (custom_command_entry_changed_cb), NULL);
+ w = GTK_WIDGET (gtk_builder_get_object (builder, "profile-name-entry"));
+ g_signal_connect (w, "changed",
+ G_CALLBACK (visible_name_entry_changed_cb), editor);
+
+ g_signal_connect (gtk_builder_get_object (builder, "reset-compat-defaults-button"),
+ "clicked",
+ G_CALLBACK (reset_compat_defaults_cb),
+ profile);
+
+ SET_ENUM_VALUE ("image-radiobutton", TERMINAL_BACKGROUND_IMAGE);
+ SET_ENUM_VALUE ("solid-radiobutton", TERMINAL_BACKGROUND_SOLID);
+ SET_ENUM_VALUE ("transparent-radiobutton", TERMINAL_BACKGROUND_TRANSPARENT);
+ CONNECT ("allow-bold-checkbutton", TERMINAL_PROFILE_ALLOW_BOLD);
+ CONNECT ("background-colorpicker", TERMINAL_PROFILE_BACKGROUND_COLOR);
+ CONNECT ("background-image-filechooser", TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE);
+ CONNECT ("backspace-binding-combobox", TERMINAL_PROFILE_BACKSPACE_BINDING);
+ CONNECT ("bold-color-same-as-fg-checkbox", TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG);
+ CONNECT ("bold-colorpicker", TERMINAL_PROFILE_BOLD_COLOR);
+ CONNECT ("cursor-shape-combobox", TERMINAL_PROFILE_CURSOR_SHAPE);
+ CONNECT ("custom-command-entry", TERMINAL_PROFILE_CUSTOM_COMMAND);
+ CONNECT ("darken-background-scale", TERMINAL_PROFILE_BACKGROUND_DARKNESS);
+ CONNECT ("default-size-columns-spinbutton", TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS);
+ CONNECT ("default-size-rows-spinbutton", TERMINAL_PROFILE_DEFAULT_SIZE_ROWS);
+ CONNECT ("delete-binding-combobox", TERMINAL_PROFILE_DELETE_BINDING);
+ CONNECT ("exit-action-combobox", TERMINAL_PROFILE_EXIT_ACTION);
+ CONNECT ("font-selector", TERMINAL_PROFILE_FONT);
+ CONNECT ("foreground-colorpicker", TERMINAL_PROFILE_FOREGROUND_COLOR);
+ CONNECT ("image-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
+ CONNECT ("login-shell-checkbutton", TERMINAL_PROFILE_LOGIN_SHELL);
+ CONNECT ("profile-name-entry", TERMINAL_PROFILE_VISIBLE_NAME);
+ CONNECT ("scrollback-lines-spinbutton", TERMINAL_PROFILE_SCROLLBACK_LINES);
+ CONNECT ("scrollback-unlimited-checkbutton", TERMINAL_PROFILE_SCROLLBACK_UNLIMITED);
+ CONNECT ("scroll-background-checkbutton", TERMINAL_PROFILE_SCROLL_BACKGROUND);
+ CONNECT ("scrollbar-position-combobox", TERMINAL_PROFILE_SCROLLBAR_POSITION);
+ CONNECT ("scroll-on-keystroke-checkbutton", TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE);
+ CONNECT ("scroll-on-output-checkbutton", TERMINAL_PROFILE_SCROLL_ON_OUTPUT);
+ CONNECT ("show-menubar-checkbutton", TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR);
+ CONNECT ("solid-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
+ CONNECT ("system-font-checkbutton", TERMINAL_PROFILE_USE_SYSTEM_FONT);
+ CONNECT ("title-entry", TERMINAL_PROFILE_TITLE);
+ CONNECT ("title-mode-combobox", TERMINAL_PROFILE_TITLE_MODE);
+ CONNECT ("transparent-radiobutton", TERMINAL_PROFILE_BACKGROUND_TYPE);
+ CONNECT ("update-records-checkbutton", TERMINAL_PROFILE_UPDATE_RECORDS);
+ CONNECT ("use-custom-command-checkbutton", TERMINAL_PROFILE_USE_CUSTOM_COMMAND);
+ CONNECT ("use-custom-default-size-checkbutton", TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE);
+ CONNECT ("use-theme-colors-checkbutton", TERMINAL_PROFILE_USE_THEME_COLORS);
+ CONNECT ("word-chars-entry", TERMINAL_PROFILE_WORD_CHARS);
+ CONNECT_WITH_FLAGS ("bell-checkbutton", TERMINAL_PROFILE_SILENT_BELL, FLAG_INVERT_BOOL);
+
+#undef CONNECT
+#undef CONNECT_WITH_FLAGS
+#undef SET_ENUM_VALUE
+
+ profile_notify_sensitivity_cb (profile, NULL, editor);
+ g_signal_connect (profile, "notify",
+ G_CALLBACK (profile_notify_sensitivity_cb),
+ editor);
+ g_signal_connect (profile,
+ "forgotten",
+ G_CALLBACK (profile_forgotten_cb),
+ editor);
+
+ terminal_profile_editor_focus_widget (editor, widget_name);
+
+ gtk_window_set_transient_for (GTK_WINDOW (editor),
+ GTK_WINDOW (transient_parent));
+ gtk_window_present (GTK_WINDOW (editor));
+}
diff --git a/src/profile-editor.h b/src/profile-editor.h
new file mode 100644
index 0000000..2eec796
--- /dev/null
+++ b/src/profile-editor.h
@@ -0,0 +1,34 @@
+/*
+ * Copyright © 2002 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_PROFILE_EDITOR_H
+#define TERMINAL_PROFILE_EDITOR_H
+
+#include "terminal-profile.h"
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void terminal_profile_edit (TerminalProfile *profile,
+ GtkWindow *transient_parent,
+ const char *widget_name);
+
+G_END_DECLS
+
+#endif /* TERMINAL_PROFILE_EDITOR_H */
diff --git a/src/profile-manager.glade b/src/profile-manager.glade
new file mode 100644
index 0000000..1eb3931
--- /dev/null
+++ b/src/profile-manager.glade
@@ -0,0 +1,213 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="profile-manager">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Profiles</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="default_width">400</property>
+ <property name="default_height">300</property>
+ <property name="resizable">True</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="role">mate-terminal-profile-manager</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area5">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="helpbutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-help</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-11</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="closebutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox84">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox25">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkScrolledWindow" id="profiles-treeview-container">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="hscrollbar_policy">GTK_POLICY_NEVER</property>
+ <property name="vscrollbar_policy">GTK_POLICY_AUTOMATIC</property>
+ <property name="shadow_type">GTK_SHADOW_IN</property>
+ <property name="window_placement">GTK_CORNER_TOP_LEFT</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVButtonBox" id="vbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkButton" id="new-profile-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-new</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="edit-profile-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-edit</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="delete-profile-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-delete</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="default-profile-hbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="default-profile-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Profile used when launching a new terminal:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/profile-new-dialog.glade b/src/profile-new-dialog.glade
new file mode 100644
index 0000000..1a22599
--- /dev/null
+++ b/src/profile-new-dialog.glade
@@ -0,0 +1,261 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="mate"/>
+
+<widget class="GtkDialog" id="new-profile-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes">New Profile</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">False</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area5">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="new-profile-cancel-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="new-profile-create-button">
+ <property name="visible">True</property>
+ <property name="sensitive">False</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-3</property>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment34">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">0</property>
+ <property name="yscale">0</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">0</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox10">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child>
+ <widget class="GtkImage" id="icon-1212">
+ <property name="visible">True</property>
+ <property name="stock">gtk-apply</property>
+ <property name="icon_size">4</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="create-button">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">C_reate</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox7">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkTable" id="new-profile-table">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox77">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <placeholder/>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="new-profile-name-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Profile _name:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">new-profile-name-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="new-profile-name-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ <property name="width_chars">14</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="new-profile-base-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Base on:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/profile-preferences.glade b/src/profile-preferences.glade
new file mode 100644
index 0000000..09be1bc
--- /dev/null
+++ b/src/profile-preferences.glade
@@ -0,0 +1,2814 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+<requires lib="mate"/>
+
+<widget class="GtkDialog" id="profile-editor-dialog">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="title" translatable="yes">Profile Editor</property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="role">mate-terminal-profile-editor</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox1">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="helpbutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-help</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-11</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="closebutton2">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-close</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-7</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkNotebook" id="profile-editor-notebook">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="show_tabs">True</property>
+ <property name="show_border">True</property>
+ <property name="tab_pos">GTK_POS_TOP</property>
+ <property name="scrollable">False</property>
+ <property name="enable_popup">False</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox3">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox135">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="profile-name-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Profile name:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">4</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">profile-name-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="profile-name-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="system-font-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Use the system fixed width font</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10109">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="font-hbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="font-selector-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Font:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">font-selector</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFontButton" id="font-selector">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="title" translatable="yes">Choose A Terminal Font</property>
+ <property name="show_style">True</property>
+ <property name="show_size">True</property>
+ <property name="use_font">True</property>
+ <property name="use_size">True</property>
+ <property name="focus_on_click">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="allow-bold-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Allow bold text</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="show-menubar-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Show _menubar by default in new terminals</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="bell-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Terminal _bell</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox140">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label480">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Cursor _shape:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">cursor-shape-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="cursor-shape-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Block
+I-Beam
+Underline</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox136">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="word-chars-entry-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Select-by-_word characters:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">word-chars-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="word-chars-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="use-custom-default-size-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Use custom default terminal si_ze</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10110">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="default-size-hbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="default-size-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Default size:</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox143">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="default-size-columns-spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">80 1 1024 1 10 0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="default-size-columns-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">columns</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox142">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="default-size-rows-spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">False</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">24 1 1024 1 10 0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="default-size-rows-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">rows</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label32">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">General</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox91">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox79">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label33">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Title&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10108">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox93">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox137">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="title-entry-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Initial _title:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">title-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="title-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox138">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="title-mode-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">When terminal commands set their o_wn titles:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">title-mode-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="title-mode-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Replace initial title
+Append initial title
+Prepend initial title
+Keep initial title</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox80">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label36">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Command&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10107">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox81">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox92">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="login-shell-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Run command as a login shell</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="update-records-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Update login records when command is launched</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="use-custom-command-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Ru_n a custom command instead of my shell</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="custom-command-box">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox134">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="custom-command-entry-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Custom co_mmand:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">custom-command-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="custom-command-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">True</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">False</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox27">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="exit-action-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">When command _exits:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">exit-action-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="exit-action-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Exit the terminal
+Restart the command
+Hold the terminal open</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label38">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Title and Command</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox90">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox82">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label39">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Foreground, Background, Bold and Underline&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10105">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox94">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkCheckButton" id="use-theme-colors-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Use colors from system theme</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox145">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="color-scheme-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Built-in sche_mes:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">color-scheme-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="color-scheme-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Custom</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox146">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">18</property>
+
+ <child>
+ <widget class="GtkTable" id="table31">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="foreground-colorpicker-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Text color:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">foreground-colorpicker</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="background-colorpicker-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Background color:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">background-colorpicker</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="background-colorpicker">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Choose Terminal Background Color</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="foreground-colorpicker">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="title" translatable="yes">Choose Terminal Text Color</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="underline-colorpicker-label">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkColorButton" id="bold-colorpicker">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label481">
+ <property name="label" translatable="yes">_Underline color:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">underline-colorpicker</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="underline-colorpicker">
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="underline-color-same-as-fg-checkbox">
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Same as text color</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="bold-colorpicker-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Bol_d color:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">bold-colorpicker</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">shrink|fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="bold-color-same-as-fg-checkbox">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Same as text color</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox83">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="label42">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;b&gt;Palette&lt;/b&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10106">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkTable" id="table25">
+ <property name="visible">True</property>
+ <property name="n_rows">3</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="palette-optionmenu-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Built-in _schemes:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">palette-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="palette-table">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">8</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">6</property>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-1">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-2">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-3">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-4">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-5">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-6">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="right_attach">6</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-8">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">7</property>
+ <property name="right_attach">8</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-9">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-10">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-12">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">3</property>
+ <property name="right_attach">4</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-11">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">2</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-13">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">4</property>
+ <property name="right_attach">5</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-16">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">7</property>
+ <property name="right_attach">8</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-14">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">5</property>
+ <property name="right_attach">6</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-7">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">7</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options"></property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkColorButton" id="palette-colorpicker-15">
+ <property name="visible">True</property>
+ <property name="tooltip">dummy</property>
+ <property name="can_focus">True</property>
+ <property name="use_alpha">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">6</property>
+ <property name="right_attach">7</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label44">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;&lt;b&gt;Note:&lt;/b&gt; Terminal applications have these colors available to them.&lt;/i&gt;&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label43">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Color p_alette:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">palette-colorpicker-1</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="palette-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Tango
+Linux console
+XTerm
+Rxvt
+Custom</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label45">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Colors</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox86">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="solid-radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Solid color</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">True</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox87">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkRadioButton" id="image-radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Background image</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">solid-radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkAlignment" id="alignment10103">
+ <property name="visible">True</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xscale">1</property>
+ <property name="yscale">1</property>
+ <property name="top_padding">0</property>
+ <property name="bottom_padding">0</property>
+ <property name="left_padding">12</property>
+ <property name="right_padding">0</property>
+
+ <child>
+ <widget class="GtkVBox" id="vbox89">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkHBox" id="hbox2">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="background-image-filechooser-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Image _file:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">background-image-filechooser</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkFileChooserButton" id="background-image-filechooser">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="title" translatable="yes">Select Background Image</property>
+ <property name="action">GTK_FILE_CHOOSER_ACTION_OPEN</property>
+ <property name="local_only">True</property>
+ <property name="show_hidden">False</property>
+ <property name="do_overwrite_confirmation">False</property>
+ <property name="width_chars">-1</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="scroll-background-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Background image _scrolls</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkRadioButton" id="transparent-radiobutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Transparent background</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ <property name="group">solid-radiobutton</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="darken-background-vbox">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkLabel" id="darken-background-scale-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">S_hade transparent or image background:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">darken-background-scale</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkLabel" id="label64">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;None&lt;/i&gt;&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">6</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHScale" id="darken-background-scale">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="draw_value">False</property>
+ <property name="value_pos">GTK_POS_BOTTOM</property>
+ <property name="digits">2</property>
+ <property name="update_policy">GTK_UPDATE_DELAYED</property>
+ <property name="inverted">False</property>
+ <property name="adjustment">0.10000000149 0 1 0.00999999977648 0.10000000149 0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label63">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;Maximum&lt;/i&gt;&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">1</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">6</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">1</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label479">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Background</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table27">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="n_rows">5</property>
+ <property name="n_columns">2</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="scrollbar-position-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Scrollbar is:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">scrollbar-position-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="scrollback-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Scroll_back:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">scrollback-lines-spinbutton</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="scroll-on-keystroke-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Scroll on _keystroke</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">4</property>
+ <property name="bottom_attach">5</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="scroll-on-output-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">Scroll on _output</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">3</property>
+ <property name="bottom_attach">4</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkCheckButton" id="scrollback-unlimited-checkbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Unlimited</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="active">False</property>
+ <property name="inconsistent">False</property>
+ <property name="draw_indicator">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">2</property>
+ <property name="bottom_attach">3</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox139">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkComboBox" id="scrollbar-position-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">On the left side
+On the right side
+Disabled</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="scrollback-box">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">6</property>
+
+ <child>
+ <widget class="GtkSpinButton" id="scrollback-lines-spinbutton">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="climb_rate">1</property>
+ <property name="digits">0</property>
+ <property name="numeric">True</property>
+ <property name="update_policy">GTK_UPDATE_ALWAYS</property>
+ <property name="snap_to_ticks">False</property>
+ <property name="wrap">False</property>
+ <property name="adjustment">1 1 2147483647 1 100 0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="scrollback-lines-spinbutton-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">lines</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">scrollback-lines-spinbutton</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">2</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label60">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Scrolling</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox4">
+ <property name="border_width">12</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label51">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">&lt;small&gt;&lt;i&gt;&lt;b&gt;Note:&lt;/b&gt; These options may cause some applications to behave incorrectly. They are only here to allow you to work around certain applications and operating systems that expect different terminal behavior.&lt;/i&gt;&lt;/small&gt;</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">True</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">7.45058015283e-09</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkTable" id="table30">
+ <property name="visible">True</property>
+ <property name="n_rows">2</property>
+ <property name="n_columns">3</property>
+ <property name="homogeneous">False</property>
+ <property name="row_spacing">6</property>
+ <property name="column_spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="delete-binding-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Delete key generates:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">delete-binding-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="backspace-binding-combobox-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Backspace key generates:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">backspace-binding-combobox</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="left_attach">0</property>
+ <property name="right_attach">1</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options"></property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="backspace-binding-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Automatic
+Control-H
+ASCII DEL
+Escape sequence
+TTY Erase</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">0</property>
+ <property name="bottom_attach">1</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkComboBox" id="delete-binding-combobox">
+ <property name="visible">True</property>
+ <property name="items" translatable="yes">Automatic
+Control-H
+ASCII DEL
+Escape sequence
+TTY Erase</property>
+ <property name="add_tearoffs">False</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ <packing>
+ <property name="left_attach">1</property>
+ <property name="right_attach">3</property>
+ <property name="top_attach">1</property>
+ <property name="bottom_attach">2</property>
+ <property name="x_options">fill</property>
+ <property name="y_options">fill</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHButtonBox" id="hbuttonbox1">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_START</property>
+ <property name="spacing">0</property>
+
+ <child>
+ <widget class="GtkButton" id="reset-compat-defaults-button">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="label" translatable="yes">_Reset Compatibility Options to Defaults</property>
+ <property name="use_underline">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="tab_expand">False</property>
+ <property name="tab_fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkLabel" id="label54">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">Compatibility</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_CENTER</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="type">tab</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/skey-challenge.glade b/src/skey-challenge.glade
new file mode 100644
index 0000000..6947783
--- /dev/null
+++ b/src/skey-challenge.glade
@@ -0,0 +1,198 @@
+<?xml version="1.0" standalone="no"?> <!--*- mode: xml -*-->
+<!DOCTYPE glade-interface SYSTEM "http://glade.mate.org/glade-2.0.dtd">
+
+<glade-interface>
+
+<widget class="GtkDialog" id="skey-dialog">
+ <property name="border_width">5</property>
+ <property name="title" translatable="yes"></property>
+ <property name="type">GTK_WINDOW_TOPLEVEL</property>
+ <property name="window_position">GTK_WIN_POS_NONE</property>
+ <property name="modal">False</property>
+ <property name="resizable">False</property>
+ <property name="destroy_with_parent">True</property>
+ <property name="decorated">True</property>
+ <property name="skip_taskbar_hint">False</property>
+ <property name="skip_pager_hint">False</property>
+ <property name="type_hint">GDK_WINDOW_TYPE_HINT_DIALOG</property>
+ <property name="gravity">GDK_GRAVITY_NORTH_WEST</property>
+ <property name="focus_on_map">True</property>
+ <property name="urgency_hint">False</property>
+ <property name="has_separator">False</property>
+
+ <child internal-child="vbox">
+ <widget class="GtkVBox" id="dialog-vbox4">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">2</property>
+
+ <child internal-child="action_area">
+ <widget class="GtkHButtonBox" id="dialog-action_area4">
+ <property name="visible">True</property>
+ <property name="layout_style">GTK_BUTTONBOX_END</property>
+
+ <child>
+ <widget class="GtkButton" id="cancelbutton1">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-cancel</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-6</property>
+ </widget>
+ </child>
+
+ <child>
+ <widget class="GtkButton" id="skey-ok-button">
+ <property name="visible">True</property>
+ <property name="can_default">True</property>
+ <property name="has_default">True</property>
+ <property name="can_focus">True</property>
+ <property name="label">gtk-ok</property>
+ <property name="use_stock">True</property>
+ <property name="relief">GTK_RELIEF_NORMAL</property>
+ <property name="focus_on_click">True</property>
+ <property name="response_id">-5</property>
+ </widget>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ <property name="pack_type">GTK_PACK_END</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox4">
+ <property name="border_width">5</property>
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkImage" id="skey-image">
+ <property name="visible">True</property>
+ <property name="stock">gtk-dialog-authentication</property>
+ <property name="icon_size">6</property>
+ <property name="xalign">0.5</property>
+ <property name="yalign">0</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkVBox" id="vbox6">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="text-label">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">S/Key Challenge Response</property>
+ <property name="use_underline">False</property>
+ <property name="use_markup">True</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkHBox" id="hbox5">
+ <property name="visible">True</property>
+ <property name="homogeneous">False</property>
+ <property name="spacing">12</property>
+
+ <child>
+ <widget class="GtkLabel" id="label62">
+ <property name="visible">True</property>
+ <property name="label" translatable="yes">_Password:</property>
+ <property name="use_underline">True</property>
+ <property name="use_markup">False</property>
+ <property name="justify">GTK_JUSTIFY_LEFT</property>
+ <property name="wrap">False</property>
+ <property name="selectable">False</property>
+ <property name="xalign">0</property>
+ <property name="yalign">0.5</property>
+ <property name="xpad">0</property>
+ <property name="ypad">0</property>
+ <property name="mnemonic_widget">skey-entry</property>
+ <property name="ellipsize">PANGO_ELLIPSIZE_NONE</property>
+ <property name="width_chars">-1</property>
+ <property name="single_line_mode">False</property>
+ <property name="angle">0</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">False</property>
+ </packing>
+ </child>
+
+ <child>
+ <widget class="GtkEntry" id="skey-entry">
+ <property name="visible">True</property>
+ <property name="can_focus">True</property>
+ <property name="editable">True</property>
+ <property name="visibility">False</property>
+ <property name="max_length">0</property>
+ <property name="text" translatable="yes"></property>
+ <property name="has_frame">True</property>
+ <property name="activates_default">True</property>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">False</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ <packing>
+ <property name="padding">0</property>
+ <property name="expand">True</property>
+ <property name="fill">True</property>
+ </packing>
+ </child>
+ </widget>
+ </child>
+</widget>
+
+</glade-interface>
diff --git a/src/skey-popup.c b/src/skey-popup.c
new file mode 100644
index 0000000..553e035
--- /dev/null
+++ b/src/skey-popup.c
@@ -0,0 +1,228 @@
+/*
+ * Copyright © 2002 Jonathan Blandford <[email protected]>
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include "terminal-intl.h"
+
+#include "terminal-util.h"
+#include "terminal-screen.h"
+#include "skey-popup.h"
+#include "skey/skey.h"
+#include <stdlib.h>
+#include <string.h>
+
+#define SKEY_PREFIX "s/key "
+#define OTP_PREFIX "otp-"
+
+typedef struct {
+ TerminalScreen *screen;
+ char *seed;
+ int seq;
+ int hash;
+} SkeyData;
+
+static void
+skey_data_free (SkeyData *data)
+{
+ g_free (data->seed);
+ g_free (data);
+}
+
+static gboolean
+extract_seq_and_seed (const gchar *skey_match,
+ gint *seq,
+ gchar **seed)
+{
+ gchar *end_ptr = NULL;
+
+ /* FIXME: use g_ascii_strtoll */
+ *seq = strtol (skey_match + strlen (SKEY_PREFIX), &end_ptr, 0);
+
+ if (end_ptr == NULL || *end_ptr == '\000')
+ return FALSE;
+
+ *seed = g_strdup (end_ptr + 1);
+
+ return TRUE;
+}
+
+static gboolean
+extract_hash_seq_and_seed (const gchar *otp_match,
+ gint *hash,
+ gint *seq,
+ gchar **seed)
+{
+ gchar *end_ptr = NULL;
+ const gchar *p = otp_match + strlen (OTP_PREFIX);
+ gint len = 3;
+
+ if (strncmp (p, "md4", 3) == 0)
+ *hash = MD4;
+ else if (strncmp (p, "md5", 3) == 0)
+ *hash = MD5;
+ else if (strncmp (p, "sha1", 4) == 0)
+ {
+ *hash = SHA1;
+ len++;
+ }
+ else
+ return FALSE;
+
+ p += len;
+
+ /* RFC mandates the following skipping */
+ while (*p == ' ' || *p == '\t')
+ {
+ if (*p == '\0')
+ return FALSE;
+
+ p++;
+ }
+
+ /* FIXME: use g_ascii_strtoll */
+ *seq = strtol (p, &end_ptr, 0);
+
+ if (end_ptr == NULL || *end_ptr == '\000')
+ return FALSE;
+
+ p = end_ptr;
+
+ while (*p == ' ' || *p == '\t')
+ {
+ if (*p == '\0')
+ return FALSE;
+ p++;
+ }
+
+ *seed = g_strdup (p);
+ return TRUE;
+}
+
+static void
+skey_challenge_response_cb (GtkWidget *dialog,
+ int response_id,
+ SkeyData *data)
+{
+ if (response_id == GTK_RESPONSE_OK)
+ {
+ GtkWidget *entry;
+ const char *password;
+ char *response;
+
+ entry = g_object_get_data (G_OBJECT (dialog), "skey-entry");
+ password = gtk_entry_get_text (GTK_ENTRY (entry));
+
+ /* FIXME: fix skey to use g_malloc */
+ response = skey (data->hash, data->seq, data->seed, password);
+ if (response)
+ {
+ VteTerminal *vte_terminal = VTE_TERMINAL (data->screen);
+ static const char newline[2] = "\n";
+
+ vte_terminal_feed_child (vte_terminal, response, strlen (response));
+ vte_terminal_feed_child (vte_terminal, newline, strlen (newline));
+ free (response);
+ }
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+void
+terminal_skey_do_popup (GtkWindow *window,
+ TerminalScreen *screen,
+ const gchar *skey_match)
+{
+ GtkWidget *dialog, *label, *entry, *ok_button;
+ char *title_text;
+ char *seed;
+ int seq;
+ int hash = MD5;
+ SkeyData *data;
+
+ if (strncmp (SKEY_PREFIX, skey_match, strlen (SKEY_PREFIX)) == 0)
+ {
+ if (!extract_seq_and_seed (skey_match, &seq, &seed))
+ {
+ terminal_util_show_error_dialog (window, NULL, NULL,
+ _("The text you clicked on doesn't "
+ "seem to be a valid S/Key "
+ "challenge."));
+ return;
+ }
+ }
+ else
+ {
+ if (!extract_hash_seq_and_seed (skey_match, &hash, &seq, &seed))
+ {
+ terminal_util_show_error_dialog (window, NULL, NULL,
+ _("The text you clicked on doesn't "
+ "seem to be a valid OTP "
+ "challenge."));
+ return;
+ }
+ }
+
+ if (!terminal_util_load_builder_file ("skey-challenge.ui",
+ "skey-dialog", &dialog,
+ "skey-entry", &entry,
+ "text-label", &label,
+ "skey-ok-button", &ok_button,
+ NULL))
+ {
+ g_free (seed);
+ return;
+ }
+
+ title_text = g_strdup_printf ("<big><b>%s</b></big>",
+ gtk_label_get_text (GTK_LABEL (label)));
+ gtk_label_set_label (GTK_LABEL (label), title_text);
+ g_free (title_text);
+
+ g_object_set_data (G_OBJECT (dialog), "skey-entry", entry);
+
+ gtk_widget_grab_focus (entry);
+ gtk_widget_grab_default (ok_button);
+ gtk_entry_set_text (GTK_ENTRY (entry), "");
+
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), window);
+ gtk_window_set_modal (GTK_WINDOW (dialog), TRUE);
+ gtk_window_set_destroy_with_parent (GTK_WINDOW (dialog), TRUE);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_OK,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ /* FIXME: make this dialogue close if the screen closes! */
+
+ data = g_new (SkeyData, 1);
+ data->hash = hash;
+ data->seq = seq;
+ data->seed = seed;
+ data->screen = screen;
+
+ g_signal_connect_data (dialog, "response",
+ G_CALLBACK (skey_challenge_response_cb),
+ data, (GClosureNotify) skey_data_free, 0);
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
diff --git a/src/skey-popup.h b/src/skey-popup.h
new file mode 100644
index 0000000..f4847eb
--- /dev/null
+++ b/src/skey-popup.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2002 Jonathan Blandford <[email protected]>
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef SKEY_POPUP_H
+#define SKEY_POPUP_H
+
+#include <gtk/gtk.h>
+
+#include "terminal-screen.h"
+
+G_BEGIN_DECLS
+
+void terminal_skey_do_popup (GtkWindow *window,
+ TerminalScreen *screen,
+ const gchar *skey_match);
+
+G_END_DECLS
+
+#endif /* SKEY_POPUP_H */
diff --git a/src/skey/Makefile.am b/src/skey/Makefile.am
new file mode 100644
index 0000000..0402507
--- /dev/null
+++ b/src/skey/Makefile.am
@@ -0,0 +1,60 @@
+NULL =
+
+noinst_LTLIBRARIES = libskey.la
+
+libskey_la_SOURCES = \
+ btoe.c \
+ btoe.h \
+ skey.h \
+ skey.c \
+ skeyutil.h\
+ skeyutil.c\
+ md4.c \
+ md4.h \
+ md5.c \
+ md5.h \
+ sha1.h \
+ sha1.c \
+ $(NULL)
+
+libskey_la_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ -DG_DISABLE_SINGLE_INCLUDES \
+ $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS)
+
+libskey_la_CFLAGS = \
+ $(TERM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLASG)
+
+libskey_la_LDFLAGS =
+
+libskey_la_LIBADD = \
+ $(TERM_LIBS)
+
+check_PROGRAMS = testskey
+
+testskey_SOURCES = \
+ test.c \
+ $(NULL)
+
+testskey_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS)
+
+testskey_CFLAGS = \
+ $(TERM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLAGS)
+
+testskey_LDFLAGS =
+
+testskey_LDADD = \
+ libskey.la \
+ $(TERM_LIBS)
+
+TESTS = testskey
+
+-include $(top_srcdir)/git.mk
diff --git a/src/skey/Makefile.in b/src/skey/Makefile.in
new file mode 100644
index 0000000..bfe467c
--- /dev/null
+++ b/src/skey/Makefile.in
@@ -0,0 +1,777 @@
+# Makefile.in generated by automake 1.11.1 from Makefile.am.
+# @configure_input@
+
+# Copyright (C) 1994, 1995, 1996, 1997, 1998, 1999, 2000, 2001, 2002,
+# 2003, 2004, 2005, 2006, 2007, 2008, 2009 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@
+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@
+check_PROGRAMS = testskey$(EXEEXT)
+TESTS = testskey$(EXEEXT)
+subdir = src/skey
+DIST_COMMON = $(srcdir)/Makefile.am $(srcdir)/Makefile.in
+ACLOCAL_M4 = $(top_srcdir)/aclocal.m4
+am__aclocal_m4_deps = $(top_srcdir)/configure.ac
+am__configure_deps = $(am__aclocal_m4_deps) $(CONFIGURE_DEPENDENCIES) \
+ $(ACLOCAL_M4)
+mkinstalldirs = $(SHELL) $(top_srcdir)/mkinstalldirs
+CONFIG_HEADER = $(top_builddir)/config.h
+CONFIG_CLEAN_FILES =
+CONFIG_CLEAN_VPATH_FILES =
+LTLIBRARIES = $(noinst_LTLIBRARIES)
+am__DEPENDENCIES_1 =
+libskey_la_DEPENDENCIES = $(am__DEPENDENCIES_1)
+am__objects_1 =
+am_libskey_la_OBJECTS = libskey_la-btoe.lo libskey_la-skey.lo \
+ libskey_la-skeyutil.lo libskey_la-md4.lo libskey_la-md5.lo \
+ libskey_la-sha1.lo $(am__objects_1)
+libskey_la_OBJECTS = $(am_libskey_la_OBJECTS)
+AM_V_lt = $(am__v_lt_$(V))
+am__v_lt_ = $(am__v_lt_$(AM_DEFAULT_VERBOSITY))
+am__v_lt_0 = --silent
+libskey_la_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(libskey_la_CFLAGS) \
+ $(CFLAGS) $(libskey_la_LDFLAGS) $(LDFLAGS) -o $@
+am_testskey_OBJECTS = testskey-test.$(OBJEXT) $(am__objects_1)
+testskey_OBJECTS = $(am_testskey_OBJECTS)
+testskey_DEPENDENCIES = libskey.la $(am__DEPENDENCIES_1)
+testskey_LINK = $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) \
+ $(LIBTOOLFLAGS) --mode=link $(CCLD) $(testskey_CFLAGS) \
+ $(CFLAGS) $(testskey_LDFLAGS) $(LDFLAGS) -o $@
+DEFAULT_INCLUDES = -I.@am__isrc@ -I$(top_builddir)
+depcomp = $(SHELL) $(top_srcdir)/depcomp
+am__depfiles_maybe = depfiles
+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_$(V))
+am__v_CC_ = $(am__v_CC_$(AM_DEFAULT_VERBOSITY))
+am__v_CC_0 = @echo " CC " $@;
+AM_V_at = $(am__v_at_$(V))
+am__v_at_ = $(am__v_at_$(AM_DEFAULT_VERBOSITY))
+am__v_at_0 = @
+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_$(V))
+am__v_CCLD_ = $(am__v_CCLD_$(AM_DEFAULT_VERBOSITY))
+am__v_CCLD_0 = @echo " CCLD " $@;
+AM_V_GEN = $(am__v_GEN_$(V))
+am__v_GEN_ = $(am__v_GEN_$(AM_DEFAULT_VERBOSITY))
+am__v_GEN_0 = @echo " GEN " $@;
+SOURCES = $(libskey_la_SOURCES) $(testskey_SOURCES)
+DIST_SOURCES = $(libskey_la_SOURCES) $(testskey_SOURCES)
+ETAGS = etags
+CTAGS = ctags
+am__tty_colors = \
+red=; grn=; lgn=; blu=; std=
+DISTFILES = $(DIST_COMMON) $(DIST_SOURCES) $(TEXINFOS) $(EXTRA_DIST)
+ACLOCAL = @ACLOCAL@
+ACLOCAL_AMFLAGS = @ACLOCAL_AMFLAGS@
+ALL_LINGUAS = @ALL_LINGUAS@
+AMTAR = @AMTAR@
+AM_DEFAULT_VERBOSITY = @AM_DEFAULT_VERBOSITY@
+AR = @AR@
+AUTOCONF = @AUTOCONF@
+AUTOHEADER = @AUTOHEADER@
+AUTOMAKE = @AUTOMAKE@
+AWK = @AWK@
+CATALOGS = @CATALOGS@
+CATOBJEXT = @CATOBJEXT@
+CC = @CC@
+CCDEPMODE = @CCDEPMODE@
+CFLAGS = @CFLAGS@
+CPP = @CPP@
+CPPFLAGS = @CPPFLAGS@
+CYGPATH_W = @CYGPATH_W@
+DATADIRNAME = @DATADIRNAME@
+DEFS = @DEFS@
+DEPDIR = @DEPDIR@
+DISTCHECK_CONFIGURE_FLAGS = @DISTCHECK_CONFIGURE_FLAGS@
+DLLTOOL = @DLLTOOL@
+DOC_USER_FORMATS = @DOC_USER_FORMATS@
+DSYMUTIL = @DSYMUTIL@
+DUMPBIN = @DUMPBIN@
+ECHO_C = @ECHO_C@
+ECHO_N = @ECHO_N@
+ECHO_T = @ECHO_T@
+EGREP = @EGREP@
+EXEEXT = @EXEEXT@
+FGREP = @FGREP@
+GETTEXT_PACKAGE = @GETTEXT_PACKAGE@
+GLIB_GENMARSHAL = @GLIB_GENMARSHAL@
+GLIB_MKENUMS = @GLIB_MKENUMS@
+GMOFILES = @GMOFILES@
+GMSGFMT = @GMSGFMT@
+GREP = @GREP@
+GTK_BUILDER_CONVERT = @GTK_BUILDER_CONVERT@
+HELP_DIR = @HELP_DIR@
+INSTALL = @INSTALL@
+INSTALL_DATA = @INSTALL_DATA@
+INSTALL_PROGRAM = @INSTALL_PROGRAM@
+INSTALL_SCRIPT = @INSTALL_SCRIPT@
+INSTALL_STRIP_PROGRAM = @INSTALL_STRIP_PROGRAM@
+INSTOBJEXT = @INSTOBJEXT@
+INTLLIBS = @INTLLIBS@
+INTLTOOL_EXTRACT = @INTLTOOL_EXTRACT@
+INTLTOOL_MERGE = @INTLTOOL_MERGE@
+INTLTOOL_PERL = @INTLTOOL_PERL@
+INTLTOOL_UPDATE = @INTLTOOL_UPDATE@
+LD = @LD@
+LDFLAGS = @LDFLAGS@
+LIBOBJS = @LIBOBJS@
+LIBS = @LIBS@
+LIBTOOL = @LIBTOOL@
+LIPO = @LIPO@
+LN_S = @LN_S@
+LTLIBOBJS = @LTLIBOBJS@
+MAINT = @MAINT@
+MAKEINFO = @MAKEINFO@
+MANIFEST_TOOL = @MANIFEST_TOOL@
+MATECONFTOOL = @MATECONFTOOL@
+MATECONF_SCHEMA_CONFIG_SOURCE = @MATECONF_SCHEMA_CONFIG_SOURCE@
+MATECONF_SCHEMA_FILE_DIR = @MATECONF_SCHEMA_FILE_DIR@
+MKDIR_P = @MKDIR_P@
+MKINSTALLDIRS = @MKINSTALLDIRS@
+MSGFMT = @MSGFMT@
+MSGFMT_OPTS = @MSGFMT_OPTS@
+MSGMERGE = @MSGMERGE@
+NM = @NM@
+NMEDIT = @NMEDIT@
+OBJDUMP = @OBJDUMP@
+OBJEXT = @OBJEXT@
+OMF_DIR = @OMF_DIR@
+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@
+POFILES = @POFILES@
+POSUB = @POSUB@
+PO_IN_DATADIR_FALSE = @PO_IN_DATADIR_FALSE@
+PO_IN_DATADIR_TRUE = @PO_IN_DATADIR_TRUE@
+RANLIB = @RANLIB@
+SED = @SED@
+SET_MAKE = @SET_MAKE@
+SHELL = @SHELL@
+SMCLIENT_CFLAGS = @SMCLIENT_CFLAGS@
+SMCLIENT_LIBS = @SMCLIENT_LIBS@
+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@
+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@
+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@
+docdir = @docdir@
+dvidir = @dvidir@
+exec_prefix = @exec_prefix@
+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@
+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 =
+noinst_LTLIBRARIES = libskey.la
+libskey_la_SOURCES = \
+ btoe.c \
+ btoe.h \
+ skey.h \
+ skey.c \
+ skeyutil.h\
+ skeyutil.c\
+ md4.c \
+ md4.h \
+ md5.c \
+ md5.h \
+ sha1.h \
+ sha1.c \
+ $(NULL)
+
+libskey_la_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ -DG_DISABLE_SINGLE_INCLUDES \
+ $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS)
+
+libskey_la_CFLAGS = \
+ $(TERM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLASG)
+
+libskey_la_LDFLAGS =
+libskey_la_LIBADD = \
+ $(TERM_LIBS)
+
+testskey_SOURCES = \
+ test.c \
+ $(NULL)
+
+testskey_CPPFLAGS = \
+ -I$(srcdir)/.. \
+ $(DISABLE_DEPRECATED) \
+ $(AM_CPPFLAGS)
+
+testskey_CFLAGS = \
+ $(TERM_CFLAGS) \
+ $(WARN_CFLAGS) \
+ $(AM_CFLAGS)
+
+testskey_LDFLAGS =
+testskey_LDADD = \
+ libskey.la \
+ $(TERM_LIBS)
+
+all: all-am
+
+.SUFFIXES:
+.SUFFIXES: .c .lo .o .obj
+$(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/skey/Makefile'; \
+ $(am__cd) $(top_srcdir) && \
+ $(AUTOMAKE) --foreign src/skey/Makefile
+.PRECIOUS: 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__depfiles_maybe)'; \
+ cd $(top_builddir) && $(SHELL) ./config.status $(subdir)/$@ $(am__depfiles_maybe);; \
+ 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):
+
+clean-noinstLTLIBRARIES:
+ -test -z "$(noinst_LTLIBRARIES)" || rm -f $(noinst_LTLIBRARIES)
+ @list='$(noinst_LTLIBRARIES)'; for p in $$list; do \
+ dir="`echo $$p | sed -e 's|/[^/]*$$||'`"; \
+ test "$$dir" != "$$p" || dir=.; \
+ echo "rm -f \"$${dir}/so_locations\""; \
+ rm -f "$${dir}/so_locations"; \
+ done
+libskey.la: $(libskey_la_OBJECTS) $(libskey_la_DEPENDENCIES)
+ $(AM_V_CCLD)$(libskey_la_LINK) $(libskey_la_OBJECTS) $(libskey_la_LIBADD) $(LIBS)
+
+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
+testskey$(EXEEXT): $(testskey_OBJECTS) $(testskey_DEPENDENCIES)
+ @rm -f testskey$(EXEEXT)
+ $(AM_V_CCLD)$(testskey_LINK) $(testskey_OBJECTS) $(testskey_LDADD) $(LIBS)
+
+mostlyclean-compile:
+ -rm -f *.$(OBJEXT)
+
+distclean-compile:
+ -rm -f *.tab.c
+
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-btoe.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-md4.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-md5.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-sha1.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-skey.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/libskey_la-skeyutil.Plo@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/testskey-test.Po@am__quote@
+
+.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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c $<
+
+.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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(COMPILE) -c `$(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
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='$<' object='$@' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LTCOMPILE) -c -o $@ $<
+
+libskey_la-btoe.lo: btoe.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-btoe.lo -MD -MP -MF $(DEPDIR)/libskey_la-btoe.Tpo -c -o libskey_la-btoe.lo `test -f 'btoe.c' || echo '$(srcdir)/'`btoe.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-btoe.Tpo $(DEPDIR)/libskey_la-btoe.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='btoe.c' object='libskey_la-btoe.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-btoe.lo `test -f 'btoe.c' || echo '$(srcdir)/'`btoe.c
+
+libskey_la-skey.lo: skey.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-skey.lo -MD -MP -MF $(DEPDIR)/libskey_la-skey.Tpo -c -o libskey_la-skey.lo `test -f 'skey.c' || echo '$(srcdir)/'`skey.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-skey.Tpo $(DEPDIR)/libskey_la-skey.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='skey.c' object='libskey_la-skey.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-skey.lo `test -f 'skey.c' || echo '$(srcdir)/'`skey.c
+
+libskey_la-skeyutil.lo: skeyutil.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-skeyutil.lo -MD -MP -MF $(DEPDIR)/libskey_la-skeyutil.Tpo -c -o libskey_la-skeyutil.lo `test -f 'skeyutil.c' || echo '$(srcdir)/'`skeyutil.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-skeyutil.Tpo $(DEPDIR)/libskey_la-skeyutil.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='skeyutil.c' object='libskey_la-skeyutil.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-skeyutil.lo `test -f 'skeyutil.c' || echo '$(srcdir)/'`skeyutil.c
+
+libskey_la-md4.lo: md4.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-md4.lo -MD -MP -MF $(DEPDIR)/libskey_la-md4.Tpo -c -o libskey_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-md4.Tpo $(DEPDIR)/libskey_la-md4.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md4.c' object='libskey_la-md4.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-md4.lo `test -f 'md4.c' || echo '$(srcdir)/'`md4.c
+
+libskey_la-md5.lo: md5.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-md5.lo -MD -MP -MF $(DEPDIR)/libskey_la-md5.Tpo -c -o libskey_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-md5.Tpo $(DEPDIR)/libskey_la-md5.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='md5.c' object='libskey_la-md5.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-md5.lo `test -f 'md5.c' || echo '$(srcdir)/'`md5.c
+
+libskey_la-sha1.lo: sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -MT libskey_la-sha1.lo -MD -MP -MF $(DEPDIR)/libskey_la-sha1.Tpo -c -o libskey_la-sha1.lo `test -f 'sha1.c' || echo '$(srcdir)/'`sha1.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/libskey_la-sha1.Tpo $(DEPDIR)/libskey_la-sha1.Plo
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='sha1.c' object='libskey_la-sha1.lo' libtool=yes @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(LIBTOOL) $(AM_V_lt) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(libskey_la_CPPFLAGS) $(CPPFLAGS) $(libskey_la_CFLAGS) $(CFLAGS) -c -o libskey_la-sha1.lo `test -f 'sha1.c' || echo '$(srcdir)/'`sha1.c
+
+testskey-test.o: test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testskey_CPPFLAGS) $(CPPFLAGS) $(testskey_CFLAGS) $(CFLAGS) -MT testskey-test.o -MD -MP -MF $(DEPDIR)/testskey-test.Tpo -c -o testskey-test.o `test -f 'test.c' || echo '$(srcdir)/'`test.c
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testskey-test.Tpo $(DEPDIR)/testskey-test.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test.c' object='testskey-test.o' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testskey_CPPFLAGS) $(CPPFLAGS) $(testskey_CFLAGS) $(CFLAGS) -c -o testskey-test.o `test -f 'test.c' || echo '$(srcdir)/'`test.c
+
+testskey-test.obj: test.c
+@am__fastdepCC_TRUE@ $(AM_V_CC)$(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testskey_CPPFLAGS) $(CPPFLAGS) $(testskey_CFLAGS) $(CFLAGS) -MT testskey-test.obj -MD -MP -MF $(DEPDIR)/testskey-test.Tpo -c -o testskey-test.obj `if test -f 'test.c'; then $(CYGPATH_W) 'test.c'; else $(CYGPATH_W) '$(srcdir)/test.c'; fi`
+@am__fastdepCC_TRUE@ $(AM_V_at)$(am__mv) $(DEPDIR)/testskey-test.Tpo $(DEPDIR)/testskey-test.Po
+@am__fastdepCC_FALSE@ $(AM_V_CC) @AM_BACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='test.c' object='testskey-test.obj' libtool=no @AMDEPBACKSLASH@
+@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
+@am__fastdepCC_FALSE@ $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(testskey_CPPFLAGS) $(CPPFLAGS) $(testskey_CFLAGS) $(CFLAGS) -c -o testskey-test.obj `if test -f 'test.c'; then $(CYGPATH_W) 'test.c'; else $(CYGPATH_W) '$(srcdir)/test.c'; fi`
+
+mostlyclean-libtool:
+ -rm -f *.lo
+
+clean-libtool:
+ -rm -rf .libs _libs
+
+ID: $(HEADERS) $(SOURCES) $(LISP) $(TAGS_FILES)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ mkid -fID $$unique
+tags: TAGS
+
+TAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ set x; \
+ here=`pwd`; \
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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
+CTAGS: $(HEADERS) $(SOURCES) $(TAGS_DEPENDENCIES) \
+ $(TAGS_FILES) $(LISP)
+ list='$(SOURCES) $(HEADERS) $(LISP) $(TAGS_FILES)'; \
+ unique=`for i in $$list; do \
+ if test -f "$$i"; then echo $$i; else echo $(srcdir)/$$i; fi; \
+ done | \
+ $(AWK) '{ files[$$0] = 1; nonempty = 1; } \
+ END { if (nonempty) { for (i in files) print i; }; }'`; \
+ 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"
+
+distclean-tags:
+ -rm -f TAGS ID GTAGS GRTAGS GSYMS GPATH tags
+
+check-TESTS: $(TESTS)
+ @failed=0; all=0; xfail=0; xpass=0; skip=0; \
+ srcdir=$(srcdir); export srcdir; \
+ list=' $(TESTS) '; \
+ $(am__tty_colors); \
+ if test -n "$$list"; then \
+ for tst in $$list; do \
+ if test -f ./$$tst; then dir=./; \
+ elif test -f $$tst; then dir=; \
+ else dir="$(srcdir)/"; fi; \
+ if $(TESTS_ENVIRONMENT) $${dir}$$tst; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xpass=`expr $$xpass + 1`; \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=XPASS; \
+ ;; \
+ *) \
+ col=$$grn; res=PASS; \
+ ;; \
+ esac; \
+ elif test $$? -ne 77; then \
+ all=`expr $$all + 1`; \
+ case " $(XFAIL_TESTS) " in \
+ *[\ \ ]$$tst[\ \ ]*) \
+ xfail=`expr $$xfail + 1`; \
+ col=$$lgn; res=XFAIL; \
+ ;; \
+ *) \
+ failed=`expr $$failed + 1`; \
+ col=$$red; res=FAIL; \
+ ;; \
+ esac; \
+ else \
+ skip=`expr $$skip + 1`; \
+ col=$$blu; res=SKIP; \
+ fi; \
+ echo "$${col}$$res$${std}: $$tst"; \
+ done; \
+ if test "$$all" -eq 1; then \
+ tests="test"; \
+ All=""; \
+ else \
+ tests="tests"; \
+ All="All "; \
+ fi; \
+ if test "$$failed" -eq 0; then \
+ if test "$$xfail" -eq 0; then \
+ banner="$$All$$all $$tests passed"; \
+ else \
+ if test "$$xfail" -eq 1; then failures=failure; else failures=failures; fi; \
+ banner="$$All$$all $$tests behaved as expected ($$xfail expected $$failures)"; \
+ fi; \
+ else \
+ if test "$$xpass" -eq 0; then \
+ banner="$$failed of $$all $$tests failed"; \
+ else \
+ if test "$$xpass" -eq 1; then passes=pass; else passes=passes; fi; \
+ banner="$$failed of $$all $$tests did not behave as expected ($$xpass unexpected $$passes)"; \
+ fi; \
+ fi; \
+ dashes="$$banner"; \
+ skipped=""; \
+ if test "$$skip" -ne 0; then \
+ if test "$$skip" -eq 1; then \
+ skipped="($$skip test was not run)"; \
+ else \
+ skipped="($$skip tests were not run)"; \
+ fi; \
+ test `echo "$$skipped" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$skipped"; \
+ fi; \
+ report=""; \
+ if test "$$failed" -ne 0 && test -n "$(PACKAGE_BUGREPORT)"; then \
+ report="Please report to $(PACKAGE_BUGREPORT)"; \
+ test `echo "$$report" | wc -c` -le `echo "$$banner" | wc -c` || \
+ dashes="$$report"; \
+ fi; \
+ dashes=`echo "$$dashes" | sed s/./=/g`; \
+ if test "$$failed" -eq 0; then \
+ echo "$$grn$$dashes"; \
+ else \
+ echo "$$red$$dashes"; \
+ fi; \
+ echo "$$banner"; \
+ test -z "$$skipped" || echo "$$skipped"; \
+ test -z "$$report" || echo "$$report"; \
+ echo "$$dashes$$std"; \
+ test "$$failed" -eq 0; \
+ else :; fi
+
+distdir: $(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: check-am
+all-am: Makefile $(LTLIBRARIES)
+installdirs:
+install: 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:
+ $(MAKE) $(AM_MAKEFLAGS) INSTALL_PROGRAM="$(INSTALL_STRIP_PROGRAM)" \
+ install_sh_PROGRAM="$(INSTALL_STRIP_PROGRAM)" INSTALL_STRIP_FLAG=-s \
+ `test -z '$(STRIP)' || \
+ echo "INSTALL_PROGRAM_ENV=STRIPPROG='$(STRIP)'"` install
+mostlyclean-generic:
+
+clean-generic:
+
+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."
+clean: clean-am
+
+clean-am: clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES mostlyclean-am
+
+distclean: distclean-am
+ -rm -rf ./$(DEPDIR)
+ -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-dvi: install-dvi-am
+
+install-dvi-am:
+
+install-exec-am:
+
+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 -rf ./$(DEPDIR)
+ -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:
+
+.MAKE: check-am install-am install-strip
+
+.PHONY: CTAGS GTAGS all all-am check check-TESTS check-am clean \
+ clean-checkPROGRAMS clean-generic clean-libtool \
+ clean-noinstLTLIBRARIES ctags distclean distclean-compile \
+ distclean-generic distclean-libtool distclean-tags distdir dvi \
+ dvi-am html html-am info info-am install install-am \
+ install-data install-data-am install-dvi install-dvi-am \
+ install-exec install-exec-am install-html install-html-am \
+ install-info install-info-am install-man 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 \
+ tags uninstall uninstall-am
+
+
+-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/skey/btoe.c b/src/skey/btoe.c
new file mode 100644
index 0000000..f9bd459
--- /dev/null
+++ b/src/skey/btoe.c
@@ -0,0 +1,304 @@
+/*
+ * This code is imported from Bollcore's S/KEY + some simple glib adaptations
+ * (See rfc2289 and rfc1760)
+ */
+
+#include <config.h>
+#include <stdio.h>
+#include <string.h>
+#include <unistd.h>
+#include <glib.h>
+
+#include "skey.h"
+#include "btoe.h"
+
+static guint32 extract (char *s, int start, int length);
+
+/* Dictionary for integer-word translations */
+static const char Wp[2048][4] = { "A", "ABE", "ACE", "ACT", "AD", "ADA", "ADD",
+"AGO", "AID", "AIM", "AIR", "ALL", "ALP", "AM", "AMY", "AN", "ANA",
+"AND", "ANN", "ANT", "ANY", "APE", "APS", "APT", "ARC", "ARE", "ARK",
+"ARM", "ART", "AS", "ASH", "ASK", "AT", "ATE", "AUG", "AUK", "AVE",
+"AWE", "AWK", "AWL", "AWN", "AX", "AYE", "BAD", "BAG", "BAH", "BAM",
+"BAN", "BAR", "BAT", "BAY", "BE", "BED", "BEE", "BEG", "BEN", "BET",
+"BEY", "BIB", "BID", "BIG", "BIN", "BIT", "BOB", "BOG", "BON", "BOO",
+"BOP", "BOW", "BOY", "BUB", "BUD", "BUG", "BUM", "BUN", "BUS", "BUT",
+"BUY", "BY", "BYE", "CAB", "CAL", "CAM", "CAN", "CAP", "CAR", "CAT",
+"CAW", "COD", "COG", "COL", "CON", "COO", "COP", "COT", "COW", "COY",
+"CRY", "CUB", "CUE", "CUP", "CUR", "CUT", "DAB", "DAD", "DAM", "DAN",
+"DAR", "DAY", "DEE", "DEL", "DEN", "DES", "DEW", "DID", "DIE", "DIG",
+"DIN", "DIP", "DO", "DOE", "DOG", "DON", "DOT", "DOW", "DRY", "DUB",
+"DUD", "DUE", "DUG", "DUN", "EAR", "EAT", "ED", "EEL", "EGG", "EGO",
+"ELI", "ELK", "ELM", "ELY", "EM", "END", "EST", "ETC", "EVA", "EVE",
+"EWE", "EYE", "FAD", "FAN", "FAR", "FAT", "FAY", "FED", "FEE", "FEW",
+"FIB", "FIG", "FIN", "FIR", "FIT", "FLO", "FLY", "FOE", "FOG", "FOR",
+"FRY", "FUM", "FUN", "FUR", "GAB", "GAD", "GAG", "GAL", "GAM", "GAP",
+"GAS", "GAY", "GEE", "GEL", "GEM", "GET", "GIG", "GIL", "GIN", "GO",
+"GOT", "GUM", "GUN", "GUS", "GUT", "GUY", "GYM", "GYP", "HA", "HAD",
+"HAL", "HAM", "HAN", "HAP", "HAS", "HAT", "HAW", "HAY", "HE", "HEM",
+"HEN", "HER", "HEW", "HEY", "HI", "HID", "HIM", "HIP", "HIS", "HIT",
+"HO", "HOB", "HOC", "HOE", "HOG", "HOP", "HOT", "HOW", "HUB", "HUE",
+"HUG", "HUH", "HUM", "HUT", "I", "ICY", "IDA", "IF", "IKE", "ILL",
+"INK", "INN", "IO", "ION", "IQ", "IRA", "IRE", "IRK", "IS", "IT", "ITS",
+"IVY", "JAB", "JAG", "JAM", "JAN", "JAR", "JAW", "JAY", "JET", "JIG",
+"JIM", "JO", "JOB", "JOE", "JOG", "JOT", "JOY", "JUG", "JUT", "KAY",
+"KEG", "KEN", "KEY", "KID", "KIM", "KIN", "KIT", "LA", "LAB", "LAC",
+"LAD", "LAG", "LAM", "LAP", "LAW", "LAY", "LEA", "LED", "LEE", "LEG",
+"LEN", "LEO", "LET", "LEW", "LID", "LIE", "LIN", "LIP", "LIT", "LO",
+"LOB", "LOG", "LOP", "LOS", "LOT", "LOU", "LOW", "LOY", "LUG", "LYE",
+"MA", "MAC", "MAD", "MAE", "MAN", "MAO", "MAP", "MAT", "MAW", "MAY",
+"ME", "MEG", "MEL", "MEN", "MET", "MEW", "MID", "MIN", "MIT", "MOB",
+"MOD", "MOE", "MOO", "MOP", "MOS", "MOT", "MOW", "MUD", "MUG", "MUM",
+"MY", "NAB", "NAG", "NAN", "NAP", "NAT", "NAY", "NE", "NED", "NEE",
+"NET", "NEW", "NIB", "NIL", "NIP", "NIT", "NO", "NOB", "NOD", "NON",
+"NOR", "NOT", "NOV", "NOW", "NU", "NUN", "NUT", "O", "OAF", "OAK",
+"OAR", "OAT", "ODD", "ODE", "OF", "OFF", "OFT", "OH", "OIL", "OK",
+"OLD", "ON", "ONE", "OR", "ORB", "ORE", "ORR", "OS", "OTT", "OUR",
+"OUT", "OVA", "OW", "OWE", "OWL", "OWN", "OX", "PA", "PAD", "PAL",
+"PAM", "PAN", "PAP", "PAR", "PAT", "PAW", "PAY", "PEA", "PEG", "PEN",
+"PEP", "PER", "PET", "PEW", "PHI", "PI", "PIE", "PIN", "PIT", "PLY",
+"PO", "POD", "POE", "POP", "POT", "POW", "PRO", "PRY", "PUB", "PUG",
+"PUN", "PUP", "PUT", "QUO", "RAG", "RAM", "RAN", "RAP", "RAT", "RAW",
+"RAY", "REB", "RED", "REP", "RET", "RIB", "RID", "RIG", "RIM", "RIO",
+"RIP", "ROB", "ROD", "ROE", "RON", "ROT", "ROW", "ROY", "RUB", "RUE",
+"RUG", "RUM", "RUN", "RYE", "SAC", "SAD", "SAG", "SAL", "SAM", "SAN",
+"SAP", "SAT", "SAW", "SAY", "SEA", "SEC", "SEE", "SEN", "SET", "SEW",
+"SHE", "SHY", "SIN", "SIP", "SIR", "SIS", "SIT", "SKI", "SKY", "SLY",
+"SO", "SOB", "SOD", "SON", "SOP", "SOW", "SOY", "SPA", "SPY", "SUB",
+"SUD", "SUE", "SUM", "SUN", "SUP", "TAB", "TAD", "TAG", "TAN", "TAP",
+"TAR", "TEA", "TED", "TEE", "TEN", "THE", "THY", "TIC", "TIE", "TIM",
+"TIN", "TIP", "TO", "TOE", "TOG", "TOM", "TON", "TOO", "TOP", "TOW",
+"TOY", "TRY", "TUB", "TUG", "TUM", "TUN", "TWO", "UN", "UP", "US",
+"USE", "VAN", "VAT", "VET", "VIE", "WAD", "WAG", "WAR", "WAS", "WAY",
+"WE", "WEB", "WED", "WEE", "WET", "WHO", "WHY", "WIN", "WIT", "WOK",
+"WON", "WOO", "WOW", "WRY", "WU", "YAM", "YAP", "YAW", "YE", "YEA",
+"YES", "YET", "YOU", "ABED", "ABEL", "ABET", "ABLE", "ABUT", "ACHE",
+"ACID", "ACME", "ACRE", "ACTA", "ACTS", "ADAM", "ADDS", "ADEN", "AFAR",
+"AFRO", "AGEE", "AHEM", "AHOY", "AIDA", "AIDE", "AIDS", "AIRY", "AJAR",
+"AKIN", "ALAN", "ALEC", "ALGA", "ALIA", "ALLY", "ALMA", "ALOE", "ALSO",
+"ALTO", "ALUM", "ALVA", "AMEN", "AMES", "AMID", "AMMO", "AMOK", "AMOS",
+"AMRA", "ANDY", "ANEW", "ANNA", "ANNE", "ANTE", "ANTI", "AQUA", "ARAB",
+"ARCH", "AREA", "ARGO", "ARID", "ARMY", "ARTS", "ARTY", "ASIA", "ASKS",
+"ATOM", "AUNT", "AURA", "AUTO", "AVER", "AVID", "AVIS", "AVON", "AVOW",
+"AWAY", "AWRY", "BABE", "BABY", "BACH", "BACK", "BADE", "BAIL", "BAIT",
+"BAKE", "BALD", "BALE", "BALI", "BALK", "BALL", "BALM", "BAND", "BANE",
+"BANG", "BANK", "BARB", "BARD", "BARE", "BARK", "BARN", "BARR", "BASE",
+"BASH", "BASK", "BASS", "BATE", "BATH", "BAWD", "BAWL", "BEAD", "BEAK",
+"BEAM", "BEAN", "BEAR", "BEAT", "BEAU", "BECK", "BEEF", "BEEN", "BEER",
+"BEET", "BELA", "BELL", "BELT", "BEND", "BENT", "BERG", "BERN", "BERT",
+"BESS", "BEST", "BETA", "BETH", "BHOY", "BIAS", "BIDE", "BIEN", "BILE",
+"BILK", "BILL", "BIND", "BING", "BIRD", "BITE", "BITS", "BLAB", "BLAT",
+"BLED", "BLEW", "BLOB", "BLOC", "BLOT", "BLOW", "BLUE", "BLUM", "BLUR",
+"BOAR", "BOAT", "BOCA", "BOCK", "BODE", "BODY", "BOGY", "BOHR", "BOIL",
+"BOLD", "BOLO", "BOLT", "BOMB", "BONA", "BOND", "BONE", "BONG", "BONN",
+"BONY", "BOOK", "BOOM", "BOON", "BOOT", "BORE", "BORG", "BORN", "BOSE",
+"BOSS", "BOTH", "BOUT", "BOWL", "BOYD", "BRAD", "BRAE", "BRAG", "BRAN",
+"BRAY", "BRED", "BREW", "BRIG", "BRIM", "BROW", "BUCK", "BUDD", "BUFF",
+"BULB", "BULK", "BULL", "BUNK", "BUNT", "BUOY", "BURG", "BURL", "BURN",
+"BURR", "BURT", "BURY", "BUSH", "BUSS", "BUST", "BUSY", "BYTE", "CADY",
+"CAFE", "CAGE", "CAIN", "CAKE", "CALF", "CALL", "CALM", "CAME", "CANE",
+"CANT", "CARD", "CARE", "CARL", "CARR", "CART", "CASE", "CASH", "CASK",
+"CAST", "CAVE", "CEIL", "CELL", "CENT", "CERN", "CHAD", "CHAR", "CHAT",
+"CHAW", "CHEF", "CHEN", "CHEW", "CHIC", "CHIN", "CHOU", "CHOW", "CHUB",
+"CHUG", "CHUM", "CITE", "CITY", "CLAD", "CLAM", "CLAN", "CLAW", "CLAY",
+"CLOD", "CLOG", "CLOT", "CLUB", "CLUE", "COAL", "COAT", "COCA", "COCK",
+"COCO", "CODA", "CODE", "CODY", "COED", "COIL", "COIN", "COKE", "COLA",
+"COLD", "COLT", "COMA", "COMB", "COME", "COOK", "COOL", "COON", "COOT",
+"CORD", "CORE", "CORK", "CORN", "COST", "COVE", "COWL", "CRAB", "CRAG",
+"CRAM", "CRAY", "CREW", "CRIB", "CROW", "CRUD", "CUBA", "CUBE", "CUFF",
+"CULL", "CULT", "CUNY", "CURB", "CURD", "CURE", "CURL", "CURT", "CUTS",
+"DADE", "DALE", "DAME", "DANA", "DANE", "DANG", "DANK", "DARE", "DARK",
+"DARN", "DART", "DASH", "DATA", "DATE", "DAVE", "DAVY", "DAWN", "DAYS",
+"DEAD", "DEAF", "DEAL", "DEAN", "DEAR", "DEBT", "DECK", "DEED", "DEEM",
+"DEER", "DEFT", "DEFY", "DELL", "DENT", "DENY", "DESK", "DIAL", "DICE",
+"DIED", "DIET", "DIME", "DINE", "DING", "DINT", "DIRE", "DIRT", "DISC",
+"DISH", "DISK", "DIVE", "DOCK", "DOES", "DOLE", "DOLL", "DOLT", "DOME",
+"DONE", "DOOM", "DOOR", "DORA", "DOSE", "DOTE", "DOUG", "DOUR", "DOVE",
+"DOWN", "DRAB", "DRAG", "DRAM", "DRAW", "DREW", "DRUB", "DRUG", "DRUM",
+"DUAL", "DUCK", "DUCT", "DUEL", "DUET", "DUKE", "DULL", "DUMB", "DUNE",
+"DUNK", "DUSK", "DUST", "DUTY", "EACH", "EARL", "EARN", "EASE", "EAST",
+"EASY", "EBEN", "ECHO", "EDDY", "EDEN", "EDGE", "EDGY", "EDIT", "EDNA",
+"EGAN", "ELAN", "ELBA", "ELLA", "ELSE", "EMIL", "EMIT", "EMMA", "ENDS",
+"ERIC", "EROS", "EVEN", "EVER", "EVIL", "EYED", "FACE", "FACT", "FADE",
+"FAIL", "FAIN", "FAIR", "FAKE", "FALL", "FAME", "FANG", "FARM", "FAST",
+"FATE", "FAWN", "FEAR", "FEAT", "FEED", "FEEL", "FEET", "FELL", "FELT",
+"FEND", "FERN", "FEST", "FEUD", "FIEF", "FIGS", "FILE", "FILL", "FILM",
+"FIND", "FINE", "FINK", "FIRE", "FIRM", "FISH", "FISK", "FIST", "FITS",
+"FIVE", "FLAG", "FLAK", "FLAM", "FLAT", "FLAW", "FLEA", "FLED", "FLEW",
+"FLIT", "FLOC", "FLOG", "FLOW", "FLUB", "FLUE", "FOAL", "FOAM", "FOGY",
+"FOIL", "FOLD", "FOLK", "FOND", "FONT", "FOOD", "FOOL", "FOOT", "FORD",
+"FORE", "FORK", "FORM", "FORT", "FOSS", "FOUL", "FOUR", "FOWL", "FRAU",
+"FRAY", "FRED", "FREE", "FRET", "FREY", "FROG", "FROM", "FUEL", "FULL",
+"FUME", "FUND", "FUNK", "FURY", "FUSE", "FUSS", "GAFF", "GAGE", "GAIL",
+"GAIN", "GAIT", "GALA", "GALE", "GALL", "GALT", "GAME", "GANG", "GARB",
+"GARY", "GASH", "GATE", "GAUL", "GAUR", "GAVE", "GAWK", "GEAR", "GELD",
+"GENE", "GENT", "GERM", "GETS", "GIBE", "GIFT", "GILD", "GILL", "GILT",
+"GINA", "GIRD", "GIRL", "GIST", "GIVE", "GLAD", "GLEE", "GLEN", "GLIB",
+"GLOB", "GLOM", "GLOW", "GLUE", "GLUM", "GLUT", "GOAD", "GOAL", "GOAT",
+"GOER", "GOES", "GOLD", "GOLF", "GONE", "GONG", "GOOD", "GOOF", "GORE",
+"GORY", "GOSH", "GOUT", "GOWN", "GRAB", "GRAD", "GRAY", "GREG", "GREW",
+"GREY", "GRID", "GRIM", "GRIN", "GRIT", "GROW", "GRUB", "GULF", "GULL",
+"GUNK", "GURU", "GUSH", "GUST", "GWEN", "GWYN", "HAAG", "HAAS", "HACK",
+"HAIL", "HAIR", "HALE", "HALF", "HALL", "HALO", "HALT", "HAND", "HANG",
+"HANK", "HANS", "HARD", "HARK", "HARM", "HART", "HASH", "HAST", "HATE",
+"HATH", "HAUL", "HAVE", "HAWK", "HAYS", "HEAD", "HEAL", "HEAR", "HEAT",
+"HEBE", "HECK", "HEED", "HEEL", "HEFT", "HELD", "HELL", "HELM", "HERB",
+"HERD", "HERE", "HERO", "HERS", "HESS", "HEWN", "HICK", "HIDE", "HIGH",
+"HIKE", "HILL", "HILT", "HIND", "HINT", "HIRE", "HISS", "HIVE", "HOBO",
+"HOCK", "HOFF", "HOLD", "HOLE", "HOLM", "HOLT", "HOME", "HONE", "HONK",
+"HOOD", "HOOF", "HOOK", "HOOT", "HORN", "HOSE", "HOST", "HOUR", "HOVE",
+"HOWE", "HOWL", "HOYT", "HUCK", "HUED", "HUFF", "HUGE", "HUGH", "HUGO",
+"HULK", "HULL", "HUNK", "HUNT", "HURD", "HURL", "HURT", "HUSH", "HYDE",
+"HYMN", "IBIS", "ICON", "IDEA", "IDLE", "IFFY", "INCA", "INCH", "INTO",
+"IONS", "IOTA", "IOWA", "IRIS", "IRMA", "IRON", "ISLE", "ITCH", "ITEM",
+"IVAN", "JACK", "JADE", "JAIL", "JAKE", "JANE", "JAVA", "JEAN", "JEFF",
+"JERK", "JESS", "JEST", "JIBE", "JILL", "JILT", "JIVE", "JOAN", "JOBS",
+"JOCK", "JOEL", "JOEY", "JOHN", "JOIN", "JOKE", "JOLT", "JOVE", "JUDD",
+"JUDE", "JUDO", "JUDY", "JUJU", "JUKE", "JULY", "JUNE", "JUNK", "JUNO",
+"JURY", "JUST", "JUTE", "KAHN", "KALE", "KANE", "KANT", "KARL", "KATE",
+"KEEL", "KEEN", "KENO", "KENT", "KERN", "KERR", "KEYS", "KICK", "KILL",
+"KIND", "KING", "KIRK", "KISS", "KITE", "KLAN", "KNEE", "KNEW", "KNIT",
+"KNOB", "KNOT", "KNOW", "KOCH", "KONG", "KUDO", "KURD", "KURT", "KYLE",
+"LACE", "LACK", "LACY", "LADY", "LAID", "LAIN", "LAIR", "LAKE", "LAMB",
+"LAME", "LAND", "LANE", "LANG", "LARD", "LARK", "LASS", "LAST", "LATE",
+"LAUD", "LAVA", "LAWN", "LAWS", "LAYS", "LEAD", "LEAF", "LEAK", "LEAN",
+"LEAR", "LEEK", "LEER", "LEFT", "LEND", "LENS", "LENT", "LEON", "LESK",
+"LESS", "LEST", "LETS", "LIAR", "LICE", "LICK", "LIED", "LIEN", "LIES",
+"LIEU", "LIFE", "LIFT", "LIKE", "LILA", "LILT", "LILY", "LIMA", "LIMB",
+"LIME", "LIND", "LINE", "LINK", "LINT", "LION", "LISA", "LIST", "LIVE",
+"LOAD", "LOAF", "LOAM", "LOAN", "LOCK", "LOFT", "LOGE", "LOIS", "LOLA",
+"LONE", "LONG", "LOOK", "LOON", "LOOT", "LORD", "LORE", "LOSE", "LOSS",
+"LOST", "LOUD", "LOVE", "LOWE", "LUCK", "LUCY", "LUGE", "LUKE", "LULU",
+"LUND", "LUNG", "LURA", "LURE", "LURK", "LUSH", "LUST", "LYLE", "LYNN",
+"LYON", "LYRA", "MACE", "MADE", "MAGI", "MAID", "MAIL", "MAIN", "MAKE",
+"MALE", "MALI", "MALL", "MALT", "MANA", "MANN", "MANY", "MARC", "MARE",
+"MARK", "MARS", "MART", "MARY", "MASH", "MASK", "MASS", "MAST", "MATE",
+"MATH", "MAUL", "MAYO", "MEAD", "MEAL", "MEAN", "MEAT", "MEEK", "MEET",
+"MELD", "MELT", "MEMO", "MEND", "MENU", "MERT", "MESH", "MESS", "MICE",
+"MIKE", "MILD", "MILE", "MILK", "MILL", "MILT", "MIMI", "MIND", "MINE",
+"MINI", "MINK", "MINT", "MIRE", "MISS", "MIST", "MITE", "MITT", "MOAN",
+"MOAT", "MOCK", "MODE", "MOLD", "MOLE", "MOLL", "MOLT", "MONA", "MONK",
+"MONT", "MOOD", "MOON", "MOOR", "MOOT", "MORE", "MORN", "MORT", "MOSS",
+"MOST", "MOTH", "MOVE", "MUCH", "MUCK", "MUDD", "MUFF", "MULE", "MULL",
+"MURK", "MUSH", "MUST", "MUTE", "MUTT", "MYRA", "MYTH", "NAGY", "NAIL",
+"NAIR", "NAME", "NARY", "NASH", "NAVE", "NAVY", "NEAL", "NEAR", "NEAT",
+"NECK", "NEED", "NEIL", "NELL", "NEON", "NERO", "NESS", "NEST", "NEWS",
+"NEWT", "NIBS", "NICE", "NICK", "NILE", "NINA", "NINE", "NOAH", "NODE",
+"NOEL", "NOLL", "NONE", "NOOK", "NOON", "NORM", "NOSE", "NOTE", "NOUN",
+"NOVA", "NUDE", "NULL", "NUMB", "OATH", "OBEY", "OBOE", "ODIN", "OHIO",
+"OILY", "OINT", "OKAY", "OLAF", "OLDY", "OLGA", "OLIN", "OMAN", "OMEN",
+"OMIT", "ONCE", "ONES", "ONLY", "ONTO", "ONUS", "ORAL", "ORGY", "OSLO",
+"OTIS", "OTTO", "OUCH", "OUST", "OUTS", "OVAL", "OVEN", "OVER", "OWLY",
+"OWNS", "QUAD", "QUIT", "QUOD", "RACE", "RACK", "RACY", "RAFT", "RAGE",
+"RAID", "RAIL", "RAIN", "RAKE", "RANK", "RANT", "RARE", "RASH", "RATE",
+"RAVE", "RAYS", "READ", "REAL", "REAM", "REAR", "RECK", "REED", "REEF",
+"REEK", "REEL", "REID", "REIN", "RENA", "REND", "RENT", "REST", "RICE",
+"RICH", "RICK", "RIDE", "RIFT", "RILL", "RIME", "RING", "RINK", "RISE",
+"RISK", "RITE", "ROAD", "ROAM", "ROAR", "ROBE", "ROCK", "RODE", "ROIL",
+"ROLL", "ROME", "ROOD", "ROOF", "ROOK", "ROOM", "ROOT", "ROSA", "ROSE",
+"ROSS", "ROSY", "ROTH", "ROUT", "ROVE", "ROWE", "ROWS", "RUBE", "RUBY",
+"RUDE", "RUDY", "RUIN", "RULE", "RUNG", "RUNS", "RUNT", "RUSE", "RUSH",
+"RUSK", "RUSS", "RUST", "RUTH", "SACK", "SAFE", "SAGE", "SAID", "SAIL",
+"SALE", "SALK", "SALT", "SAME", "SAND", "SANE", "SANG", "SANK", "SARA",
+"SAUL", "SAVE", "SAYS", "SCAN", "SCAR", "SCAT", "SCOT", "SEAL", "SEAM",
+"SEAR", "SEAT", "SEED", "SEEK", "SEEM", "SEEN", "SEES", "SELF", "SELL",
+"SEND", "SENT", "SETS", "SEWN", "SHAG", "SHAM", "SHAW", "SHAY", "SHED",
+"SHIM", "SHIN", "SHOD", "SHOE", "SHOT", "SHOW", "SHUN", "SHUT", "SICK",
+"SIDE", "SIFT", "SIGH", "SIGN", "SILK", "SILL", "SILO", "SILT", "SINE",
+"SING", "SINK", "SIRE", "SITE", "SITS", "SITU", "SKAT", "SKEW", "SKID",
+"SKIM", "SKIN", "SKIT", "SLAB", "SLAM", "SLAT", "SLAY", "SLED", "SLEW",
+"SLID", "SLIM", "SLIT", "SLOB", "SLOG", "SLOT", "SLOW", "SLUG", "SLUM",
+"SLUR", "SMOG", "SMUG", "SNAG", "SNOB", "SNOW", "SNUB", "SNUG", "SOAK",
+"SOAR", "SOCK", "SODA", "SOFA", "SOFT", "SOIL", "SOLD", "SOME", "SONG",
+"SOON", "SOOT", "SORE", "SORT", "SOUL", "SOUR", "SOWN", "STAB", "STAG",
+"STAN", "STAR", "STAY", "STEM", "STEW", "STIR", "STOW", "STUB", "STUN",
+"SUCH", "SUDS", "SUIT", "SULK", "SUMS", "SUNG", "SUNK", "SURE", "SURF",
+"SWAB", "SWAG", "SWAM", "SWAN", "SWAT", "SWAY", "SWIM", "SWUM", "TACK",
+"TACT", "TAIL", "TAKE", "TALE", "TALK", "TALL", "TANK", "TASK", "TATE",
+"TAUT", "TEAL", "TEAM", "TEAR", "TECH", "TEEM", "TEEN", "TEET", "TELL",
+"TEND", "TENT", "TERM", "TERN", "TESS", "TEST", "THAN", "THAT", "THEE",
+"THEM", "THEN", "THEY", "THIN", "THIS", "THUD", "THUG", "TICK", "TIDE",
+"TIDY", "TIED", "TIER", "TILE", "TILL", "TILT", "TIME", "TINA", "TINE",
+"TINT", "TINY", "TIRE", "TOAD", "TOGO", "TOIL", "TOLD", "TOLL", "TONE",
+"TONG", "TONY", "TOOK", "TOOL", "TOOT", "TORE", "TORN", "TOTE", "TOUR",
+"TOUT", "TOWN", "TRAG", "TRAM", "TRAY", "TREE", "TREK", "TRIG", "TRIM",
+"TRIO", "TROD", "TROT", "TROY", "TRUE", "TUBA", "TUBE", "TUCK", "TUFT",
+"TUNA", "TUNE", "TUNG", "TURF", "TURN", "TUSK", "TWIG", "TWIN", "TWIT",
+"ULAN", "UNIT", "URGE", "USED", "USER", "USES", "UTAH", "VAIL", "VAIN",
+"VALE", "VARY", "VASE", "VAST", "VEAL", "VEDA", "VEIL", "VEIN", "VEND",
+"VENT", "VERB", "VERY", "VETO", "VICE", "VIEW", "VINE", "VISE", "VOID",
+"VOLT", "VOTE", "WACK", "WADE", "WAGE", "WAIL", "WAIT", "WAKE", "WALE",
+"WALK", "WALL", "WALT", "WAND", "WANE", "WANG", "WANT", "WARD", "WARM",
+"WARN", "WART", "WASH", "WAST", "WATS", "WATT", "WAVE", "WAVY", "WAYS",
+"WEAK", "WEAL", "WEAN", "WEAR", "WEED", "WEEK", "WEIR", "WELD", "WELL",
+"WELT", "WENT", "WERE", "WERT", "WEST", "WHAM", "WHAT", "WHEE", "WHEN",
+"WHET", "WHOA", "WHOM", "WICK", "WIFE", "WILD", "WILL", "WIND", "WINE",
+"WING", "WINK", "WINO", "WIRE", "WISE", "WISH", "WITH", "WOLF", "WONT",
+"WOOD", "WOOL", "WORD", "WORE", "WORK", "WORM", "WORN", "WOVE", "WRIT",
+"WYNN", "YALE", "YANG", "YANK", "YARD", "YARN", "YAWL", "YAWN", "YEAH",
+"YEAR", "YELL", "YOGA", "YOKE"
+};
+
+/*
+ * Encode 8 bytes in 'c' as a string of English words.
+ * Returns a pointer to a static buffer
+ */
+
+char *btoe(unsigned char *md)
+{
+ char cp[9]; /* 64 + 2 = 66 bits */
+ int p, i;
+ static int buf[BUFSIZ];
+ char *engout = (char *)buf;
+
+ memcpy(cp, md, SKEY_SIZE);
+ /* compute parity */
+ for(p = 0, i = 0; i < 64; i += 2)
+ p += extract(cp, i, 2);
+ cp[8] = (char)p << 6;
+ /* now 66 bits */
+
+ engout[0] = '\0';
+ strncat(engout, &Wp[extract(cp, 0, 11)][0], 4);
+ strcat (engout," ");
+ strncat(engout, &Wp[extract(cp, 11, 11)][0], 4);
+ strcat (engout," ");
+ strncat(engout, &Wp[extract(cp, 22, 11)][0], 4);
+ strcat (engout," ");
+ strncat(engout, &Wp[extract(cp, 33, 11)][0], 4);
+ strcat (engout," ");
+ strncat(engout, &Wp[extract(cp, 44, 11)][0], 4);
+ strcat (engout," ");
+ strncat(engout, &Wp[extract(cp, 55, 11)][0], 4);
+ return (engout);
+
+}
+
+
+/*
+ * Extract 'length' bits from the char array 's'
+ * starting with bit 'start'
+ */
+
+static guint32 extract(char *s, int start, int length)
+{
+ guint8 cl;
+ guint8 cc;
+ guint8 cr;
+ guint32 x;
+
+ /* 66 = 11 x 6 */
+
+ g_assert(length >= 0);
+ g_assert(length <= 11);
+ g_assert(start >= 0);
+ g_assert(start + length <= 66);
+
+ cl = s[start/8];
+ cc = s[start/8 + 1];
+ cr = s[start/8 + 2];
+ x = (guint32) ((((cl << 8) | cc) << 8) | cr); /* 24 bits */
+ x = x >> (24 - (length + (start % 8))); /* cut tail */
+ x = (x & (0xffff >> (16 - length))); /* cut head */
+ return(x); /* length */
+}
diff --git a/src/skey/btoe.h b/src/skey/btoe.h
new file mode 100644
index 0000000..a2a719e
--- /dev/null
+++ b/src/skey/btoe.h
@@ -0,0 +1,2 @@
+char *btoe(unsigned char *md);
+
diff --git a/src/skey/md4.c b/src/skey/md4.c
new file mode 100644
index 0000000..914f101
--- /dev/null
+++ b/src/skey/md4.c
@@ -0,0 +1,335 @@
+/*
+ * Copyright (C) 2001 Nikos Mavroyanopoulos
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Library General Public License as published
+ * by the Free Software Foundation; either version 3 of the License, or
+ * (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+/*
+ * The algorithm is due to Ron Rivest. This code is based on code
+ * written by Colin Plumb in 1993.
+ */
+
+
+#include <string.h>
+#include <stdlib.h>
+#include "config.h"
+#include "skey.h"
+#include "skeyutil.h"
+#include "md4.h"
+
+#ifndef WORDS_BIGENDIAN
+#define byteReverse(buf, len) /* Nothing */
+#else
+static void byteReverse(unsigned char *buf, unsigned longs);
+
+
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ guint32 t;
+ do {
+ t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(guint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+
+#define rotl32(x,n) (((x) << ((guint32)(n))) | ((x) >> (32 - (guint32)(n))))
+
+/*
+ * Start MD4 accumulation. Set bit count to 0 and buffer to mysterious
+ * initialization constants.
+ */
+void MD4Init(MD4_CTX *ctx)
+{
+ ctx->buf[0] = 0x67452301;
+ ctx->buf[1] = 0xefcdab89;
+ ctx->buf[2] = 0x98badcfe;
+ ctx->buf[3] = 0x10325476;
+
+ ctx->bits[0] = 0;
+ ctx->bits[1] = 0;
+}
+
+/*
+ * Update context to reflect the concatenation of another buffer full
+ * of bytes.
+ */
+void MD4Update(MD4_CTX *ctx, unsigned char const *buf,
+ unsigned len)
+{
+ register guint32 t;
+
+ /* Update bitcount */
+
+ t = ctx->bits[0];
+ if ((ctx->bits[0] = t + ((guint32) len << 3)) < t)
+ ctx->bits[1]++; /* Carry from low to high */
+ ctx->bits[1] += len >> 29;
+
+ t = (t >> 3) & 0x3f; /* Bytes already in shsInfo->data */
+
+ /* Handle any leading odd-sized chunks */
+
+ if (t) {
+ unsigned char *p = (unsigned char *) ctx->in + t;
+
+ t = 64 - t;
+ if (len < t) {
+ memcpy(p, buf, len);
+ return;
+ }
+ memcpy(p, buf, t);
+ byteReverse(ctx->in, 16);
+ MD4Transform(ctx->buf, (guint32 *) ctx->in);
+ buf += t;
+ len -= t;
+ }
+ /* Process data in 64-byte chunks */
+
+ while (len >= 64) {
+ memcpy(ctx->in, buf, 64);
+ byteReverse(ctx->in, 16);
+ MD4Transform(ctx->buf, (guint32 *) ctx->in);
+ buf += 64;
+ len -= 64;
+ }
+
+ /* Handle any remaining bytes of data. */
+
+ memcpy(ctx->in, buf, len);
+}
+
+/*
+ * Final wrapup - pad to 64-byte boundary with the bit pattern
+ * 1 0* (64-bit count of bits processed, MSB-first)
+ */
+void MD4Final(unsigned char* digest, MD4_CTX *ctx)
+{
+ unsigned int count;
+ unsigned char *p;
+
+ /* Compute number of bytes mod 64 */
+ count = (ctx->bits[0] >> 3) & 0x3F;
+
+ /* Set the first char of padding to 0x80. This is safe since there is
+ always at least one byte free */
+ p = ctx->in + count;
+ *p++ = 0x80;
+
+ /* Bytes of padding needed to make 64 bytes */
+ count = 64 - 1 - count;
+
+ /* Pad out to 56 mod 64 */
+ if (count < 8) {
+ /* Two lots of padding: Pad the first block to 64 bytes */
+ memset(p, 0, count);
+ byteReverse(ctx->in, 16);
+ MD4Transform(ctx->buf, (guint32 *) ctx->in);
+
+ /* Now fill the next block with 56 bytes */
+ memset(ctx->in, 0, 56);
+ } else {
+ /* Pad block to 56 bytes */
+ memset(p, 0, count - 8);
+ }
+ byteReverse(ctx->in, 14);
+
+ /* Append length in bits and transform */
+ ((guint32 *) ctx->in)[14] = ctx->bits[0];
+ ((guint32 *) ctx->in)[15] = ctx->bits[1];
+
+ MD4Transform(ctx->buf, (guint32 *) ctx->in);
+ byteReverse((unsigned char *) ctx->buf, 4);
+
+ if (digest!=NULL)
+ memcpy(digest, ctx->buf, 16);
+ memset(ctx, 0, sizeof(ctx)); /* In case it's sensitive */
+}
+
+/* The three core functions */
+
+#define F(x, y, z) (((x) & (y)) | ((~x) & (z)))
+#define G(x, y, z) (((x) & (y)) | ((x) & (z)) | ((y) & (z)))
+#define H(x, y, z) ((x) ^ (y) ^ (z))
+
+#define FF(a, b, c, d, x, s) { \
+ (a) += F ((b), (c), (d)) + (x); \
+ (a) = rotl32 ((a), (s)); \
+ }
+#define GG(a, b, c, d, x, s) { \
+ (a) += G ((b), (c), (d)) + (x) + (guint32)0x5a827999; \
+ (a) = rotl32 ((a), (s)); \
+ }
+#define HH(a, b, c, d, x, s) { \
+ (a) += H ((b), (c), (d)) + (x) + (guint32)0x6ed9eba1; \
+ (a) = rotl32 ((a), (s)); \
+ }
+
+
+/*
+ * The core of the MD4 algorithm
+ */
+void MD4Transform(guint32 buf[4], guint32 const in[16])
+{
+ register guint32 a, b, c, d;
+
+ a = buf[0];
+ b = buf[1];
+ c = buf[2];
+ d = buf[3];
+
+ FF(a, b, c, d, in[0], 3); /* 1 */
+ FF(d, a, b, c, in[1], 7); /* 2 */
+ FF(c, d, a, b, in[2], 11); /* 3 */
+ FF(b, c, d, a, in[3], 19); /* 4 */
+ FF(a, b, c, d, in[4], 3); /* 5 */
+ FF(d, a, b, c, in[5], 7); /* 6 */
+ FF(c, d, a, b, in[6], 11); /* 7 */
+ FF(b, c, d, a, in[7], 19); /* 8 */
+ FF(a, b, c, d, in[8], 3); /* 9 */
+ FF(d, a, b, c, in[9], 7); /* 10 */
+ FF(c, d, a, b, in[10], 11); /* 11 */
+ FF(b, c, d, a, in[11], 19); /* 12 */
+ FF(a, b, c, d, in[12], 3); /* 13 */
+ FF(d, a, b, c, in[13], 7); /* 14 */
+ FF(c, d, a, b, in[14], 11); /* 15 */
+ FF(b, c, d, a, in[15], 19); /* 16 */
+
+ GG(a, b, c, d, in[0], 3); /* 17 */
+ GG(d, a, b, c, in[4], 5); /* 18 */
+ GG(c, d, a, b, in[8], 9); /* 19 */
+ GG(b, c, d, a, in[12], 13); /* 20 */
+ GG(a, b, c, d, in[1], 3); /* 21 */
+ GG(d, a, b, c, in[5], 5); /* 22 */
+ GG(c, d, a, b, in[9], 9); /* 23 */
+ GG(b, c, d, a, in[13], 13); /* 24 */
+ GG(a, b, c, d, in[2], 3); /* 25 */
+ GG(d, a, b, c, in[6], 5); /* 26 */
+ GG(c, d, a, b, in[10], 9); /* 27 */
+ GG(b, c, d, a, in[14], 13); /* 28 */
+ GG(a, b, c, d, in[3], 3); /* 29 */
+ GG(d, a, b, c, in[7], 5); /* 30 */
+ GG(c, d, a, b, in[11], 9); /* 31 */
+ GG(b, c, d, a, in[15], 13); /* 32 */
+
+ HH(a, b, c, d, in[0], 3); /* 33 */
+ HH(d, a, b, c, in[8], 9); /* 34 */
+ HH(c, d, a, b, in[4], 11); /* 35 */
+ HH(b, c, d, a, in[12], 15); /* 36 */
+ HH(a, b, c, d, in[2], 3); /* 37 */
+ HH(d, a, b, c, in[10], 9); /* 38 */
+ HH(c, d, a, b, in[6], 11); /* 39 */
+ HH(b, c, d, a, in[14], 15); /* 40 */
+ HH(a, b, c, d, in[1], 3); /* 41 */
+ HH(d, a, b, c, in[9], 9); /* 42 */
+ HH(c, d, a, b, in[5], 11); /* 43 */
+ HH(b, c, d, a, in[13], 15); /* 44 */
+ HH(a, b, c, d, in[3], 3); /* 45 */
+ HH(d, a, b, c, in[11], 9); /* 46 */
+ HH(c, d, a, b, in[7], 11); /* 47 */
+ HH(b, c, d, a, in[15], 15); /* 48 */
+
+
+ buf[0] += a;
+ buf[1] += b;
+ buf[2] += c;
+ buf[3] += d;
+}
+
+int MD4Keycrunch( char *result, const char *seed, const char *passphrase)
+{
+ int len;
+ char *buf;
+ MD4_CTX md;
+ guint32 results[4];
+
+ len = strlen(seed) + strlen(passphrase);
+ buf = (char *)malloc(len+1);
+ if (buf == NULL)
+ return -1;
+
+ strcpy(buf, seed);
+ skey_lowcase(buf);
+ strcat(buf, passphrase);
+ skey_sevenbit(buf);
+
+ MD4Init(&md);
+ MD4Update(&md, (unsigned char *)buf, len);
+ MD4Final((unsigned char *)results, &md);
+ free(buf);
+
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+ memcpy((void *)result, (void *)results, SKEY_SIZE);
+
+ return 0;
+}
+
+
+void MD4SKey(char *x)
+{
+ MD4_CTX md;
+ guint32 results[4];
+
+ MD4Init(&md);
+ MD4Update(&md, (unsigned char *)x, SKEY_SIZE);
+ MD4Final((unsigned char *)results, &md);
+
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+
+ memcpy((void *)x, (void *)results, SKEY_SIZE);
+}
+
+#ifdef MD4_MAIN
+
+#include <stdio.h>
+#include <unistd.h>
+#include <stdlib.h>
+
+int main(int argc, char *argv[])
+{
+ MD4_CTX *md4;
+ unsigned char digest[16];
+ unsigned char data[1024];
+ int i, r;
+
+ memset(digest, 0, 16);
+ printf("MD4 digest algorithm. End with Ctrl-D:\n");
+
+ md4 = (MD4_CTX *)malloc(sizeof(MD4_CTX));
+ MD4Init(md4);
+ do {
+ r = read(0, data, sizeof data);
+ MD4Update(md4, data, r);
+ } while (r);
+
+ MD4Final(digest, md4);
+ printf("MD4 Digest is: ");
+ for (i = 0; i < 16; i++)
+ printf("%02X", digest[i]);
+
+ printf("\n");
+ free(md4);
+ return 0;
+}
+
+#endif
diff --git a/src/skey/md4.h b/src/skey/md4.h
new file mode 100644
index 0000000..bd43a26
--- /dev/null
+++ b/src/skey/md4.h
@@ -0,0 +1,19 @@
+#ifndef MD4_H
+#define MD4_H
+
+#include <glib.h>
+
+typedef struct {
+ guint32 buf[4];
+ guint32 bits[2];
+ unsigned char in[64];
+} MD4_CTX;
+
+void MD4Transform(guint32 buf[4], guint32 const in[16]);
+void MD4Init(MD4_CTX *context);
+void MD4Update(MD4_CTX *context, unsigned char const *buf, unsigned len);
+void MD4Final(unsigned char *digest, MD4_CTX *context);
+int MD4Keycrunch(char *result, const char *seed, const char *passphrase);
+void MD4SKey(char *x);
+
+#endif /* !MD4_H */
diff --git a/src/skey/md5.c b/src/skey/md5.c
new file mode 100644
index 0000000..9447c15
--- /dev/null
+++ b/src/skey/md5.c
@@ -0,0 +1,67 @@
+#include <config.h>
+#include <stdlib.h>
+
+#include <string.h>
+#include <glib.h>
+
+#include "skey.h"
+#include "skeyutil.h"
+#include "md5.h"
+
+int MD5Keycrunch(char *result, const char *seed, const char *passhrase)
+{
+ char *buf;
+ gsize len;
+ GChecksum *checksum;
+ guint8 digest[16];
+ gsize digest_len = sizeof (digest);
+ guint32 *results;
+
+ len = strlen(seed) + strlen(passhrase);
+ buf = (char *)g_try_malloc(len+1);
+ if (buf == NULL)
+ return -1;
+
+ strcpy(buf, seed);
+ skey_lowcase(buf);
+ strcat(buf, passhrase);
+ skey_sevenbit(buf);
+
+ checksum = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (checksum, (const guchar *) buf, len);
+ g_free(buf);
+
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_assert (digest_len == 16);
+
+ results = (guint32 *) digest;
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+
+ memcpy((void *)result, (void *)results, SKEY_SIZE);
+
+ g_checksum_free (checksum);
+
+ return 0;
+}
+
+void MD5SKey(char *x)
+{
+ GChecksum *checksum;
+ guint8 digest[16];
+ gsize digest_len = sizeof (digest);
+ guint32 *results;
+
+ checksum = g_checksum_new (G_CHECKSUM_MD5);
+ g_checksum_update (checksum, (const guchar *) x, SKEY_SIZE);
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_assert (digest_len == 16);
+
+ results = (guint32 *) digest;
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+
+ memcpy((void *)x, (void *)results, SKEY_SIZE);
+
+ g_checksum_free (checksum);
+}
diff --git a/src/skey/md5.h b/src/skey/md5.h
new file mode 100644
index 0000000..3129f99
--- /dev/null
+++ b/src/skey/md5.h
@@ -0,0 +1,9 @@
+#ifndef MD5_H
+#define MD5_H
+
+#include <glib.h>
+
+int MD5Keycrunch(char *result, const char *seed, const char *passhrase);
+void MD5SKey(char *x);
+
+#endif /* !MD5_H */
diff --git a/src/skey/sha1.c b/src/skey/sha1.c
new file mode 100644
index 0000000..ac34ccc
--- /dev/null
+++ b/src/skey/sha1.c
@@ -0,0 +1,112 @@
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <arpa/inet.h>
+
+#include <glib.h>
+
+#include "skey.h"
+#include "skeyutil.h"
+#include "sha1.h"
+
+
+#define SHA1_DIGESTSIZE 20
+#define SHA1_BLOCKSIZE 64
+
+#define HTONDIGEST(x) { \
+ x[0] = htonl(x[0]); \
+ x[1] = htonl(x[1]); \
+ x[2] = htonl(x[2]); \
+ x[3] = htonl(x[3]); \
+ x[4] = htonl(x[4]); }
+
+#ifdef WORDS_BIGENDIAN
+/*
+ * Note: this code is harmless on little-endian machines.
+ */
+static void byteReverse(unsigned char *buf, unsigned longs)
+{
+ guint32 t;
+ do {
+ t = (guint32) ((unsigned) buf[3] << 8 | buf[2]) << 16 |
+ ((unsigned) buf[1] << 8 | buf[0]);
+ *(guint32 *) buf = t;
+ buf += 4;
+ } while (--longs);
+}
+#endif
+
+
+int SHA1Keycrunch(char *result, const char *seed, const char *passphrase)
+{
+ char *buf;
+ gsize len;
+ GChecksum *checksum;
+ guint8 digest[20];
+ gsize digest_len = sizeof (digest);
+ guint32 *results;
+
+ len = strlen(seed) + strlen(passphrase);
+ if ((buf = (char *)g_try_malloc(len+1)) == NULL)
+ return -1;
+
+ strcpy(buf, seed);
+ skey_lowcase(buf);
+ strcat(buf, passphrase);
+ skey_sevenbit(buf);
+
+ checksum = g_checksum_new (G_CHECKSUM_SHA1);
+ g_checksum_update (checksum, (const guchar *) buf, len);
+ g_free(buf);
+
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_assert (digest_len == 20);
+
+ results = (guint32 *) digest;
+
+#ifndef WORDS_BIGENDIAN
+ HTONDIGEST(results);
+#else
+ byteReverse((unsigned char *)digest, 5);
+#endif
+
+ results = (guint32 *) digest;
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+ results[0] ^= results[4];
+
+ memcpy((void *)result, (void *)results, SKEY_SIZE);
+
+ g_checksum_free (checksum);
+
+ return 0;
+}
+
+void SHA1SKey(char *x)
+{
+ GChecksum *checksum;
+ guint8 digest[20];
+ gsize digest_len = sizeof (digest);
+ guint32 *results;
+
+ checksum = g_checksum_new (G_CHECKSUM_SHA1);
+ g_checksum_update (checksum, (const guchar *) x, SKEY_SIZE);
+ g_checksum_get_digest (checksum, digest, &digest_len);
+ g_assert (digest_len == 20);
+
+ results = (guint32 *) digest;
+#ifndef WORDS_BIGENDIAN
+ HTONDIGEST(results);
+#else
+ byteReverse((unsigned char *)digest, 5);
+#endif
+
+ results[0] ^= results[2];
+ results[1] ^= results[3];
+ results[0] ^= results[4];
+
+ memcpy((void *)x, (void *)results, SKEY_SIZE);
+
+ g_checksum_free (checksum);
+}
diff --git a/src/skey/sha1.h b/src/skey/sha1.h
new file mode 100644
index 0000000..7feed07
--- /dev/null
+++ b/src/skey/sha1.h
@@ -0,0 +1,9 @@
+#ifndef _SHA1_H
+#define _SHA1_H
+
+#include <glib.h>
+
+int SHA1Keycrunch(char *result, const char *seed, const char *passphrase);
+void SHA1SKey(char *x);
+
+#endif /* _SHA1_H */
diff --git a/src/skey/skey.c b/src/skey/skey.c
new file mode 100644
index 0000000..2517842
--- /dev/null
+++ b/src/skey/skey.c
@@ -0,0 +1,37 @@
+#include <config.h>
+
+#include <stdio.h>
+#include <stdlib.h>
+#include <string.h>
+#include <unistd.h>
+
+#include "md4.h"
+#include "md5.h"
+#include "sha1.h"
+#include "skey.h"
+#include "btoe.h"
+
+struct skey_hash {
+ int (*Keycrunch) (char *, const char *, const char *);
+ void (*Skey) (char *);
+};
+static struct skey_hash hash_table[] = {
+ { MD4Keycrunch, MD4SKey },
+ { MD5Keycrunch, MD5SKey },
+ { SHA1Keycrunch, SHA1SKey }
+};
+
+
+char *skey(SKeyAlgorithm algorithm, int seq, const char *seed, const char *passphrase)
+{
+ char key[SKEY_SIZE];
+ int i;
+ g_assert (algorithm < G_N_ELEMENTS (hash_table));
+ if (hash_table[algorithm].Keycrunch(key, seed, passphrase) == -1)
+ return NULL;
+
+ for (i = 0; i < seq; i++)
+ hash_table[algorithm].Skey(key);
+
+ return strdup(btoe((unsigned char *)key));
+}
diff --git a/src/skey/skey.h b/src/skey/skey.h
new file mode 100644
index 0000000..0475629
--- /dev/null
+++ b/src/skey/skey.h
@@ -0,0 +1,10 @@
+typedef enum {
+ MD4,
+ MD5,
+ SHA1
+} SKeyAlgorithm;
+
+#define SKEY_SIZE 8
+
+char *skey(SKeyAlgorithm algorithm, int seq, const char *seed, const char *passhrase);
+
diff --git a/src/skey/skeyutil.c b/src/skey/skeyutil.c
new file mode 100644
index 0000000..b9e56dc
--- /dev/null
+++ b/src/skey/skeyutil.c
@@ -0,0 +1,24 @@
+#include <config.h>
+
+#include <ctype.h>
+
+#include <glib.h>
+
+#include "skeyutil.h"
+
+void skey_sevenbit(char *s)
+{
+ char *p;
+
+ for (p = s; *p; p++)
+ *p &= 0x7f;
+}
+
+void skey_lowcase(char *s)
+{
+ char *p;
+
+ for (p = s; *p; p++)
+ if (g_ascii_isupper(*p))
+ *p = g_ascii_tolower(*p);
+}
diff --git a/src/skey/skeyutil.h b/src/skey/skeyutil.h
new file mode 100644
index 0000000..02d4c34
--- /dev/null
+++ b/src/skey/skeyutil.h
@@ -0,0 +1,3 @@
+void skey_sevenbit(char *s);
+void skey_lowcase(char *s);
+
diff --git a/src/skey/test.c b/src/skey/test.c
new file mode 100644
index 0000000..1fc1a09
--- /dev/null
+++ b/src/skey/test.c
@@ -0,0 +1,99 @@
+#include <config.h>
+
+#include <locale.h>
+#include <stdlib.h>
+#include <string.h>
+
+#include <glib.h>
+
+#include "skey.h"
+
+typedef struct {
+ SKeyAlgorithm algorithm;
+ const char *passphrase;
+ const char *seed;
+ int count;
+ const char *hex;
+ const char *btoe;
+} TestEntry;
+
+static const TestEntry tests[] = {
+ { MD4, "This is a test.", "TeSt", 0, "D185 4218 EBBB 0B51", "ROME MUG FRED SCAN LIVE LACE" },
+ { MD4, "This is a test.", "TeSt", 1, "6347 3EF0 1CD0 B444", "CARD SAD MINI RYE COL KIN" },
+ { MD4, "This is a test.", "TeSt", 99, "C5E6 1277 6E6C 237A", "NOTE OUT IBIS SINK NAVE MODE" },
+ { MD4, "AbCdEfGhIjK", "alpha1", 0, "5007 6F47 EB1A DE4E", "AWAY SEN ROOK SALT LICE MAP" },
+ { MD4, "AbCdEfGhIjK", "alpha1", 1, "65D2 0D19 49B5 F7AB", "CHEW GRIM WU HANG BUCK SAID" },
+ { MD4, "AbCdEfGhIjK", "alpha1", 99, "D150 C82C CE6F 62D1", "ROIL FREE COG HUNK WAIT COCA" },
+ { MD4, "OTP's are good", "correct", 0, "849C 79D4 F6F5 5388", "FOOL STEM DONE TOOL BECK NILE" },
+ { MD4, "OTP's are good", "correct", 1, "8C09 92FB 2508 47B1", "GIST AMOS MOOT AIDS FOOD SEEM" },
+ { MD4, "OTP's are good", "correct", 99, "3F3B F4B4 145F D74B", "TAG SLOW NOV MIN WOOL KENO" },
+ { MD5, "This is a test.", "TeSt", 0, "9E87 6134 D904 99DD", "INCH SEA ANNE LONG AHEM TOUR" },
+ { MD5, "This is a test.", "TeSt", 1, "7965 E054 36F5 029F", "EASE OIL FUM CURE AWRY AVIS" },
+ { MD5, "This is a test.", "TeSt", 99, "50FE 1962 C496 5880", "BAIL TUFT BITS GANG CHEF THY" },
+ { MD5, "AbCdEfGhIjK", "alpha1", 0, "8706 6DD9 644B F206", "FULL PEW DOWN ONCE MORT ARC" },
+ { MD5, "AbCdEfGhIjK", "alpha1", 1, "7CD3 4C10 40AD D14B", "FACT HOOF AT FIST SITE KENT" },
+ { MD5, "AbCdEfGhIjK", "alpha1", 99, "5AA3 7A81 F212 146C", "BODE HOP JAKE STOW JUT RAP" },
+ { MD5, "OTP's are good", "correct", 0, "F205 7539 43DE 4CF9", "ULAN NEW ARMY FUSE SUIT EYED" },
+ { MD5, "OTP's are good", "correct", 1, "DDCD AC95 6F23 4937", "SKIM CULT LOB SLAM POE HOWL" },
+ { MD5, "OTP's are good", "correct", 99, "B203 E28F A525 BE47", "LONG IVY JULY AJAR BOND LEE" },
+ { SHA1, "This is a test.", "TeSt", 0, "BB9E 6AE1 979D 8FF4", "MILT VARY MAST OK SEES WENT" },
+ { SHA1, "This is a test.", "TeSt", 1, "63D9 3663 9734 385B", "CART OTTO HIVE ODE VAT NUT" },
+ { SHA1, "This is a test.", "TeSt", 99, "87FE C776 8B73 CCF9", "GAFF WAIT SKID GIG SKY EYED" },
+ { SHA1, "AbCdEfGhIjK", "alpha1", 0, "AD85 F658 EBE3 83C9", "LEST OR HEEL SCOT ROB SUIT" },
+ { SHA1, "AbCdEfGhIjK", "alpha1", 1, "D07C E229 B5CF 119B", "RITE TAKE GELD COST TUNE RECK" },
+ { SHA1, "AbCdEfGhIjK", "alpha1", 99, "27BC 7103 5AAF 3DC6", "MAY STAR TIN LYON VEDA STAN" },
+ { SHA1, "OTP's are good", "correct", 0, "D51F 3E99 BF8E 6F0B", "RUST WELT KICK FELL TAIL FRAU" },
+ { SHA1, "OTP's are good", "correct", 1, "82AE B52D 9437 74E4", "FLIT DOSE ALSO MEW DRUM DEFY" },
+ { SHA1, "OTP's are good", "correct", 99, "4F29 6A74 FE15 67EC", "AURA ALOE HURL WING BERG WAIT" },
+
+ { SHA1, "Passphrase", "IiIi", 100, "27F4 01CC 0AC8 5112", "MEG JACK DIET GAD FORK GARY" }
+};
+
+static const char *algos[] = {
+ "MD4",
+ "MD5",
+ "SHA1"
+};
+
+static void
+skey_test (gconstpointer data)
+{
+ const TestEntry *test = (const TestEntry *) data;
+ char *key;
+
+ key = skey (test->algorithm,
+ test->count,
+ test->seed,
+ test->passphrase);
+ g_assert (key != NULL);
+ g_assert (strcmp (key, test->btoe) == 0);
+ free (key);
+}
+
+int main(int argc, char *argv[])
+{
+ guint i;
+
+ if (!setlocale (LC_ALL, ""))
+ g_error ("Locale not supported by C library!\n");
+
+ g_test_init (&argc, &argv, NULL);
+ g_test_bug_base ("http://bugzilla.mate.org/enter_bug.cgi?product=mate-terminal");
+
+ for (i = 0; i < G_N_ELEMENTS (tests); ++i) {
+ const TestEntry *test = &tests[i];
+ char *name;
+
+ name = g_strdup_printf ("/%s/%s/%s/%d/%s/%s",
+ algos[test->algorithm],
+ test->passphrase,
+ test->seed,
+ test->count,
+ test->hex,
+ test->btoe);
+ g_test_add_data_func (name, test, skey_test);
+ g_free (name);
+ }
+
+ return g_test_run ();
+}
diff --git a/src/terminal-accels.c b/src/terminal-accels.c
new file mode 100644
index 0000000..73ed7ca
--- /dev/null
+++ b/src/terminal-accels.c
@@ -0,0 +1,1012 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington, Red Hat Inc.
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gdk/gdkkeysyms.h>
+
+#include "terminal-accels.h"
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-intl.h"
+#include "terminal-profile.h"
+#include "terminal-util.h"
+
+/* NOTES
+ *
+ * There are two sources of keybindings changes, from MateConf and from
+ * the accel map (happens with in-place menu editing).
+ *
+ * When a keybinding mateconf key changes, we propagate that into the
+ * accel map.
+ * When the accel map changes, we queue a sync to mateconf.
+ *
+ * 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 mateconf and rely on the mateconf callback to
+ * actually apply the change to the accel map.
+ */
+
+#define ACCEL_PATH_ROOT "<Actions>/Main/"
+#define ACCEL_PATH_NEW_TAB ACCEL_PATH_ROOT "FileNewTab"
+#define ACCEL_PATH_NEW_WINDOW ACCEL_PATH_ROOT "FileNewWindow"
+#define ACCEL_PATH_NEW_PROFILE ACCEL_PATH_ROOT "FileNewProfile"
+#define ACCEL_PATH_SAVE_CONTENTS ACCEL_PATH_ROOT "FileSaveContents"
+#define ACCEL_PATH_CLOSE_TAB ACCEL_PATH_ROOT "FileCloseTab"
+#define ACCEL_PATH_CLOSE_WINDOW ACCEL_PATH_ROOT "FileCloseWindow"
+#define ACCEL_PATH_COPY ACCEL_PATH_ROOT "EditCopy"
+#define ACCEL_PATH_PASTE ACCEL_PATH_ROOT "EditPaste"
+#define ACCEL_PATH_TOGGLE_MENUBAR ACCEL_PATH_ROOT "ViewMenubar"
+#define ACCEL_PATH_FULL_SCREEN ACCEL_PATH_ROOT "ViewFullscreen"
+#define ACCEL_PATH_RESET ACCEL_PATH_ROOT "TerminalReset"
+#define ACCEL_PATH_RESET_AND_CLEAR ACCEL_PATH_ROOT "TerminalResetClear"
+#define ACCEL_PATH_PREV_TAB ACCEL_PATH_ROOT "TabsPrevious"
+#define ACCEL_PATH_NEXT_TAB ACCEL_PATH_ROOT "TabsNext"
+#define ACCEL_PATH_SET_TERMINAL_TITLE ACCEL_PATH_ROOT "TerminalSetTitle"
+#define ACCEL_PATH_HELP ACCEL_PATH_ROOT "HelpContents"
+#define ACCEL_PATH_ZOOM_IN ACCEL_PATH_ROOT "ViewZoomIn"
+#define ACCEL_PATH_ZOOM_OUT ACCEL_PATH_ROOT "ViewZoomOut"
+#define ACCEL_PATH_ZOOM_NORMAL ACCEL_PATH_ROOT "ViewZoom100"
+#define ACCEL_PATH_MOVE_TAB_LEFT ACCEL_PATH_ROOT "TabsMoveLeft"
+#define ACCEL_PATH_MOVE_TAB_RIGHT ACCEL_PATH_ROOT "TabsMoveRight"
+#define ACCEL_PATH_DETACH_TAB ACCEL_PATH_ROOT "TabsDetach"
+#define ACCEL_PATH_SWITCH_TAB_PREFIX ACCEL_PATH_ROOT "TabsSwitch"
+
+#define KEY_CLOSE_TAB CONF_KEYS_PREFIX "/close_tab"
+#define KEY_CLOSE_WINDOW CONF_KEYS_PREFIX "/close_window"
+#define KEY_COPY CONF_KEYS_PREFIX "/copy"
+#define KEY_DETACH_TAB CONF_KEYS_PREFIX "/detach_tab"
+#define KEY_FULL_SCREEN CONF_KEYS_PREFIX "/full_screen"
+#define KEY_HELP CONF_KEYS_PREFIX "/help"
+#define KEY_MOVE_TAB_LEFT CONF_KEYS_PREFIX "/move_tab_left"
+#define KEY_MOVE_TAB_RIGHT CONF_KEYS_PREFIX "/move_tab_right"
+#define KEY_NEW_PROFILE CONF_KEYS_PREFIX "/new_profile"
+#define KEY_NEW_TAB CONF_KEYS_PREFIX "/new_tab"
+#define KEY_NEW_WINDOW CONF_KEYS_PREFIX "/new_window"
+#define KEY_NEXT_TAB CONF_KEYS_PREFIX "/next_tab"
+#define KEY_PASTE CONF_KEYS_PREFIX "/paste"
+#define KEY_PREV_TAB CONF_KEYS_PREFIX "/prev_tab"
+#define KEY_RESET_AND_CLEAR CONF_KEYS_PREFIX "/reset_and_clear"
+#define KEY_RESET CONF_KEYS_PREFIX "/reset"
+#define KEY_SAVE_CONTENTS CONF_KEYS_PREFIX "/save_contents"
+#define KEY_SET_TERMINAL_TITLE CONF_KEYS_PREFIX "/set_window_title"
+#define KEY_TOGGLE_MENUBAR CONF_KEYS_PREFIX "/toggle_menubar"
+#define KEY_ZOOM_IN CONF_KEYS_PREFIX "/zoom_in"
+#define KEY_ZOOM_NORMAL CONF_KEYS_PREFIX "/zoom_normal"
+#define KEY_ZOOM_OUT CONF_KEYS_PREFIX "/zoom_out"
+#define KEY_SWITCH_TAB_PREFIX CONF_KEYS_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 *mateconf_key;
+ const char *accel_path;
+ /* last values received from mateconf */
+ GdkModifierType mateconf_mask;
+ guint mateconf_keyval;
+ GClosure *closure;
+ /* have gotten a notification from gtk */
+ gboolean needs_mateconf_sync;
+ gboolean accel_path_unlocked;
+} KeyEntry;
+
+typedef struct
+{
+ KeyEntry *key_entry;
+ guint n_elements;
+ const char *user_visible_name;
+} KeyEntryList;
+
+static KeyEntry file_entries[] =
+{
+ { N_("New Tab"),
+ KEY_NEW_TAB, ACCEL_PATH_NEW_TAB, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_t, NULL, FALSE, TRUE },
+ { N_("New Window"),
+ KEY_NEW_WINDOW, ACCEL_PATH_NEW_WINDOW, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_n, NULL, FALSE, TRUE },
+ { N_("New Profile"),
+ KEY_NEW_PROFILE, ACCEL_PATH_NEW_PROFILE, 0, 0, NULL, FALSE, TRUE },
+#ifdef ENABLE_SAVE
+ { N_("Save Contents"),
+ KEY_SAVE_CONTENTS, ACCEL_PATH_SAVE_CONTENTS, 0, 0, NULL, FALSE, TRUE },
+#endif
+ { N_("Close Tab"),
+ KEY_CLOSE_TAB, ACCEL_PATH_CLOSE_TAB, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_w, NULL, FALSE, TRUE },
+ { N_("Close Window"),
+ KEY_CLOSE_WINDOW, ACCEL_PATH_CLOSE_WINDOW, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_q, NULL, FALSE, TRUE },
+};
+
+static KeyEntry edit_entries[] =
+{
+ { N_("Copy"),
+ KEY_COPY, ACCEL_PATH_COPY, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_c, NULL, FALSE, TRUE },
+ { N_("Paste"),
+ KEY_PASTE, ACCEL_PATH_PASTE, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_v, NULL, FALSE, TRUE },
+};
+
+static KeyEntry view_entries[] =
+{
+ { N_("Hide and Show menubar"),
+ KEY_TOGGLE_MENUBAR, ACCEL_PATH_TOGGLE_MENUBAR, 0, 0, NULL, FALSE, TRUE },
+ { N_("Full Screen"),
+ KEY_FULL_SCREEN, ACCEL_PATH_FULL_SCREEN, 0, GDK_F11, NULL, FALSE, TRUE },
+ { N_("Zoom In"),
+ KEY_ZOOM_IN, ACCEL_PATH_ZOOM_IN, GDK_CONTROL_MASK, GDK_plus, NULL, FALSE, TRUE },
+ { N_("Zoom Out"),
+ KEY_ZOOM_OUT, ACCEL_PATH_ZOOM_OUT, GDK_CONTROL_MASK, GDK_minus, NULL, FALSE, TRUE },
+ { N_("Normal Size"),
+ KEY_ZOOM_NORMAL, ACCEL_PATH_ZOOM_NORMAL, GDK_CONTROL_MASK, GDK_0, NULL, FALSE, TRUE }
+};
+
+static KeyEntry terminal_entries[] =
+{
+ { N_("Set Title"),
+ KEY_SET_TERMINAL_TITLE, ACCEL_PATH_SET_TERMINAL_TITLE, 0, 0, NULL, FALSE, TRUE },
+ { N_("Reset"),
+ KEY_RESET, ACCEL_PATH_RESET, 0, 0, NULL, FALSE, TRUE },
+ { N_("Reset and Clear"),
+ KEY_RESET_AND_CLEAR, ACCEL_PATH_RESET_AND_CLEAR, 0, 0, NULL, FALSE, TRUE },
+};
+
+static KeyEntry tabs_entries[] =
+{
+ { N_("Switch to Previous Tab"),
+ KEY_PREV_TAB, ACCEL_PATH_PREV_TAB, GDK_CONTROL_MASK, GDK_Page_Up, NULL, FALSE, TRUE },
+ { N_("Switch to Next Tab"),
+ KEY_NEXT_TAB, ACCEL_PATH_NEXT_TAB, GDK_CONTROL_MASK, GDK_Page_Down, NULL, FALSE, TRUE },
+ { N_("Move Tab to the Left"),
+ KEY_MOVE_TAB_LEFT, ACCEL_PATH_MOVE_TAB_LEFT, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_Page_Up, NULL, FALSE, TRUE },
+ { N_("Move Tab to the Right"),
+ KEY_MOVE_TAB_RIGHT, ACCEL_PATH_MOVE_TAB_RIGHT, GDK_SHIFT_MASK | GDK_CONTROL_MASK, GDK_Page_Down, NULL, FALSE, TRUE },
+ { N_("Detach Tab"),
+ KEY_DETACH_TAB, ACCEL_PATH_DETACH_TAB, 0, 0, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 1"),
+ KEY_SWITCH_TAB_PREFIX "1",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "1", GDK_MOD1_MASK, GDK_1, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 2"),
+ KEY_SWITCH_TAB_PREFIX "2",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "2", GDK_MOD1_MASK, GDK_2, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 3"),
+ KEY_SWITCH_TAB_PREFIX "3",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "3", GDK_MOD1_MASK, GDK_3, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 4"),
+ KEY_SWITCH_TAB_PREFIX "4",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "4", GDK_MOD1_MASK, GDK_4, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 5"),
+ KEY_SWITCH_TAB_PREFIX "5",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "5", GDK_MOD1_MASK, GDK_5, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 6"),
+ KEY_SWITCH_TAB_PREFIX "6",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "6", GDK_MOD1_MASK, GDK_6, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 7"),
+ KEY_SWITCH_TAB_PREFIX "7",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "7", GDK_MOD1_MASK, GDK_7, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 8"),
+ KEY_SWITCH_TAB_PREFIX "8",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "8", GDK_MOD1_MASK, GDK_8, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 9"),
+ KEY_SWITCH_TAB_PREFIX "9",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "9", GDK_MOD1_MASK, GDK_9, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 10"),
+ KEY_SWITCH_TAB_PREFIX "10",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "10", GDK_MOD1_MASK, GDK_0, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 11"),
+ KEY_SWITCH_TAB_PREFIX "11",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "11", 0, 0, NULL, FALSE, TRUE },
+ { N_("Switch to Tab 12"),
+ KEY_SWITCH_TAB_PREFIX "12",
+ ACCEL_PATH_SWITCH_TAB_PREFIX "12", 0, 0, NULL, FALSE, TRUE }
+};
+
+static KeyEntry help_entries[] = {
+ { N_("Contents"), KEY_HELP, ACCEL_PATH_HELP, 0, GDK_F1, NULL, FALSE, TRUE }
+};
+
+static KeyEntryList all_entries[] =
+{
+ { file_entries, G_N_ELEMENTS (file_entries), N_("File") },
+ { edit_entries, G_N_ELEMENTS (edit_entries), N_("Edit") },
+ { view_entries, G_N_ELEMENTS (view_entries), N_("View") },
+ { terminal_entries, G_N_ELEMENTS (terminal_entries), N_("Terminal") },
+ { tabs_entries, G_N_ELEMENTS (tabs_entries), N_("Tabs") },
+ { help_entries, G_N_ELEMENTS (help_entries), N_("Help") }
+};
+
+enum
+{
+ ACTION_COLUMN,
+ KEYVAL_COLUMN,
+ N_COLUMNS
+};
+
+static void keys_change_notify (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data);
+
+static void accel_changed_callback (GtkAccelGroup *accel_group,
+ guint keyval,
+ GdkModifierType modifier,
+ GClosure *accel_closure,
+ gpointer data);
+
+static gboolean binding_from_string (const char *str,
+ guint *accelerator_key,
+ GdkModifierType *accelerator_mods);
+
+static gboolean binding_from_value (MateConfValue *value,
+ guint *accelerator_key,
+ GdkModifierType *accelerator_mods);
+
+static gboolean sync_idle_cb (gpointer data);
+
+static guint sync_idle_id = 0;
+static GtkAccelGroup *notification_group = NULL;
+/* never set mateconf keys in response to receiving a mateconf notify. */
+static int inside_mateconf_notify = 0;
+static GtkWidget *edit_keys_dialog = NULL;
+static GtkTreeStore *edit_keys_store = NULL;
+static guint mateconf_notify_id;
+static GHashTable *mateconf_key_to_entry;
+
+static char*
+binding_name (guint keyval,
+ GdkModifierType mask)
+{
+ if (keyval != 0)
+ return gtk_accelerator_name (keyval, mask);
+
+ return g_strdup ("disabled");
+}
+
+static char*
+binding_display_name (guint keyval,
+ GdkModifierType mask)
+{
+ if (keyval != 0)
+ return gtk_accelerator_get_label (keyval, mask);
+
+ return g_strdup (_("Disabled"));
+}
+
+static const char *
+key_from_mateconf_key (const char *mateconf_key)
+{
+ const char *last_slash = strrchr (mateconf_key, '/');
+ if (last_slash)
+ return ++last_slash;
+ return NULL;
+}
+
+void
+terminal_accels_init (void)
+{
+ MateConfClient *conf;
+ guint i, j;
+
+ conf = mateconf_client_get_default ();
+
+ mateconf_client_add_dir (conf, CONF_KEYS_PREFIX,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ mateconf_notify_id =
+ mateconf_client_notify_add (conf,
+ CONF_KEYS_PREFIX,
+ keys_change_notify,
+ NULL, NULL, NULL);
+
+ mateconf_key_to_entry = g_hash_table_new (g_str_hash, g_str_equal);
+
+ notification_group = gtk_accel_group_new ();
+
+ 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]);
+
+ g_hash_table_insert (mateconf_key_to_entry,
+ (gpointer) key_from_mateconf_key (key_entry->mateconf_key),
+ key_entry);
+
+ key_entry->closure = g_closure_new_simple (sizeof (GClosure), key_entry);
+
+ g_closure_ref (key_entry->closure);
+ g_closure_sink (key_entry->closure);
+
+ gtk_accel_group_connect_by_path (notification_group,
+ I_(key_entry->accel_path),
+ key_entry->closure);
+
+ mateconf_client_notify (conf, key_entry->mateconf_key);
+ }
+ }
+
+ g_object_unref (conf);
+
+ g_signal_connect (notification_group, "accel-changed",
+ G_CALLBACK (accel_changed_callback), NULL);
+}
+
+void
+terminal_accels_shutdown (void)
+{
+ MateConfClient *conf;
+
+ conf = mateconf_client_get_default ();
+ mateconf_client_notify_remove (conf, mateconf_notify_id);
+ mateconf_client_remove_dir (conf, CONF_KEYS_PREFIX, NULL);
+ g_object_unref (conf);
+
+ if (sync_idle_id != 0)
+ {
+ g_source_remove (sync_idle_id);
+ sync_idle_id = 0;
+
+ sync_idle_cb (NULL);
+ }
+
+ g_hash_table_destroy (mateconf_key_to_entry);
+ mateconf_key_to_entry = NULL;
+
+ g_object_unref (notification_group);
+ notification_group = NULL;
+}
+
+static gboolean
+update_model_foreach (GtkTreeModel *model,
+ GtkTreePath *path,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ KeyEntry *key_entry = NULL;
+
+ gtk_tree_model_get (model, iter,
+ KEYVAL_COLUMN, &key_entry,
+ -1);
+
+ if (key_entry == (KeyEntry *) data)
+ {
+ gtk_tree_model_row_changed (model, path, iter);
+ return TRUE;
+ }
+ return FALSE;
+}
+
+static void
+keys_change_notify (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ MateConfValue *val;
+ KeyEntry *key_entry;
+ GdkModifierType mask;
+ guint keyval;
+
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "key %s changed\n",
+ mateconf_entry_get_key (entry));
+
+ val = mateconf_entry_get_value (entry);
+
+#ifdef MATE_ENABLE_DEBUG
+ _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS)
+ {
+ if (val == NULL)
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " changed to be unset\n");
+ else if (val->type != MATECONF_VALUE_STRING)
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS, " changed to non-string value\n");
+ else
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ " changed to \"%s\"\n",
+ mateconf_value_get_string (val));
+ }
+#endif
+
+ key_entry = g_hash_table_lookup (mateconf_key_to_entry, key_from_mateconf_key (mateconf_entry_get_key (entry)));
+ 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;
+ }
+
+ if (!binding_from_value (val, &keyval, &mask))
+ {
+ const char *str = val->type == MATECONF_VALUE_STRING ? mateconf_value_get_string (val) : NULL;
+ g_printerr ("The value \"%s\" of configuration key %s is not a valid accelerator\n",
+ str ? str : "(null)",
+ key_entry->mateconf_key);
+ return;
+ }
+
+ key_entry->mateconf_keyval = keyval;
+ key_entry->mateconf_mask = mask;
+
+ /* Unlock the path, so we can change its accel */
+ if (!key_entry->accel_path_unlocked)
+ gtk_accel_map_unlock_path (key_entry->accel_path);
+
+ /* sync over to GTK */
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "changing path %s to %s\n",
+ key_entry->accel_path,
+ binding_name (keyval, mask)); /* memleak */
+ inside_mateconf_notify += 1;
+ /* Note that this may return FALSE, e.g. when the entry was already set correctly. */
+ gtk_accel_map_change_entry (key_entry->accel_path,
+ keyval, mask,
+ TRUE);
+ inside_mateconf_notify -= 1;
+
+ /* Lock the path if the mateconf key isn't writable */
+ key_entry->accel_path_unlocked = mateconf_entry_get_is_writable (entry);
+ if (!key_entry->accel_path_unlocked)
+ gtk_accel_map_lock_path (key_entry->accel_path);
+
+ /* This seems necessary to update the tree model, since sometimes the
+ * notification on the notification_group seems not to be emitted correctly.
+ * Without this change, when trying to set an accel to e.g. Alt-T (while the main
+ * menu in the terminal windows is _Terminal with Alt-T mnemonic) only displays
+ * the accel change after a re-expose of the row.
+ * FIXME: Find out *why* the accel-changed signal is wrong here!
+ */
+ if (edit_keys_store)
+ gtk_tree_model_foreach (GTK_TREE_MODEL (edit_keys_store), update_model_foreach, key_entry);
+}
+
+static void
+accel_changed_callback (GtkAccelGroup *accel_group,
+ guint keyval,
+ GdkModifierType modifier,
+ GClosure *accel_closure,
+ gpointer data)
+{
+ /* FIXME because GTK accel API is so nonsensical, we get
+ * a notify for each closure, on both the added and the removed
+ * accelerator. We just use the accel closure to find our
+ * accel entry, then update the value of that entry.
+ * We use an idle function to avoid setting the entry
+ * in mateconf when the accelerator gets removed and then
+ * setting it again when it gets added.
+ */
+ KeyEntry *key_entry;
+
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "Changed accel %s closure %p\n",
+ binding_name (keyval, modifier), /* memleak */
+ accel_closure);
+
+ if (inside_mateconf_notify)
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "Ignoring change from gtk because we're inside a mateconf notify\n");
+ return;
+ }
+
+ key_entry = accel_closure->data;
+ g_assert (key_entry);
+
+ key_entry->needs_mateconf_sync = TRUE;
+
+ if (sync_idle_id == 0)
+ sync_idle_id = g_idle_add (sync_idle_cb, NULL);
+}
+
+static gboolean
+binding_from_string (const char *str,
+ guint *accelerator_key,
+ GdkModifierType *accelerator_mods)
+{
+ if (str == NULL ||
+ strcmp (str, "disabled") == 0)
+ {
+ *accelerator_key = 0;
+ *accelerator_mods = 0;
+ return TRUE;
+ }
+
+ gtk_accelerator_parse (str, accelerator_key, accelerator_mods);
+ if (*accelerator_key == 0 &&
+ *accelerator_mods == 0)
+ return FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+binding_from_value (MateConfValue *value,
+ guint *accelerator_key,
+ GdkModifierType *accelerator_mods)
+{
+ if (value == NULL)
+ {
+ /* unset */
+ *accelerator_key = 0;
+ *accelerator_mods = 0;
+ return TRUE;
+ }
+
+ if (value->type != MATECONF_VALUE_STRING)
+ return FALSE;
+
+ return binding_from_string (mateconf_value_get_string (value),
+ accelerator_key,
+ accelerator_mods);
+}
+
+static void
+add_key_entry_to_changeset (gpointer key,
+ KeyEntry *key_entry,
+ MateConfChangeSet *changeset)
+{
+ GtkAccelKey gtk_key;
+
+ if (!key_entry->needs_mateconf_sync)
+ return;
+
+ key_entry->needs_mateconf_sync = FALSE;
+
+ if (gtk_accel_map_lookup_entry (key_entry->accel_path, &gtk_key) &&
+ (gtk_key.accel_key != key_entry->mateconf_keyval ||
+ gtk_key.accel_mods != key_entry->mateconf_mask))
+ {
+ char *accel_name;
+
+ accel_name = binding_name (gtk_key.accel_key, gtk_key.accel_mods);
+ mateconf_change_set_set_string (changeset, key_entry->mateconf_key, accel_name);
+ g_free (accel_name);
+ }
+}
+
+static gboolean
+sync_idle_cb (gpointer data)
+{
+ MateConfClient *conf;
+ MateConfChangeSet *changeset;
+ GError *error = NULL;
+
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "mateconf sync handler\n");
+
+ sync_idle_id = 0;
+
+ conf = mateconf_client_get_default ();
+
+ changeset = mateconf_change_set_new ();
+ g_hash_table_foreach (mateconf_key_to_entry, (GHFunc) add_key_entry_to_changeset, changeset);
+ if (!mateconf_client_commit_change_set (conf, changeset, TRUE, &error))
+ {
+ g_printerr ("Error committing the accelerator changeset: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ mateconf_change_set_unref (changeset);
+ g_object_unref (conf);
+
+ return FALSE;
+}
+
+/* We have the same KeyEntry* in both columns;
+ * we only have two columns because we want to be able
+ * to sort by either one of them.
+ */
+
+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
+ g_object_set (cell,
+ "visible", TRUE,
+ "sensitive", ke->accel_path_unlocked,
+ "editable", ke->accel_path_unlocked,
+ "accel-key", ke->mateconf_keyval,
+ "accel-mods", ke->mateconf_mask,
+ NULL);
+}
+
+static int
+accel_compare_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ KeyEntry *ke_a;
+ KeyEntry *ke_b;
+ char *name_a;
+ char *name_b;
+ int result;
+
+ gtk_tree_model_get (model, a,
+ KEYVAL_COLUMN, &ke_a,
+ -1);
+ if (ke_a == NULL)
+ {
+ gtk_tree_model_get (model, a,
+ ACTION_COLUMN, &name_a,
+ -1);
+ }
+ else
+ {
+ name_a = binding_display_name (ke_a->mateconf_keyval,
+ ke_a->mateconf_mask);
+ }
+
+ gtk_tree_model_get (model, b,
+ KEYVAL_COLUMN, &ke_b,
+ -1);
+ if (ke_b == NULL)
+ {
+ gtk_tree_model_get (model, b,
+ ACTION_COLUMN, &name_b,
+ -1);
+ }
+ else
+ {
+ name_b = binding_display_name (ke_b->mateconf_keyval,
+ ke_b->mateconf_mask);
+ }
+
+ result = g_utf8_collate (name_a, name_b);
+
+ g_free (name_a);
+ g_free (name_b);
+
+ return result;
+}
+
+static void
+treeview_accel_changed_cb (GtkAccelGroup *accel_group,
+ guint keyval,
+ GdkModifierType modifier,
+ GClosure *accel_closure,
+ GtkTreeModel *model)
+{
+ gtk_tree_model_foreach (model, update_model_foreach, accel_closure->data);
+}
+
+static void
+accel_edited_callback (GtkCellRendererAccel *cell,
+ gchar *path_string,
+ guint keyval,
+ GdkModifierType mask,
+ guint hardware_keycode,
+ GtkTreeView *view)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ KeyEntry *ke;
+ GtkAccelGroupEntry *entries;
+ guint n_entries;
+ char *str;
+ MateConfClient *conf;
+
+ 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)) {
+ gtk_tree_path_free (path);
+ return;
+ }
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1);
+
+ /* sanity check */
+ if (ke == NULL)
+ return;
+
+ /* Check if we already have an entry using this accel */
+ entries = gtk_accel_group_query (notification_group, keyval, mask, &n_entries);
+ if (n_entries > 0)
+ {
+ if (entries[0].accel_path_quark != g_quark_from_string (ke->accel_path))
+ {
+ GtkWidget *dialog;
+ char *name;
+ KeyEntry *other_key;
+
+ name = gtk_accelerator_get_label (keyval, mask);
+ other_key = entries[0].closure->data;
+ g_assert (other_key);
+
+ dialog =
+ gtk_message_dialog_new (GTK_WINDOW (gtk_widget_get_toplevel (GTK_WIDGET (view))),
+ GTK_DIALOG_DESTROY_WITH_PARENT | GTK_DIALOG_MODAL,
+ GTK_MESSAGE_WARNING,
+ GTK_BUTTONS_OK,
+ _("The shortcut key “%s” is already bound to the “%s” action"),
+ name,
+ other_key->user_visible_name ? _(other_key->user_visible_name) : other_key->mateconf_key);
+ g_free (name);
+
+ g_signal_connect (dialog, "response", G_CALLBACK (gtk_widget_destroy), NULL);
+ gtk_window_present (GTK_WINDOW (dialog));
+ }
+
+ return;
+ }
+
+ str = binding_name (keyval, mask);
+
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "Edited path %s keyval %s, setting mateconf to %s\n",
+ ke->accel_path,
+ gdk_keyval_name (keyval) ? gdk_keyval_name (keyval) : "null",
+ str);
+#ifdef MATE_ENABLE_DEBUG
+ _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ACCELS)
+ {
+ GtkAccelKey old_key;
+
+ if (gtk_accel_map_lookup_entry (ke->accel_path, &old_key)) {
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ " Old entry of path %s is keyval %s mask %x\n",
+ ke->accel_path, gdk_keyval_name (old_key.accel_key), old_key.accel_mods);
+ } else {
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ " Failed to look up the old entry of path %s\n",
+ ke->accel_path);
+ }
+ }
+#endif
+
+ conf = mateconf_client_get_default ();
+ mateconf_client_set_string (conf,
+ ke->mateconf_key,
+ str,
+ NULL);
+ g_object_unref (conf);
+ g_free (str);
+}
+
+static void
+accel_cleared_callback (GtkCellRendererAccel *cell,
+ gchar *path_string,
+ GtkTreeView *view)
+{
+ GtkTreeModel *model;
+ GtkTreePath *path;
+ GtkTreeIter iter;
+ KeyEntry *ke;
+ char *str;
+ MateConfClient *conf;
+
+ 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)) {
+ gtk_tree_path_free (path);
+ return;
+ }
+ gtk_tree_path_free (path);
+
+ gtk_tree_model_get (model, &iter, KEYVAL_COLUMN, &ke, -1);
+
+ /* sanity check */
+ if (ke == NULL)
+ return;
+
+ ke->mateconf_keyval = 0;
+ ke->mateconf_mask = 0;
+ ke->needs_mateconf_sync = TRUE;
+
+ str = binding_name (0, 0);
+
+ _terminal_debug_print (TERMINAL_DEBUG_ACCELS,
+ "Cleared keybinding for mateconf %s",
+ ke->mateconf_key);
+
+ conf = mateconf_client_get_default ();
+ mateconf_client_set_string (conf,
+ ke->mateconf_key,
+ str,
+ NULL);
+ g_object_unref (conf);
+ g_free (str);
+}
+
+static void
+edit_keys_dialog_destroy_cb (GtkWidget *widget,
+ gpointer user_data)
+{
+ g_signal_handlers_disconnect_by_func (notification_group, G_CALLBACK (treeview_accel_changed_cb), user_data);
+ edit_keys_dialog = NULL;
+ edit_keys_store = NULL;
+}
+
+static void
+edit_keys_dialog_response_cb (GtkWidget *editor,
+ int response,
+ gpointer use_data)
+{
+ if (response == GTK_RESPONSE_HELP)
+ {
+ terminal_util_show_help ("mate-terminal-shortcuts", GTK_WINDOW (editor));
+ return;
+ }
+
+ gtk_widget_destroy (editor);
+}
+
+#ifdef MATE_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_edit_keys_dialog_show (GtkWindow *transient_parent)
+{
+ TerminalApp *app;
+ GtkWidget *dialog, *tree_view, *disable_mnemonics_button, *disable_menu_accel_button;
+ GtkTreeViewColumn *column;
+ GtkCellRenderer *cell_renderer;
+ GtkTreeStore *tree;
+ guint i;
+
+ if (edit_keys_dialog != NULL)
+ goto done;
+
+ if (!terminal_util_load_builder_file ("keybinding-editor.ui",
+ "keybindings-dialog", &dialog,
+ "disable-mnemonics-checkbutton", &disable_mnemonics_button,
+ "disable-menu-accel-checkbutton", &disable_menu_accel_button,
+ "accelerators-treeview", &tree_view,
+ NULL))
+ return;
+
+ app = terminal_app_get ();
+ terminal_util_bind_object_property_to_widget (G_OBJECT (app), TERMINAL_APP_ENABLE_MNEMONICS,
+ disable_mnemonics_button, 0);
+ terminal_util_bind_object_property_to_widget (G_OBJECT (app), TERMINAL_APP_ENABLE_MENU_BAR_ACCEL,
+ disable_menu_accel_button, 0);
+
+ /* 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);
+ gtk_tree_view_column_set_sort_column_id (column, ACTION_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, NULL, NULL);
+ gtk_tree_view_column_set_sort_column_id (column, KEYVAL_COLUMN);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view), column);
+
+ /* Add the data */
+
+ tree = edit_keys_store = gtk_tree_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_POINTER);
+
+#ifdef MATE_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_append (tree, &parent_iter, NULL);
+ gtk_tree_store_set (tree, &parent_iter,
+ ACTION_COLUMN, _(all_entries[i].user_visible_name),
+ -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_sortable_set_sort_func (GTK_TREE_SORTABLE (tree),
+ KEYVAL_COLUMN, accel_compare_func,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (tree), ACTION_COLUMN,
+ GTK_SORT_ASCENDING);
+
+ gtk_tree_view_set_model (GTK_TREE_VIEW (tree_view), GTK_TREE_MODEL (tree));
+ g_object_unref (tree);
+
+ gtk_tree_view_expand_all (GTK_TREE_VIEW (tree_view));
+
+ g_signal_connect (notification_group, "accel-changed",
+ G_CALLBACK (treeview_accel_changed_cb), tree);
+
+ edit_keys_dialog = dialog;
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (edit_keys_dialog_destroy_cb), tree);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (edit_keys_dialog_response_cb),
+ NULL);
+ gtk_window_set_default_size (GTK_WINDOW (dialog), -1, 350);
+
+done:
+ gtk_window_set_transient_for (GTK_WINDOW (edit_keys_dialog), transient_parent);
+ gtk_window_present (GTK_WINDOW (edit_keys_dialog));
+}
diff --git a/src/terminal-accels.h b/src/terminal-accels.h
new file mode 100644
index 0000000..ee2cc6a
--- /dev/null
+++ b/src/terminal-accels.h
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_ACCELS_H
+#define TERMINAL_ACCELS_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+void terminal_accels_init (void);
+
+void terminal_accels_shutdown (void);
+
+void terminal_edit_keys_dialog_show (GtkWindow *transient_parent);
+
+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..aa3ede7
--- /dev/null
+++ b/src/terminal-app.c
@@ -0,0 +1,2116 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2002 Sun Microsystems
+ * Copyright © 2003 Mariano Suarez-Alvarez
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+
+#include <glib.h>
+
+#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-util.h"
+#include "profile-editor.h"
+#include "terminal-encoding.h"
+#include <mateconf/mateconf-client.h>
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+
+#ifdef WITH_SMCLIENT
+#include "eggsmclient.h"
+#ifdef GDK_WINDOWING_X11
+#include "eggdesktopfile.h"
+#endif
+#endif
+
+#define FALLBACK_PROFILE_ID "Default"
+
+/* Settings storage works as follows:
+ * /apps/mate-terminal/global/
+ * /apps/mate-terminal/profiles/Foo/
+ *
+ * It's somewhat tricky to manage the profiles/ dir since we need to track
+ * the list of profiles, but mateconf doesn't have a concept of notifying that
+ * a directory has appeared or disappeared.
+ *
+ * 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 mate-terminal 1.x for why.
+ *
+ * Don't use this code as an example of how to use MateConf - it's hugely
+ * overcomplicated due to the profiles stuff. Most apps should not
+ * have to do scary things of this nature, and should not have
+ * a profiles feature.
+ *
+ */
+
+struct _TerminalAppClass {
+ GObjectClass parent_class;
+
+ void (* quit) (TerminalApp *app);
+ void (* profile_list_changed) (TerminalApp *app);
+ void (* encoding_list_changed) (TerminalApp *app);
+};
+
+struct _TerminalApp
+{
+ GObject parent_instance;
+
+ GList *windows;
+ GtkWidget *new_profile_dialog;
+ GtkWidget *manage_profiles_dialog;
+ GtkWidget *manage_profiles_list;
+ GtkWidget *manage_profiles_new_button;
+ GtkWidget *manage_profiles_edit_button;
+ GtkWidget *manage_profiles_delete_button;
+ GtkWidget *manage_profiles_default_menu;
+
+ MateConfClient *conf;
+ guint profile_list_notify_id;
+ guint default_profile_notify_id;
+ guint encoding_list_notify_id;
+ guint system_font_notify_id;
+ guint enable_mnemonics_notify_id;
+ guint enable_menu_accels_notify_id;
+
+ GHashTable *profiles;
+ char* default_profile_id;
+ TerminalProfile *default_profile;
+ gboolean default_profile_locked;
+
+ GHashTable *encodings;
+ gboolean encodings_locked;
+
+ PangoFontDescription *system_font_desc;
+ gboolean enable_mnemonics;
+ gboolean enable_menu_accels;
+};
+
+enum
+{
+ PROP_0,
+ PROP_DEFAULT_PROFILE,
+ PROP_ENABLE_MENU_BAR_ACCEL,
+ PROP_ENABLE_MNEMONICS,
+ PROP_SYSTEM_FONT,
+};
+
+enum
+{
+ QUIT,
+ PROFILE_LIST_CHANGED,
+ ENCODING_LIST_CHANGED,
+ LAST_SIGNAL
+};
+
+static guint signals[LAST_SIGNAL];
+
+enum
+{
+ COL_PROFILE,
+ NUM_COLUMNS
+};
+
+enum
+{
+ SOURCE_DEFAULT = 0,
+ SOURCE_SESSION = 1
+};
+
+static TerminalApp *global_app = NULL;
+
+/* Evil hack alert: this is exported from libmateconf-2 but not in a public header */
+extern gboolean mateconf_spawn_daemon(GError** err);
+
+#define MONOSPACE_FONT_DIR "/desktop/mate/interface"
+#define MONOSPACE_FONT_KEY MONOSPACE_FONT_DIR "/monospace_font_name"
+#define DEFAULT_MONOSPACE_FONT ("Monospace 10")
+
+#define ENABLE_MNEMONICS_KEY CONF_GLOBAL_PREFIX "/use_mnemonics"
+#define DEFAULT_ENABLE_MNEMONICS (TRUE)
+
+#define ENABLE_MENU_BAR_ACCEL_KEY CONF_GLOBAL_PREFIX"/use_menu_accelerators"
+#define DEFAULT_ENABLE_MENU_BAR_ACCEL (TRUE)
+
+#define PROFILE_LIST_KEY CONF_GLOBAL_PREFIX "/profile_list"
+#define DEFAULT_PROFILE_KEY CONF_GLOBAL_PREFIX "/default_profile"
+
+#define ENCODING_LIST_KEY CONF_GLOBAL_PREFIX "/active_encodings"
+
+/* Helper functions */
+
+static GdkScreen*
+terminal_app_get_screen_by_display_name (const char *display_name,
+ int screen_number)
+{
+ GdkDisplay *display = NULL;
+ GdkScreen *screen = NULL;
+
+ /* --screen=screen_number overrides --display */
+
+ if (display_name == NULL)
+ display = gdk_display_get_default ();
+ else
+ {
+ GSList *displays, *l;
+ const char *period;
+
+ period = strrchr (display_name, '.');
+ if (period)
+ {
+ gulong n;
+ char *end;
+
+ errno = 0;
+ end = NULL;
+ n = g_ascii_strtoull (period + 1, &end, 0);
+ if (errno == 0 && (period + 1) != end)
+ screen_number = n;
+ }
+
+ displays = gdk_display_manager_list_displays (gdk_display_manager_get ());
+ for (l = displays; l != NULL; l = l->next)
+ {
+ GdkDisplay *disp = l->data;
+
+ /* compare without the screen number part, if present */
+ if ((period && strncmp (gdk_display_get_name (disp), display_name, period - display_name) == 0) ||
+ (period == NULL && strcmp (gdk_display_get_name (disp), display_name) == 0))
+ {
+ display = disp;
+ break;
+ }
+ }
+ g_slist_free (displays);
+
+ if (display == NULL)
+ display = gdk_display_open (display_name); /* FIXME we never close displays */
+ }
+
+ if (display == NULL)
+ return NULL;
+ if (screen_number >= 0)
+ screen = gdk_display_get_screen (display, screen_number);
+ if (screen == NULL)
+ screen = gdk_display_get_default_screen (display);
+
+ return screen;
+}
+
+/* Menubar mnemonics settings handling */
+
+static int
+profiles_alphabetic_cmp (gconstpointer pa,
+ gconstpointer pb)
+{
+ TerminalProfile *a = (TerminalProfile *) pa;
+ TerminalProfile *b = (TerminalProfile *) pb;
+ int result;
+
+ result = g_utf8_collate (terminal_profile_get_property_string (a, TERMINAL_PROFILE_VISIBLE_NAME),
+ terminal_profile_get_property_string (b, TERMINAL_PROFILE_VISIBLE_NAME));
+ if (result == 0)
+ result = strcmp (terminal_profile_get_property_string (a, TERMINAL_PROFILE_NAME),
+ terminal_profile_get_property_string (b, TERMINAL_PROFILE_NAME));
+
+ return result;
+}
+
+typedef struct
+{
+ TerminalProfile *result;
+ const char *target;
+} LookupInfo;
+
+static void
+profiles_lookup_by_visible_name_foreach (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ LookupInfo *info = data;
+ const char *name;
+
+ name = terminal_profile_get_property_string (value, TERMINAL_PROFILE_VISIBLE_NAME);
+ if (name && strcmp (info->target, name) == 0)
+ info->result = value;
+}
+
+static void
+terminal_window_destroyed (TerminalWindow *window,
+ TerminalApp *app)
+{
+ app->windows = g_list_remove (app->windows, window);
+
+ if (app->windows == NULL)
+ g_signal_emit (app, signals[QUIT], 0);
+}
+
+static TerminalProfile *
+terminal_app_create_profile (TerminalApp *app,
+ const char *name)
+{
+ TerminalProfile *profile;
+
+ g_assert (terminal_app_get_profile_by_name (app, name) == NULL);
+
+ profile = _terminal_profile_new (name);
+
+ g_hash_table_insert (app->profiles,
+ g_strdup (terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME)),
+ profile /* adopts the refcount */);
+
+ if (app->default_profile == NULL &&
+ app->default_profile_id != NULL &&
+ strcmp (app->default_profile_id,
+ terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME)) == 0)
+ {
+ /* We are the default profile */
+ app->default_profile = profile;
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_DEFAULT_PROFILE);
+ }
+
+ return profile;
+}
+
+static void
+terminal_app_delete_profile (TerminalApp *app,
+ TerminalProfile *profile)
+{
+ GHashTableIter iter;
+ GSList *name_list;
+ const char *name, *profile_name;
+ char *mateconf_dir;
+ GError *error = NULL;
+ const char **nameptr = &name;
+
+ profile_name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME);
+ mateconf_dir = mateconf_concat_dir_and_key (CONF_PREFIX "/profiles", profile_name);
+
+ name_list = NULL;
+ g_hash_table_iter_init (&iter, app->profiles);
+ while (g_hash_table_iter_next (&iter, (gpointer *) nameptr, NULL))
+ {
+ if (strcmp (name, profile_name) == 0)
+ continue;
+
+ name_list = g_slist_prepend (name_list, g_strdup (name));
+ }
+
+ mateconf_client_set_list (app->conf,
+ CONF_GLOBAL_PREFIX"/profile_list",
+ MATECONF_VALUE_STRING,
+ name_list,
+ NULL);
+
+ g_slist_foreach (name_list, (GFunc) g_free, NULL);
+ g_slist_free (name_list);
+
+ /* And remove the profile directory */
+ if (!mateconf_client_recursive_unset (app->conf, mateconf_dir, MATECONF_UNSET_INCLUDING_SCHEMA_NAMES, &error))
+ {
+ g_warning ("Failed to recursively unset %s: %s\n", mateconf_dir, error->message);
+ g_error_free (error);
+ }
+
+ g_free (mateconf_dir);
+}
+
+static void
+terminal_app_profile_cell_data_func (GtkTreeViewColumn *tree_column,
+ GtkCellRenderer *cell,
+ GtkTreeModel *tree_model,
+ GtkTreeIter *iter,
+ gpointer data)
+{
+ TerminalProfile *profile;
+ GValue value = { 0, };
+
+ gtk_tree_model_get (tree_model, iter, (int) COL_PROFILE, &profile, (int) -1);
+
+ g_value_init (&value, G_TYPE_STRING);
+ g_object_get_property (G_OBJECT (profile), "visible-name", &value);
+ g_object_set_property (G_OBJECT (cell), "text", &value);
+ g_value_unset (&value);
+}
+
+static int
+terminal_app_profile_sort_func (GtkTreeModel *model,
+ GtkTreeIter *a,
+ GtkTreeIter *b,
+ gpointer user_data)
+{
+ TerminalProfile *profile_a, *profile_b;
+ int retval;
+
+ gtk_tree_model_get (model, a, (int) COL_PROFILE, &profile_a, (int) -1);
+ gtk_tree_model_get (model, b, (int) COL_PROFILE, &profile_b, (int) -1);
+
+ retval = profiles_alphabetic_cmp (profile_a, profile_b);
+
+ g_object_unref (profile_a);
+ g_object_unref (profile_b);
+
+ return retval;
+}
+
+static /* ref */ GtkTreeModel *
+terminal_app_get_profile_liststore (TerminalApp *app,
+ TerminalProfile *selected_profile,
+ GtkTreeIter *selected_profile_iter,
+ gboolean *selected_profile_iter_set)
+{
+ GtkListStore *store;
+ GtkTreeIter iter;
+ GList *profiles, *l;
+ TerminalProfile *default_profile;
+
+ store = gtk_list_store_new (NUM_COLUMNS, TERMINAL_TYPE_PROFILE);
+
+ *selected_profile_iter_set = FALSE;
+
+ if (selected_profile &&
+ _terminal_profile_get_forgotten (selected_profile))
+ selected_profile = NULL;
+
+ profiles = terminal_app_get_profile_list (app);
+ default_profile = terminal_app_get_default_profile (app);
+
+ for (l = profiles; l != NULL; l = l->next)
+ {
+ TerminalProfile *profile = TERMINAL_PROFILE (l->data);
+
+ gtk_list_store_insert_with_values (store, &iter, 0,
+ (int) COL_PROFILE, profile,
+ (int) -1);
+
+ if (selected_profile_iter && profile == selected_profile)
+ {
+ *selected_profile_iter = iter;
+ *selected_profile_iter_set = TRUE;
+ }
+ }
+ g_list_free (profiles);
+
+ /* Now turn on sorting */
+ gtk_tree_sortable_set_sort_func (GTK_TREE_SORTABLE (store),
+ COL_PROFILE,
+ terminal_app_profile_sort_func,
+ NULL, NULL);
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (store),
+ COL_PROFILE, GTK_SORT_ASCENDING);
+
+ return GTK_TREE_MODEL (store);
+}
+
+static /* ref */ TerminalProfile*
+profile_combo_box_get_selected (GtkWidget *widget)
+{
+ GtkComboBox *combo = GTK_COMBO_BOX (widget);
+ TerminalProfile *profile = NULL;
+ GtkTreeIter iter;
+
+ if (gtk_combo_box_get_active_iter (combo, &iter))
+ gtk_tree_model_get (gtk_combo_box_get_model (combo), &iter,
+ (int) COL_PROFILE, &profile, (int) -1);
+
+ return profile;
+}
+
+static void
+profile_combo_box_refill (TerminalApp *app,
+ GtkWidget *widget)
+{
+ GtkComboBox *combo = GTK_COMBO_BOX (widget);
+ GtkTreeIter iter;
+ gboolean iter_set;
+ TerminalProfile *selected_profile;
+ GtkTreeModel *model;
+
+ selected_profile = profile_combo_box_get_selected (widget);
+ if (!selected_profile)
+ {
+ selected_profile = terminal_app_get_default_profile (app);
+ if (selected_profile)
+ g_object_ref (selected_profile);
+ }
+
+ model = terminal_app_get_profile_liststore (app,
+ selected_profile,
+ &iter,
+ &iter_set);
+ gtk_combo_box_set_model (combo, model);
+ g_object_unref (model);
+
+ if (iter_set)
+ gtk_combo_box_set_active_iter (combo, &iter);
+
+ if (selected_profile)
+ g_object_unref (selected_profile);
+}
+
+static GtkWidget*
+profile_combo_box_new (TerminalApp *app)
+{
+ GtkWidget *combo;
+ GtkCellRenderer *renderer;
+
+ combo = gtk_combo_box_new ();
+ terminal_util_set_atk_name_description (combo, NULL, _("Click button to choose profile"));
+
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (combo), renderer, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (combo), renderer,
+ (GtkCellLayoutDataFunc) terminal_app_profile_cell_data_func,
+ NULL, NULL);
+
+ profile_combo_box_refill (app, combo);
+ g_signal_connect (app, "profile-list-changed",
+ G_CALLBACK (profile_combo_box_refill), combo);
+
+ gtk_widget_show (combo);
+ return combo;
+}
+
+static void
+profile_combo_box_changed_cb (GtkWidget *widget,
+ TerminalApp *app)
+{
+ TerminalProfile *profile;
+
+ profile = profile_combo_box_get_selected (widget);
+ if (!profile)
+ return;
+
+ mateconf_client_set_string (app->conf,
+ CONF_GLOBAL_PREFIX "/default_profile",
+ terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME),
+ NULL);
+
+ /* Even though the mateconf change notification does this, it happens too late.
+ * In some cases, the default profile changes twice in quick succession,
+ * and update_default_profile must be called in sync with those changes.
+ */
+ app->default_profile = profile;
+
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_DEFAULT_PROFILE);
+
+ g_object_unref (profile);
+}
+
+static void
+profile_list_treeview_refill (TerminalApp *app,
+ GtkWidget *widget)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GtkTreeIter iter;
+ gboolean iter_set;
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ TerminalProfile *selected_profile = NULL;
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ selection = gtk_tree_view_get_selection (tree_view);
+ if (gtk_tree_selection_get_selected (selection, NULL, &iter))
+ gtk_tree_model_get (model, &iter, (int) COL_PROFILE, &selected_profile, (int) -1);
+
+ model = terminal_app_get_profile_liststore (terminal_app_get (),
+ selected_profile,
+ &iter,
+ &iter_set);
+ gtk_tree_view_set_model (tree_view, model);
+ g_object_unref (model);
+
+ if (!iter_set)
+ iter_set = gtk_tree_model_get_iter_first (model, &iter);
+
+ if (iter_set)
+ gtk_tree_selection_select_iter (selection, &iter);
+
+ if (selected_profile)
+ g_object_unref (selected_profile);
+}
+
+static GtkWidget*
+profile_list_treeview_create (TerminalApp *app)
+{
+ GtkWidget *tree_view;
+ GtkTreeSelection *selection;
+ GtkCellRenderer *renderer;
+ GtkTreeViewColumn *column;
+
+ tree_view = gtk_tree_view_new ();
+ terminal_util_set_atk_name_description (tree_view, _("Profile list"), NULL);
+ gtk_tree_view_set_headers_visible (GTK_TREE_VIEW (tree_view), FALSE);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (tree_view));
+ gtk_tree_selection_set_mode (GTK_TREE_SELECTION (selection),
+ GTK_SELECTION_BROWSE);
+
+ column = gtk_tree_view_column_new ();
+ renderer = gtk_cell_renderer_text_new ();
+ gtk_cell_layout_pack_start (GTK_CELL_LAYOUT (column), renderer, TRUE);
+ gtk_cell_layout_set_cell_data_func (GTK_CELL_LAYOUT (column), renderer,
+ (GtkCellLayoutDataFunc) terminal_app_profile_cell_data_func,
+ NULL, NULL);
+ gtk_tree_view_append_column (GTK_TREE_VIEW (tree_view),
+ GTK_TREE_VIEW_COLUMN (column));
+
+ return tree_view;
+}
+
+static void
+profile_list_delete_confirm_response_cb (GtkWidget *dialog,
+ int response,
+ TerminalApp *app)
+{
+ TerminalProfile *profile;
+
+ profile = TERMINAL_PROFILE (g_object_get_data (G_OBJECT (dialog), "profile"));
+ g_assert (profile != NULL);
+
+ if (response == GTK_RESPONSE_ACCEPT)
+ terminal_app_delete_profile (app, profile);
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+profile_list_delete_button_clicked_cb (GtkWidget *button,
+ GtkWidget *widget)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ TerminalApp *app = terminal_app_get ();
+ GtkTreeSelection *selection;
+ GtkWidget *dialog;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ TerminalProfile *selected_profile;
+ GtkWidget *transient_parent;
+
+ model = gtk_tree_view_get_model (tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, (int) COL_PROFILE, &selected_profile, (int) -1);
+
+ transient_parent = gtk_widget_get_toplevel (widget);
+ dialog = gtk_message_dialog_new (GTK_WINDOW (transient_parent),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_NONE,
+ _("Delete profile “%s”?"),
+ terminal_profile_get_property_string (selected_profile, TERMINAL_PROFILE_VISIBLE_NAME));
+
+ gtk_dialog_add_buttons (GTK_DIALOG (dialog),
+ GTK_STOCK_CANCEL,
+ GTK_RESPONSE_REJECT,
+ GTK_STOCK_DELETE,
+ GTK_RESPONSE_ACCEPT,
+ NULL);
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_REJECT,
+ -1);
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT);
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Delete Profile"));
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+
+ /* Transfer refcount of |selected_profile|, so no unref below */
+ g_object_set_data_full (G_OBJECT (dialog), "profile", selected_profile, g_object_unref);
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (profile_list_delete_confirm_response_cb),
+ app);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+profile_list_new_button_clicked_cb (GtkWidget *button,
+ gpointer data)
+{
+ TerminalApp *app;
+
+ app = terminal_app_get ();
+ terminal_app_new_profile (app, NULL, GTK_WINDOW (app->manage_profiles_dialog));
+}
+
+static void
+profile_list_edit_button_clicked_cb (GtkWidget *button,
+ GtkWidget *widget)
+{
+ GtkTreeView *tree_view = GTK_TREE_VIEW (widget);
+ GtkTreeSelection *selection;
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ TerminalProfile *selected_profile;
+ TerminalApp *app;
+
+ app = terminal_app_get ();
+
+ model = gtk_tree_view_get_model (tree_view);
+ selection = gtk_tree_view_get_selection (tree_view);
+
+ if (!gtk_tree_selection_get_selected (selection, NULL, &iter))
+ return;
+
+ gtk_tree_model_get (model, &iter, (int) COL_PROFILE, &selected_profile, (int) -1);
+
+ terminal_app_edit_profile (app, selected_profile,
+ GTK_WINDOW (app->manage_profiles_dialog),
+ NULL);
+ g_object_unref (selected_profile);
+}
+
+static void
+profile_list_row_activated_cb (GtkTreeView *tree_view,
+ GtkTreePath *path,
+ GtkTreeViewColumn *column,
+ gpointer data)
+{
+ GtkTreeIter iter;
+ GtkTreeModel *model;
+ TerminalProfile *selected_profile;
+ TerminalApp *app;
+
+ app = terminal_app_get ();
+
+ model = gtk_tree_view_get_model (tree_view);
+
+ if (!gtk_tree_model_get_iter (model, &iter, path))
+ return;
+
+ gtk_tree_model_get (model, &iter, (int) COL_PROFILE, &selected_profile, (int) -1);
+
+ terminal_app_edit_profile (app, selected_profile,
+ GTK_WINDOW (app->manage_profiles_dialog),
+ NULL);
+ g_object_unref (selected_profile);
+}
+
+static GList*
+find_profile_link (GList *profiles,
+ const char *name)
+{
+ GList *l;
+
+ for (l = profiles; l != NULL; l = l->next)
+ {
+ const char *profile_name;
+
+ profile_name = terminal_profile_get_property_string (TERMINAL_PROFILE (l->data), TERMINAL_PROFILE_NAME);
+ if (profile_name && strcmp (profile_name, name) == 0)
+ break;
+ }
+
+ return l;
+}
+
+static void
+terminal_app_profile_list_notify_cb (MateConfClient *conf,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ GObject *object = G_OBJECT (app);
+ MateConfValue *val;
+ GSList *value_list, *sl;
+ GList *profiles_to_delete, *l;
+ gboolean need_new_default;
+ TerminalProfile *fallback;
+ guint count;
+
+ g_object_freeze_notify (object);
+
+ profiles_to_delete = terminal_app_get_profile_list (app);
+
+ val = mateconf_entry_get_value (entry);
+ if (val == NULL ||
+ val->type != MATECONF_VALUE_LIST ||
+ mateconf_value_get_list_type (val) != MATECONF_VALUE_STRING)
+ goto ensure_one_profile;
+
+ value_list = mateconf_value_get_list (val);
+
+ /* Add any new ones */
+ for (sl = value_list; sl != NULL; sl = sl->next)
+ {
+ MateConfValue *listvalue = (MateConfValue *) (sl->data);
+ const char *profile_name;
+ GList *link;
+
+ profile_name = mateconf_value_get_string (listvalue);
+ if (!profile_name)
+ continue;
+
+ link = find_profile_link (profiles_to_delete, profile_name);
+ if (link)
+ /* make profiles_to_delete point to profiles we didn't find in the list */
+ profiles_to_delete = g_list_delete_link (profiles_to_delete, link);
+ else
+ terminal_app_create_profile (app, profile_name);
+ }
+
+ensure_one_profile:
+
+ fallback = NULL;
+ count = g_hash_table_size (app->profiles);
+ if (count == 0 || count <= g_list_length (profiles_to_delete))
+ {
+ /* We are going to run out, so create the fallback
+ * to be sure we always have one. Must be done
+ * here before we emit "forgotten" signals so that
+ * screens have a profile to fall back to.
+ *
+ * If the profile with the FALLBACK_ID already exists,
+ * we aren't allowed to delete it, unless at least one
+ * other profile will still exist. And if you delete
+ * all profiles, the FALLBACK_ID profile returns as
+ * the living dead.
+ */
+ fallback = terminal_app_get_profile_by_name (app, FALLBACK_PROFILE_ID);
+ if (fallback == NULL)
+ fallback = terminal_app_create_profile (app, FALLBACK_PROFILE_ID);
+ g_assert (fallback != NULL);
+ }
+
+ /* Forget no-longer-existing profiles */
+ need_new_default = FALSE;
+ for (l = profiles_to_delete; l != NULL; l = l->next)
+ {
+ TerminalProfile *profile = TERMINAL_PROFILE (l->data);
+ const char *name;
+
+ name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME);
+ if (strcmp (name, FALLBACK_PROFILE_ID) == 0)
+ continue;
+
+ if (profile == app->default_profile)
+ {
+ app->default_profile = NULL;
+ need_new_default = TRUE;
+ }
+
+ _terminal_profile_forget (profile);
+ g_hash_table_remove (app->profiles, name);
+
+ /* |profile| possibly isn't dead yet since the profiles dialogue's tree model holds a ref too... */
+ }
+ g_list_free (profiles_to_delete);
+
+ if (need_new_default)
+ {
+ TerminalProfile *new_default;
+ TerminalProfile **new_default_ptr = &new_default;
+
+ new_default = terminal_app_get_profile_by_name (app, FALLBACK_PROFILE_ID);
+ if (new_default == NULL)
+ {
+ GHashTableIter iter;
+
+ g_hash_table_iter_init (&iter, app->profiles);
+ if (!g_hash_table_iter_next (&iter, NULL, (gpointer *) new_default_ptr))
+ /* shouldn't really happen ever, but just to be safe */
+ new_default = terminal_app_create_profile (app, FALLBACK_PROFILE_ID);
+ }
+ g_assert (new_default != NULL);
+
+ app->default_profile = new_default;
+
+ g_object_notify (object, TERMINAL_APP_DEFAULT_PROFILE);
+ }
+
+ g_assert (g_hash_table_size (app->profiles) > 0);
+
+ g_signal_emit (app, signals[PROFILE_LIST_CHANGED], 0);
+
+ g_object_thaw_notify (object);
+}
+
+static void
+terminal_app_default_profile_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ MateConfValue *val;
+ const char *name = NULL;
+
+ app->default_profile_locked = !mateconf_entry_get_is_writable (entry);
+
+ val = mateconf_entry_get_value (entry);
+ if (val != NULL &&
+ val->type == MATECONF_VALUE_STRING)
+ name = mateconf_value_get_string (val);
+ if (!name || !name[0])
+ name = FALLBACK_PROFILE_ID;
+ g_assert (name != NULL);
+
+ g_free (app->default_profile_id);
+ app->default_profile_id = g_strdup (name);
+
+ app->default_profile = terminal_app_get_profile_by_name (app, name);
+
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_DEFAULT_PROFILE);
+}
+
+static int
+compare_encodings (TerminalEncoding *a,
+ TerminalEncoding *b)
+{
+ return g_utf8_collate (a->name, b->name);
+}
+
+static void
+encoding_mark_active (gpointer key,
+ gpointer value,
+ gpointer data)
+{
+ TerminalEncoding *encoding = (TerminalEncoding *) value;
+ guint active = GPOINTER_TO_UINT (data);
+
+ encoding->is_active = active;
+}
+
+static void
+terminal_app_encoding_list_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ MateConfValue *val;
+ GSList *strings, *tmp;
+ TerminalEncoding *encoding;
+ const char *charset;
+
+ app->encodings_locked = !mateconf_entry_get_is_writable (entry);
+
+ /* Mark all as non-active, then re-enable the active ones */
+ g_hash_table_foreach (app->encodings, (GHFunc) encoding_mark_active, GUINT_TO_POINTER (FALSE));
+
+ /* First add the locale's charset */
+ encoding = g_hash_table_lookup (app->encodings, "current");
+ g_assert (encoding);
+ if (terminal_encoding_is_valid (encoding))
+ encoding->is_active = TRUE;
+
+ /* Also always make UTF-8 available */
+ encoding = g_hash_table_lookup (app->encodings, "UTF-8");
+ g_assert (encoding);
+ if (terminal_encoding_is_valid (encoding))
+ encoding->is_active = TRUE;
+
+ val = mateconf_entry_get_value (entry);
+ if (val != NULL &&
+ val->type == MATECONF_VALUE_LIST &&
+ mateconf_value_get_list_type (val) == MATECONF_VALUE_STRING)
+ strings = mateconf_value_get_list (val);
+ else
+ strings = NULL;
+
+ for (tmp = strings; tmp != NULL; tmp = tmp->next)
+ {
+ MateConfValue *v = (MateConfValue *) tmp->data;
+
+ charset = mateconf_value_get_string (v);
+ if (!charset)
+ continue;
+
+ encoding = terminal_app_ensure_encoding (app, charset);
+ if (!terminal_encoding_is_valid (encoding))
+ continue;
+
+ encoding->is_active = TRUE;
+ }
+
+ g_signal_emit (app, signals[ENCODING_LIST_CHANGED], 0);
+}
+
+static void
+terminal_app_system_font_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ MateConfValue *mateconf_value;
+ const char *font = NULL;
+ PangoFontDescription *font_desc;
+
+ if (strcmp (mateconf_entry_get_key (entry), MONOSPACE_FONT_KEY) != 0)
+ return;
+
+ mateconf_value = mateconf_entry_get_value (entry);
+ if (mateconf_value &&
+ mateconf_value->type == MATECONF_VALUE_STRING)
+ font = mateconf_value_get_string (mateconf_value);
+ if (!font)
+ font = DEFAULT_MONOSPACE_FONT;
+ g_assert (font != NULL);
+
+ font_desc = pango_font_description_from_string (font);
+ if (app->system_font_desc &&
+ pango_font_description_equal (app->system_font_desc, font_desc))
+ {
+ pango_font_description_free (font_desc);
+ return;
+ }
+
+ if (app->system_font_desc)
+ pango_font_description_free (app->system_font_desc);
+
+ app->system_font_desc = font_desc;
+
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_SYSTEM_FONT);
+}
+
+static void
+terminal_app_enable_mnemonics_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ MateConfValue *mateconf_value;
+ gboolean enable;
+
+ if (strcmp (mateconf_entry_get_key (entry), ENABLE_MNEMONICS_KEY) != 0)
+ return;
+
+ mateconf_value = mateconf_entry_get_value (entry);
+ if (mateconf_value &&
+ mateconf_value->type == MATECONF_VALUE_BOOL)
+ enable = mateconf_value_get_bool (mateconf_value);
+ else
+ enable = TRUE;
+
+ if (enable == app->enable_mnemonics)
+ return;
+
+ app->enable_mnemonics = enable;
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_ENABLE_MNEMONICS);
+}
+
+static void
+terminal_app_enable_menu_accels_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalApp *app = TERMINAL_APP (user_data);
+ MateConfValue *mateconf_value;
+ gboolean enable;
+
+ if (strcmp (mateconf_entry_get_key (entry), ENABLE_MENU_BAR_ACCEL_KEY) != 0)
+ return;
+
+ mateconf_value = mateconf_entry_get_value (entry);
+ if (mateconf_value &&
+ mateconf_value->type == MATECONF_VALUE_BOOL)
+ enable = mateconf_value_get_bool (mateconf_value);
+ else
+ enable = TRUE;
+
+ if (enable == app->enable_menu_accels)
+ return;
+
+ app->enable_menu_accels = enable;
+ g_object_notify (G_OBJECT (app), TERMINAL_APP_ENABLE_MENU_BAR_ACCEL);
+}
+
+static void
+new_profile_response_cb (GtkWidget *new_profile_dialog,
+ int response_id,
+ TerminalApp *app)
+{
+ if (response_id == GTK_RESPONSE_ACCEPT)
+ {
+ GtkWidget *name_entry;
+ char *name;
+ const char *new_profile_name;
+ GtkWidget *base_option_menu;
+ TerminalProfile *base_profile = NULL;
+ TerminalProfile *new_profile;
+ GList *profiles;
+ GList *tmp;
+ GtkWindow *transient_parent;
+ GtkWidget *confirm_dialog;
+ gint retval;
+ GSList *list;
+
+ base_option_menu = g_object_get_data (G_OBJECT (new_profile_dialog), "base_option_menu");
+ base_profile = profile_combo_box_get_selected (base_option_menu);
+ if (!base_profile)
+ base_profile = terminal_app_get_default_profile (app);
+ if (!base_profile)
+ return; /* shouldn't happen ever though */
+
+ name_entry = g_object_get_data (G_OBJECT (new_profile_dialog), "name_entry");
+ name = gtk_editable_get_chars (GTK_EDITABLE (name_entry), 0, -1);
+ g_strstrip (name); /* name will be non empty after stripping */
+
+ profiles = terminal_app_get_profile_list (app);
+ for (tmp = profiles; tmp != NULL; tmp = tmp->next)
+ {
+ TerminalProfile *profile = tmp->data;
+ const char *visible_name;
+
+ visible_name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_VISIBLE_NAME);
+
+ if (visible_name && strcmp (name, visible_name) == 0)
+ break;
+ }
+ if (tmp)
+ {
+ confirm_dialog = gtk_message_dialog_new (GTK_WINDOW (new_profile_dialog),
+ GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_QUESTION,
+ GTK_BUTTONS_YES_NO,
+ _("You already have a profile called “%s”. Do you want to create another profile with the same name?"), name);
+ /* Alternative button order was set automatically by GtkMessageDialog */
+ retval = gtk_dialog_run (GTK_DIALOG (confirm_dialog));
+ gtk_widget_destroy (confirm_dialog);
+ if (retval == GTK_RESPONSE_NO)
+ goto cleanup;
+ }
+ g_list_free (profiles);
+
+ transient_parent = gtk_window_get_transient_for (GTK_WINDOW (new_profile_dialog));
+
+ new_profile = _terminal_profile_clone (base_profile, name);
+ new_profile_name = terminal_profile_get_property_string (new_profile, TERMINAL_PROFILE_NAME);
+ g_hash_table_insert (app->profiles,
+ g_strdup (new_profile_name),
+ new_profile /* adopts the refcount */);
+
+ /* And now save the list to mateconf */
+ list = mateconf_client_get_list (app->conf,
+ CONF_GLOBAL_PREFIX"/profile_list",
+ MATECONF_VALUE_STRING,
+ NULL);
+ list = g_slist_append (list, g_strdup (new_profile_name));
+ mateconf_client_set_list (app->conf,
+ CONF_GLOBAL_PREFIX"/profile_list",
+ MATECONF_VALUE_STRING,
+ list,
+ NULL);
+
+ terminal_profile_edit (new_profile, transient_parent, NULL);
+
+ cleanup:
+ g_free (name);
+ }
+
+ gtk_widget_destroy (new_profile_dialog);
+}
+
+static void
+new_profile_dialog_destroy_cb (GtkWidget *new_profile_dialog,
+ TerminalApp *app)
+{
+ GtkWidget *combo;
+
+ combo = g_object_get_data (G_OBJECT (new_profile_dialog), "base_option_menu");
+ g_signal_handlers_disconnect_by_func (app, G_CALLBACK (profile_combo_box_refill), combo);
+
+ app->new_profile_dialog = NULL;
+}
+
+static void
+new_profile_name_entry_changed_cb (GtkEntry *entry,
+ GtkDialog *dialog)
+{
+ const char *name;
+
+ name = gtk_entry_get_text (entry);
+
+ /* make the create button sensitive only if something other than space has been set */
+ while (*name != '\0' && g_ascii_isspace (*name))
+ ++name;
+
+ gtk_dialog_set_response_sensitive (dialog, GTK_RESPONSE_ACCEPT, name[0] != '\0');
+}
+
+void
+terminal_app_new_profile (TerminalApp *app,
+ TerminalProfile *default_base_profile,
+ GtkWindow *transient_parent)
+{
+ if (app->new_profile_dialog == NULL)
+ {
+ GtkWidget *create_button, *table, *name_label, *name_entry, *base_label, *combo;
+
+ if (!terminal_util_load_builder_file ("profile-new-dialog.ui",
+ "new-profile-dialog", &app->new_profile_dialog,
+ "new-profile-create-button", &create_button,
+ "new-profile-table", &table,
+ "new-profile-name-label", &name_label,
+ "new-profile-name-entry", &name_entry,
+ "new-profile-base-label", &base_label,
+ NULL))
+ return;
+
+ g_signal_connect (G_OBJECT (app->new_profile_dialog), "response", G_CALLBACK (new_profile_response_cb), app);
+ g_signal_connect (app->new_profile_dialog, "destroy", G_CALLBACK (new_profile_dialog_destroy_cb), app);
+
+ g_object_set_data (G_OBJECT (app->new_profile_dialog), "create_button", create_button);
+ gtk_widget_set_sensitive (create_button, FALSE);
+
+ /* the name entry */
+ g_object_set_data (G_OBJECT (app->new_profile_dialog), "name_entry", name_entry);
+ g_signal_connect (name_entry, "changed", G_CALLBACK (new_profile_name_entry_changed_cb), app->new_profile_dialog);
+ gtk_entry_set_activates_default (GTK_ENTRY (name_entry), TRUE);
+ gtk_widget_grab_focus (name_entry);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (name_label), name_entry);
+
+ /* the base profile option menu */
+ combo = profile_combo_box_new (app);
+ gtk_table_attach_defaults (GTK_TABLE (table), combo, 1, 2, 1, 2);
+ g_object_set_data (G_OBJECT (app->new_profile_dialog), "base_option_menu", combo);
+ terminal_util_set_atk_name_description (combo, NULL, _("Choose base profile"));
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (base_label), combo);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (app->new_profile_dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_CANCEL,
+ -1);
+ gtk_dialog_set_default_response (GTK_DIALOG (app->new_profile_dialog), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (app->new_profile_dialog), GTK_RESPONSE_ACCEPT, FALSE);
+ }
+
+ gtk_window_set_transient_for (GTK_WINDOW (app->new_profile_dialog),
+ transient_parent);
+
+ gtk_window_present (GTK_WINDOW (app->new_profile_dialog));
+}
+
+static void
+profile_list_selection_changed_cb (GtkTreeSelection *selection,
+ TerminalApp *app)
+{
+ gboolean selected;
+
+ selected = gtk_tree_selection_get_selected (selection, NULL, NULL);
+
+ gtk_widget_set_sensitive (app->manage_profiles_edit_button, selected);
+ gtk_widget_set_sensitive (app->manage_profiles_delete_button,
+ selected &&
+ g_hash_table_size (app->profiles) > 1);
+}
+
+static void
+profile_list_response_cb (GtkWidget *dialog,
+ int id,
+ TerminalApp *app)
+{
+ g_assert (app->manage_profiles_dialog == dialog);
+
+ if (id == GTK_RESPONSE_HELP)
+ {
+ terminal_util_show_help ("mate-terminal-manage-profiles", GTK_WINDOW (dialog));
+ return;
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+profile_list_destroyed_cb (GtkWidget *manage_profiles_dialog,
+ TerminalApp *app)
+{
+ g_signal_handlers_disconnect_by_func (app, G_CALLBACK (profile_list_treeview_refill), app->manage_profiles_list);
+ g_signal_handlers_disconnect_by_func (app, G_CALLBACK (profile_combo_box_refill), app->manage_profiles_default_menu);
+
+ app->manage_profiles_dialog = NULL;
+ app->manage_profiles_list = NULL;
+ app->manage_profiles_new_button = NULL;
+ app->manage_profiles_edit_button = NULL;
+ app->manage_profiles_delete_button = NULL;
+ app->manage_profiles_default_menu = NULL;
+}
+
+void
+terminal_app_manage_profiles (TerminalApp *app,
+ GtkWindow *transient_parent)
+{
+ GObject *dialog;
+ GObject *tree_view_container, *new_button, *edit_button, *remove_button;
+ GObject *default_hbox, *default_label;
+ GtkTreeSelection *selection;
+
+ if (app->manage_profiles_dialog)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (app->manage_profiles_dialog), transient_parent);
+ gtk_window_present (GTK_WINDOW (app->manage_profiles_dialog));
+ return;
+ }
+
+ if (!terminal_util_load_builder_file ("profile-manager.ui",
+ "profile-manager", &dialog,
+ "profiles-treeview-container", &tree_view_container,
+ "new-profile-button", &new_button,
+ "edit-profile-button", &edit_button,
+ "delete-profile-button", &remove_button,
+ "default-profile-hbox", &default_hbox,
+ "default-profile-label", &default_label,
+ NULL))
+ return;
+
+ app->manage_profiles_dialog = GTK_WIDGET (dialog);
+ app->manage_profiles_new_button = GTK_WIDGET (new_button);
+ app->manage_profiles_edit_button = GTK_WIDGET (edit_button);
+ app->manage_profiles_delete_button = GTK_WIDGET (remove_button);
+
+ g_signal_connect (dialog, "response", G_CALLBACK (profile_list_response_cb), app);
+ g_signal_connect (dialog, "destroy", G_CALLBACK (profile_list_destroyed_cb), app);
+
+ app->manage_profiles_list = profile_list_treeview_create (app);
+
+ selection = gtk_tree_view_get_selection (GTK_TREE_VIEW (app->manage_profiles_list));
+ g_signal_connect (selection, "changed", G_CALLBACK (profile_list_selection_changed_cb), app);
+
+ profile_list_treeview_refill (app, app->manage_profiles_list);
+ g_signal_connect (app, "profile-list-changed",
+ G_CALLBACK (profile_list_treeview_refill), app->manage_profiles_list);
+
+ g_signal_connect (app->manage_profiles_list, "row-activated",
+ G_CALLBACK (profile_list_row_activated_cb), app);
+
+ gtk_container_add (GTK_CONTAINER (tree_view_container), app->manage_profiles_list);
+ gtk_widget_show (app->manage_profiles_list);
+
+ g_signal_connect (new_button, "clicked",
+ G_CALLBACK (profile_list_new_button_clicked_cb),
+ app->manage_profiles_list);
+ g_signal_connect (edit_button, "clicked",
+ G_CALLBACK (profile_list_edit_button_clicked_cb),
+ app->manage_profiles_list);
+ g_signal_connect (remove_button, "clicked",
+ G_CALLBACK (profile_list_delete_button_clicked_cb),
+ app->manage_profiles_list);
+
+ app->manage_profiles_default_menu = profile_combo_box_new (app);
+ g_signal_connect (app->manage_profiles_default_menu, "changed",
+ G_CALLBACK (profile_combo_box_changed_cb), app);
+
+ gtk_box_pack_start (GTK_BOX (default_hbox), app->manage_profiles_default_menu, FALSE, FALSE, 0);
+ gtk_widget_show (app->manage_profiles_default_menu);
+
+ gtk_label_set_mnemonic_widget (GTK_LABEL (default_label), app->manage_profiles_default_menu);
+
+ gtk_widget_grab_focus (app->manage_profiles_list);
+
+ gtk_window_set_transient_for (GTK_WINDOW (app->manage_profiles_dialog),
+ transient_parent);
+
+ gtk_window_present (GTK_WINDOW (app->manage_profiles_dialog));
+}
+
+#ifdef WITH_SMCLIENT
+
+static void
+terminal_app_save_state_cb (EggSMClient *client,
+ GKeyFile *key_file,
+ TerminalApp *app)
+{
+ terminal_app_save_config (app, key_file);
+}
+
+static void
+terminal_app_client_quit_cb (EggSMClient *client,
+ TerminalApp *app)
+{
+ g_signal_emit (app, signals[QUIT], 0);
+}
+
+#endif /* WITH_SMCLIENT */
+
+/* Class implementation */
+
+G_DEFINE_TYPE (TerminalApp, terminal_app, G_TYPE_OBJECT)
+
+static void
+terminal_app_init (TerminalApp *app)
+{
+ GError *error = NULL;
+
+ global_app = app;
+
+ /* If the mateconf daemon isn't available (e.g. because there's no dbus
+ * session bus running), we'd crash later on. Tell the user about it
+ * now, and exit. See bug #561663.
+ * Don't use mateconf_ping_daemon() here since the server may just not
+ * be running yet, but able to be started. See comments on bug #564649.
+ */
+ if (!mateconf_spawn_daemon (&error))
+ {
+ g_printerr ("Failed to summon the MateConf demon; exiting. %s\n", error->message);
+ g_error_free (error);
+
+ exit (EXIT_FAILURE);
+ }
+
+ gtk_window_set_default_icon_name (MATE_TERMINAL_ICON_NAME);
+
+ /* Initialise defaults */
+ app->enable_mnemonics = DEFAULT_ENABLE_MNEMONICS;
+ app->enable_menu_accels = DEFAULT_ENABLE_MENU_BAR_ACCEL;
+
+ app->profiles = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_object_unref);
+
+ app->encodings = terminal_encodings_get_builtins ();
+
+ app->conf = mateconf_client_get_default ();
+
+ mateconf_client_add_dir (app->conf, CONF_GLOBAL_PREFIX,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ mateconf_client_add_dir (app->conf, MONOSPACE_FONT_DIR,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ mateconf_client_add_dir (app->conf, CONF_PROXY_PREFIX,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ mateconf_client_add_dir (app->conf, CONF_HTTP_PROXY_PREFIX,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+
+ app->profile_list_notify_id =
+ mateconf_client_notify_add (app->conf, PROFILE_LIST_KEY,
+ terminal_app_profile_list_notify_cb,
+ app, NULL, NULL);
+
+ app->default_profile_notify_id =
+ mateconf_client_notify_add (app->conf,
+ DEFAULT_PROFILE_KEY,
+ terminal_app_default_profile_notify_cb,
+ app, NULL, NULL);
+
+ app->encoding_list_notify_id =
+ mateconf_client_notify_add (app->conf,
+ ENCODING_LIST_KEY,
+ terminal_app_encoding_list_notify_cb,
+ app, NULL, NULL);
+
+ app->system_font_notify_id =
+ mateconf_client_notify_add (app->conf,
+ MONOSPACE_FONT_KEY,
+ terminal_app_system_font_notify_cb,
+ app, NULL, NULL);
+
+ app->enable_mnemonics_notify_id =
+ mateconf_client_notify_add (app->conf,
+ ENABLE_MNEMONICS_KEY,
+ terminal_app_enable_mnemonics_notify_cb,
+ app, NULL, NULL);
+
+ app->enable_menu_accels_notify_id =
+ mateconf_client_notify_add (app->conf,
+ ENABLE_MENU_BAR_ACCEL_KEY,
+ terminal_app_enable_menu_accels_notify_cb,
+ app, NULL, NULL);
+
+ /* Load the settings */
+ mateconf_client_notify (app->conf, PROFILE_LIST_KEY);
+ mateconf_client_notify (app->conf, DEFAULT_PROFILE_KEY);
+ mateconf_client_notify (app->conf, ENCODING_LIST_KEY);
+ mateconf_client_notify (app->conf, MONOSPACE_FONT_KEY);
+ mateconf_client_notify (app->conf, ENABLE_MENU_BAR_ACCEL_KEY);
+ mateconf_client_notify (app->conf, ENABLE_MNEMONICS_KEY);
+
+ /* Ensure we have valid settings */
+ g_assert (app->default_profile_id != NULL);
+ g_assert (app->system_font_desc != NULL);
+
+ terminal_accels_init ();
+
+#ifdef WITH_SMCLIENT
+{
+ EggSMClient *sm_client;
+#ifdef GDK_WINDOWING_X11
+ char *desktop_file;
+
+ desktop_file = g_build_filename (TERM_DATADIR,
+ "applications",
+ PACKAGE ".desktop",
+ NULL);
+ egg_set_desktop_file_without_defaults (desktop_file);
+ g_free (desktop_file);
+#endif /* GDK_WINDOWING_X11 */
+
+ sm_client = egg_sm_client_get ();
+ g_signal_connect (sm_client, "save-state",
+ G_CALLBACK (terminal_app_save_state_cb), app);
+ g_signal_connect (sm_client, "quit",
+ G_CALLBACK (terminal_app_client_quit_cb), app);
+}
+#endif
+}
+
+static void
+terminal_app_finalize (GObject *object)
+{
+ TerminalApp *app = TERMINAL_APP (object);
+
+#ifdef WITH_SMCLIENT
+ EggSMClient *sm_client;
+
+ sm_client = egg_sm_client_get ();
+ g_signal_handlers_disconnect_matched (sm_client, G_SIGNAL_MATCH_DATA,
+ 0, 0, NULL, NULL, app);
+#endif
+
+ if (app->profile_list_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->profile_list_notify_id);
+ if (app->default_profile_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->default_profile_notify_id);
+ if (app->encoding_list_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->encoding_list_notify_id);
+ if (app->system_font_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->system_font_notify_id);
+ if (app->enable_menu_accels_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->enable_menu_accels_notify_id);
+ if (app->enable_mnemonics_notify_id != 0)
+ mateconf_client_notify_remove (app->conf, app->enable_mnemonics_notify_id);
+
+ mateconf_client_remove_dir (app->conf, CONF_GLOBAL_PREFIX, NULL);
+ mateconf_client_remove_dir (app->conf, MONOSPACE_FONT_DIR, NULL);
+
+ g_object_unref (app->conf);
+
+ g_free (app->default_profile_id);
+
+ g_hash_table_destroy (app->profiles);
+
+ g_hash_table_destroy (app->encodings);
+
+ pango_font_description_free (app->system_font_desc);
+
+ terminal_accels_shutdown ();
+
+ G_OBJECT_CLASS (terminal_app_parent_class)->finalize (object);
+
+ global_app = NULL;
+}
+
+static void
+terminal_app_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TerminalApp *app = TERMINAL_APP (object);
+
+ switch (prop_id)
+ {
+ case PROP_SYSTEM_FONT:
+ if (app->system_font_desc)
+ g_value_set_boxed (value, app->system_font_desc);
+ else
+ g_value_take_boxed (value, pango_font_description_from_string (DEFAULT_MONOSPACE_FONT));
+ break;
+ case PROP_ENABLE_MENU_BAR_ACCEL:
+ g_value_set_boolean (value, app->enable_menu_accels);
+ break;
+ case PROP_ENABLE_MNEMONICS:
+ g_value_set_boolean (value, app->enable_mnemonics);
+ break;
+ case PROP_DEFAULT_PROFILE:
+ g_value_set_object (value, app->default_profile);
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+terminal_app_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TerminalApp *app = TERMINAL_APP (object);
+
+ switch (prop_id)
+ {
+ case PROP_ENABLE_MENU_BAR_ACCEL:
+ app->enable_menu_accels = g_value_get_boolean (value);
+ mateconf_client_set_bool (app->conf, ENABLE_MENU_BAR_ACCEL_KEY, app->enable_menu_accels, NULL);
+ break;
+ case PROP_ENABLE_MNEMONICS:
+ app->enable_mnemonics = g_value_get_boolean (value);
+ mateconf_client_set_bool (app->conf, ENABLE_MNEMONICS_KEY, app->enable_mnemonics, NULL);
+ break;
+ case PROP_DEFAULT_PROFILE:
+ case PROP_SYSTEM_FONT:
+ /* not writable */
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+terminal_app_real_quit (TerminalApp *app)
+{
+ gtk_main_quit();
+}
+
+static void
+terminal_app_class_init (TerminalAppClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->finalize = terminal_app_finalize;
+ object_class->get_property = terminal_app_get_property;
+ object_class->set_property = terminal_app_set_property;
+
+ klass->quit = terminal_app_real_quit;
+
+ signals[QUIT] =
+ g_signal_new (I_("quit"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TerminalAppClass, quit),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[PROFILE_LIST_CHANGED] =
+ g_signal_new (I_("profile-list-changed"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TerminalAppClass, profile_list_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ signals[ENCODING_LIST_CHANGED] =
+ g_signal_new (I_("encoding-list-changed"),
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TerminalAppClass, profile_list_changed),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ENABLE_MENU_BAR_ACCEL,
+ g_param_spec_boolean (TERMINAL_APP_ENABLE_MENU_BAR_ACCEL, NULL, NULL,
+ DEFAULT_ENABLE_MENU_BAR_ACCEL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ENABLE_MNEMONICS,
+ g_param_spec_boolean (TERMINAL_APP_ENABLE_MNEMONICS, NULL, NULL,
+ DEFAULT_ENABLE_MNEMONICS,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_SYSTEM_FONT,
+ g_param_spec_boxed (TERMINAL_APP_SYSTEM_FONT, NULL, NULL,
+ PANGO_TYPE_FONT_DESCRIPTION,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_DEFAULT_PROFILE,
+ g_param_spec_object (TERMINAL_APP_DEFAULT_PROFILE, NULL, NULL,
+ TERMINAL_TYPE_PROFILE,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+}
+
+/* Public API */
+
+TerminalApp*
+terminal_app_get (void)
+{
+ if (global_app == NULL) {
+ g_object_new (TERMINAL_TYPE_APP, NULL);
+ g_assert (global_app != NULL);
+ }
+
+ return global_app;
+}
+
+void
+terminal_app_shutdown (void)
+{
+ if (global_app == NULL)
+ return;
+
+ g_object_unref (global_app);
+ g_assert (global_app == NULL);
+}
+
+/**
+ * terminal_app_handle_options:
+ * @app:
+ * @options: a #TerminalOptions
+ * @allow_resume: whether to merge the terminal configuration from the
+ * saved session on resume
+ * @error: a #GError to fill in
+ *
+ * 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
+ */
+gboolean
+terminal_app_handle_options (TerminalApp *app,
+ TerminalOptions *options,
+ gboolean allow_resume,
+ GError **error)
+{
+ GList *lw;
+ GdkScreen *gdk_screen;
+
+ gdk_screen = terminal_app_get_screen_by_display_name (options->display_name,
+ options->screen_number);
+
+ if (options->save_config)
+ {
+ if (options->remote_arguments)
+ return terminal_app_save_config_file (app, options->config_file, error);
+
+ g_set_error_literal (error, TERMINAL_OPTION_ERROR, TERMINAL_OPTION_ERROR_NOT_IN_FACTORY,
+ "Cannot use \"--save-config\" when starting the factory process");
+ return FALSE;
+ }
+
+ if (options->load_config)
+ {
+ GKeyFile *key_file;
+ gboolean result;
+
+ key_file = g_key_file_new ();
+ result = g_key_file_load_from_file (key_file, options->config_file, 0, error) &&
+ terminal_options_merge_config (options, key_file, SOURCE_DEFAULT, error);
+ g_key_file_free (key_file);
+
+ if (!result)
+ return FALSE;
+
+ /* fall-through on success */
+ }
+
+#ifdef WITH_SMCLIENT
+{
+ EggSMClient *sm_client;
+
+ sm_client = egg_sm_client_get ();
+
+ if (allow_resume && egg_sm_client_is_resumed (sm_client))
+ {
+ GKeyFile *key_file;
+
+ key_file = egg_sm_client_get_state_file (sm_client);
+ if (key_file != NULL &&
+ !terminal_options_merge_config (options, key_file, SOURCE_SESSION, error))
+ return FALSE;
+ }
+}
+#endif
+
+ /* Make sure we open at least one window */
+ terminal_options_ensure_window (options);
+
+ if (options->startup_id != NULL)
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Startup ID is '%s'\n",
+ options->startup_id);
+
+ for (lw = options->initial_windows; lw != NULL; lw = lw->next)
+ {
+ InitialWindow *iw = lw->data;
+ TerminalWindow *window;
+ GList *lt;
+
+ g_assert (iw->tabs);
+
+ /* Create & setup new window */
+ window = terminal_app_new_window (app, gdk_screen);
+
+ /* Restored windows shouldn't demand attention; see bug #586308. */
+ if (iw->source_tag == SOURCE_SESSION)
+ terminal_window_set_is_restored (window);
+
+ if (options->startup_id != NULL)
+ gtk_window_set_startup_id (GTK_WINDOW (window), options->startup_id);
+
+ /* Overwrite the default, unique window role set in terminal_window_init */
+ if (iw->role)
+ gtk_window_set_role (GTK_WINDOW (window), iw->role);
+
+ if (iw->force_menubar_state)
+ terminal_window_set_menubar_visible (window, iw->menubar_state);
+
+ if (iw->start_fullscreen)
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ if (iw->start_maximized)
+ gtk_window_maximize (GTK_WINDOW (window));
+
+ /* Now add the tabs */
+ for (lt = iw->tabs; lt != NULL; lt = lt->next)
+ {
+ InitialTab *it = lt->data;
+ TerminalProfile *profile = NULL;
+ TerminalScreen *screen;
+ const char *profile_name;
+ gboolean profile_is_id;
+
+ if (it->profile)
+ {
+ profile_name = it->profile;
+ profile_is_id = it->profile_is_id;
+ }
+ else
+ {
+ profile_name = options->default_profile;
+ profile_is_id = options->default_profile_is_id;
+ }
+
+ if (profile_name)
+ {
+ if (profile_is_id)
+ profile = terminal_app_get_profile_by_name (app, profile_name);
+ else
+ profile = terminal_app_get_profile_by_visible_name (app, profile_name);
+
+ if (profile == NULL)
+ g_printerr (_("No such profile \"%s\", using default profile\n"), it->profile);
+ }
+ if (profile == NULL)
+ profile = terminal_app_get_profile_for_new_term (app);
+ g_assert (profile);
+
+ screen = terminal_app_new_terminal (app, window, profile,
+ it->exec_argv ? it->exec_argv : options->exec_argv,
+ it->title ? it->title : options->default_title,
+ it->working_dir ? it->working_dir : options->default_working_dir,
+ options->env,
+ it->zoom_set ? it->zoom : options->zoom);
+
+ if (it->active)
+ terminal_window_switch_screen (window, screen);
+ }
+
+ if (iw->geometry)
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[window %p] applying geometry %s\n",
+ window, iw->geometry);
+
+ if (!gtk_window_parse_geometry (GTK_WINDOW (window), iw->geometry))
+ g_printerr (_("Invalid geometry string \"%s\"\n"), iw->geometry);
+ }
+
+ gtk_window_present (GTK_WINDOW (window));
+ }
+
+ return TRUE;
+}
+
+TerminalWindow *
+terminal_app_new_window (TerminalApp *app,
+ GdkScreen *screen)
+{
+ TerminalWindow *window;
+
+ window = terminal_window_new ();
+
+ app->windows = g_list_append (app->windows, window);
+ g_signal_connect (window, "destroy",
+ G_CALLBACK (terminal_window_destroyed), app);
+
+ if (screen)
+ gtk_window_set_screen (GTK_WINDOW (window), screen);
+
+ return window;
+}
+
+TerminalScreen *
+terminal_app_new_terminal (TerminalApp *app,
+ TerminalWindow *window,
+ TerminalProfile *profile,
+ char **override_command,
+ const char *title,
+ const char *working_dir,
+ char **child_env,
+ double zoom)
+{
+ TerminalScreen *screen;
+
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+ g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
+
+ screen = terminal_screen_new (profile, override_command, title,
+ working_dir, child_env, zoom);
+
+ terminal_window_add_screen (window, screen, -1);
+ terminal_window_switch_screen (window, screen);
+ gtk_widget_grab_focus (GTK_WIDGET (screen));
+
+ return screen;
+}
+
+void
+terminal_app_edit_profile (TerminalApp *app,
+ TerminalProfile *profile,
+ GtkWindow *transient_parent,
+ const char *widget_name)
+{
+ terminal_profile_edit (profile, transient_parent, widget_name);
+}
+
+void
+terminal_app_edit_keybindings (TerminalApp *app,
+ GtkWindow *transient_parent)
+{
+ terminal_edit_keys_dialog_show (transient_parent);
+}
+
+void
+terminal_app_edit_encodings (TerminalApp *app,
+ GtkWindow *transient_parent)
+{
+ terminal_encoding_dialog_show (transient_parent);
+}
+
+TerminalWindow *
+terminal_app_get_current_window (TerminalApp *app)
+{
+ if (app->windows == NULL)
+ return NULL;
+
+ return g_list_last (app->windows)->data;
+}
+
+/**
+ * terminal_profile_get_list:
+ *
+ * Returns: a #GList containing all #TerminalProfile objects.
+ * The content of the list is owned by the backend and
+ * should not be modified or freed. Use g_list_free() when done
+ * using the list.
+ */
+GList*
+terminal_app_get_profile_list (TerminalApp *app)
+{
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+
+ return g_list_sort (g_hash_table_get_values (app->profiles), profiles_alphabetic_cmp);
+}
+
+TerminalProfile*
+terminal_app_get_profile_by_name (TerminalApp *app,
+ const char *name)
+{
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ return g_hash_table_lookup (app->profiles, name);
+}
+
+TerminalProfile*
+terminal_app_get_profile_by_visible_name (TerminalApp *app,
+ const char *name)
+{
+ LookupInfo info;
+
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+ g_return_val_if_fail (name != NULL, NULL);
+
+ info.result = NULL;
+ info.target = name;
+
+ g_hash_table_foreach (app->profiles,
+ profiles_lookup_by_visible_name_foreach,
+ &info);
+ return info.result;
+}
+
+TerminalProfile*
+terminal_app_get_default_profile (TerminalApp *app)
+{
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+
+ return app->default_profile;
+}
+
+TerminalProfile*
+terminal_app_get_profile_for_new_term (TerminalApp *app)
+{
+ GHashTableIter iter;
+ TerminalProfile *profile = NULL;
+ TerminalProfile **profileptr = &profile;
+
+ g_return_val_if_fail (TERMINAL_IS_APP (app), NULL);
+
+ if (app->default_profile)
+ return app->default_profile;
+
+ g_hash_table_iter_init (&iter, app->profiles);
+ if (g_hash_table_iter_next (&iter, NULL, (gpointer *) profileptr))
+ return profile;
+
+ return NULL;
+}
+
+GHashTable *
+terminal_app_get_encodings (TerminalApp *app)
+{
+ return app->encodings;
+}
+
+/**
+ * terminal_app_ensure_encoding:
+ * @app:
+ * @charset:
+ *
+ * Ensures there's a #TerminalEncoding for @charset available.
+ */
+TerminalEncoding *
+terminal_app_ensure_encoding (TerminalApp *app,
+ const char *charset)
+{
+ TerminalEncoding *encoding;
+
+ encoding = g_hash_table_lookup (app->encodings, charset);
+ if (encoding == NULL)
+ {
+ encoding = terminal_encoding_new (charset,
+ _("User Defined"),
+ TRUE,
+ TRUE /* scary! */);
+ g_hash_table_insert (app->encodings,
+ (gpointer) terminal_encoding_get_id (encoding),
+ encoding);
+ }
+
+ return encoding;
+}
+
+/**
+ * terminal_app_get_active_encodings:
+ *
+ * Returns: a newly allocated list of newly referenced #TerminalEncoding objects.
+ */
+GSList*
+terminal_app_get_active_encodings (TerminalApp *app)
+{
+ GSList *list = NULL;
+ GHashTableIter iter;
+ gpointer key, value;
+
+ g_hash_table_iter_init (&iter, app->encodings);
+ while (g_hash_table_iter_next (&iter, &key, &value))
+ {
+ TerminalEncoding *encoding = (TerminalEncoding *) value;
+
+ if (!encoding->is_active)
+ continue;
+
+ list = g_slist_prepend (list, terminal_encoding_ref (encoding));
+ }
+
+ return g_slist_sort (list, (GCompareFunc) compare_encodings);
+}
+
+void
+terminal_app_save_config (TerminalApp *app,
+ GKeyFile *key_file)
+{
+ GList *lw;
+ guint n = 0;
+ GPtrArray *window_names_array;
+ char **window_names;
+ gsize len;
+
+ g_key_file_set_comment (key_file, NULL, NULL, "Written by " PACKAGE_STRING, NULL);
+
+ g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_VERSION, TERMINAL_CONFIG_VERSION);
+ g_key_file_set_integer (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_COMPAT_VERSION, TERMINAL_CONFIG_COMPAT_VERSION);
+
+ window_names_array = g_ptr_array_sized_new (g_list_length (app->windows) + 1);
+
+ for (lw = app->windows; lw != NULL; lw = lw->next)
+ {
+ TerminalWindow *window = TERMINAL_WINDOW (lw->data);
+ char *group;
+
+ group = g_strdup_printf ("Window%u", n++);
+ g_ptr_array_add (window_names_array, group);
+
+ terminal_window_save_state (window, key_file, group);
+ }
+
+ len = window_names_array->len;
+ g_ptr_array_add (window_names_array, NULL);
+ window_names = (char **) g_ptr_array_free (window_names_array, FALSE);
+ g_key_file_set_string_list (key_file, TERMINAL_CONFIG_GROUP, TERMINAL_CONFIG_PROP_WINDOWS, (const char * const *) window_names, len);
+ g_strfreev (window_names);
+}
+
+gboolean
+terminal_app_save_config_file (TerminalApp *app,
+ const char *file_name,
+ GError **error)
+{
+ GKeyFile *key_file;
+ char *data;
+ gsize len;
+ gboolean result;
+
+ key_file = g_key_file_new ();
+ terminal_app_save_config (app, key_file);
+
+ data = g_key_file_to_data (key_file, &len, NULL);
+ result = g_file_set_contents (file_name, data, len, error);
+ g_free (data);
+
+ return result;
+}
diff --git a/src/terminal-app.h b/src/terminal-app.h
new file mode 100644
index 0000000..0b90b2f
--- /dev/null
+++ b/src/terminal-app.h
@@ -0,0 +1,159 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2008 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_APP_H
+#define TERMINAL_APP_H
+
+#include <gtk/gtk.h>
+
+#include "terminal-encoding.h"
+#include "terminal-screen.h"
+#include "terminal-options.h"
+
+G_BEGIN_DECLS
+
+/* Terminal conf files */
+
+#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 "MATE 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"
+
+/* Configuration */
+
+#define CONF_PREFIX "/apps/mate-terminal"
+#define CONF_GLOBAL_PREFIX CONF_PREFIX "/global"
+#define CONF_PROFILES_PREFIX CONF_PREFIX "/profiles"
+#define CONF_KEYS_PREFIX CONF_PREFIX "/keybindings"
+
+#define MATE_TERMINAL_ICON_NAME "utilities-terminal"
+
+#define TERMINAL_APP_DEFAULT_PROFILE "default-profile"
+#define TERMINAL_APP_ENABLE_MENU_BAR_ACCEL "enable-menu-accels"
+#define TERMINAL_APP_ENABLE_MNEMONICS "enable-mnemonics"
+#define TERMINAL_APP_SYSTEM_FONT "system-font"
+
+/* 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);
+
+TerminalApp* terminal_app_get (void);
+
+void terminal_app_shutdown (void);
+
+gboolean terminal_app_handle_options (TerminalApp *app,
+ TerminalOptions *options,
+ gboolean allow_resume,
+ GError **error);
+
+void terminal_app_edit_profile (TerminalApp *app,
+ TerminalProfile *profile,
+ GtkWindow *transient_parent,
+ const char *widget_name);
+
+void terminal_app_new_profile (TerminalApp *app,
+ TerminalProfile *default_base_profile,
+ GtkWindow *transient_parent);
+
+TerminalWindow * terminal_app_new_window (TerminalApp *app,
+ GdkScreen *screen);
+
+TerminalScreen *terminal_app_new_terminal (TerminalApp *app,
+ TerminalWindow *window,
+ TerminalProfile *profile,
+ char **override_command,
+ const char *title,
+ const char *working_dir,
+ char **child_env,
+ double zoom);
+
+TerminalWindow *terminal_app_get_current_window (TerminalApp *app);
+
+void terminal_app_manage_profiles (TerminalApp *app,
+ GtkWindow *transient_parent);
+
+void terminal_app_edit_keybindings (TerminalApp *app,
+ GtkWindow *transient_parent);
+void terminal_app_edit_encodings (TerminalApp *app,
+ GtkWindow *transient_parent);
+
+
+GList* terminal_app_get_profile_list (TerminalApp *app);
+
+TerminalProfile* terminal_app_ensure_profile_fallback (TerminalApp *app);
+
+TerminalProfile* terminal_app_get_profile_by_name (TerminalApp *app,
+ const char *name);
+
+TerminalProfile* terminal_app_get_profile_by_visible_name (TerminalApp *app,
+ const char *name);
+
+/* may return NULL */
+TerminalProfile* terminal_app_get_default_profile (TerminalApp *app);
+
+/* never returns NULL if any profiles exist, one is always supposed to */
+TerminalProfile* terminal_app_get_profile_for_new_term (TerminalApp *app);
+
+TerminalEncoding *terminal_app_ensure_encoding (TerminalApp *app,
+ const char *charset);
+
+GHashTable *terminal_app_get_encodings (TerminalApp *app);
+
+GSList* terminal_app_get_active_encodings (TerminalApp *app);
+
+void terminal_app_save_config (TerminalApp *app,
+ GKeyFile *key_file);
+
+gboolean terminal_app_save_config_file (TerminalApp *app,
+ const char *file_name,
+ GError **error);
+
+G_END_DECLS
+
+#endif /* !TERMINAL_APP_H */
diff --git a/src/terminal-debug.c b/src/terminal-debug.c
new file mode 100644
index 0000000..ec9c3ee
--- /dev/null
+++ b/src/terminal-debug.c
@@ -0,0 +1,45 @@
+/*
+ * Copyright (C) 2002,2003 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library 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 Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+#include <config.h>
+
+#include <glib.h>
+
+#include "terminal-debug.h"
+
+TerminalDebugFlags _terminal_debug_flags;
+
+void
+_terminal_debug_init(void)
+{
+#ifdef MATE_ENABLE_DEBUG
+ const GDebugKey keys[] = {
+ { "accels", TERMINAL_DEBUG_ACCELS },
+ { "encodings", TERMINAL_DEBUG_ENCODINGS },
+ { "factory", TERMINAL_DEBUG_FACTORY },
+ { "geometry", TERMINAL_DEBUG_GEOMETRY },
+ { "mdi", TERMINAL_DEBUG_MDI },
+ { "processes", TERMINAL_DEBUG_PROCESSES },
+ { "profile", TERMINAL_DEBUG_PROFILE }
+ };
+
+ _terminal_debug_flags = g_parse_debug_string (g_getenv ("MATE_TERMINAL_DEBUG"),
+ keys, G_N_ELEMENTS (keys));
+#endif /* MATE_ENABLE_DEBUG */
+}
+
diff --git a/src/terminal-debug.h b/src/terminal-debug.h
new file mode 100644
index 0000000..6be1716
--- /dev/null
+++ b/src/terminal-debug.h
@@ -0,0 +1,74 @@
+/*
+ * Copyright (C) 2002 Red Hat, Inc.
+ *
+ * This is free software; you can redistribute it and/or modify it under
+ * the terms of the GNU Library 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 Library General Public
+ * License along with this program; if not, write to the Free Software
+ * Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
+ */
+
+/* The interfaces in this file are subject to change at any time. */
+
+#ifndef MATE_ENABLE_DEBUG_H
+#define MATE_ENABLE_DEBUG_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef enum {
+ TERMINAL_DEBUG_ACCELS = 1 << 0,
+ TERMINAL_DEBUG_ENCODINGS = 1 << 1,
+ TERMINAL_DEBUG_FACTORY = 1 << 2,
+ TERMINAL_DEBUG_GEOMETRY = 1 << 3,
+ TERMINAL_DEBUG_MDI = 1 << 4,
+ TERMINAL_DEBUG_PROCESSES = 1 << 5,
+ TERMINAL_DEBUG_PROFILE = 1 << 6
+} 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 MATE_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 <stdarg.h>
+#include <glib/gstdio.h>
+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 /* !MATE_ENABLE_DEBUG_H */
diff --git a/src/terminal-encoding.c b/src/terminal-encoding.c
new file mode 100644
index 0000000..25d343b
--- /dev/null
+++ b/src/terminal-encoding.c
@@ -0,0 +1,614 @@
+/*
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+
+#include <gtk/gtk.h>
+
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-encoding.h"
+#include "terminal-intl.h"
+#include "terminal-profile.h"
+#include "terminal-util.h"
+
+/* Overview
+ *
+ * There's a list of character sets stored in mateconf, indicating
+ * which encodings to display in the encoding menu.
+ *
+ * We have a pre-canned list of available encodings
+ * (hardcoded in the table below) that can be added to
+ * the encoding menu, and to give a human-readable name
+ * to certain encodings.
+ *
+ * If the mateconf list contains an encoding not in the
+ * predetermined table, then that encoding is
+ * labeled "user defined" but still appears in the menu.
+ */
+
+static const struct {
+ const char *charset;
+ const char *name;
+} encodings[] = {
+ { "ISO-8859-1", N_("Western") },
+ { "ISO-8859-2", N_("Central European") },
+ { "ISO-8859-3", N_("South European") },
+ { "ISO-8859-4", N_("Baltic") },
+ { "ISO-8859-5", N_("Cyrillic") },
+ { "ISO-8859-6", N_("Arabic") },
+ { "ISO-8859-7", N_("Greek") },
+ { "ISO-8859-8", N_("Hebrew Visual") },
+ { "ISO-8859-8-I", N_("Hebrew") },
+ { "ISO-8859-9", N_("Turkish") },
+ { "ISO-8859-10", N_("Nordic") },
+ { "ISO-8859-13", N_("Baltic") },
+ { "ISO-8859-14", N_("Celtic") },
+ { "ISO-8859-15", N_("Western") },
+ { "ISO-8859-16", N_("Romanian") },
+ { "UTF-8", N_("Unicode") },
+ { "ARMSCII-8", N_("Armenian") },
+ { "BIG5", N_("Chinese Traditional") },
+ { "BIG5-HKSCS", N_("Chinese Traditional") },
+ { "CP866", N_("Cyrillic/Russian") },
+ { "EUC-JP", N_("Japanese") },
+ { "EUC-KR", N_("Korean") },
+ { "EUC-TW", N_("Chinese Traditional") },
+ { "GB18030", N_("Chinese Simplified") },
+ { "GB2312", N_("Chinese Simplified") },
+ { "GBK", N_("Chinese Simplified") },
+ { "GEORGIAN-PS", N_("Georgian") },
+ { "IBM850", N_("Western") },
+ { "IBM852", N_("Central European") },
+ { "IBM855", N_("Cyrillic") },
+ { "IBM857", N_("Turkish") },
+ { "IBM862", N_("Hebrew") },
+ { "IBM864", N_("Arabic") },
+ { "ISO-2022-JP", N_("Japanese") },
+ { "ISO-2022-KR", N_("Korean") },
+ { "ISO-IR-111", N_("Cyrillic") },
+ { "KOI8-R", N_("Cyrillic") },
+ { "KOI8-U", N_("Cyrillic/Ukrainian") },
+ { "MAC_ARABIC", N_("Arabic") },
+ { "MAC_CE", N_("Central European") },
+ { "MAC_CROATIAN", N_("Croatian") },
+ { "MAC-CYRILLIC", N_("Cyrillic") },
+ { "MAC_DEVANAGARI", N_("Hindi") },
+ { "MAC_FARSI", N_("Persian") },
+ { "MAC_GREEK", N_("Greek") },
+ { "MAC_GUJARATI", N_("Gujarati") },
+ { "MAC_GURMUKHI", N_("Gurmukhi") },
+ { "MAC_HEBREW", N_("Hebrew") },
+ { "MAC_ICELANDIC", N_("Icelandic") },
+ { "MAC_ROMAN", N_("Western") },
+ { "MAC_ROMANIAN", N_("Romanian") },
+ { "MAC_TURKISH", N_("Turkish") },
+ { "MAC_UKRAINIAN", N_("Cyrillic/Ukrainian") },
+ { "SHIFT_JIS", N_("Japanese") },
+ { "TCVN", N_("Vietnamese") },
+ { "TIS-620", N_("Thai") },
+ { "UHC", N_("Korean") },
+ { "VISCII", N_("Vietnamese") },
+ { "WINDOWS-1250", N_("Central European") },
+ { "WINDOWS-1251", N_("Cyrillic") },
+ { "WINDOWS-1252", N_("Western") },
+ { "WINDOWS-1253", N_("Greek") },
+ { "WINDOWS-1254", N_("Turkish") },
+ { "WINDOWS-1255", N_("Hebrew") },
+ { "WINDOWS-1256", N_("Arabic") },
+ { "WINDOWS-1257", N_("Baltic") },
+ { "WINDOWS-1258", N_("Vietnamese") },
+#if 0
+ /* These encodings do NOT pass-through ASCII, so are always rejected.
+ * FIXME: why are they in this table; or rather why do we need
+ * the ASCII pass-through requirement?
+ */
+ { "UTF-7", N_("Unicode") },
+ { "UTF-16", N_("Unicode") },
+ { "UCS-2", N_("Unicode") },
+ { "UCS-4", N_("Unicode") },
+ { "JOHAB", N_("Korean") },
+#endif
+};
+
+typedef struct {
+ GtkWidget *dialog;
+ GtkListStore *base_store;
+ GtkTreeView *available_tree_view;
+ GtkTreeSelection *available_selection;
+ GtkTreeModel *available_model;
+ GtkTreeView *active_tree_view;
+ GtkTreeSelection *active_selection;
+ GtkTreeModel *active_model;
+ GtkWidget *add_button;
+ GtkWidget *remove_button;
+} EncodingDialogData;
+
+static GtkWidget *encoding_dialog = NULL;
+
+TerminalEncoding *
+terminal_encoding_new (const char *charset,
+ const char *display_name,
+ gboolean is_custom,
+ gboolean force_valid)
+{
+ TerminalEncoding *encoding;
+
+ encoding = g_slice_new (TerminalEncoding);
+ encoding->refcount = 1;
+ encoding->id = g_strdup (charset);
+ encoding->name = g_strdup (display_name);
+ encoding->valid = encoding->validity_checked = force_valid;
+ encoding->is_custom = is_custom;
+ encoding->is_active = FALSE;
+
+ return encoding;
+}
+
+TerminalEncoding*
+terminal_encoding_ref (TerminalEncoding *encoding)
+{
+ g_return_val_if_fail (encoding != NULL, NULL);
+
+ encoding->refcount++;
+ return encoding;
+}
+
+void
+terminal_encoding_unref (TerminalEncoding *encoding)
+{
+ if (--encoding->refcount > 0)
+ return;
+
+ g_free (encoding->name);
+ g_free (encoding->id);
+ g_slice_free (TerminalEncoding, encoding);
+}
+
+const char *
+terminal_encoding_get_id (TerminalEncoding *encoding)
+{
+ g_return_val_if_fail (encoding != NULL, NULL);
+
+ return encoding->id;
+}
+
+const char *
+terminal_encoding_get_charset (TerminalEncoding *encoding)
+{
+ g_return_val_if_fail (encoding != NULL, NULL);
+
+ if (strcmp (encoding->id, "current") == 0)
+ {
+ const char *charset;
+
+ g_get_charset (&charset);
+ return charset;
+ }
+
+ return encoding->id;
+}
+
+gboolean
+terminal_encoding_is_valid (TerminalEncoding *encoding)
+{
+ /* All of the printing ASCII characters from space (32) to the tilde (126) */
+ static const char ascii_sample[] =
+ " !\"#$%&'()*+,-./0123456789:;<=>?@ABCDEFGHIJKLMNOPQRSTUVWXYZ[\\]^_`abcdefghijklmnopqrstuvwxyz{|}~";
+ char *converted;
+ gsize bytes_read = 0, bytes_written = 0;
+ GError *error = NULL;
+
+ if (encoding->validity_checked)
+ return encoding->valid;
+
+ /* Test that the encoding is a proper superset of ASCII (which naive
+ * apps are going to use anyway) by attempting to validate the text
+ * using the current encoding. This also flushes out any encodings
+ * which the underlying GIConv implementation can't support.
+ */
+ converted = g_convert (ascii_sample, sizeof (ascii_sample) - 1,
+ terminal_encoding_get_charset (encoding), "UTF-8",
+ &bytes_read, &bytes_written, &error);
+
+ /* The encoding is only valid if ASCII passes through cleanly. */
+ encoding->valid = (bytes_read == (sizeof (ascii_sample) - 1)) &&
+ (converted != NULL) &&
+ (strcmp (converted, ascii_sample) == 0);
+
+#ifdef MATE_ENABLE_DEBUG
+ _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_ENCODINGS)
+ {
+ if (!encoding->valid)
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
+ "Rejecting encoding %s as invalid:\n",
+ terminal_encoding_get_charset (encoding));
+ _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
+ " input \"%s\"\n",
+ ascii_sample);
+ _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
+ " output \"%s\" bytes read %u written %u\n",
+ converted ? converted : "(null)", bytes_read, bytes_written);
+ if (error)
+ _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
+ " Error: %s\n",
+ error->message);
+ }
+ else
+ _terminal_debug_print (TERMINAL_DEBUG_ENCODINGS,
+ "Encoding %s is valid\n\n",
+ terminal_encoding_get_charset (encoding));
+ }
+#endif
+
+ g_clear_error (&error);
+ g_free (converted);
+
+ encoding->validity_checked = TRUE;
+ return encoding->valid;
+}
+
+GType
+terminal_encoding_get_type (void)
+{
+ static GType type = 0;
+
+ if (G_UNLIKELY (type == 0)) {
+ type = g_boxed_type_register_static (I_("TerminalEncoding"),
+ (GBoxedCopyFunc) terminal_encoding_ref,
+ (GBoxedFreeFunc) terminal_encoding_unref);
+ }
+
+ return type;
+}
+
+static void
+update_active_encodings_mateconf (void)
+{
+ GSList *list, *l;
+ GSList *strings = NULL;
+ MateConfClient *conf;
+
+ list = terminal_app_get_active_encodings (terminal_app_get ());
+ for (l = list; l != NULL; l = l->next)
+ {
+ TerminalEncoding *encoding = (TerminalEncoding *) l->data;
+
+ strings = g_slist_prepend (strings, (gpointer) terminal_encoding_get_id (encoding));
+ }
+
+ conf = mateconf_client_get_default ();
+ mateconf_client_set_list (conf,
+ CONF_GLOBAL_PREFIX"/active_encodings",
+ MATECONF_VALUE_STRING,
+ strings,
+ NULL);
+ g_object_unref (conf);
+
+ g_slist_free (strings);
+ g_slist_foreach (list, (GFunc) terminal_encoding_unref, NULL);
+ g_slist_free (list);
+}
+
+static void
+response_callback (GtkWidget *window,
+ int id,
+ EncodingDialogData *data)
+{
+ if (id == GTK_RESPONSE_HELP)
+ terminal_util_show_help ("mate-terminal-encoding-add", GTK_WINDOW (window));
+ else
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+enum
+{
+ COLUMN_NAME,
+ COLUMN_CHARSET,
+ COLUMN_DATA,
+ N_COLUMNS
+};
+
+static void
+selection_changed_cb (GtkTreeSelection *selection,
+ EncodingDialogData *data)
+{
+ GtkWidget *button;
+ gboolean have_selection;
+
+ if (selection == data->available_selection)
+ button = data->add_button;
+ else if (selection == data->active_selection)
+ button = data->remove_button;
+ else
+ g_assert_not_reached ();
+
+ have_selection = gtk_tree_selection_get_selected (selection, NULL, NULL);
+ gtk_widget_set_sensitive (button, have_selection);
+}
+
+static void
+button_clicked_cb (GtkWidget *button,
+ EncodingDialogData *data)
+{
+ GtkTreeSelection *selection;
+ GtkTreeModel *model;
+ GtkTreeIter filter_iter, iter;
+ TerminalEncoding *encoding;
+
+ if (button == data->add_button)
+ selection = data->available_selection;
+ else if (button == data->remove_button)
+ selection = data->active_selection;
+ else
+ g_assert_not_reached ();
+
+ if (!gtk_tree_selection_get_selected (selection, &model, &filter_iter))
+ return;
+
+ gtk_tree_model_filter_convert_iter_to_child_iter (GTK_TREE_MODEL_FILTER (model),
+ &iter,
+ &filter_iter);
+
+ model = GTK_TREE_MODEL (data->base_store);
+ gtk_tree_model_get (model, &iter, COLUMN_DATA, &encoding, -1);
+ g_assert (encoding != NULL);
+
+ if (button == data->add_button)
+ encoding->is_active = TRUE;
+ else if (button == data->remove_button)
+ encoding->is_active = FALSE;
+ else
+ g_assert_not_reached ();
+
+ terminal_encoding_unref (encoding);
+
+ /* We don't need to emit row-changed here, since updating the mateconf pref
+ * will update the models.
+ */
+ update_active_encodings_mateconf ();
+}
+
+static void
+liststore_insert_encoding (gpointer key,
+ TerminalEncoding *encoding,
+ GtkListStore *store)
+{
+ GtkTreeIter iter;
+
+ if (!terminal_encoding_is_valid (encoding))
+ return;
+
+ gtk_list_store_insert_with_values (store, &iter, -1,
+ COLUMN_CHARSET, terminal_encoding_get_charset (encoding),
+ COLUMN_NAME, encoding->name,
+ COLUMN_DATA, encoding,
+ -1);
+}
+
+static gboolean
+filter_active_encodings (GtkTreeModel *child_model,
+ GtkTreeIter *child_iter,
+ gpointer data)
+{
+ TerminalEncoding *encoding;
+ gboolean active = GPOINTER_TO_UINT (data);
+ gboolean visible;
+
+ gtk_tree_model_get (child_model, child_iter, COLUMN_DATA, &encoding, -1);
+ visible = active ? encoding->is_active : !encoding->is_active;
+ terminal_encoding_unref (encoding);
+
+ return visible;
+}
+
+static GtkTreeModel *
+encodings_create_treemodel (GtkListStore *base_store,
+ gboolean active)
+{
+ GtkTreeModel *model;
+
+ model = gtk_tree_model_filter_new (GTK_TREE_MODEL (base_store), NULL);
+ gtk_tree_model_filter_set_visible_func (GTK_TREE_MODEL_FILTER (model),
+ filter_active_encodings,
+ GUINT_TO_POINTER (active), NULL);
+
+ return model;
+}
+
+static void
+encodings_list_changed_cb (TerminalApp *app,
+ EncodingDialogData *data)
+{
+ gtk_list_store_clear (data->base_store);
+
+ g_hash_table_foreach (terminal_app_get_encodings (app), (GHFunc) liststore_insert_encoding, data->base_store);
+}
+
+static void
+encoding_dialog_data_free (EncodingDialogData *data)
+{
+ g_signal_handlers_disconnect_by_func (terminal_app_get (),
+ G_CALLBACK (encodings_list_changed_cb),
+ data);
+
+ g_free (data);
+}
+
+void
+terminal_encoding_dialog_show (GtkWindow *transient_parent)
+{
+ TerminalApp *app;
+ GtkCellRenderer *cell_renderer;
+ GtkTreeViewColumn *column;
+ GtkTreeModel *model;
+ EncodingDialogData *data;
+
+ if (encoding_dialog)
+ {
+ gtk_window_set_transient_for (GTK_WINDOW (encoding_dialog), transient_parent);
+ gtk_window_present (GTK_WINDOW (encoding_dialog));
+ return;
+ }
+
+ data = g_new (EncodingDialogData, 1);
+
+ if (!terminal_util_load_builder_file ("encodings-dialog.ui",
+ "encodings-dialog", &data->dialog,
+ "add-button", &data->add_button,
+ "remove-button", &data->remove_button,
+ "available-treeview", &data->available_tree_view,
+ "displayed-treeview", &data->active_tree_view,
+ NULL))
+ {
+ g_free (data);
+ return;
+ }
+
+ g_object_set_data_full (G_OBJECT (data->dialog), "GT::Data", data, (GDestroyNotify) encoding_dialog_data_free);
+
+ gtk_window_set_transient_for (GTK_WINDOW (data->dialog), transient_parent);
+ gtk_window_set_role (GTK_WINDOW (data->dialog), "mate-terminal-encodings");
+ g_signal_connect (data->dialog, "response",
+ G_CALLBACK (response_callback), data);
+
+ /* buttons */
+ g_signal_connect (data->add_button, "clicked",
+ G_CALLBACK (button_clicked_cb), data);
+
+ g_signal_connect (data->remove_button, "clicked",
+ G_CALLBACK (button_clicked_cb), data);
+
+ /* Tree view of available encodings */
+ /* Column 1 */
+ cell_renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("_Description"),
+ cell_renderer,
+ "text", COLUMN_NAME,
+ NULL);
+ gtk_tree_view_append_column (data->available_tree_view, column);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
+
+ /* Column 2 */
+ cell_renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
+ cell_renderer,
+ "text", COLUMN_CHARSET,
+ NULL);
+ gtk_tree_view_append_column (data->available_tree_view, column);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
+
+ data->available_selection = gtk_tree_view_get_selection (data->available_tree_view);
+ gtk_tree_selection_set_mode (data->available_selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect (data->available_selection, "changed",
+ G_CALLBACK (selection_changed_cb), data);
+
+ /* Tree view of selected encodings */
+ /* Column 1 */
+ cell_renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("_Description"),
+ cell_renderer,
+ "text", COLUMN_NAME,
+ NULL);
+ gtk_tree_view_append_column (data->active_tree_view, column);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_NAME);
+
+ /* Column 2 */
+ cell_renderer = gtk_cell_renderer_text_new ();
+ column = gtk_tree_view_column_new_with_attributes (_("_Encoding"),
+ cell_renderer,
+ "text", COLUMN_CHARSET,
+ NULL);
+ gtk_tree_view_append_column (data->active_tree_view, column);
+ gtk_tree_view_column_set_sort_column_id (column, COLUMN_CHARSET);
+
+ /* Add the data */
+
+ data->active_selection = gtk_tree_view_get_selection (data->active_tree_view);
+ gtk_tree_selection_set_mode (data->active_selection, GTK_SELECTION_BROWSE);
+
+ g_signal_connect (data->active_selection, "changed",
+ G_CALLBACK (selection_changed_cb), data);
+
+ data->base_store = gtk_list_store_new (N_COLUMNS, G_TYPE_STRING, G_TYPE_STRING, TERMINAL_TYPE_ENCODING);
+
+ app = terminal_app_get ();
+ encodings_list_changed_cb (app, data);
+ g_signal_connect (app, "encoding-list-changed",
+ G_CALLBACK (encodings_list_changed_cb), data);
+
+ /* Now turn on sorting */
+ gtk_tree_sortable_set_sort_column_id (GTK_TREE_SORTABLE (data->base_store),
+ COLUMN_NAME,
+ GTK_SORT_ASCENDING);
+
+ model = encodings_create_treemodel (data->base_store, FALSE);
+ gtk_tree_view_set_model (data->available_tree_view, model);
+ g_object_unref (model);
+
+ model = encodings_create_treemodel (data->base_store, TRUE);
+ gtk_tree_view_set_model (data->active_tree_view, model);
+ g_object_unref (model);
+
+ g_object_unref (data->base_store);
+
+ gtk_window_present (GTK_WINDOW (data->dialog));
+
+ encoding_dialog = data->dialog;
+ g_signal_connect (data->dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed), &encoding_dialog);
+}
+
+GHashTable *
+terminal_encodings_get_builtins (void)
+{
+ GHashTable *encodings_hashtable;
+ guint i;
+ TerminalEncoding *encoding;
+
+ encodings_hashtable = g_hash_table_new_full (g_str_hash, g_str_equal,
+ NULL,
+ (GDestroyNotify) terminal_encoding_unref);
+
+
+ /* Placeholder entry for the current locale's charset */
+ encoding = terminal_encoding_new ("current",
+ _("Current Locale"),
+ FALSE,
+ TRUE);
+ g_hash_table_insert (encodings_hashtable,
+ (gpointer) terminal_encoding_get_id (encoding),
+ encoding);
+
+ for (i = 0; i < G_N_ELEMENTS (encodings); ++i)
+ {
+ encoding = terminal_encoding_new (encodings[i].charset,
+ _(encodings[i].name),
+ FALSE,
+ FALSE);
+ g_hash_table_insert (encodings_hashtable,
+ (gpointer) terminal_encoding_get_id (encoding),
+ encoding);
+ }
+
+ return encodings_hashtable;
+}
diff --git a/src/terminal-encoding.h b/src/terminal-encoding.h
new file mode 100644
index 0000000..ddfe9ed
--- /dev/null
+++ b/src/terminal-encoding.h
@@ -0,0 +1,61 @@
+/* Encoding stuff */
+
+/*
+ * Copyright © 2002 Red Hat, Inc.
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_ENCODING_H
+#define TERMINAL_ENCODING_H
+
+#include <gtk/gtk.h>
+
+#define TERMINAL_TYPE_ENCODING (terminal_encoding_get_type ())
+
+typedef struct
+{
+ int refcount;
+ char *id;
+ char *name;
+ guint valid : 1;
+ guint validity_checked : 1;
+ guint is_custom : 1;
+ guint is_active : 1;
+} TerminalEncoding;
+
+GType terminal_encoding_get_type (void);
+
+TerminalEncoding *terminal_encoding_new (const char *charset,
+ const char *display_name,
+ gboolean is_custom,
+ gboolean force_valid);
+
+TerminalEncoding *terminal_encoding_ref (TerminalEncoding *encoding);
+
+void terminal_encoding_unref (TerminalEncoding *encoding);
+
+gboolean terminal_encoding_is_valid (TerminalEncoding *encoding);
+
+const char *terminal_encoding_get_id (TerminalEncoding *encoding);
+
+const char *terminal_encoding_get_charset (TerminalEncoding *encoding);
+
+GHashTable *terminal_encodings_get_builtins (void);
+
+void terminal_encoding_dialog_show (GtkWindow *transient_parent);
+
+#endif /* TERMINAL_ENCODING_H */
diff --git a/src/terminal-info-bar.c b/src/terminal-info-bar.c
new file mode 100644
index 0000000..57c132b
--- /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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope info_bar 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "terminal-info-bar.h"
+
+#include <gtk/gtk.h>
+
+#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_vbox_new (FALSE, 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;
+ char *text;
+ 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);
+ g_free (text);
+
+ gtk_label_set_line_wrap (GTK_LABEL (label), TRUE);
+ gtk_label_set_selectable (GTK_LABEL (label), TRUE);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 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..09d2794
--- /dev/null
+++ b/src/terminal-info-bar.h
@@ -0,0 +1,62 @@
+/*
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope info_bar 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_INFO_BAR_H
+#define TERMINAL_INFO_BAR_H
+
+#include <gtk/gtk.h>
+
+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..cc9f9a2
--- /dev/null
+++ b/src/terminal-intl.h
@@ -0,0 +1,27 @@
+/*
+ * Copyright © 2002 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_INTL_H
+#define TERMINAL_INTL_H
+
+#include <glib/gi18n.h>
+
+#define I_(string) g_intern_static_string (string)
+
+#endif /* TERMINAL_INTL_H */
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-options.c b/src/terminal-options.c
new file mode 100644
index 0000000..82a0d7c
--- /dev/null
+++ b/src/terminal-options.c
@@ -0,0 +1,1396 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2002 Sun Microsystems
+ * Copyright © 2003 Mariano Suarez-Alvarez
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <string.h>
+#include <stdlib.h>
+
+#include <glib.h>
+
+#include "terminal-options.h"
+#include "terminal-screen.h"
+#include "terminal-app.h"
+#include "terminal-intl.h"
+#include "terminal-util.h"
+
+static GOptionContext *get_goption_context (TerminalOptions *options);
+
+static InitialTab*
+initial_tab_new (const char *profile,
+ gboolean is_id)
+{
+ InitialTab *it;
+
+ it = g_slice_new (InitialTab);
+
+ it->profile = g_strdup (profile);
+ it->profile_is_id = is_id;
+ it->exec_argv = NULL;
+ it->title = NULL;
+ it->working_dir = NULL;
+ it->zoom = 1.0;
+ it->zoom_set = FALSE;
+ it->active = FALSE;
+
+ 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_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_foreach (iw->tabs, (GFunc) initial_tab_free, NULL);
+ g_list_free (iw->tabs);
+ g_free (iw->geometry);
+ g_free (iw->role);
+ g_slice_free (InitialWindow, iw);
+}
+
+static void
+apply_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 InitialWindow*
+ensure_top_window (TerminalOptions *options)
+{
+ InitialWindow *iw;
+
+ if (options->initial_windows == NULL)
+ {
+ iw = initial_window_new (0);
+ iw->tabs = g_list_append (NULL, initial_tab_new (NULL, FALSE));
+ apply_defaults (options, iw);
+
+ options->initial_windows = g_list_append (options->initial_windows, iw);
+ }
+ else
+ {
+ iw = g_list_last (options->initial_windows)->data;
+ }
+
+ g_assert (iw->tabs);
+
+ return iw;
+}
+
+static InitialTab*
+ensure_top_tab (TerminalOptions *options)
+{
+ InitialWindow *iw;
+ InitialTab *it;
+
+ iw = ensure_top_window (options);
+
+ g_assert (iw->tabs);
+
+ it = g_list_last (iw->tabs)->data;
+
+ return it;
+}
+
+static InitialWindow*
+add_new_window (TerminalOptions *options,
+ const char *profile,
+ gboolean is_id)
+{
+ InitialWindow *iw;
+
+ iw = initial_window_new (0);
+ iw->tabs = g_list_prepend (NULL, initial_tab_new (profile, is_id));
+ apply_defaults (options, iw);
+
+ options->initial_windows = g_list_append (options->initial_windows, iw);
+
+ return iw;
+}
+
+/* handle deprecated command line options */
+static gboolean
+unsupported_option_callback (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ g_printerr (_("Option \"%s\" is no longer supported in this version of mate-terminal;"
+ " you might want to create a profile with the desired setting, and use"
+ " the new '--profile' option\n"), option_name);
+ return TRUE; /* we do not want to bail out here but continue */
+}
+
+
+static gboolean G_GNUC_NORETURN
+option_version_cb (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ g_print ("%s %s\n", _("MATE Terminal"), VERSION);
+
+ exit (EXIT_SUCCESS);
+}
+
+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;
+
+ 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;
+
+ if (options->initial_windows)
+ {
+ InitialTab *it = ensure_top_tab (options);
+
+ g_free (it->profile);
+ it->profile = g_strdup (value);
+ it->profile_is_id = FALSE;
+ }
+ else
+ {
+ g_free (options->default_profile);
+ options->default_profile = g_strdup (value);
+ options->default_profile_is_id = FALSE;
+ }
+
+ return TRUE;
+}
+
+static gboolean
+option_profile_id_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->profile);
+ it->profile = g_strdup (value);
+ it->profile_is_id = TRUE;
+ }
+ else
+ {
+ g_free (options->default_profile);
+ options->default_profile = g_strdup (value);
+ options->default_profile_is_id = TRUE;
+ }
+
+ return TRUE;
+}
+
+
+static gboolean
+option_window_callback (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ TerminalOptions *options = data;
+ gboolean is_profile_id;
+
+ is_profile_id = g_str_has_suffix (option_name, "-with-profile-internal-id");
+
+ add_new_window (options, value, is_profile_id);
+
+ return TRUE;
+}
+
+static gboolean
+option_tab_callback (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ TerminalOptions *options = data;
+ gboolean is_profile_id;
+
+ is_profile_id = g_str_has_suffix (option_name, "-with-profile-internal-id");
+
+ if (options->initial_windows)
+ {
+ InitialWindow *iw;
+
+ iw = g_list_last (options->initial_windows)->data;
+ iw->tabs = g_list_append (iw->tabs, initial_tab_new (value, is_profile_id));
+ }
+ else
+ add_new_window (options, value, is_profile_id);
+
+ 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)
+ {
+ g_printerr (_("\"%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)
+ {
+ g_printerr (_("\"%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_disable_factory_callback (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ TerminalOptions *options = data;
+
+ options->use_factory = FALSE;
+
+ return TRUE;
+}
+
+static gboolean
+option_load_save_config_cb (const gchar *option_name,
+ const gchar *value,
+ gpointer data,
+ GError **error)
+{
+ TerminalOptions *options = data;
+
+ if (options->config_file)
+ {
+ g_set_error_literal (error, TERMINAL_OPTION_ERROR, TERMINAL_OPTION_ERROR_EXCLUSIVE_OPTIONS,
+ "Options \"--load-config\" and \"--save-config\" are mutually exclusive");
+ return FALSE;
+ }
+
+ options->config_file = terminal_util_resolve_relative_path (options->default_working_dir, value);
+ options->load_config = strcmp (option_name, "--load-config") == 0;
+ options->save_config = strcmp (option_name, "--save-config") == 0;
+
+ return TRUE;
+}
+
+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_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))
+ {
+ g_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))
+ {
+ g_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;
+
+ 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:
+ * @working_directory: the default working directory
+ * @display_name: the default X display name
+ * @startup_id: the startup notification ID
+ * @env: the environment as variable=value pairs
+ * @remote_arguments: whether the caller is the factory process or not
+ * @ignore_unknown_options: whether to ignore unknown options when parsing
+ * the arguments
+ * @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
+ * @...: a %NULL terminated list of extra #GOptionGroup<!-- -->s
+ *
+ * Parses the argument vector *@argvp.
+ *
+ * Returns: a new #TerminalOptions containing the windows and tabs to open,
+ * or %NULL on error.
+ */
+TerminalOptions *
+terminal_options_parse (const char *working_directory,
+ const char *display_name,
+ const char *startup_id,
+ char **env,
+ gboolean remote_arguments,
+ gboolean ignore_unknown_options,
+ int *argcp,
+ char ***argvp,
+ GError **error,
+ ...)
+{
+ TerminalOptions *options;
+ GOptionContext *context;
+ GOptionGroup *extra_group;
+ va_list va_args;
+ gboolean retval;
+ int i;
+ char **argv = *argvp;
+
+ options = g_slice_new0 (TerminalOptions);
+
+ options->remote_arguments = remote_arguments;
+ options->default_window_menubar_forced = FALSE;
+ options->default_window_menubar_state = TRUE;
+ options->default_fullscreen = FALSE;
+ options->default_maximize = FALSE;
+ options->execute = FALSE;
+ options->use_factory = TRUE;
+
+ options->env = g_strdupv (env);
+ options->startup_id = g_strdup (startup_id && startup_id[0] ? startup_id : NULL);
+ options->display_name = g_strdup (display_name);
+ options->initial_windows = NULL;
+ options->default_role = NULL;
+ options->default_geometry = NULL;
+ options->default_title = NULL;
+ options->zoom = 1.0;
+
+ options->screen_number = -1;
+ options->default_working_dir = g_strdup (working_directory);
+
+ /* 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;
+
+ 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);
+
+ g_option_context_set_ignore_unknown_options (context, ignore_unknown_options);
+
+ va_start (va_args, error);
+ extra_group = va_arg (va_args, GOptionGroup*);
+ while (extra_group != NULL)
+ {
+ g_option_context_add_group (context, extra_group);
+ extra_group = va_arg (va_args, GOptionGroup*);
+ }
+ va_end (va_args);
+
+ retval = g_option_context_parse (context, argcp, argvp, error);
+ g_option_context_free (context);
+
+ if (retval)
+ return options;
+
+ terminal_options_free (options);
+ return NULL;
+}
+
+/**
+ * terminal_options_merge_config:
+ * @options:
+ * @key_file: a #GKeyFile containing to merge the options from
+ * @source_tag: a source_tag to use in new #InitialWindow<!-- -->s
+ * @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 **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_defaults (options, iw);
+
+ 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, TRUE);
+ g_free (profile);
+
+ iw->tabs = g_list_append (iw->tabs, it);
+
+/* 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_strfreev (tab_groups);
+
+ if (have_error)
+ break;
+ }
+
+ g_strfreev (groups);
+
+ if (have_error)
+ {
+ g_list_foreach (initial_windows, (GFunc) initial_window_free, NULL);
+ g_list_free (initial_windows);
+ 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)
+{
+ ensure_top_window (options);
+}
+
+/**
+ * terminal_options_free:
+ * @options:
+ *
+ * Frees @options.
+ */
+void
+terminal_options_free (TerminalOptions *options)
+{
+ g_list_foreach (options->initial_windows, (GFunc) initial_window_free, NULL);
+ g_list_free (options->initial_windows);
+
+ g_strfreev (options->env);
+ 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->display_name);
+ g_free (options->startup_id);
+
+ g_slice_free (TerminalOptions, options);
+}
+
+static GOptionContext *
+get_goption_context (TerminalOptions *options)
+{
+ const GOptionEntry global_unique_goptions[] = {
+ {
+ "disable-factory",
+ 0,
+ G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ option_disable_factory_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_save_config_cb,
+ N_("Load a terminal configuration file"),
+ N_("FILE")
+ },
+ {
+ "save-config",
+ 0,
+ G_OPTION_FLAG_FILENAME,
+ G_OPTION_ARG_CALLBACK,
+ option_load_save_config_cb,
+ N_("Save the terminal configuration to a file"),
+ N_("FILE")
+ },
+ { "version", 0, G_OPTION_FLAG_NO_ARG | G_OPTION_FLAG_HIDDEN, G_OPTION_ARG_CALLBACK, option_version_cb, NULL, 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_("Maximise 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 (ROWSxCOLS+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 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")
+ },
+ {
+ "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_HIDDEN,
+ G_OPTION_ARG_NONE,
+ &options->use_factory,
+ NULL, NULL
+ },
+ {
+ "startup-id",
+ 0,
+ G_OPTION_FLAG_HIDDEN,
+ G_OPTION_ARG_STRING,
+ &options->startup_id,
+ NULL,
+ NULL
+ },
+ /*
+ * Crappy old compat args
+ */
+ {
+ "tclass",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "font",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "nologin",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "login",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "foreground",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "background",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "solid",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "bgscroll",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "bgnoscroll",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "shaded",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "noshaded",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "transparent",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "utmp",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "noutmp",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "wtmp",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "nowtmp",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "lastlog",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "nolastlog",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "icon",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "termname",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ {
+ "start-factory-server",
+ 0,
+ G_OPTION_FLAG_HIDDEN | G_OPTION_FLAG_NO_ARG,
+ G_OPTION_ARG_CALLBACK,
+ unsupported_option_callback,
+ NULL, NULL
+ },
+ { NULL, 0, 0, 0, NULL, NULL, NULL }
+ };
+
+ GOptionContext *context;
+ GOptionGroup *group;
+
+ context = g_option_context_new (NULL);
+ g_option_context_set_translation_domain (context, GETTEXT_PACKAGE);
+ g_option_context_set_description (context, N_("MATE Terminal Emulator"));
+
+ group = g_option_group_new ("mate-terminal",
+ N_("MATE Terminal Emulator"),
+ N_("Show MATE 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);
+
+ return context;
+}
diff --git a/src/terminal-options.h b/src/terminal-options.h
new file mode 100644
index 0000000..2094ddc
--- /dev/null
+++ b/src/terminal-options.h
@@ -0,0 +1,118 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2002 Sun Microsystems
+ * Copyright © 2003 Mariano Suarez-Alvarez
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#ifndef TERMINAL_OPTIONS_H
+#define TERMINAL_OPTIONS_H
+
+#include <glib.h>
+
+G_BEGIN_DECLS
+
+typedef struct
+{
+ gboolean remote_arguments;
+ char **env;
+ char *startup_id;
+ char *display_name;
+ int screen_number;
+ GList *initial_windows;
+ gboolean default_window_menubar_forced;
+ gboolean default_window_menubar_state;
+ gboolean default_fullscreen;
+ gboolean default_maximize;
+ 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 execute;
+ gboolean use_factory;
+ double zoom;
+
+ char *config_file;
+ gboolean load_config;
+ gboolean save_config;
+} TerminalOptions;
+
+typedef struct
+{
+ char *profile;
+ gboolean profile_is_id;
+ char **exec_argv;
+ char *title;
+ char *working_dir;
+ double zoom;
+ guint zoom_set : 1;
+ guint active : 1;
+} InitialTab;
+
+typedef struct
+{
+ guint source_tag;
+
+ 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_IN_FACTORY,
+ TERMINAL_OPTION_ERROR_EXCLUSIVE_OPTIONS,
+ TERMINAL_OPTION_ERROR_INVALID_CONFIG_FILE,
+ TERMINAL_OPTION_ERROR_INCOMPATIBLE_CONFIG_FILE
+} TerminalOptionError;
+
+TerminalOptions *terminal_options_parse (const char *working_directory,
+ const char *display_name,
+ const char *startup_id,
+ char **env,
+ gboolean remote_arguments,
+ gboolean ignore_unknown_options,
+ int *argcp,
+ char ***argvp,
+ GError **error,
+ ...) G_GNUC_NULL_TERMINATED;
+
+gboolean terminal_options_merge_config (TerminalOptions *options,
+ GKeyFile *key_file,
+ guint source_tag,
+ GError **error);
+
+void terminal_options_ensure_window (TerminalOptions *options);
+
+void terminal_options_free (TerminalOptions *options);
+
+G_END_DECLS
+
+#endif /* !TERMINAL_OPTIONS_H */
diff --git a/src/terminal-profile.c b/src/terminal-profile.c
new file mode 100644
index 0000000..61bab09
--- /dev/null
+++ b/src/terminal-profile.c
@@ -0,0 +1,1690 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2002 Mathias Hasselmann
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include <mateconf/mateconf-client.h>
+
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-intl.h"
+#include "terminal-profile.h"
+#include "terminal-screen.h"
+#include "terminal-type-builtins.h"
+
+/* To add a new key, you need to:
+ *
+ * - add an entry to the enum below
+ * - add a #define with its name in terminal-profile.h
+ * - add a gobject property for it in terminal_profile_class_init
+ * - if the property's type needs special casing, add that to
+ * terminal_profile_mateconf_notify_cb and
+ * terminal_profile_mateconf_changeset_add
+ * - if necessary the default value cannot be handled via the paramspec,
+ * handle that in terminal_profile_reset_property_internal
+ */
+enum
+{
+ PROP_0,
+ PROP_ALLOW_BOLD,
+ PROP_BACKGROUND_COLOR,
+ PROP_BACKGROUND_DARKNESS,
+ PROP_BACKGROUND_IMAGE,
+ PROP_BACKGROUND_IMAGE_FILE,
+ PROP_BACKGROUND_TYPE,
+ PROP_BACKSPACE_BINDING,
+ PROP_BOLD_COLOR,
+ PROP_BOLD_COLOR_SAME_AS_FG,
+ PROP_CURSOR_BLINK_MODE,
+ PROP_CURSOR_SHAPE,
+ PROP_CUSTOM_COMMAND,
+ PROP_DEFAULT_SIZE_COLUMNS,
+ PROP_DEFAULT_SIZE_ROWS,
+ PROP_DEFAULT_SHOW_MENUBAR,
+ PROP_DELETE_BINDING,
+ PROP_EXIT_ACTION,
+ PROP_FONT,
+ PROP_FOREGROUND_COLOR,
+ PROP_LOGIN_SHELL,
+ PROP_NAME,
+ PROP_PALETTE,
+ PROP_SCROLL_BACKGROUND,
+ PROP_SCROLLBACK_LINES,
+ PROP_SCROLLBACK_UNLIMITED,
+ PROP_SCROLLBAR_POSITION,
+ PROP_SCROLL_ON_KEYSTROKE,
+ PROP_SCROLL_ON_OUTPUT,
+ PROP_SILENT_BELL,
+ PROP_TITLE,
+ PROP_TITLE_MODE,
+ PROP_UPDATE_RECORDS,
+ PROP_USE_CUSTOM_COMMAND,
+ PROP_USE_CUSTOM_DEFAULT_SIZE,
+ PROP_USE_SKEY,
+ PROP_USE_SYSTEM_FONT,
+ PROP_USE_THEME_COLORS,
+ PROP_VISIBLE_NAME,
+ PROP_WORD_CHARS,
+ LAST_PROP
+};
+
+#define KEY_ALLOW_BOLD "allow_bold"
+#define KEY_BACKGROUND_COLOR "background_color"
+#define KEY_BACKGROUND_DARKNESS "background_darkness"
+#define KEY_BACKGROUND_IMAGE_FILE "background_image"
+#define KEY_BACKGROUND_TYPE "background_type"
+#define KEY_BACKSPACE_BINDING "backspace_binding"
+#define KEY_BOLD_COLOR "bold_color"
+#define KEY_BOLD_COLOR_SAME_AS_FG "bold_color_same_as_fg"
+#define KEY_CURSOR_BLINK_MODE "cursor_blink_mode"
+#define KEY_CURSOR_SHAPE "cursor_shape"
+#define KEY_CUSTOM_COMMAND "custom_command"
+#define KEY_DEFAULT_SHOW_MENUBAR "default_show_menubar"
+#define KEY_DEFAULT_SIZE_COLUMNS "default_size_columns"
+#define KEY_DEFAULT_SIZE_ROWS "default_size_rows"
+#define KEY_DELETE_BINDING "delete_binding"
+#define KEY_EXIT_ACTION "exit_action"
+#define KEY_FONT "font"
+#define KEY_FOREGROUND_COLOR "foreground_color"
+#define KEY_LOGIN_SHELL "login_shell"
+#define KEY_PALETTE "palette"
+#define KEY_SCROLL_BACKGROUND "scroll_background"
+#define KEY_SCROLLBACK_LINES "scrollback_lines"
+#define KEY_SCROLLBACK_UNLIMITED "scrollback_unlimited"
+#define KEY_SCROLLBAR_POSITION "scrollbar_position"
+#define KEY_SCROLL_ON_KEYSTROKE "scroll_on_keystroke"
+#define KEY_SCROLL_ON_OUTPUT "scroll_on_output"
+#define KEY_SILENT_BELL "silent_bell"
+#define KEY_TITLE_MODE "title_mode"
+#define KEY_TITLE "title"
+#define KEY_UPDATE_RECORDS "update_records"
+#define KEY_USE_CUSTOM_COMMAND "use_custom_command"
+#define KEY_USE_CUSTOM_DEFAULT_SIZE "use_custom_default_size"
+#define KEY_USE_SKEY "use_skey"
+#define KEY_USE_SYSTEM_FONT "use_system_font"
+#define KEY_USE_THEME_COLORS "use_theme_colors"
+#define KEY_VISIBLE_NAME "visible_name"
+#define KEY_WORD_CHARS "word_chars"
+
+/* Keep these in sync with the MateConf schema! */
+#define DEFAULT_ALLOW_BOLD (TRUE)
+#define DEFAULT_BACKGROUND_COLOR ("#FFFFDD")
+#define DEFAULT_BOLD_COLOR_SAME_AS_FG (TRUE)
+#define DEFAULT_BACKGROUND_DARKNESS (0.5)
+#define DEFAULT_BACKGROUND_IMAGE_FILE ("")
+#define DEFAULT_BACKGROUND_IMAGE (NULL)
+#define DEFAULT_BACKGROUND_TYPE (TERMINAL_BACKGROUND_SOLID)
+#define DEFAULT_BACKSPACE_BINDING (VTE_ERASE_ASCII_DELETE)
+#define DEFAULT_CURSOR_BLINK_MODE (VTE_CURSOR_BLINK_SYSTEM)
+#define DEFAULT_CURSOR_SHAPE (VTE_CURSOR_SHAPE_BLOCK)
+#define DEFAULT_CUSTOM_COMMAND ("")
+#define DEFAULT_DEFAULT_SHOW_MENUBAR (TRUE)
+#define DEFAULT_DEFAULT_SIZE_COLUMNS (80)
+#define DEFAULT_DEFAULT_SIZE_ROWS (24)
+#define DEFAULT_DELETE_BINDING (VTE_ERASE_DELETE_SEQUENCE)
+#define DEFAULT_EXIT_ACTION (TERMINAL_EXIT_CLOSE)
+#define DEFAULT_FONT ("Monospace 12")
+#define DEFAULT_FOREGROUND_COLOR ("#000000")
+#define DEFAULT_LOGIN_SHELL (FALSE)
+#define DEFAULT_NAME (NULL)
+#define DEFAULT_PALETTE (terminal_palettes[TERMINAL_PALETTE_TANGO])
+#define DEFAULT_SCROLL_BACKGROUND (TRUE)
+#define DEFAULT_SCROLLBACK_LINES (512)
+#define DEFAULT_SCROLLBACK_UNLIMITED (FALSE)
+#define DEFAULT_SCROLLBAR_POSITION (TERMINAL_SCROLLBAR_RIGHT)
+#define DEFAULT_SCROLL_ON_KEYSTROKE (TRUE)
+#define DEFAULT_SCROLL_ON_OUTPUT (FALSE)
+#define DEFAULT_SILENT_BELL (FALSE)
+#define DEFAULT_TITLE_MODE (TERMINAL_TITLE_REPLACE)
+#define DEFAULT_TITLE (N_("Terminal"))
+#define DEFAULT_UPDATE_RECORDS (TRUE)
+#define DEFAULT_USE_CUSTOM_COMMAND (FALSE)
+#define DEFAULT_USE_CUSTOM_DEFAULT_SIZE (FALSE)
+#define DEFAULT_USE_SKEY (TRUE)
+#define DEFAULT_USE_SYSTEM_FONT (TRUE)
+#define DEFAULT_USE_THEME_COLORS (TRUE)
+#define DEFAULT_VISIBLE_NAME (N_("Unnamed"))
+#define DEFAULT_WORD_CHARS ("-A-Za-z0-9,./?%&#:_=+@~")
+
+struct _TerminalProfilePrivate
+{
+ GValueArray *properties;
+ gboolean *locked;
+
+ MateConfClient *conf;
+ char *profile_dir;
+ guint notify_id;
+
+ GSList *dirty_pspecs;
+ guint save_idle_id;
+
+ GParamSpec *mateconf_notification_pspec;
+
+ gboolean background_load_failed;
+
+ guint forgotten : 1;
+};
+
+/* We have to continue to use these since they're unfortunately different
+ * from the value nicks of the vte_terminal_erase_binding_get_type() enum type.
+ */
+static const MateConfEnumStringPair erase_bindings[] = {
+ { VTE_ERASE_AUTO, "auto" },
+ { VTE_ERASE_ASCII_BACKSPACE, "control-h" },
+ { VTE_ERASE_ASCII_DELETE, "ascii-del" },
+ { VTE_ERASE_DELETE_SEQUENCE, "escape-sequence" },
+ { VTE_ERASE_TTY, "tty" },
+ { -1, NULL }
+};
+
+static const GdkColor terminal_palettes[TERMINAL_PALETTE_N_BUILTINS][TERMINAL_PALETTE_SIZE] =
+{
+ /* Tango palette */
+ {
+ { 0, 0x0000, 0x0000, 0x0000 },
+ { 0, 0xcccc, 0x0000, 0x0000 },
+ { 0, 0x4e4e, 0x9a9a, 0x0606 },
+ { 0, 0xc4c4, 0xa0a0, 0x0000 },
+ { 0, 0x3434, 0x6565, 0xa4a4 },
+ { 0, 0x7575, 0x5050, 0x7b7b },
+ { 0, 0x0606, 0x9820, 0x9a9a },
+ { 0, 0xd3d3, 0xd7d7, 0xcfcf },
+ { 0, 0x5555, 0x5757, 0x5353 },
+ { 0, 0xefef, 0x2929, 0x2929 },
+ { 0, 0x8a8a, 0xe2e2, 0x3434 },
+ { 0, 0xfcfc, 0xe9e9, 0x4f4f },
+ { 0, 0x7272, 0x9f9f, 0xcfcf },
+ { 0, 0xadad, 0x7f7f, 0xa8a8 },
+ { 0, 0x3434, 0xe2e2, 0xe2e2 },
+ { 0, 0xeeee, 0xeeee, 0xecec }
+ },
+
+ /* Linux palette */
+ {
+ { 0, 0x0000, 0x0000, 0x0000 },
+ { 0, 0xaaaa, 0x0000, 0x0000 },
+ { 0, 0x0000, 0xaaaa, 0x0000 },
+ { 0, 0xaaaa, 0x5555, 0x0000 },
+ { 0, 0x0000, 0x0000, 0xaaaa },
+ { 0, 0xaaaa, 0x0000, 0xaaaa },
+ { 0, 0x0000, 0xaaaa, 0xaaaa },
+ { 0, 0xaaaa, 0xaaaa, 0xaaaa },
+ { 0, 0x5555, 0x5555, 0x5555 },
+ { 0, 0xffff, 0x5555, 0x5555 },
+ { 0, 0x5555, 0xffff, 0x5555 },
+ { 0, 0xffff, 0xffff, 0x5555 },
+ { 0, 0x5555, 0x5555, 0xffff },
+ { 0, 0xffff, 0x5555, 0xffff },
+ { 0, 0x5555, 0xffff, 0xffff },
+ { 0, 0xffff, 0xffff, 0xffff }
+ },
+
+ /* XTerm palette */
+ {
+ { 0, 0x0000, 0x0000, 0x0000 },
+ { 0, 0xcdcb, 0x0000, 0x0000 },
+ { 0, 0x0000, 0xcdcb, 0x0000 },
+ { 0, 0xcdcb, 0xcdcb, 0x0000 },
+ { 0, 0x1e1a, 0x908f, 0xffff },
+ { 0, 0xcdcb, 0x0000, 0xcdcb },
+ { 0, 0x0000, 0xcdcb, 0xcdcb },
+ { 0, 0xe5e2, 0xe5e2, 0xe5e2 },
+ { 0, 0x4ccc, 0x4ccc, 0x4ccc },
+ { 0, 0xffff, 0x0000, 0x0000 },
+ { 0, 0x0000, 0xffff, 0x0000 },
+ { 0, 0xffff, 0xffff, 0x0000 },
+ { 0, 0x4645, 0x8281, 0xb4ae },
+ { 0, 0xffff, 0x0000, 0xffff },
+ { 0, 0x0000, 0xffff, 0xffff },
+ { 0, 0xffff, 0xffff, 0xffff }
+ },
+
+ /* RXVT palette */
+ {
+ { 0, 0x0000, 0x0000, 0x0000 },
+ { 0, 0xcdcd, 0x0000, 0x0000 },
+ { 0, 0x0000, 0xcdcd, 0x0000 },
+ { 0, 0xcdcd, 0xcdcd, 0x0000 },
+ { 0, 0x0000, 0x0000, 0xcdcd },
+ { 0, 0xcdcd, 0x0000, 0xcdcd },
+ { 0, 0x0000, 0xcdcd, 0xcdcd },
+ { 0, 0xfafa, 0xebeb, 0xd7d7 },
+ { 0, 0x4040, 0x4040, 0x4040 },
+ { 0, 0xffff, 0x0000, 0x0000 },
+ { 0, 0x0000, 0xffff, 0x0000 },
+ { 0, 0xffff, 0xffff, 0x0000 },
+ { 0, 0x0000, 0x0000, 0xffff },
+ { 0, 0xffff, 0x0000, 0xffff },
+ { 0, 0x0000, 0xffff, 0xffff },
+ { 0, 0xffff, 0xffff, 0xffff }
+ }
+};
+
+static const GdkColor default_fg_color = { 0, 0, 0, 0 };
+static const GdkColor default_bg_color = { 0, 0xffff, 0xffff, 0xdddd };
+
+enum
+{
+ FORGOTTEN,
+ LAST_SIGNAL
+};
+
+static void terminal_profile_finalize (GObject *object);
+static void terminal_profile_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec);
+static void ensure_pixbuf_property (TerminalProfile *profile,
+ guint path_prop_id,
+ guint pixbuf_prop_id,
+ gboolean *load_failed);
+
+static guint signals[LAST_SIGNAL];
+static GQuark mateconf_key_quark;
+
+G_DEFINE_TYPE (TerminalProfile, terminal_profile, G_TYPE_OBJECT);
+
+static gboolean
+palette_cmp (const GdkColor *ca,
+ const GdkColor *cb)
+{
+ guint i;
+
+ for (i = 0; i < TERMINAL_PALETTE_SIZE; ++i)
+ if (!gdk_color_equal (&ca[i], &cb[i]))
+ return FALSE;
+
+ return TRUE;
+}
+
+static GParamSpec *
+get_pspec_from_name (TerminalProfile *profile,
+ const char *prop_name)
+{
+ TerminalProfileClass *klass = TERMINAL_PROFILE_GET_CLASS (profile);
+ GParamSpec *pspec;
+
+ pspec = g_object_class_find_property (G_OBJECT_CLASS (klass), prop_name);
+ if (pspec &&
+ pspec->owner_type != TERMINAL_TYPE_PROFILE)
+ pspec = NULL;
+
+ return pspec;
+}
+
+static const GValue *
+get_prop_value_from_prop_name (TerminalProfile *profile,
+ const char *prop_name)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ GParamSpec *pspec;
+
+ pspec = get_pspec_from_name (profile, prop_name);
+ if (!pspec)
+ return NULL;
+
+ if (G_UNLIKELY (pspec->param_id == PROP_BACKGROUND_IMAGE))
+ ensure_pixbuf_property (profile, PROP_BACKGROUND_IMAGE_FILE, PROP_BACKGROUND_IMAGE, &priv->background_load_failed);
+
+ return g_value_array_get_nth (priv->properties, pspec->param_id);
+}
+
+static void
+set_value_from_palette (GValue *ret_value,
+ const GdkColor *colors,
+ guint n_colors)
+{
+ GValueArray *array;
+ guint i, max_n_colors;
+
+ max_n_colors = MAX (n_colors, TERMINAL_PALETTE_SIZE);
+ array = g_value_array_new (max_n_colors);
+ for (i = 0; i < max_n_colors; ++i)
+ g_value_array_append (array, NULL);
+
+ for (i = 0; i < n_colors; ++i)
+ {
+ GValue *value = g_value_array_get_nth (array, i);
+
+ g_value_init (value, GDK_TYPE_COLOR);
+ g_value_set_boxed (value, &colors[i]);
+ }
+
+ /* If we haven't enough colours yet, fill up with the default palette */
+ for (i = n_colors; i < TERMINAL_PALETTE_SIZE; ++i)
+ {
+ GValue *value = g_value_array_get_nth (array, i);
+
+ g_value_init (value, GDK_TYPE_COLOR);
+ g_value_set_boxed (value, &DEFAULT_PALETTE[i]);
+ }
+
+ g_value_take_boxed (ret_value, array);
+}
+
+static int
+values_equal (GParamSpec *pspec,
+ const GValue *va,
+ const GValue *vb)
+{
+ /* g_param_values_cmp isn't good enough for some types, since e.g.
+ * it compares colours and font descriptions by pointer value, not
+ * with the correct compare functions. Providing extra
+ * PangoParamSpecFontDescription and GdkParamSpecColor wouldn't
+ * have fixed this either, since it's unclear how to _order_ them.
+ * Luckily we only need to check them for equality here.
+ */
+
+ if (g_param_values_cmp (pspec, va, vb) == 0)
+ return TRUE;
+
+ if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
+ return gdk_color_equal (g_value_get_boxed (va), g_value_get_boxed (vb));
+
+ if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
+ return pango_font_description_equal (g_value_get_boxed (va), g_value_get_boxed (vb));
+
+ if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
+ G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
+ {
+ GValueArray *ara, *arb;
+ guint i;
+
+ ara = g_value_get_boxed (va);
+ arb = g_value_get_boxed (vb);
+
+ if (!ara || !arb || ara->n_values != arb->n_values)
+ return FALSE;
+
+ for (i = 0; i < ara->n_values; ++i)
+ if (!gdk_color_equal (g_value_get_boxed (g_value_array_get_nth (ara, i)),
+ g_value_get_boxed (g_value_array_get_nth (arb, i))))
+ return FALSE;
+
+ return TRUE;
+ }
+
+ return FALSE;
+}
+
+static void
+ensure_pixbuf_property (TerminalProfile *profile,
+ guint path_prop_id,
+ guint pixbuf_prop_id,
+ gboolean *load_failed)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ GValue *path_value, *pixbuf_value;
+ GdkPixbuf *pixbuf;
+ const char *path_utf8;
+ char *path;
+ GError *error = NULL;
+
+ pixbuf_value = g_value_array_get_nth (priv->properties, pixbuf_prop_id);
+
+ pixbuf = g_value_get_object (pixbuf_value);
+ if (pixbuf)
+ return;
+
+ if (*load_failed)
+ return;
+
+ path_value = g_value_array_get_nth (priv->properties, path_prop_id);
+ path_utf8 = g_value_get_string (path_value);
+ if (!path_utf8 || !path_utf8[0])
+ goto failed;
+
+ path = g_filename_from_utf8 (path_utf8, -1, NULL, NULL, NULL);
+ if (!path)
+ goto failed;
+
+ pixbuf = gdk_pixbuf_new_from_file (path, &error);
+ if (!pixbuf)
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "Failed to load image \"%s\": %s\n",
+ path, error->message);
+
+ g_error_free (error);
+ g_free (path);
+ goto failed;
+ }
+
+ g_value_take_object (pixbuf_value, pixbuf);
+ g_free (path);
+ return;
+
+failed:
+ *load_failed = TRUE;
+}
+
+static void
+terminal_profile_reset_property_internal (TerminalProfile *profile,
+ GParamSpec *pspec,
+ gboolean notify)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ GValue value_ = { 0, };
+ GValue *value;
+
+ if (notify)
+ {
+ value = &value_;
+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+ }
+ else
+ value = g_value_array_get_nth (priv->properties, pspec->param_id);
+ g_assert (value != NULL);
+
+ /* A few properties don't have defaults via the param spec; set them explicitly */
+ switch (pspec->param_id)
+ {
+ case PROP_FOREGROUND_COLOR:
+ case PROP_BOLD_COLOR:
+ g_value_set_boxed (value, &DEFAULT_FOREGROUND_COLOR);
+ break;
+
+ case PROP_BACKGROUND_COLOR:
+ g_value_set_boxed (value, &DEFAULT_BACKGROUND_COLOR);
+ break;
+
+ case PROP_FONT:
+ g_value_take_boxed (value, pango_font_description_from_string (DEFAULT_FONT));
+ break;
+
+ case PROP_PALETTE:
+ set_value_from_palette (value, DEFAULT_PALETTE, TERMINAL_PALETTE_SIZE);
+ break;
+
+ default:
+ g_param_value_set_default (pspec, value);
+ break;
+ }
+
+ if (notify)
+ {
+ g_object_set_property (G_OBJECT (profile), pspec->name, value);
+ g_value_unset (value);
+ }
+}
+
+static void
+terminal_profile_mateconf_notify_cb (MateConfClient *client,
+ guint cnxn_id,
+ MateConfEntry *entry,
+ gpointer user_data)
+{
+ TerminalProfile *profile = TERMINAL_PROFILE (user_data);
+ TerminalProfilePrivate *priv = profile->priv;
+ TerminalProfileClass *klass;
+ const char *key;
+ MateConfValue *mateconf_value;
+ GParamSpec *pspec;
+ GValue value = { 0, };
+ gboolean equal;
+ gboolean force_set = FALSE;
+
+ key = mateconf_entry_get_key (entry);
+ if (!key || !g_str_has_prefix (key, priv->profile_dir))
+ return;
+
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "MateConf notification for key %s [%s]\n",
+ key,
+ mateconf_entry_get_is_writable (entry) ? "writable" : "LOCKED");
+
+ key += strlen (priv->profile_dir);
+ if (!key[0])
+ return;
+
+ key++;
+ klass = TERMINAL_PROFILE_GET_CLASS (profile);
+ pspec = g_hash_table_lookup (klass->mateconf_keys, key);
+ if (!pspec)
+ return; /* ignore unknown keys, for future extensibility */
+
+ priv->locked[pspec->param_id] = !mateconf_entry_get_is_writable (entry);
+
+ mateconf_value = mateconf_entry_get_value (entry);
+ if (!mateconf_value)
+ return;
+
+ g_value_init (&value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+ {
+ if (mateconf_value->type != MATECONF_VALUE_BOOL)
+ goto out;
+
+ g_value_set_boolean (&value, mateconf_value_get_bool (mateconf_value));
+ }
+ else if (G_IS_PARAM_SPEC_STRING (pspec))
+ {
+ if (mateconf_value->type != MATECONF_VALUE_STRING)
+ goto out;
+
+ g_value_set_string (&value, mateconf_value_get_string (mateconf_value));
+ }
+ else if (G_IS_PARAM_SPEC_ENUM (pspec))
+ {
+ const GEnumValue *eval;
+ int enum_value;
+
+ if (mateconf_value->type != MATECONF_VALUE_STRING)
+ goto out;
+
+ eval = g_enum_get_value_by_nick (G_PARAM_SPEC_ENUM (pspec)->enum_class,
+ mateconf_value_get_string (mateconf_value));
+ if (eval)
+ enum_value = eval->value;
+ else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == vte_terminal_erase_binding_get_type ())
+ {
+ /* Backward compatibility */
+ if (!mateconf_string_to_enum ((MateConfEnumStringPair*) erase_bindings,
+ mateconf_value_get_string (mateconf_value),
+ &enum_value))
+ goto out;
+ }
+ else
+ goto out;
+
+ g_value_set_enum (&value, enum_value);
+ }
+ else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
+ {
+ GdkColor color;
+
+ if (mateconf_value->type != MATECONF_VALUE_STRING)
+ goto out;
+
+ if (!gdk_color_parse (mateconf_value_get_string (mateconf_value), &color))
+ goto out;
+
+ g_value_set_boxed (&value, &color);
+ }
+ else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
+ {
+ if (mateconf_value->type != MATECONF_VALUE_STRING)
+ goto out;
+
+ g_value_take_boxed (&value, pango_font_description_from_string (mateconf_value_get_string (mateconf_value)));
+ }
+ else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
+ {
+ if (mateconf_value->type != MATECONF_VALUE_FLOAT)
+ goto out;
+
+ g_value_set_double (&value, mateconf_value_get_float (mateconf_value));
+ }
+ else if (G_IS_PARAM_SPEC_INT (pspec))
+ {
+ if (mateconf_value->type != MATECONF_VALUE_INT)
+ goto out;
+
+ g_value_set_int (&value, mateconf_value_get_int (mateconf_value));
+ }
+ else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
+ G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
+ {
+ char **color_strings;
+ GdkColor *colors;
+ int n_colors, i;
+
+ if (mateconf_value->type != MATECONF_VALUE_STRING)
+ goto out;
+
+ color_strings = g_strsplit (mateconf_value_get_string (mateconf_value), ":", -1);
+ if (!color_strings)
+ goto out;
+
+ n_colors = g_strv_length (color_strings);
+ colors = g_new0 (GdkColor, n_colors);
+ for (i = 0; i < n_colors; ++i)
+ {
+ if (!gdk_color_parse (color_strings[i], &colors[i]))
+ continue; /* ignore errors */
+ }
+ g_strfreev (color_strings);
+
+ /* We continue even with a palette size != TERMINAL_PALETTE_SIZE,
+ * so we can change the palette size in future versions without
+ * causing too many issues.
+ */
+ set_value_from_palette (&value, colors, n_colors);
+ g_free (colors);
+ }
+ else
+ {
+ g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name);
+ goto out;
+ }
+
+ if (g_param_value_validate (pspec, &value))
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "Invalid value in mateconf for key %s was changed to comply with pspec %s\n",
+ mateconf_entry_get_key (entry), pspec->name);
+
+ force_set = TRUE;
+ }
+
+ /* Only set the property if the value is different than our current value,
+ * so we don't go into an infinite loop.
+ */
+ equal = values_equal (pspec, &value, g_value_array_get_nth (priv->properties, pspec->param_id));
+#ifdef MATE_ENABLE_DEBUG
+ _TERMINAL_DEBUG_IF (TERMINAL_DEBUG_PROFILE)
+ {
+ if (!equal)
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "Setting property %s to a different value\n"
+ " now: %s\n"
+ " new: %s\n",
+ pspec->name,
+ g_strdup_value_contents (g_value_array_get_nth (priv->properties, pspec->param_id)),
+ g_strdup_value_contents (&value));
+ }
+#endif
+
+ if (!equal || force_set)
+ {
+ priv->mateconf_notification_pspec = pspec;
+ g_object_set_property (G_OBJECT (profile), pspec->name, &value);
+ priv->mateconf_notification_pspec = NULL;
+ }
+
+out:
+ /* FIXME: if we arrive here through goto in the error cases,
+ * should we maybe reset the property to its default value?
+ */
+
+ g_value_unset (&value);
+}
+
+static void
+terminal_profile_mateconf_changeset_add (TerminalProfile *profile,
+ MateConfChangeSet *changeset,
+ GParamSpec *pspec)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ const char *mateconf_key;
+ char *key;
+ const GValue *value;
+
+ /* FIXME: do this? */
+#if 0
+ if (priv->locked[pspec->param_id])
+ return;
+
+ if (!mateconf_client_key_is_writable (priv->conf, mateconf_key, NULL))
+ return;
+#endif
+
+ mateconf_key = g_param_spec_get_qdata (pspec, mateconf_key_quark);
+ if (!mateconf_key)
+ return;
+
+ key = mateconf_concat_dir_and_key (priv->profile_dir, mateconf_key);
+ value = g_value_array_get_nth (priv->properties, pspec->param_id);
+
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "Adding pspec %s with value %s to the mateconf changeset\n",
+ pspec->name, g_strdup_value_contents (value));
+
+ if (G_IS_PARAM_SPEC_BOOLEAN (pspec))
+ mateconf_change_set_set_bool (changeset, key, g_value_get_boolean (value));
+ else if (G_IS_PARAM_SPEC_STRING (pspec))
+ {
+ const char *str;
+
+ str = g_value_get_string (value);
+ mateconf_change_set_set_string (changeset, key, str ? str : "");
+ }
+ else if (G_IS_PARAM_SPEC_ENUM (pspec))
+ {
+ const GEnumValue *eval;
+ const char *string;
+
+ eval = g_enum_get_value (G_PARAM_SPEC_ENUM (pspec)->enum_class, g_value_get_enum (value));
+
+ if (G_PARAM_SPEC_VALUE_TYPE (pspec) == vte_terminal_erase_binding_get_type ())
+ {
+ /* Backward compatibility */
+ string = mateconf_enum_to_string ((MateConfEnumStringPair*) erase_bindings, g_value_get_enum (value));
+ if (!string)
+ goto cleanup;
+ }
+ else if (eval)
+ string = eval->value_nick;
+ else
+ goto cleanup;
+
+ mateconf_change_set_set_string (changeset, key, string);
+ }
+ else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == GDK_TYPE_COLOR)
+ {
+ GdkColor *color;
+ char str[16];
+
+ color = g_value_get_boxed (value);
+ if (!color)
+ goto cleanup;
+
+ g_snprintf (str, sizeof (str),
+ "#%04X%04X%04X",
+ color->red,
+ color->green,
+ color->blue);
+
+ mateconf_change_set_set_string (changeset, key, str);
+ }
+ else if (G_PARAM_SPEC_VALUE_TYPE (pspec) == PANGO_TYPE_FONT_DESCRIPTION)
+ {
+ PangoFontDescription *font_desc;
+ char *font;
+
+ font_desc = g_value_get_boxed (value);
+ if (!font_desc)
+ goto cleanup;
+
+ font = pango_font_description_to_string (font_desc);
+ mateconf_change_set_set_string (changeset, key, font);
+ g_free (font);
+ }
+ else if (G_IS_PARAM_SPEC_DOUBLE (pspec))
+ mateconf_change_set_set_float (changeset, key, (float) g_value_get_double (value));
+ else if (G_IS_PARAM_SPEC_INT (pspec))
+ mateconf_change_set_set_int (changeset, key, g_value_get_int (value));
+ else if (G_IS_PARAM_SPEC_VALUE_ARRAY (pspec) &&
+ G_PARAM_SPEC_VALUE_TYPE (G_PARAM_SPEC_VALUE_ARRAY (pspec)->element_spec) == GDK_TYPE_COLOR)
+ {
+ GValueArray *array;
+ GString *string;
+ guint n_colors, i;
+
+ /* We need to do this ourselves, because the gtk_color_selection_palette_to_string
+ * does not carry all the bytes, and xterm's palette is messed up...
+ */
+
+ array = g_value_get_boxed (value);
+ if (!array)
+ goto cleanup;
+
+ n_colors = array->n_values;
+ string = g_string_sized_new (n_colors * (1 /* # */ + 3 * 4) + n_colors /* : separators and terminating \0 */);
+ for (i = 0; i < n_colors; ++i)
+ {
+ GdkColor *color;
+
+ if (i > 0)
+ g_string_append_c (string, ':');
+
+ color = g_value_get_boxed (g_value_array_get_nth (array, i));
+ if (!color)
+ continue;
+
+ g_string_append_printf (string,
+ "#%04X%04X%04X",
+ color->red,
+ color->green,
+ color->blue);
+ }
+
+ mateconf_change_set_set_string (changeset, key, string->str);
+ g_string_free (string, TRUE);
+ }
+ else
+ g_printerr ("Unhandled value type %s of pspec %s\n", g_type_name (G_PARAM_SPEC_VALUE_TYPE (pspec)), pspec->name);
+
+cleanup:
+ g_free (key);
+}
+
+static void
+terminal_profile_save (TerminalProfile *profile)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ MateConfChangeSet *changeset;
+ GSList *l;
+ GError *error = NULL;
+
+ priv->save_idle_id = 0;
+
+ changeset = mateconf_change_set_new ();
+
+ for (l = priv->dirty_pspecs; l != NULL; l = l->next)
+ {
+ GParamSpec *pspec = (GParamSpec *) l->data;
+
+ if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
+ continue;
+
+ if ((pspec->flags & G_PARAM_WRITABLE) == 0)
+ continue;
+
+ terminal_profile_mateconf_changeset_add (profile, changeset, pspec);
+ }
+
+ g_slist_free (priv->dirty_pspecs);
+ priv->dirty_pspecs = NULL;
+
+ if (!mateconf_client_commit_change_set (priv->conf, changeset, TRUE, &error))
+ {
+ g_message ("Failed to commit the changeset to mateconf: %s", error->message);
+ g_error_free (error);
+ }
+
+ mateconf_change_set_unref (changeset);
+}
+
+static gboolean
+terminal_profile_save_idle_cb (TerminalProfile *profile)
+{
+ terminal_profile_save (profile);
+
+ /* don't run again */
+ return FALSE;
+}
+
+static void
+terminal_profile_schedule_save (TerminalProfile *profile,
+ GParamSpec *pspec)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+
+ g_assert (pspec != NULL);
+
+ if (!g_slist_find (priv->dirty_pspecs, pspec))
+ priv->dirty_pspecs = g_slist_prepend (priv->dirty_pspecs, pspec);
+
+ if (priv->save_idle_id != 0)
+ return;
+
+ priv->save_idle_id = g_idle_add ((GSourceFunc) terminal_profile_save_idle_cb, profile);
+}
+
+static void
+terminal_profile_init (TerminalProfile *profile)
+{
+ TerminalProfilePrivate *priv;
+ GObjectClass *object_class;
+ GParamSpec **pspecs;
+ guint n_pspecs, i;
+
+ priv = profile->priv = G_TYPE_INSTANCE_GET_PRIVATE (profile, TERMINAL_TYPE_PROFILE, TerminalProfilePrivate);
+
+ priv->mateconf_notification_pspec = NULL;
+
+ priv->conf = mateconf_client_get_default ();
+
+ priv->locked = g_new0 (gboolean, LAST_PROP);
+
+ priv->properties = g_value_array_new (LAST_PROP);
+ for (i = 0; i < LAST_PROP; ++i)
+ g_value_array_append (priv->properties, NULL);
+
+ pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile)), &n_pspecs);
+ for (i = 0; i < n_pspecs; ++i)
+ {
+ GParamSpec *pspec = pspecs[i];
+ GValue *value;
+
+ if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
+ continue;
+
+ g_assert (pspec->param_id < LAST_PROP);
+ value = g_value_array_get_nth (priv->properties, pspec->param_id);
+ g_value_init (value, pspec->value_type);
+ g_param_value_set_default (pspec, value);
+ }
+
+ g_free (pspecs);
+
+ /* A few properties don't have defaults via the param spec; set them explicitly */
+ object_class = G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile));
+ terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_FOREGROUND_COLOR), FALSE);
+ terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_BOLD_COLOR), FALSE);
+ terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_BACKGROUND_COLOR), FALSE);
+ terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_FONT), FALSE);
+ terminal_profile_reset_property_internal (profile, g_object_class_find_property (object_class, TERMINAL_PROFILE_PALETTE), FALSE);
+}
+
+static GObject *
+terminal_profile_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ TerminalProfile *profile;
+ TerminalProfilePrivate *priv;
+ const char *name;
+ GParamSpec **pspecs;
+ guint n_pspecs, i;
+
+ object = G_OBJECT_CLASS (terminal_profile_parent_class)->constructor
+ (type, n_construct_properties, construct_params);
+
+ profile = TERMINAL_PROFILE (object);
+ priv = profile->priv;
+
+ name = g_value_get_string (g_value_array_get_nth (priv->properties, PROP_NAME));
+ g_assert (name != NULL);
+
+ /* Now load those properties from mateconf that were not set as construction params */
+ pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (profile)), &n_pspecs);
+ for (i = 0; i < n_pspecs; ++i)
+ {
+ GParamSpec *pspec = pspecs[i];
+ guint j;
+ gboolean is_construct = FALSE;
+ const char *mateconf_key;
+ char *key;
+
+ if (pspec->owner_type != TERMINAL_TYPE_PROFILE)
+ continue;
+
+ if ((pspec->flags & G_PARAM_WRITABLE) == 0 ||
+ (pspec->flags & G_PARAM_CONSTRUCT_ONLY) != 0)
+ continue;
+
+ for (j = 0; j < n_construct_properties; ++j)
+ if (pspec == construct_params[j].pspec)
+ {
+ is_construct = TRUE;
+ break;
+ }
+
+ if (is_construct)
+ continue;
+
+ mateconf_key = g_param_spec_get_qdata (pspec, mateconf_key_quark);
+ if (!mateconf_key)
+ continue;
+
+ key = mateconf_concat_dir_and_key (priv->profile_dir, mateconf_key);
+ mateconf_client_notify (priv->conf, key);
+ g_free (key);
+ }
+
+ g_free (pspecs);
+
+ return object;
+}
+
+static void
+terminal_profile_finalize (GObject *object)
+{
+ TerminalProfile *profile = TERMINAL_PROFILE (object);
+ TerminalProfilePrivate *priv = profile->priv;
+
+ mateconf_client_notify_remove (priv->conf, priv->notify_id);
+ priv->notify_id = 0;
+
+ if (priv->save_idle_id)
+ {
+ g_source_remove (priv->save_idle_id);
+
+ /* Save now */
+ terminal_profile_save (profile);
+ }
+
+ _terminal_profile_forget (profile);
+
+ g_object_unref (priv->conf);
+
+ g_free (priv->profile_dir);
+ g_free (priv->locked);
+ g_value_array_free (priv->properties);
+
+ G_OBJECT_CLASS (terminal_profile_parent_class)->finalize (object);
+}
+
+static void
+terminal_profile_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ TerminalProfile *profile = TERMINAL_PROFILE (object);
+ TerminalProfilePrivate *priv = profile->priv;
+
+ if (prop_id == 0 || prop_id >= LAST_PROP)
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ return;
+ }
+
+ /* Note: When adding things here, do the same in get_prop_value_from_prop_name! */
+ switch (prop_id)
+ {
+ case PROP_BACKGROUND_IMAGE:
+ ensure_pixbuf_property (profile, PROP_BACKGROUND_IMAGE_FILE, PROP_BACKGROUND_IMAGE, &priv->background_load_failed);
+ break;
+ default:
+ break;
+ }
+
+ g_value_copy (g_value_array_get_nth (priv->properties, prop_id), value);
+}
+
+static void
+terminal_profile_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TerminalProfile *profile = TERMINAL_PROFILE (object);
+ TerminalProfilePrivate *priv = profile->priv;
+ GValue *prop_value;
+
+ if (prop_id == 0 || prop_id >= LAST_PROP)
+ {
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ return;
+ }
+
+ prop_value = g_value_array_get_nth (priv->properties, prop_id);
+
+ /* Preprocessing */
+ switch (prop_id)
+ {
+#if 0
+ case PROP_FONT: {
+ PangoFontDescription *font_desc, *new_font_desc;
+
+ font_desc = g_value_get_boxed (prop_value);
+ new_font_desc = g_value_get_boxed (value);
+
+ if (font_desc && new_font_desc)
+ {
+ /* Merge in case the new string isn't complete enough to load a font */
+ pango_font_description_merge (font_desc, new_font_desc, TRUE);
+ pango_font_description_free (new_font_desc);
+ break;
+ }
+
+ /* fall-through */
+ }
+#endif
+ default:
+ g_value_copy (value, prop_value);
+ break;
+ }
+
+ /* Postprocessing */
+ switch (prop_id)
+ {
+ case PROP_NAME: {
+ const char *name = g_value_get_string (value);
+
+ g_assert (name != NULL);
+ priv->profile_dir = mateconf_concat_dir_and_key (CONF_PROFILES_PREFIX, name);
+
+ mateconf_client_add_dir (priv->conf, priv->profile_dir,
+ MATECONF_CLIENT_PRELOAD_ONELEVEL,
+ NULL);
+ priv->notify_id =
+ mateconf_client_notify_add (priv->conf,
+ priv->profile_dir,
+ terminal_profile_mateconf_notify_cb,
+ profile, NULL,
+ NULL);
+
+ break;
+ }
+
+ case PROP_BACKGROUND_IMAGE_FILE:
+ /* Clear the cached image */
+ g_value_set_object (g_value_array_get_nth (priv->properties, PROP_BACKGROUND_IMAGE), NULL);
+ priv->background_load_failed = FALSE;
+ g_object_notify (object, TERMINAL_PROFILE_BACKGROUND_IMAGE);
+ break;
+
+ default:
+ break;
+ }
+}
+
+static void
+terminal_profile_notify (GObject *object,
+ GParamSpec *pspec)
+{
+ TerminalProfilePrivate *priv = TERMINAL_PROFILE (object)->priv;
+ void (* notify) (GObject *, GParamSpec *) = G_OBJECT_CLASS (terminal_profile_parent_class)->notify;
+
+ _terminal_debug_print (TERMINAL_DEBUG_PROFILE,
+ "Property notification for prop %s\n",
+ pspec->name);
+
+ if (notify)
+ notify (object, pspec);
+
+ if (pspec->owner_type == TERMINAL_TYPE_PROFILE &&
+ (pspec->flags & G_PARAM_WRITABLE) &&
+ g_param_spec_get_qdata (pspec, mateconf_key_quark) != NULL &&
+ pspec != priv->mateconf_notification_pspec)
+ terminal_profile_schedule_save (TERMINAL_PROFILE (object), pspec);
+}
+
+static void
+terminal_profile_class_init (TerminalProfileClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ mateconf_key_quark = g_quark_from_static_string ("GT::MateConfKey");
+
+ g_type_class_add_private (object_class, sizeof (TerminalProfilePrivate));
+
+ object_class->constructor = terminal_profile_constructor;
+ object_class->finalize = terminal_profile_finalize;
+ object_class->get_property = terminal_profile_get_property;
+ object_class->set_property = terminal_profile_set_property;
+ object_class->notify = terminal_profile_notify;
+
+ signals[FORGOTTEN] =
+ g_signal_new ("forgotten",
+ G_OBJECT_CLASS_TYPE (object_class),
+ G_SIGNAL_RUN_LAST,
+ G_STRUCT_OFFSET (TerminalProfileClass, forgotten),
+ NULL, NULL,
+ g_cclosure_marshal_VOID__VOID,
+ G_TYPE_NONE, 0);
+
+ /* mateconf_key -> pspec hash */
+ klass->mateconf_keys = g_hash_table_new (g_str_hash, g_str_equal);
+
+#define TERMINAL_PROFILE_PSPEC_STATIC (G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB)
+
+#define TERMINAL_PROFILE_PROPERTY(propId, propSpec, propMateConf) \
+{\
+ GParamSpec *pspec = propSpec;\
+ g_object_class_install_property (object_class, propId, pspec);\
+\
+ if (propMateConf)\
+ {\
+ g_param_spec_set_qdata (pspec, mateconf_key_quark, (gpointer) propMateConf);\
+ g_hash_table_insert (klass->mateconf_keys, (gpointer) propMateConf, pspec);\
+ }\
+}
+
+#define TERMINAL_PROFILE_PROPERTY_BOOLEAN(prop, propDefault, propMateConf) \
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_boolean (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propDefault,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_BOXED(prop, propType, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_boxed (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propType,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_DOUBLE(prop, propMin, propMax, propDefault, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_double (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propMin, propMax, propDefault,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_ENUM(prop, propType, propDefault, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_enum (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propType, propDefault,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_INT(prop, propMin, propMax, propDefault, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_int (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propMin, propMax, propDefault,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+/* these are all read-only */
+#define TERMINAL_PROFILE_PROPERTY_OBJECT(prop, propType, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_object (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propType,\
+ G_PARAM_READABLE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_STRING(prop, propDefault, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_string (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propDefault,\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_STRING_CO(prop, propDefault, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_string (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ propDefault,\
+ G_PARAM_READWRITE | G_PARAM_CONSTRUCT_ONLY | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+#define TERMINAL_PROFILE_PROPERTY_VALUE_ARRAY_BOXED(prop, propElementName, propElementType, propMateConf)\
+ TERMINAL_PROFILE_PROPERTY (PROP_##prop,\
+ g_param_spec_value_array (TERMINAL_PROFILE_##prop, NULL, NULL,\
+ g_param_spec_boxed (propElementName, NULL, NULL,\
+ propElementType, \
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ G_PARAM_READWRITE | TERMINAL_PROFILE_PSPEC_STATIC),\
+ propMateConf)
+
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (ALLOW_BOLD, DEFAULT_ALLOW_BOLD, KEY_ALLOW_BOLD);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (BOLD_COLOR_SAME_AS_FG, DEFAULT_BOLD_COLOR_SAME_AS_FG, KEY_BOLD_COLOR_SAME_AS_FG);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (DEFAULT_SHOW_MENUBAR, DEFAULT_DEFAULT_SHOW_MENUBAR, KEY_DEFAULT_SHOW_MENUBAR);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (LOGIN_SHELL, DEFAULT_LOGIN_SHELL, KEY_LOGIN_SHELL);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_BACKGROUND, DEFAULT_SCROLL_BACKGROUND, KEY_SCROLL_BACKGROUND);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLLBACK_UNLIMITED, DEFAULT_SCROLLBACK_UNLIMITED, KEY_SCROLLBACK_UNLIMITED);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_ON_KEYSTROKE, DEFAULT_SCROLL_ON_KEYSTROKE, KEY_SCROLL_ON_KEYSTROKE);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (SCROLL_ON_OUTPUT, DEFAULT_SCROLL_ON_OUTPUT, KEY_SCROLL_ON_OUTPUT);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (SILENT_BELL, DEFAULT_SILENT_BELL, KEY_SILENT_BELL);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (UPDATE_RECORDS, DEFAULT_UPDATE_RECORDS, KEY_UPDATE_RECORDS);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_CUSTOM_COMMAND, DEFAULT_USE_CUSTOM_COMMAND, KEY_USE_CUSTOM_COMMAND);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_CUSTOM_DEFAULT_SIZE, DEFAULT_USE_CUSTOM_DEFAULT_SIZE, KEY_USE_CUSTOM_DEFAULT_SIZE);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_SKEY, DEFAULT_USE_SKEY, KEY_USE_SKEY);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_SYSTEM_FONT, DEFAULT_USE_SYSTEM_FONT, KEY_USE_SYSTEM_FONT);
+ TERMINAL_PROFILE_PROPERTY_BOOLEAN (USE_THEME_COLORS, DEFAULT_USE_THEME_COLORS, KEY_USE_THEME_COLORS);
+
+ TERMINAL_PROFILE_PROPERTY_BOXED (BACKGROUND_COLOR, GDK_TYPE_COLOR, KEY_BACKGROUND_COLOR);
+ TERMINAL_PROFILE_PROPERTY_BOXED (BOLD_COLOR, GDK_TYPE_COLOR, KEY_BOLD_COLOR);
+ TERMINAL_PROFILE_PROPERTY_BOXED (FONT, PANGO_TYPE_FONT_DESCRIPTION, KEY_FONT);
+ TERMINAL_PROFILE_PROPERTY_BOXED (FOREGROUND_COLOR, GDK_TYPE_COLOR, KEY_FOREGROUND_COLOR);
+
+ /* 0.0 = normal bg, 1.0 = all black bg, 0.5 = half darkened */
+ TERMINAL_PROFILE_PROPERTY_DOUBLE (BACKGROUND_DARKNESS, 0.0, 1.0, DEFAULT_BACKGROUND_DARKNESS, KEY_BACKGROUND_DARKNESS);
+
+ TERMINAL_PROFILE_PROPERTY_ENUM (BACKGROUND_TYPE, TERMINAL_TYPE_BACKGROUND_TYPE, DEFAULT_BACKGROUND_TYPE, KEY_BACKGROUND_TYPE);
+ TERMINAL_PROFILE_PROPERTY_ENUM (BACKSPACE_BINDING, VTE_TYPE_TERMINAL_ERASE_BINDING, DEFAULT_BACKSPACE_BINDING, KEY_BACKSPACE_BINDING);
+ TERMINAL_PROFILE_PROPERTY_ENUM (CURSOR_BLINK_MODE, VTE_TYPE_TERMINAL_CURSOR_BLINK_MODE, DEFAULT_CURSOR_BLINK_MODE, KEY_CURSOR_BLINK_MODE);
+ TERMINAL_PROFILE_PROPERTY_ENUM (CURSOR_SHAPE, VTE_TYPE_TERMINAL_CURSOR_SHAPE, DEFAULT_CURSOR_SHAPE, KEY_CURSOR_SHAPE);
+ TERMINAL_PROFILE_PROPERTY_ENUM (DELETE_BINDING, VTE_TYPE_TERMINAL_ERASE_BINDING, DEFAULT_DELETE_BINDING, KEY_DELETE_BINDING);
+ TERMINAL_PROFILE_PROPERTY_ENUM (EXIT_ACTION, TERMINAL_TYPE_EXIT_ACTION, DEFAULT_EXIT_ACTION, KEY_EXIT_ACTION);
+ TERMINAL_PROFILE_PROPERTY_ENUM (SCROLLBAR_POSITION, TERMINAL_TYPE_SCROLLBAR_POSITION, DEFAULT_SCROLLBAR_POSITION, KEY_SCROLLBAR_POSITION);
+ TERMINAL_PROFILE_PROPERTY_ENUM (TITLE_MODE, TERMINAL_TYPE_TITLE_MODE, DEFAULT_TITLE_MODE, KEY_TITLE_MODE);
+
+ TERMINAL_PROFILE_PROPERTY_INT (DEFAULT_SIZE_COLUMNS, 1, 1024, DEFAULT_DEFAULT_SIZE_COLUMNS, KEY_DEFAULT_SIZE_COLUMNS);
+ TERMINAL_PROFILE_PROPERTY_INT (DEFAULT_SIZE_ROWS, 1, 1024, DEFAULT_DEFAULT_SIZE_ROWS, KEY_DEFAULT_SIZE_ROWS);
+ TERMINAL_PROFILE_PROPERTY_INT (SCROLLBACK_LINES, 1, G_MAXINT, DEFAULT_SCROLLBACK_LINES, KEY_SCROLLBACK_LINES);
+
+ TERMINAL_PROFILE_PROPERTY_OBJECT (BACKGROUND_IMAGE, GDK_TYPE_PIXBUF, NULL);
+
+ TERMINAL_PROFILE_PROPERTY_STRING_CO (NAME, DEFAULT_NAME, NULL);
+ TERMINAL_PROFILE_PROPERTY_STRING (BACKGROUND_IMAGE_FILE, DEFAULT_BACKGROUND_IMAGE_FILE, KEY_BACKGROUND_IMAGE_FILE);
+ TERMINAL_PROFILE_PROPERTY_STRING (CUSTOM_COMMAND, DEFAULT_CUSTOM_COMMAND, KEY_CUSTOM_COMMAND);
+ TERMINAL_PROFILE_PROPERTY_STRING (TITLE, _(DEFAULT_TITLE), KEY_TITLE);
+ TERMINAL_PROFILE_PROPERTY_STRING (VISIBLE_NAME, _(DEFAULT_VISIBLE_NAME), KEY_VISIBLE_NAME);
+ TERMINAL_PROFILE_PROPERTY_STRING (WORD_CHARS, DEFAULT_WORD_CHARS, KEY_WORD_CHARS);
+
+ TERMINAL_PROFILE_PROPERTY_VALUE_ARRAY_BOXED (PALETTE, "palette-color", GDK_TYPE_COLOR, KEY_PALETTE);
+}
+
+/* Semi-Public API */
+
+TerminalProfile*
+_terminal_profile_new (const char *name)
+{
+ return g_object_new (TERMINAL_TYPE_PROFILE,
+ "name", name,
+ NULL);
+}
+
+void
+_terminal_profile_forget (TerminalProfile *profile)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+
+ if (!priv->forgotten)
+ {
+ mateconf_client_remove_dir (priv->conf,
+ priv->profile_dir,
+ NULL);
+
+ priv->forgotten = TRUE;
+
+ g_signal_emit (G_OBJECT (profile), signals[FORGOTTEN], 0);
+ }
+}
+
+gboolean
+_terminal_profile_get_forgotten (TerminalProfile *profile)
+{
+ return profile->priv->forgotten;
+}
+
+TerminalProfile *
+_terminal_profile_clone (TerminalProfile *base_profile,
+ const char *visible_name)
+{
+ TerminalApp *app = terminal_app_get ();
+ GObject *base_object = G_OBJECT (base_profile);
+ TerminalProfilePrivate *new_priv;
+ char profile_name[32];
+ GParameter *params;
+ GParamSpec **pspecs;
+ guint n_pspecs, i, n_params, profile_num;
+ TerminalProfile *new_profile;
+
+ g_object_ref (base_profile);
+
+ profile_num = 0;
+ do
+ {
+ g_snprintf (profile_name, sizeof (profile_name), "Profile%u", profile_num++);
+ }
+ while (terminal_app_get_profile_by_name (app, profile_name) != NULL);
+
+ /* Now we have an unused profile name */
+ pspecs = g_object_class_list_properties (G_OBJECT_CLASS (TERMINAL_PROFILE_GET_CLASS (base_profile)), &n_pspecs);
+
+ params = g_newa (GParameter, n_pspecs);
+ n_params = 0;
+
+ for (i = 0; i < n_pspecs; ++i)
+ {
+ GParamSpec *pspec = pspecs[i];
+ GValue *value;
+
+ if (pspec->owner_type != TERMINAL_TYPE_PROFILE ||
+ (pspec->flags & G_PARAM_WRITABLE) == 0)
+ continue;
+
+ params[n_params].name = pspec->name;
+
+ value = &params[n_params].value;
+ G_VALUE_TYPE (value) = 0;
+ g_value_init (value, G_PARAM_SPEC_VALUE_TYPE (pspec));
+
+ if (pspec->name == I_(TERMINAL_PROFILE_NAME))
+ g_value_set_static_string (value, profile_name);
+ else if (pspec->name == I_(TERMINAL_PROFILE_VISIBLE_NAME))
+ g_value_set_static_string (value, visible_name);
+ else
+ g_object_get_property (base_object, pspec->name, value);
+
+ ++n_params;
+ }
+
+ new_profile = g_object_newv (TERMINAL_TYPE_PROFILE, n_params, params);
+
+ g_object_unref (base_profile);
+
+ for (i = 0; i < n_params; ++i)
+ g_value_unset (&params[i].value);
+
+ /* Flush the new profile to mateconf */
+ new_priv = new_profile->priv;
+
+ g_slist_free (new_priv->dirty_pspecs);
+ new_priv->dirty_pspecs = NULL;
+ if (new_priv->save_idle_id != 0)
+ {
+ g_source_remove (new_priv->save_idle_id);
+ new_priv->save_idle_id = 0;
+ }
+
+ for (i = 0; i < n_pspecs; ++i)
+ {
+ GParamSpec *pspec = pspecs[i];
+
+ if (pspec->owner_type != TERMINAL_TYPE_PROFILE ||
+ (pspec->flags & G_PARAM_WRITABLE) == 0)
+ continue;
+
+ new_priv->dirty_pspecs = g_slist_prepend (new_priv->dirty_pspecs, pspec);
+ }
+ g_free (pspecs);
+
+ terminal_profile_save (new_profile);
+
+ return new_profile;
+}
+
+/* Public API */
+
+gboolean
+terminal_profile_get_property_boolean (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_BOOLEAN (value), FALSE);
+ if (!value || !G_VALUE_HOLDS_BOOLEAN (value))
+ return FALSE;
+
+ return g_value_get_boolean (value);
+}
+
+gconstpointer
+terminal_profile_get_property_boxed (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_BOXED (value), NULL);
+ if (!value || !G_VALUE_HOLDS_BOXED (value))
+ return NULL;
+
+ return g_value_get_boxed (value);
+}
+
+double
+terminal_profile_get_property_double (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_DOUBLE (value), 0.0);
+ if (!value || !G_VALUE_HOLDS_DOUBLE (value))
+ return 0.0;
+
+ return g_value_get_double (value);
+}
+
+int
+terminal_profile_get_property_enum (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_ENUM (value), 0);
+ if (!value || !G_VALUE_HOLDS_ENUM (value))
+ return 0;
+
+ return g_value_get_enum (value);
+}
+
+int
+terminal_profile_get_property_int (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_INT (value), 0);
+ if (!value || !G_VALUE_HOLDS_INT (value))
+ return 0;
+
+ return g_value_get_int (value);
+}
+
+gpointer
+terminal_profile_get_property_object (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_OBJECT (value), NULL);
+ if (!value || !G_VALUE_HOLDS_OBJECT (value))
+ return NULL;
+
+ return g_value_get_object (value);
+}
+
+const char*
+terminal_profile_get_property_string (TerminalProfile *profile,
+ const char *prop_name)
+{
+ const GValue *value;
+
+ value = get_prop_value_from_prop_name (profile, prop_name);
+ g_return_val_if_fail (value != NULL && G_VALUE_HOLDS_STRING (value), NULL);
+ if (!value || !G_VALUE_HOLDS_STRING (value))
+ return NULL;
+
+ return g_value_get_string (value);
+}
+
+gboolean
+terminal_profile_property_locked (TerminalProfile *profile,
+ const char *prop_name)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ GParamSpec *pspec;
+
+ pspec = get_pspec_from_name (profile, prop_name);
+ g_return_val_if_fail (pspec != NULL, FALSE);
+ if (!pspec)
+ return FALSE;
+
+ return priv->locked[pspec->param_id];
+}
+
+void
+terminal_profile_reset_property (TerminalProfile *profile,
+ const char *prop_name)
+{
+ GParamSpec *pspec;
+
+ pspec = get_pspec_from_name (profile, prop_name);
+ g_return_if_fail (pspec != NULL);
+ if (!pspec ||
+ (pspec->flags & G_PARAM_WRITABLE) == 0)
+ return;
+
+ terminal_profile_reset_property_internal (profile, pspec, TRUE);
+}
+
+gboolean
+terminal_profile_get_palette (TerminalProfile *profile,
+ GdkColor *colors,
+ guint *n_colors)
+{
+ TerminalProfilePrivate *priv;
+ GValueArray *array;
+ guint i, n;
+
+ g_return_val_if_fail (TERMINAL_IS_PROFILE (profile), FALSE);
+ g_return_val_if_fail (colors != NULL && n_colors != NULL, FALSE);
+
+ priv = profile->priv;
+ array = g_value_get_boxed (g_value_array_get_nth (priv->properties, PROP_PALETTE));
+ if (!array)
+ return FALSE;
+
+ n = MIN (array->n_values, *n_colors);
+ for (i = 0; i < n; ++i)
+ {
+ GdkColor *color = g_value_get_boxed (g_value_array_get_nth (array, i));
+ if (!color)
+ continue; /* shouldn't happen!! */
+
+ colors[i] = *color;
+ }
+
+ *n_colors = n;
+ return TRUE;
+}
+
+gboolean
+terminal_profile_get_palette_is_builtin (TerminalProfile *profile,
+ guint *n)
+{
+ GdkColor colors[TERMINAL_PALETTE_SIZE];
+ guint n_colors;
+ guint i;
+
+ n_colors = G_N_ELEMENTS (colors);
+ if (!terminal_profile_get_palette (profile, colors, &n_colors) ||
+ 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;
+}
+
+void
+terminal_profile_set_palette_builtin (TerminalProfile *profile,
+ guint n)
+{
+ GValue value = { 0, };
+
+ g_return_if_fail (n < TERMINAL_PALETTE_N_BUILTINS);
+
+ g_value_init (&value, G_TYPE_VALUE_ARRAY);
+ set_value_from_palette (&value, terminal_palettes[n], TERMINAL_PALETTE_SIZE);
+ g_object_set_property (G_OBJECT (profile), TERMINAL_PROFILE_PALETTE, &value);
+ g_value_unset (&value);
+}
+
+gboolean
+terminal_profile_modify_palette_entry (TerminalProfile *profile,
+ guint i,
+ const GdkColor *color)
+{
+ TerminalProfilePrivate *priv = profile->priv;
+ GValueArray *array;
+ GValue *value;
+ GdkColor *old_color;
+
+ array = g_value_get_boxed (g_value_array_get_nth (priv->properties, PROP_PALETTE));
+ if (!array ||
+ i >= array->n_values)
+ return FALSE;
+
+ value = g_value_array_get_nth (array, i);
+ old_color = g_value_get_boxed (value);
+ if (!old_color ||
+ !gdk_color_equal (old_color, color))
+ {
+ g_value_set_boxed (value, color);
+ g_object_notify (G_OBJECT (profile), TERMINAL_PROFILE_PALETTE);
+ }
+
+ return TRUE;
+}
diff --git a/src/terminal-profile.h b/src/terminal-profile.h
new file mode 100644
index 0000000..4275e53
--- /dev/null
+++ b/src/terminal-profile.h
@@ -0,0 +1,191 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2002 Mathias Hasselmann
+ * Copyright © 2008 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_PROFILE_H
+#define TERMINAL_PROFILE_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef enum
+{
+ /* this has to be kept in sync with the option menu in the profile editor UI file */
+ TERMINAL_TITLE_REPLACE,
+ TERMINAL_TITLE_BEFORE,
+ TERMINAL_TITLE_AFTER,
+ TERMINAL_TITLE_IGNORE
+} TerminalTitleMode;
+
+typedef enum
+{
+ TERMINAL_SCROLLBAR_LEFT,
+ TERMINAL_SCROLLBAR_RIGHT,
+ TERMINAL_SCROLLBAR_HIDDEN
+} TerminalScrollbarPosition;
+
+typedef enum
+{
+ TERMINAL_EXIT_CLOSE,
+ TERMINAL_EXIT_RESTART,
+ TERMINAL_EXIT_HOLD
+} TerminalExitAction;
+
+typedef enum
+{
+ TERMINAL_BACKGROUND_SOLID,
+ TERMINAL_BACKGROUND_IMAGE,
+ TERMINAL_BACKGROUND_TRANSPARENT
+} TerminalBackgroundType;
+
+#define TERMINAL_PALETTE_SIZE 16
+
+#define TERMINAL_PALETTE_TANGO 0
+#define TERMINAL_PALETTE_LINUX 1
+#define TERMINAL_PALETTE_XTERM 2
+#define TERMINAL_PALETTE_RXVT 3
+#define TERMINAL_PALETTE_N_BUILTINS 4
+
+/* Property names */
+#define TERMINAL_PROFILE_ALLOW_BOLD "allow-bold"
+#define TERMINAL_PROFILE_BACKGROUND_COLOR "background-color"
+#define TERMINAL_PROFILE_BACKGROUND_DARKNESS "background-darkness"
+#define TERMINAL_PROFILE_BACKGROUND_IMAGE "background-image"
+#define TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE "background-image-file"
+#define TERMINAL_PROFILE_BACKGROUND_TYPE "background-type"
+#define TERMINAL_PROFILE_BACKSPACE_BINDING "backspace-binding"
+#define TERMINAL_PROFILE_BOLD_COLOR "bold-color"
+#define TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG "bold-color-same-as-fg"
+#define TERMINAL_PROFILE_CURSOR_BLINK_MODE "cursor-blink-mode"
+#define TERMINAL_PROFILE_CURSOR_SHAPE "cursor-shape"
+#define TERMINAL_PROFILE_CUSTOM_COMMAND "custom-command"
+#define TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR "default-show-menubar"
+#define TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS "default-size-columns"
+#define TERMINAL_PROFILE_DEFAULT_SIZE_ROWS "default-size-rows"
+#define TERMINAL_PROFILE_DELETE_BINDING "delete-binding"
+#define TERMINAL_PROFILE_EXIT_ACTION "exit-action"
+#define TERMINAL_PROFILE_FONT "font"
+#define TERMINAL_PROFILE_FOREGROUND_COLOR "foreground-color"
+#define TERMINAL_PROFILE_LOGIN_SHELL "login-shell"
+#define TERMINAL_PROFILE_NAME "name"
+#define TERMINAL_PROFILE_PALETTE "palette"
+#define TERMINAL_PROFILE_SCROLL_BACKGROUND "scroll-background"
+#define TERMINAL_PROFILE_SCROLLBACK_LINES "scrollback-lines"
+#define TERMINAL_PROFILE_SCROLLBACK_UNLIMITED "scrollback-unlimited"
+#define TERMINAL_PROFILE_SCROLLBAR_POSITION "scrollbar-position"
+#define TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE "scroll-on-keystroke"
+#define TERMINAL_PROFILE_SCROLL_ON_OUTPUT "scroll-on-output"
+#define TERMINAL_PROFILE_SILENT_BELL "silent-bell"
+#define TERMINAL_PROFILE_TITLE_MODE "title-mode"
+#define TERMINAL_PROFILE_TITLE "title"
+#define TERMINAL_PROFILE_UPDATE_RECORDS "update-records"
+#define TERMINAL_PROFILE_USE_CUSTOM_COMMAND "use-custom-command"
+#define TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE "use-custom-default-size"
+#define TERMINAL_PROFILE_USE_SKEY "use-skey"
+#define TERMINAL_PROFILE_USE_SYSTEM_FONT "use-system-font"
+#define TERMINAL_PROFILE_USE_THEME_COLORS "use-theme-colors"
+#define TERMINAL_PROFILE_VISIBLE_NAME "visible-name"
+#define TERMINAL_PROFILE_WORD_CHARS "word-chars"
+
+/* TerminalProfile object */
+
+#define TERMINAL_TYPE_PROFILE (terminal_profile_get_type ())
+#define TERMINAL_PROFILE(object) (G_TYPE_CHECK_INSTANCE_CAST ((object), TERMINAL_TYPE_PROFILE, TerminalProfile))
+#define TERMINAL_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_CAST ((klass), TERMINAL_TYPE_PROFILE, TerminalProfileClass))
+#define TERMINAL_IS_PROFILE(object) (G_TYPE_CHECK_INSTANCE_TYPE ((object), TERMINAL_TYPE_PROFILE))
+#define TERMINAL_IS_PROFILE_CLASS(klass) (G_TYPE_CHECK_CLASS_TYPE ((klass), TERMINAL_TYPE_PROFILE))
+#define TERMINAL_PROFILE_GET_CLASS(obj) (G_TYPE_INSTANCE_GET_CLASS ((obj), TERMINAL_TYPE_PROFILE, TerminalProfileClass))
+
+typedef struct _TerminalProfile TerminalProfile;
+typedef struct _TerminalProfileClass TerminalProfileClass;
+typedef struct _TerminalProfilePrivate TerminalProfilePrivate;
+
+struct _TerminalProfile
+{
+ GObject parent_instance;
+
+ TerminalProfilePrivate *priv;
+};
+
+struct _TerminalProfileClass
+{
+ GObjectClass parent_class;
+
+ void (* forgotten) (TerminalProfile *profile);
+
+ GHashTable *mateconf_keys;
+};
+
+GType terminal_profile_get_type (void);
+
+TerminalProfile* _terminal_profile_new (const char *name);
+
+void _terminal_profile_forget (TerminalProfile *profile);
+
+gboolean _terminal_profile_get_forgotten (TerminalProfile *profile);
+
+TerminalProfile* _terminal_profile_clone (TerminalProfile *base_profile,
+ const char *visible_name);
+
+gboolean terminal_profile_property_locked (TerminalProfile *profile,
+ const char *prop_name);
+
+void terminal_profile_reset_property (TerminalProfile *profile,
+ const char *prop_name);
+
+gboolean terminal_profile_get_property_boolean (TerminalProfile *profile,
+ const char *prop_name);
+
+gconstpointer terminal_profile_get_property_boxed (TerminalProfile *profile,
+ const char *prop_name);
+
+double terminal_profile_get_property_double (TerminalProfile *profile,
+ const char *prop_name);
+
+int terminal_profile_get_property_enum (TerminalProfile *profile,
+ const char *prop_name);
+
+int terminal_profile_get_property_int (TerminalProfile *profile,
+ const char *prop_name);
+
+gpointer terminal_profile_get_property_object (TerminalProfile *profile,
+ const char *prop_name);
+
+const char* terminal_profile_get_property_string (TerminalProfile *profile,
+ const char *prop_name);
+
+gboolean terminal_profile_get_palette (TerminalProfile *profile,
+ GdkColor *colors,
+ guint *n_colors);
+
+gboolean terminal_profile_get_palette_is_builtin (TerminalProfile *profile,
+ guint *n);
+
+void terminal_profile_set_palette_builtin (TerminalProfile *profile,
+ guint n);
+
+gboolean terminal_profile_modify_palette_entry (TerminalProfile *profile,
+ guint i,
+ const GdkColor *color);
+
+G_END_DECLS
+
+#endif /* TERMINAL_PROFILE_H */
diff --git a/src/terminal-screen-container.c b/src/terminal-screen-container.c
new file mode 100644
index 0000000..7aa6265
--- /dev/null
+++ b/src/terminal-screen-container.c
@@ -0,0 +1,409 @@
+/*
+ * Copyright © 2008, 2010 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include "terminal-screen-container.h"
+#include "terminal-debug.h"
+#include "terminal-intl.h"
+
+#include <gtk/gtk.h>
+
+#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;
+ GtkCornerType window_placement;
+ guint window_placement_set : 1;
+};
+
+enum
+{
+ PROP_0,
+ PROP_SCREEN,
+ PROP_HSCROLLBAR_POLICY,
+ PROP_VSCROLLBAR_POLICY,
+ PROP_WINDOW_PLACEMENT,
+ PROP_WINDOW_PLACEMENT_SET
+};
+
+G_DEFINE_TYPE (TerminalScreenContainer, terminal_screen_container, GTK_TYPE_VBOX)
+
+/* helper functions */
+
+static void
+terminal_screen_container_set_placement_internal (TerminalScreenContainer *container,
+ GtkCornerType corner)
+{
+ TerminalScreenContainerPrivate *priv = container->priv;
+
+#ifdef USE_SCROLLED_WINDOW
+ gtk_scrolled_window_set_placement (GTK_SCROLLED_WINDOW (priv->scrolled_window), corner);
+#else
+ 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
+
+ priv->window_placement = corner;
+ g_object_notify (G_OBJECT (container), "window-placement");
+}
+
+static void
+terminal_screen_container_set_placement_set (TerminalScreenContainer *container,
+ gboolean set)
+{
+ TerminalScreenContainerPrivate *priv = container->priv;
+
+#ifdef USE_SCROLLED_WINDOW
+ g_object_set (priv->scrolled_window, "window-placement-set", set, NULL);
+#endif
+
+ priv->window_placement_set = set != FALSE;
+ g_object_notify (G_OBJECT (container), "window-placement-set");
+}
+
+#if defined(USE_SCROLLED_WINDOW) && defined(MATE_ENABLE_DEBUG)
+static void
+size_request_cb (GtkWidget *widget,
+ GtkRequisition *req,
+ TerminalScreenContainer *container)
+{
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[screen %p] scrolled-window size req %d : %d\n",
+ container->priv->screen, req->width, req->height);
+}
+#endif
+
+/* 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;
+ priv->window_placement = GTK_CORNER_BOTTOM_RIGHT;
+ priv->window_placement_set = FALSE;
+}
+
+static GObject *
+terminal_screen_container_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ TerminalScreenContainer *container;
+ TerminalScreenContainerPrivate *priv;
+
+ object = G_OBJECT_CLASS (terminal_screen_container_parent_class)->constructor
+ (type, n_construct_properties, construct_params);
+
+ container = TERMINAL_SCREEN_CONTAINER (object);
+ priv = container->priv;
+
+ g_assert (priv->screen != NULL);
+
+#ifdef USE_SCROLLED_WINDOW
+ priv->scrolled_window = gtk_scrolled_window_new (NULL, vte_terminal_get_adjustment (VTE_TERMINAL (priv->screen)));
+
+ gtk_scrolled_window_set_policy (GTK_SCROLLED_WINDOW (priv->scrolled_window),
+ priv->hscrollbar_policy,
+ priv->vscrollbar_policy);
+ gtk_scrolled_window_set_shadow_type (GTK_SCROLLED_WINDOW (priv->scrolled_window),
+ GTK_SHADOW_NONE);
+ gtk_container_add (GTK_CONTAINER (priv->scrolled_window), GTK_WIDGET (priv->screen));
+ gtk_widget_show (GTK_WIDGET (priv->screen));
+ gtk_box_pack_end (GTK_BOX (container), priv->scrolled_window, TRUE, TRUE, 0);
+ gtk_widget_show (priv->scrolled_window);
+
+#ifdef MATE_ENABLE_DEBUG
+ g_signal_connect (priv->scrolled_window, "size-request", G_CALLBACK (size_request_cb), container);
+#endif
+
+#else
+
+ priv->hbox = gtk_hbox_new (FALSE, 0);
+
+ priv->vscrollbar = gtk_vscrollbar_new (vte_terminal_get_adjustment (VTE_TERMINAL (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_box_pack_end (GTK_BOX (container), priv->hbox, TRUE, TRUE, 0);
+ gtk_widget_show_all (priv->hbox);
+#endif /* USE_SCROLLED_WINDOW */
+
+ _terminal_screen_update_scrollbar (priv->screen);
+
+ return object;
+}
+
+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;
+ case PROP_WINDOW_PLACEMENT:
+ g_value_set_enum (value, priv->window_placement);
+ break;
+ case PROP_WINDOW_PLACEMENT_SET:
+ g_value_set_boolean (value, priv->window_placement_set);
+ 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;
+ case PROP_WINDOW_PLACEMENT:
+ terminal_screen_container_set_placement_internal (container, g_value_get_enum (value));
+ break;
+ case PROP_WINDOW_PLACEMENT_SET:
+ terminal_screen_container_set_placement_set (container, g_value_get_boolean (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->constructor = terminal_screen_container_constructor;
+ gobject_class->get_property = terminal_screen_container_get_property;
+ gobject_class->set_property = terminal_screen_container_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_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));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WINDOW_PLACEMENT,
+ g_param_spec_enum ("window-placement", NULL, NULL,
+ GTK_TYPE_CORNER_TYPE,
+ GTK_CORNER_TOP_LEFT,
+ G_PARAM_READWRITE |
+ G_PARAM_STATIC_STRINGS));
+
+ g_object_class_install_property
+ (gobject_class,
+ PROP_WINDOW_PLACEMENT_SET,
+ g_param_spec_boolean ("window-placement-set", NULL, NULL,
+ FALSE,
+ 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)
+{
+ 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)
+{
+ 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 G_GNUC_UNUSED,
+ 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
+ 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
+
+ g_object_thaw_notify (object);
+}
+
+/**
+ * terminal_screen_container_set_placement:
+ * @container: a #TerminalScreenContainer
+ * @corner: a #GtkCornerType
+ *
+ * Sets @container's window placement.
+ */
+void
+terminal_screen_container_set_placement (TerminalScreenContainer *container,
+ GtkCornerType corner)
+{
+ g_return_if_fail (TERMINAL_IS_SCREEN_CONTAINER (container));
+
+ terminal_screen_container_set_placement_internal (container, corner);
+ terminal_screen_container_set_placement_set (container, TRUE);
+}
diff --git a/src/terminal-screen-container.h b/src/terminal-screen-container.h
new file mode 100644
index 0000000..31e4859
--- /dev/null
+++ b/src/terminal-screen-container.h
@@ -0,0 +1,69 @@
+/*
+ * Copyright © 2008, 2010 Christian Persch
+*
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_SCREEN_CONTAINER_H
+#define TERMINAL_SCREEN_CONTAINER_H
+
+#include <gtk/gtk.h>
+#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
+{
+ GtkVBox parent_instance;
+
+ /*< private >*/
+ TerminalScreenContainerPrivate *priv;
+};
+
+struct _TerminalScreenContainerClass
+{
+ GtkVBoxClass 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);
+
+void terminal_screen_container_set_placement (TerminalScreenContainer *container,
+ GtkCornerType corner);
+
+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..3899e30
--- /dev/null
+++ b/src/terminal-screen.c
@@ -0,0 +1,2343 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2007, 2008, 2010 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <sys/wait.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+
+#include "terminal-accels.h"
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-intl.h"
+#include "terminal-marshal.h"
+#include "terminal-profile.h"
+#include "terminal-screen-container.h"
+#include "terminal-util.h"
+#include "terminal-window.h"
+#include "terminal-info-bar.h"
+
+#include "eggshell.h"
+
+#define URL_MATCH_CURSOR (GDK_HAND2)
+#define SKEY_MATCH_CURSOR (GDK_HAND2)
+
+typedef struct
+{
+ int tag;
+ TerminalURLFlavour flavor;
+} TagData;
+
+struct _TerminalScreenPrivate
+{
+ TerminalProfile *profile; /* may be NULL at times */
+ guint profile_changed_id;
+ guint profile_forgotten_id;
+ char *raw_title, *raw_icon_title;
+ char *cooked_title, *cooked_icon_title;
+ char *override_title;
+ gboolean icon_title_set;
+ char *initial_working_directory;
+ char **initial_env;
+ char **override_command;
+ int child_pid;
+ int pty_fd;
+ double font_scale;
+ gboolean user_title; /* title was manually set */
+ GSList *match_tags;
+ guint launch_child_source_id;
+};
+
+enum
+{
+ PROFILE_SET,
+ SHOW_POPUP_MENU,
+ MATCH_CLICKED,
+ CLOSE_SCREEN,
+ LAST_SIGNAL
+};
+
+enum {
+ PROP_0,
+ PROP_PROFILE,
+ PROP_ICON_TITLE,
+ PROP_ICON_TITLE_SET,
+ PROP_OVERRIDE_COMMAND,
+ PROP_TITLE,
+ PROP_INITIAL_ENVIRONMENT
+};
+
+enum
+{
+ TARGET_COLOR,
+ TARGET_BGIMAGE,
+ TARGET_RESET_BG,
+ TARGET_MOZ_URL,
+ TARGET_NETSCAPE_URL,
+ TARGET_TAB
+};
+
+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_system_font_notify_cb (TerminalApp *app,
+ GParamSpec *pspec,
+ TerminalScreen *screen);
+static void terminal_screen_change_font (TerminalScreen *screen);
+static gboolean terminal_screen_popup_menu (GtkWidget *widget);
+static gboolean terminal_screen_button_press (GtkWidget *widget,
+ GdkEventButton *event);
+static void terminal_screen_launch_child_on_idle (TerminalScreen *screen);
+static void terminal_screen_child_exited (VteTerminal *terminal);
+
+static void terminal_screen_window_title_changed (VteTerminal *vte_terminal,
+ TerminalScreen *screen);
+static void terminal_screen_icon_title_changed (VteTerminal *vte_terminal,
+ TerminalScreen *screen);
+
+static void update_color_scheme (TerminalScreen *screen);
+
+static gboolean terminal_screen_format_title (TerminalScreen *screen, const char *raw_title, char **old_cooked_title);
+
+static void terminal_screen_cook_title (TerminalScreen *screen);
+static void terminal_screen_cook_icon_title (TerminalScreen *screen);
+
+static char* terminal_screen_check_match (TerminalScreen *screen,
+ int column,
+ int row,
+ int *flavor);
+
+static guint signals[LAST_SIGNAL];
+
+#define USERCHARS "-[:alnum:]"
+#define USERCHARS_CLASS "[" USERCHARS "]"
+#define PASSCHARS_CLASS "[-[:alnum:]\\Q,?;.:/!%$^*&~\"#'\\E]"
+#define HOSTCHARS_CLASS "[-[:alnum:]]"
+#define HOST HOSTCHARS_CLASS "+(\\." HOSTCHARS_CLASS "+)*"
+#define PORT "(?:\\:[[:digit:]]{1,5})?"
+#define PATHCHARS_CLASS "[-[:alnum:]\\Q_$.+!*,;@&=?/~#%\\E]"
+#define PATHTERM_CLASS "[^\\Q]'.}>) \t\r\n,\"\\E]"
+#define SCHEME "(?:news:|telnet:|nntp:|file:\\/|https?:|ftps?:|sftp:|webcal:)"
+#define USERPASS USERCHARS_CLASS "+(?:" PASSCHARS_CLASS "+)?"
+#define URLPATH "(?:(/"PATHCHARS_CLASS"+(?:[(]"PATHCHARS_CLASS"*[)])*"PATHCHARS_CLASS"*)*"PATHTERM_CLASS")?"
+
+typedef struct {
+ const char *pattern;
+ TerminalURLFlavour flavor;
+ GRegexCompileFlags flags;
+} TerminalRegexPattern;
+
+static const TerminalRegexPattern url_regex_patterns[] = {
+ { SCHEME "//(?:" USERPASS "\\@)?" HOST PORT URLPATH, FLAVOR_AS_IS, G_REGEX_CASELESS },
+ { "(?:www|ftp)" HOSTCHARS_CLASS "*\\." HOST PORT URLPATH , FLAVOR_DEFAULT_TO_HTTP, G_REGEX_CASELESS },
+ { "(?:callto:|h323:|sip:)" USERCHARS_CLASS "[" USERCHARS ".]*(?:" PORT "/[a-z0-9]+)?\\@" HOST, FLAVOR_VOIP_CALL, G_REGEX_CASELESS },
+ { "(?:mailto:)?" USERCHARS_CLASS "[" USERCHARS ".]*\\@" HOSTCHARS_CLASS "+\\." HOST, FLAVOR_EMAIL, G_REGEX_CASELESS },
+ { "news:[[:alnum:]\\Q^_{|}~!\"#$%&'()*+,./;:=?`\\E]+", FLAVOR_AS_IS, G_REGEX_CASELESS },
+};
+
+static GRegex **url_regexes;
+static TerminalURLFlavour *url_regex_flavors;
+static guint n_url_regexes;
+
+#ifdef ENABLE_SKEY
+static const TerminalRegexPattern skey_regex_patterns[] = {
+ { "s/key [[:digit:]]* [-[:alnum:]]*", FLAVOR_AS_IS },
+ { "otp-[a-z0-9]* [[:digit:]]* [-[:alnum:]]*", FLAVOR_AS_IS },
+};
+
+static GRegex **skey_regexes;
+static guint n_skey_regexes;
+
+static void terminal_screen_skey_match_remove (TerminalScreen *screen);
+#endif /* ENABLE_SKEY */
+
+G_DEFINE_TYPE (TerminalScreen, terminal_screen, VTE_TYPE_TERMINAL)
+
+static char *
+cwd_of_pid (int pid)
+{
+ static const char patterns[][18] = {
+ "/proc/%d/cwd", /* Linux */
+ "/proc/%d/path/cwd", /* Solaris >= 10 */
+ };
+ guint i;
+
+ if (pid == -1)
+ return NULL;
+
+ /* Try to get the working directory using various OS-specific mechanisms */
+ for (i = 0; i < G_N_ELEMENTS (patterns); ++i)
+ {
+ char cwd_file[64];
+ char buf[PATH_MAX + 1];
+ int len;
+
+ g_snprintf (cwd_file, sizeof (cwd_file), patterns[i], pid);
+ len = readlink (cwd_file, buf, sizeof (buf) - 1);
+
+ if (len > 0 && buf[0] == '/')
+ return g_strndup (buf, len);
+
+ /* If that didn't do it, try this hack */
+ if (len <= 0)
+ {
+ char *cwd, *working_dir = NULL;
+
+ cwd = g_get_current_dir ();
+ if (cwd != NULL)
+ {
+ /* On Solaris, readlink returns an empty string, but the
+ * link can be used as a directory, including as a target
+ * of chdir().
+ */
+ if (chdir (cwd_file) == 0)
+ {
+ working_dir = g_get_current_dir ();
+ (void) chdir (cwd);
+ }
+ g_free (cwd);
+ }
+
+ if (working_dir)
+ return working_dir;
+ }
+ }
+
+ return NULL;
+}
+
+static void
+free_tag_data (TagData *tagdata)
+{
+ g_slice_free (TagData, tagdata);
+}
+
+static void
+terminal_screen_class_enable_menu_bar_accel_notify_cb (TerminalApp *app,
+ GParamSpec *pspec,
+ TerminalScreenClass *klass)
+{
+ static gboolean is_enabled = TRUE; /* the binding is enabled by default since GtkWidgetClass installs it */
+ gboolean enable;
+ GtkBindingSet *binding_set;
+
+ g_object_get (app, TERMINAL_APP_ENABLE_MENU_BAR_ACCEL, &enable, NULL);
+
+ /* 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_F10, GDK_SHIFT_MASK);
+ else
+ gtk_binding_entry_skip (binding_set, GDK_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 gboolean
+window_uses_argb_visual (TerminalScreen *screen)
+{
+ TerminalWindow *window;
+
+ window = terminal_screen_get_window (screen);
+ if (window == NULL || !gtk_widget_get_realized (GTK_WIDGET (window)))
+ return FALSE;
+
+ return terminal_window_uses_argb_visual (window);
+}
+
+static void
+terminal_screen_realize (GtkWidget *widget)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (widget);
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalBackgroundType bg_type;
+
+ GTK_WIDGET_CLASS (terminal_screen_parent_class)->realize (widget);
+
+ /* FIXME: Don't enable this if we have a compmgr. */
+ bg_type = terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
+ vte_terminal_set_background_transparent (VTE_TERMINAL (screen),
+ bg_type == TERMINAL_BACKGROUND_TRANSPARENT &&
+ !window_uses_argb_visual (screen));
+}
+
+static void
+terminal_screen_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (widget);
+ void (* style_set) (GtkWidget*, GtkStyle*) = GTK_WIDGET_CLASS (terminal_screen_parent_class)->style_set;
+
+ if (style_set)
+ style_set (widget, previous_style);
+
+ update_color_scheme (screen);
+
+ if (gtk_widget_get_realized (widget))
+ terminal_screen_change_font (screen);
+}
+
+#ifdef MATE_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[] = {
+ { "GTK_NOTEBOOK_TAB", GTK_TARGET_SAME_APP, TARGET_TAB },
+ { "application/x-color", 0, TARGET_COLOR },
+ { "property/bgimage", 0, TARGET_BGIMAGE },
+ { "x-special/mate-reset-background", 0, TARGET_RESET_BG },
+ { "text/x-moz-url", 0, TARGET_MOZ_URL },
+ { "_NETSCAPE_URL", 0, TARGET_NETSCAPE_URL }
+ };
+ VteTerminal *terminal = VTE_TERMINAL (screen);
+ TerminalScreenPrivate *priv;
+ GtkTargetList *target_list;
+ GtkTargetEntry *targets;
+ int n_targets;
+ guint i;
+
+ priv = screen->priv = G_TYPE_INSTANCE_GET_PRIVATE (screen, TERMINAL_TYPE_SCREEN, TerminalScreenPrivate);
+
+ vte_terminal_set_mouse_autohide (VTE_TERMINAL (screen), TRUE);
+
+ priv->child_pid = -1;
+ priv->pty_fd = -1;
+
+ priv->font_scale = PANGO_SCALE_MEDIUM;
+
+ 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_gregex (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);
+
+ priv->override_title = NULL;
+ priv->user_title = FALSE;
+
+ g_signal_connect (screen, "window-title-changed",
+ G_CALLBACK (terminal_screen_window_title_changed),
+ screen);
+ g_signal_connect (screen, "icon-title-changed",
+ G_CALLBACK (terminal_screen_icon_title_changed),
+ screen);
+
+ g_signal_connect (terminal_app_get (), "notify::system-font",
+ G_CALLBACK (terminal_screen_system_font_notify_cb), screen);
+
+#ifdef MATE_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_ICON_TITLE:
+ g_value_set_string (value, terminal_screen_get_icon_title (screen));
+ break;
+ case PROP_ICON_TITLE_SET:
+ g_value_set_boolean (value, terminal_screen_get_icon_title_set (screen));
+ break;
+ case PROP_OVERRIDE_COMMAND:
+ g_value_set_boxed (value, terminal_screen_get_override_command (screen));
+ break;
+ case PROP_INITIAL_ENVIRONMENT:
+ g_value_set_boxed (value, terminal_screen_get_initial_environment (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: {
+ TerminalProfile *profile;
+
+ profile = g_value_get_object (value);
+ g_assert (profile != NULL);
+ terminal_screen_set_profile (screen, profile);
+ break;
+ }
+ case PROP_OVERRIDE_COMMAND:
+ terminal_screen_set_override_command (screen, g_value_get_boxed (value));
+ break;
+ case PROP_INITIAL_ENVIRONMENT:
+ terminal_screen_set_initial_environment (screen, g_value_get_boxed (value));
+ break;
+ case PROP_ICON_TITLE:
+ case PROP_ICON_TITLE_SET:
+ 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);
+ TerminalApp *app;
+ guint i;
+
+ 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_set = terminal_screen_style_set;
+ 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, TERMINAL_TYPE_PROFILE);
+
+ 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_string ("profile", NULL, NULL,
+ NULL,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ICON_TITLE,
+ g_param_spec_string ("icon-title", NULL, NULL,
+ NULL,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_ICON_TITLE_SET,
+ g_param_spec_boolean ("icon-title-set", NULL, NULL,
+ FALSE,
+ G_PARAM_READABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_object_class_install_property
+ (object_class,
+ PROP_OVERRIDE_COMMAND,
+ g_param_spec_boxed ("override-command", NULL, NULL,
+ G_TYPE_STRV,
+ 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_object_class_install_property
+ (object_class,
+ PROP_INITIAL_ENVIRONMENT,
+ g_param_spec_boxed ("initial-environment", NULL, NULL,
+ G_TYPE_STRV,
+ G_PARAM_READWRITE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB));
+
+ g_type_class_add_private (object_class, sizeof (TerminalScreenPrivate));
+
+ /* Precompile the regexes */
+ n_url_regexes = G_N_ELEMENTS (url_regex_patterns);
+ url_regexes = g_new0 (GRegex*, n_url_regexes);
+ url_regex_flavors = g_new0 (TerminalURLFlavour, n_url_regexes);
+
+ for (i = 0; i < n_url_regexes; ++i)
+ {
+ GError *error = NULL;
+
+ url_regexes[i] = g_regex_new (url_regex_patterns[i].pattern,
+ url_regex_patterns[i].flags | G_REGEX_OPTIMIZE,
+ 0, &error);
+ if (error)
+ {
+ g_message ("%s", error->message);
+ g_error_free (error);
+ }
+
+ url_regex_flavors[i] = url_regex_patterns[i].flavor;
+ }
+
+#ifdef ENABLE_SKEY
+ n_skey_regexes = G_N_ELEMENTS (skey_regex_patterns);
+ skey_regexes = g_new0 (GRegex*, n_skey_regexes);
+
+ for (i = 0; i < n_skey_regexes; ++i)
+ {
+ GError *error = NULL;
+
+ skey_regexes[i] = g_regex_new (skey_regex_patterns[i].pattern, G_REGEX_OPTIMIZE, 0, &error);
+ if (error)
+ {
+ g_message ("%s", error->message);
+ g_error_free (error);
+ }
+ }
+#endif /* ENABLE_SKEY */
+
+ /* This fixes bug #329827 */
+ app = terminal_app_get ();
+ terminal_screen_class_enable_menu_bar_accel_notify_cb (app, NULL, klass);
+ g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MENU_BAR_ACCEL,
+ G_CALLBACK (terminal_screen_class_enable_menu_bar_accel_notify_cb), klass);
+}
+
+static void
+terminal_screen_dispose (GObject *object)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (object);
+ TerminalScreenPrivate *priv = screen->priv;
+ GtkSettings *settings;
+
+ 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->launch_child_source_id != 0)
+ {
+ g_source_remove (priv->launch_child_source_id);
+ priv->launch_child_source_id = 0;
+ }
+
+ G_OBJECT_CLASS (terminal_screen_parent_class)->dispose (object);
+}
+
+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 (),
+ G_CALLBACK (terminal_screen_system_font_notify_cb),
+ screen);
+
+ terminal_screen_set_profile (screen, NULL);
+
+ g_free (priv->raw_title);
+ g_free (priv->cooked_title);
+ g_free (priv->override_title);
+ g_free (priv->raw_icon_title);
+ g_free (priv->cooked_icon_title);
+ g_free (priv->initial_working_directory);
+ g_strfreev (priv->override_command);
+ g_strfreev (priv->initial_env);
+
+ g_slist_foreach (priv->match_tags, (GFunc) free_tag_data, NULL);
+ g_slist_free (priv->match_tags);
+
+ G_OBJECT_CLASS (terminal_screen_parent_class)->finalize (object);
+}
+
+TerminalScreen *
+terminal_screen_new (TerminalProfile *profile,
+ char **override_command,
+ const char *title,
+ const char *working_dir,
+ char **child_env,
+ double zoom)
+{
+ TerminalScreen *screen;
+ TerminalScreenPrivate *priv;
+
+ g_return_val_if_fail (TERMINAL_IS_PROFILE (profile), NULL);
+
+ screen = g_object_new (TERMINAL_TYPE_SCREEN, NULL);
+ priv = screen->priv;
+
+ terminal_screen_set_profile (screen, profile);
+
+ if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_DEFAULT_SIZE)) {
+ vte_terminal_set_size (VTE_TERMINAL (screen),
+ terminal_profile_get_property_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_COLUMNS),
+ terminal_profile_get_property_int (profile, TERMINAL_PROFILE_DEFAULT_SIZE_ROWS));
+ }
+
+ if (title)
+ terminal_screen_set_override_title (screen, title);
+
+ priv->initial_working_directory = g_strdup (working_dir);
+
+ if (override_command)
+ terminal_screen_set_override_command (screen, override_command);
+
+ if (child_env)
+ terminal_screen_set_initial_environment (screen, child_env);
+
+ terminal_screen_set_font_scale (screen, zoom);
+ terminal_screen_set_font (screen);
+
+ /* Launch the child on idle */
+ terminal_screen_launch_child_on_idle (screen);
+
+ return screen;
+}
+
+const char*
+terminal_screen_get_raw_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->raw_title)
+ return priv->raw_title;
+
+ return "";
+}
+
+const char*
+terminal_screen_get_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->cooked_title == NULL)
+ terminal_screen_cook_title (screen);
+
+ /* cooked_title may still be NULL */
+ if (priv->cooked_title != NULL)
+ return priv->cooked_title;
+ else
+ return "";
+}
+
+const char*
+terminal_screen_get_icon_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->cooked_icon_title == NULL)
+ terminal_screen_cook_icon_title (screen);
+
+ /* cooked_icon_title may still be NULL */
+ if (priv->cooked_icon_title != NULL)
+ return priv->cooked_icon_title;
+ else
+ return "";
+}
+
+gboolean
+terminal_screen_get_icon_title_set (TerminalScreen *screen)
+{
+ return screen->priv->icon_title_set;
+}
+
+/* Supported format specifiers:
+ * %S = static title
+ * %D = dynamic title
+ * %A = dynamic title, falling back to static title if empty
+ * %- = separator, if not at start or end of string (excluding whitespace)
+ */
+static const char *
+terminal_screen_get_title_format (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ static const char *formats[] = {
+ "%A" /* TERMINAL_TITLE_REPLACE */,
+ "%D%-%S" /* TERMINAL_TITLE_BEFORE */,
+ "%S%-%D" /* TERMINAL_TITLE_AFTER */,
+ "%S" /* TERMINAL_TITLE_IGNORE */
+ };
+
+ return formats[terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_TITLE_MODE)];
+}
+
+/**
+ * terminal_screen_format_title::
+ * @screen:
+ * @raw_title: main ingredient
+ * @titleptr <inout>: pointer of the current title string
+ *
+ * Format title according @format, and stores it in <literal>*titleptr</literal>.
+ * Always ensures that *titleptr will be non-NULL.
+ *
+ * Returns: %TRUE iff the title changed
+ */
+static gboolean
+terminal_screen_format_title (TerminalScreen *screen,
+ const char *raw_title,
+ char **titleptr)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ const char *format, *arg;
+ const char *static_title = NULL;
+ GString *title;
+ gboolean add_sep = FALSE;
+
+ g_assert (titleptr);
+
+ /* use --title argument if one was supplied, otherwise ask the profile */
+ if (priv->override_title)
+ static_title = priv->override_title;
+ else
+ static_title = terminal_profile_get_property_string (priv->profile, TERMINAL_PROFILE_TITLE);
+
+ //title = g_string_sized_new (strlen (static_title) + strlen (raw_title) + 3 + 1);
+ title = g_string_sized_new (128);
+
+ format = terminal_screen_get_title_format (screen);
+ for (arg = format; *arg; arg += 2)
+ {
+ const char *text_to_append = NULL;
+
+ g_assert (arg[0] == '%');
+
+ switch (arg[1])
+ {
+ case 'A':
+ text_to_append = raw_title ? raw_title : static_title;
+ break;
+ case 'D':
+ text_to_append = raw_title;
+ break;
+ case 'S':
+ text_to_append = static_title;
+ break;
+ case '-':
+ text_to_append = NULL;
+ add_sep = TRUE;
+ break;
+ default:
+ g_assert_not_reached ();
+ }
+
+ if (!text_to_append || !text_to_append[0])
+ continue;
+
+ if (add_sep && title->len > 0)
+ g_string_append (title, " - ");
+
+ g_string_append (title, text_to_append);
+ add_sep = FALSE;
+ }
+
+ if (*titleptr == NULL || strcmp (title->str, *titleptr) != 0)
+ {
+ g_free (*titleptr);
+ *titleptr = g_string_free (title, FALSE);
+ return TRUE;
+ }
+
+ g_string_free (title, TRUE);
+ return FALSE;
+}
+
+static void
+terminal_screen_cook_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (terminal_screen_format_title (screen, priv->raw_title, &priv->cooked_title))
+ g_object_notify (G_OBJECT (screen), "title");
+}
+
+static void
+terminal_screen_cook_icon_title (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (terminal_screen_format_title (screen, priv->raw_icon_title, &priv->cooked_icon_title))
+ g_object_notify (G_OBJECT (screen), "icon-title");
+}
+
+static void
+terminal_screen_profile_notify_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GObject *object = G_OBJECT (screen);
+ VteTerminal *vte_terminal = VTE_TERMINAL (screen);
+ const char *prop_name;
+ TerminalBackgroundType bg_type;
+ TerminalWindow *window;
+
+ if (pspec)
+ prop_name = pspec->name;
+ else
+ prop_name = NULL;
+
+ 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_POSITION))
+ _terminal_screen_update_scrollbar (screen);
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_TITLE_MODE) ||
+ prop_name == I_(TERMINAL_PROFILE_TITLE))
+ {
+ terminal_screen_cook_title (screen);
+ terminal_screen_cook_icon_title (screen);
+ }
+
+ if (gtk_widget_get_realized (GTK_WIDGET (screen)) &&
+ (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_USE_SYSTEM_FONT) ||
+ prop_name == I_(TERMINAL_PROFILE_FONT)))
+ terminal_screen_change_font (screen);
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_USE_THEME_COLORS) ||
+ prop_name == I_(TERMINAL_PROFILE_FOREGROUND_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BACKGROUND_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG) ||
+ prop_name == I_(TERMINAL_PROFILE_BOLD_COLOR) ||
+ prop_name == I_(TERMINAL_PROFILE_PALETTE))
+ update_color_scheme (screen);
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SILENT_BELL))
+ vte_terminal_set_audible_bell (vte_terminal, !terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SILENT_BELL));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_WORD_CHARS))
+ vte_terminal_set_word_chars (vte_terminal,
+ terminal_profile_get_property_string (profile, TERMINAL_PROFILE_WORD_CHARS));
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE))
+ vte_terminal_set_scroll_on_keystroke (vte_terminal,
+ terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_KEYSTROKE));
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_SCROLL_ON_OUTPUT))
+ vte_terminal_set_scroll_on_output (vte_terminal,
+ terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLL_ON_OUTPUT));
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_LINES) ||
+ prop_name == I_(TERMINAL_PROFILE_SCROLLBACK_UNLIMITED))
+ {
+ glong lines = terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLLBACK_UNLIMITED) ?
+ -1 : terminal_profile_get_property_int (profile, TERMINAL_PROFILE_SCROLLBACK_LINES);
+ vte_terminal_set_scrollback_lines (vte_terminal, lines);
+ }
+
+#ifdef ENABLE_SKEY
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_USE_SKEY))
+ {
+ if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SKEY))
+ {
+ guint i;
+
+ for (i = 0; i < n_skey_regexes; ++i)
+ {
+ TagData *tag_data;
+
+ tag_data = g_slice_new (TagData);
+ tag_data->flavor = FLAVOR_SKEY;
+ tag_data->tag = vte_terminal_match_add_gregex (vte_terminal, skey_regexes[i], 0);
+ vte_terminal_match_set_cursor_type (vte_terminal, tag_data->tag, SKEY_MATCH_CURSOR);
+
+ priv->match_tags = g_slist_prepend (priv->match_tags, tag_data);
+ }
+ }
+ else
+ {
+ terminal_screen_skey_match_remove (screen);
+ }
+ }
+#endif /* ENABLE_SKEY */
+
+ if (!prop_name ||
+ prop_name == I_(TERMINAL_PROFILE_BACKGROUND_TYPE) ||
+ prop_name == I_(TERMINAL_PROFILE_BACKGROUND_IMAGE) ||
+ prop_name == I_(TERMINAL_PROFILE_BACKGROUND_DARKNESS) ||
+ prop_name == I_(TERMINAL_PROFILE_SCROLL_BACKGROUND))
+ {
+ bg_type = terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKGROUND_TYPE);
+
+ if (bg_type == TERMINAL_BACKGROUND_IMAGE)
+ {
+ vte_terminal_set_background_image (vte_terminal,
+ terminal_profile_get_property_object (profile, TERMINAL_PROFILE_BACKGROUND_IMAGE));
+ vte_terminal_set_scroll_background (vte_terminal,
+ terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_SCROLL_BACKGROUND));
+ }
+ else
+ {
+ vte_terminal_set_background_image (vte_terminal, NULL);
+ vte_terminal_set_scroll_background (vte_terminal, FALSE);
+ }
+
+ if (bg_type == TERMINAL_BACKGROUND_IMAGE ||
+ bg_type == TERMINAL_BACKGROUND_TRANSPARENT)
+ {
+ vte_terminal_set_background_saturation (vte_terminal,
+ 1.0 - terminal_profile_get_property_double (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS));
+ vte_terminal_set_opacity (vte_terminal,
+ 0xffff * terminal_profile_get_property_double (profile, TERMINAL_PROFILE_BACKGROUND_DARKNESS));
+ }
+ else
+ {
+ vte_terminal_set_background_saturation (vte_terminal, 1.0); /* normal color */
+ vte_terminal_set_opacity (vte_terminal, 0xffff);
+ }
+
+ /* FIXME: Don't enable this if we have a compmgr. */
+ vte_terminal_set_background_transparent (vte_terminal,
+ bg_type == TERMINAL_BACKGROUND_TRANSPARENT &&
+ !window_uses_argb_visual (screen));
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_BACKSPACE_BINDING))
+ vte_terminal_set_backspace_binding (vte_terminal,
+ terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_BACKSPACE_BINDING));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_DELETE_BINDING))
+ vte_terminal_set_delete_binding (vte_terminal,
+ terminal_profile_get_property_enum (profile, TERMINAL_PROFILE_DELETE_BINDING));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_ALLOW_BOLD))
+ vte_terminal_set_allow_bold (vte_terminal,
+ terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_ALLOW_BOLD));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_BLINK_MODE))
+ vte_terminal_set_cursor_blink_mode (vte_terminal,
+ terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_CURSOR_BLINK_MODE));
+
+ if (!prop_name || prop_name == I_(TERMINAL_PROFILE_CURSOR_SHAPE))
+ vte_terminal_set_cursor_shape (vte_terminal,
+ terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_CURSOR_SHAPE));
+
+ g_object_thaw_notify (object);
+}
+
+static void
+update_color_scheme (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalProfile *profile = priv->profile;
+ GtkStyle *style;
+ GdkColor colors[TERMINAL_PALETTE_SIZE];
+ const GdkColor *fg_color, *bg_color, *bold_color;
+ GdkColor fg, bg;
+ guint n_colors;
+
+ style = gtk_widget_get_style (GTK_WIDGET (screen));
+ if (!style)
+ return;
+
+ fg = style->text[GTK_STATE_NORMAL];
+ bg = style->base[GTK_STATE_NORMAL];
+ bold_color = NULL;
+
+ if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_THEME_COLORS))
+ {
+ fg_color = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_FOREGROUND_COLOR);
+ bg_color = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BACKGROUND_COLOR);
+
+ if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_BOLD_COLOR_SAME_AS_FG))
+ bold_color = terminal_profile_get_property_boxed (profile, TERMINAL_PROFILE_BOLD_COLOR);
+
+ if (fg_color)
+ fg = *fg_color;
+ if (bg_color)
+ bg = *bg_color;
+ }
+
+ n_colors = G_N_ELEMENTS (colors);
+ terminal_profile_get_palette (priv->profile, colors, &n_colors);
+ vte_terminal_set_colors (VTE_TERMINAL (screen), &fg, &bg,
+ colors, n_colors);
+ if (bold_color)
+ vte_terminal_set_color_bold (VTE_TERMINAL (screen), bold_color);
+ vte_terminal_set_background_tint_color (VTE_TERMINAL (screen), &bg);
+}
+
+void
+terminal_screen_set_font (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalProfile *profile;
+ PangoFontDescription *desc;
+
+ profile = priv->profile;
+
+ if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_SYSTEM_FONT))
+ g_object_get (terminal_app_get (), "system-font", &desc, NULL);
+ else
+ g_object_get (profile, TERMINAL_PROFILE_FONT, &desc, NULL);
+ g_assert (desc);
+
+ if (pango_font_description_get_size_is_absolute (desc))
+ pango_font_description_set_absolute_size (desc,
+ priv->font_scale *
+ pango_font_description_get_size (desc));
+ else
+ pango_font_description_set_size (desc,
+ priv->font_scale *
+ pango_font_description_get_size (desc));
+
+ vte_terminal_set_font (VTE_TERMINAL (screen), desc);
+
+ pango_font_description_free (desc);
+}
+
+static void
+terminal_screen_system_font_notify_cb (TerminalApp *app,
+ GParamSpec *pspec,
+ TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
+ return;
+
+ if (!terminal_profile_get_property_boolean (priv->profile, TERMINAL_PROFILE_USE_SYSTEM_FONT))
+ return;
+
+ terminal_screen_change_font (screen);
+}
+
+static void
+terminal_screen_change_font (TerminalScreen *screen)
+{
+ TerminalWindow *window;
+
+ terminal_screen_set_font (screen);
+
+ window = terminal_screen_get_window (screen);
+ terminal_window_set_size (window, screen, TRUE);
+}
+
+static void
+profile_forgotten_callback (TerminalProfile *profile,
+ TerminalScreen *screen)
+{
+ TerminalProfile *new_profile;
+
+ new_profile = terminal_app_get_profile_for_new_term (terminal_app_get ());
+ g_assert (new_profile != NULL);
+ terminal_screen_set_profile (screen, new_profile);
+}
+
+void
+terminal_screen_set_profile (TerminalScreen *screen,
+ TerminalProfile *profile)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalProfile *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;
+ }
+
+ if (priv->profile_forgotten_id)
+ {
+ g_signal_handler_disconnect (G_OBJECT (priv->profile),
+ priv->profile_forgotten_id);
+ priv->profile_forgotten_id = 0;
+ }
+
+ priv->profile = profile;
+ if (profile)
+ {
+ g_object_ref (profile);
+ priv->profile_changed_id =
+ g_signal_connect (profile, "notify",
+ G_CALLBACK (terminal_screen_profile_notify_cb),
+ screen);
+ priv->profile_forgotten_id =
+ g_signal_connect (G_OBJECT (profile),
+ "forgotten",
+ G_CALLBACK (profile_forgotten_callback),
+ screen);
+
+ terminal_screen_profile_notify_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");
+}
+
+TerminalProfile*
+terminal_screen_get_profile (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ g_assert (priv->profile != NULL);
+ return priv->profile;
+}
+
+void
+terminal_screen_set_override_command (TerminalScreen *screen,
+ char **argv)
+{
+ TerminalScreenPrivate *priv;
+
+ g_return_if_fail (TERMINAL_IS_SCREEN (screen));
+
+ priv = screen->priv;
+ g_strfreev (priv->override_command);
+ priv->override_command = g_strdupv (argv);
+}
+
+const char**
+terminal_screen_get_override_command (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return (const char**) screen->priv->override_command;
+}
+
+void
+terminal_screen_set_initial_environment (TerminalScreen *screen,
+ char **argv)
+{
+ TerminalScreenPrivate *priv;
+
+ g_return_if_fail (TERMINAL_IS_SCREEN (screen));
+
+ priv = screen->priv;
+ g_assert (priv->initial_env == NULL);
+ priv->initial_env = g_strdupv (argv);
+}
+
+char**
+terminal_screen_get_initial_environment (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return screen->priv->initial_env;
+}
+
+static gboolean
+get_child_command (TerminalScreen *screen,
+ const char *shell_env,
+ GSpawnFlags *spawn_flags_p,
+ char ***argv_p,
+ GError **err)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalProfile *profile;
+ char **argv;
+
+ g_assert (spawn_flags_p != NULL && argv_p != NULL);
+
+ profile = priv->profile;
+
+ *argv_p = argv = NULL;
+
+ if (priv->override_command)
+ {
+ argv = g_strdupv (priv->override_command);
+
+ *spawn_flags_p |= G_SPAWN_SEARCH_PATH;
+ }
+ else if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_USE_CUSTOM_COMMAND))
+ {
+ if (!g_shell_parse_argv (terminal_profile_get_property_string (profile, TERMINAL_PROFILE_CUSTOM_COMMAND),
+ NULL, &argv,
+ err))
+ return FALSE;
+
+ *spawn_flags_p |= G_SPAWN_SEARCH_PATH;
+ }
+ else
+ {
+ 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;
+
+ argv = g_new (char*, 3);
+
+ argv[argc++] = shell;
+
+ if (terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_LOGIN_SHELL))
+ argv[argc++] = g_strconcat ("-", only_name, NULL);
+ else
+ argv[argc++] = g_strdup (only_name);
+
+ argv[argc++] = NULL;
+
+ *spawn_flags_p |= G_SPAWN_FILE_AND_ARGV_ZERO;
+ }
+
+ *argv_p = argv;
+
+ return TRUE;
+}
+
+static char**
+get_child_environment (TerminalScreen *screen,
+ char **shell)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GtkWidget *term = GTK_WIDGET (screen);
+ GtkWidget *window;
+ char **env;
+ char *e, *v;
+ GHashTable *env_table;
+ GHashTableIter iter;
+ GPtrArray *retval;
+ guint i;
+
+ window = gtk_widget_get_toplevel (term);
+ g_assert (window != NULL);
+ g_assert (gtk_widget_is_toplevel (window));
+
+ env_table = g_hash_table_new_full (g_str_hash, g_str_equal, g_free, g_free);
+
+ /* First take the factory's environment */
+ env = g_listenv ();
+ for (i = 0; env[i]; ++i)
+ g_hash_table_insert (env_table, env[i], g_strdup (g_getenv (env[i])));
+ g_free (env); /* the strings themselves are now owned by the hash table */
+
+ /* and then merge the child environment, if any */
+ env = priv->initial_env;
+ 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, "MATE_DESKTOP_ICON");
+
+ g_hash_table_replace (env_table, g_strdup ("COLORTERM"), g_strdup (EXECUTABLE_NAME));
+ g_hash_table_replace (env_table, g_strdup ("TERM"), g_strdup ("xterm")); /* FIXME configurable later? */
+
+#ifdef GDK_WINDOWING_X11
+ /* FIXME: moving the tab between windows, or the window between displays will make the next two invalid... */
+ g_hash_table_replace (env_table, g_strdup ("WINDOWID"), g_strdup_printf ("%ld", GDK_WINDOW_XWINDOW (gtk_widget_get_window (window))));
+ g_hash_table_replace (env_table, g_strdup ("DISPLAY"), g_strdup (gdk_display_get_name (gtk_widget_get_display (window))));
+#endif
+
+ terminal_util_add_proxy_env (env_table);
+
+ 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);
+
+ *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_PROFILE
+};
+
+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_launch_child_on_idle (screen);
+ break;
+ case RESPONSE_EDIT_PROFILE:
+ terminal_app_edit_profile (terminal_app_get (),
+ terminal_screen_get_profile (screen),
+ GTK_WINDOW (terminal_screen_get_window (screen)),
+ "custom-command-entry");
+ break;
+ default:
+ gtk_widget_destroy (info_bar);
+ break;
+ }
+}
+
+static gboolean
+terminal_screen_launch_child_cb (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ VteTerminal *terminal = VTE_TERMINAL (screen);
+ TerminalProfile *profile;
+ char **env, **argv;
+ char *shell = NULL;
+ GError *err = NULL;
+ const char *working_dir;
+ VtePtyFlags pty_flags = VTE_PTY_DEFAULT;
+ GSpawnFlags spawn_flags = 0;
+ GPid pid;
+
+ priv->launch_child_source_id = 0;
+
+ _terminal_debug_print (TERMINAL_DEBUG_PROCESSES,
+ "[screen %p] now launching the child process\n",
+ screen);
+
+ profile = priv->profile;
+
+ env = get_child_environment (screen, &shell);
+
+ if (priv->initial_working_directory)
+ working_dir = priv->initial_working_directory;
+ else
+ working_dir = g_get_home_dir ();
+
+ if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_LOGIN_SHELL))
+ pty_flags |= VTE_PTY_NO_LASTLOG;
+ if (!terminal_profile_get_property_boolean (profile, TERMINAL_PROFILE_UPDATE_RECORDS))
+ pty_flags |= VTE_PTY_NO_UTMP | VTE_PTY_NO_WTMP;
+
+ if (!get_child_command (screen, shell, &spawn_flags, &argv, &err) ||
+ !vte_terminal_fork_command_full (terminal,
+ pty_flags,
+ working_dir,
+ argv,
+ env,
+ spawn_flags,
+ NULL, NULL,
+ &pid,
+ &err)) {
+ GtkWidget *info_bar;
+
+ info_bar = terminal_info_bar_new (GTK_MESSAGE_ERROR,
+ _("_Profile Preferences"), RESPONSE_EDIT_PROFILE,
+ _("_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", err->message);
+ g_signal_connect (info_bar, "response",
+ G_CALLBACK (info_bar_response_cb), screen);
+
+ gtk_box_pack_start (GTK_BOX (terminal_screen_container_get_from_screen (screen)),
+ info_bar, FALSE, FALSE, 0);
+ gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), GTK_RESPONSE_CANCEL);
+ gtk_widget_show (info_bar);
+
+ g_error_free (err);
+ g_strfreev (env);
+ g_free (shell);
+
+ return FALSE;
+ }
+
+ priv->child_pid = pid;
+ priv->pty_fd = vte_terminal_get_pty (terminal);
+
+ g_free (shell);
+ g_strfreev (argv);
+ g_strfreev (env);
+
+ return FALSE; /* don't run again */
+}
+
+static void
+terminal_screen_launch_child_on_idle (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->launch_child_source_id != 0)
+ return;
+
+ _terminal_debug_print (TERMINAL_DEBUG_PROCESSES,
+ "[screen %p] scheduling launching the child process on idle\n",
+ screen);
+
+ priv->launch_child_source_id = g_idle_add ((GSourceFunc) terminal_screen_launch_child_cb, screen);
+}
+
+static TerminalScreenPopupInfo *
+terminal_screen_popup_info_new (TerminalScreen *screen)
+{
+ TerminalScreenPopupInfo *info;
+
+ info = g_slice_new0 (TerminalScreenPopupInfo);
+ info->ref_count = 1;
+ info->screen = g_object_ref (screen);
+ info->window = terminal_screen_get_window (screen);
+
+ 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_object_unref (info->screen);
+ g_free (info->string);
+ 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 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;
+ int char_width, char_height, row, col;
+ char *matched_string;
+ int matched_flavor = 0;
+ guint state;
+ GtkBorder *inner_border = NULL;
+
+ state = event->state & gtk_accelerator_get_default_mod_mask ();
+
+ terminal_screen_get_cell_size (screen, &char_width, &char_height);
+
+ gtk_widget_style_get (widget, "inner-border", &inner_border, NULL);
+ row = (event->x - (inner_border ? inner_border->left : 0)) / char_width;
+ col = (event->y - (inner_border ? inner_border->top : 0)) / char_height;
+ gtk_border_free (inner_border);
+
+ /* FIXMEchpe: add vte API to do this check by widget coords instead of grid coords */
+ matched_string = terminal_screen_check_match (screen, row, col, &matched_flavor);
+
+ if (matched_string != NULL &&
+ (event->button == 1 || event->button == 2) &&
+ (state & GDK_CONTROL_MASK))
+ {
+ gboolean handled = FALSE;
+
+#ifdef ENABLE_SKEY
+ if (matched_flavor != FLAVOR_SKEY ||
+ terminal_profile_get_property_boolean (screen->priv->profile, TERMINAL_PROFILE_USE_SKEY))
+#endif
+ {
+ g_signal_emit (screen, signals[MATCH_CLICKED], 0,
+ matched_string,
+ matched_flavor,
+ state,
+ &handled);
+ }
+
+ g_free (matched_string);
+
+ if (handled)
+ return TRUE; /* don't do anything else such as select with the click */
+ }
+
+ if (event->button == 3 &&
+ (state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK | GDK_MOD1_MASK)) == 0)
+ {
+ TerminalScreenPopupInfo *info;
+
+ info = terminal_screen_popup_info_new (screen);
+ info->button = event->button;
+ info->state = state;
+ info->timestamp = event->time;
+ info->string = matched_string; /* adopted */
+ info->flavour = matched_flavor;
+
+ g_signal_emit (screen, signals[SHOW_POPUP_MENU], 0, info);
+ terminal_screen_popup_info_unref (info);
+
+ 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;
+}
+
+static void
+terminal_screen_set_dynamic_title (TerminalScreen *screen,
+ const char *title,
+ gboolean userset)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ g_assert (TERMINAL_IS_SCREEN (screen));
+
+ if ((priv->user_title && !userset) ||
+ (priv->raw_title && title &&
+ strcmp (priv->raw_title, title) == 0))
+ return;
+
+ g_free (priv->raw_title);
+ priv->raw_title = g_strdup (title);
+ terminal_screen_cook_title (screen);
+}
+
+static void
+terminal_screen_set_dynamic_icon_title (TerminalScreen *screen,
+ const char *icon_title,
+ gboolean userset)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GObject *object = G_OBJECT (screen);
+
+ g_assert (TERMINAL_IS_SCREEN (screen));
+
+ if ((priv->user_title && !userset) ||
+ (priv->icon_title_set &&
+ priv->raw_icon_title &&
+ icon_title &&
+ strcmp (priv->raw_icon_title, icon_title) == 0))
+ return;
+
+ g_object_freeze_notify (object);
+
+ g_free (priv->raw_icon_title);
+ priv->raw_icon_title = g_strdup (icon_title);
+ priv->icon_title_set = TRUE;
+
+ g_object_notify (object, "icon-title-set");
+ terminal_screen_cook_icon_title (screen);
+
+ g_object_thaw_notify (object);
+}
+
+void
+terminal_screen_set_override_title (TerminalScreen *screen,
+ const char *title)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ char *old_title;
+
+ old_title = priv->override_title;
+ priv->override_title = g_strdup (title);
+ g_free (old_title);
+
+ terminal_screen_set_dynamic_title (screen, title, FALSE);
+ terminal_screen_set_dynamic_icon_title (screen, title, FALSE);
+}
+
+const char*
+terminal_screen_get_dynamic_title (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return screen->priv->raw_title;
+}
+
+const char*
+terminal_screen_get_dynamic_icon_title (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), NULL);
+
+ return screen->priv->raw_icon_title;
+}
+
+/**
+ * terminal_screen_get_current_dir:
+ * @screen:
+ *
+ * Tries to determine the current working directory of the foreground process
+ * in @screen's PTY, falling back to the current working directory of the
+ * primary child.
+ *
+ * Returns: a newly allocated string containing the current working directory,
+ * or %NULL on failure
+ */
+char*
+terminal_screen_get_current_dir (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ char *cwd;
+
+ if (priv->pty_fd != -1) {
+#if 0
+ /* Get the foreground process ID */
+ cwd = cwd_of_pid (tcgetpgrp (priv->pty_fd));
+ if (cwd != NULL)
+ return cwd;
+#endif
+
+ /* If that didn't work, try falling back to the primary child. See bug #575184. */
+ cwd = cwd_of_pid (priv->child_pid);
+ if (cwd != NULL)
+ return cwd;
+ }
+
+ return NULL;
+}
+
+/**
+ * terminal_screen_get_current_dir_with_fallback:
+ * @screen:
+ *
+ * Like terminal_screen_get_current_dir(), but falls back to returning
+ * @screen's initial working directory, with a further fallback to the
+ * user's home directory.
+ *
+ * Returns: a newly allocated string containing the current working directory,
+ * or %NULL on failure
+ */
+char*
+terminal_screen_get_current_dir_with_fallback (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ if (priv->pty_fd == -1)
+ return g_strdup (priv->initial_working_directory);
+
+ return terminal_screen_get_current_dir (screen);
+}
+
+void
+terminal_screen_set_font_scale (TerminalScreen *screen,
+ double factor)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ g_return_if_fail (TERMINAL_IS_SCREEN (screen));
+
+ if (factor < TERMINAL_SCALE_MINIMUM)
+ factor = TERMINAL_SCALE_MINIMUM;
+ if (factor > TERMINAL_SCALE_MAXIMUM)
+ factor = TERMINAL_SCALE_MAXIMUM;
+
+ priv->font_scale = factor;
+
+ if (gtk_widget_get_realized (GTK_WIDGET (screen)))
+ {
+ /* Update the font */
+ terminal_screen_change_font (screen);
+ }
+}
+
+double
+terminal_screen_get_font_scale (TerminalScreen *screen)
+{
+ g_return_val_if_fail (TERMINAL_IS_SCREEN (screen), 1.0);
+
+ return screen->priv->font_scale;
+}
+
+static void
+terminal_screen_window_title_changed (VteTerminal *vte_terminal,
+ TerminalScreen *screen)
+{
+ terminal_screen_set_dynamic_title (screen,
+ vte_terminal_get_window_title (vte_terminal),
+ FALSE);
+}
+
+static void
+terminal_screen_icon_title_changed (VteTerminal *vte_terminal,
+ TerminalScreen *screen)
+{
+ terminal_screen_set_dynamic_icon_title (screen,
+ vte_terminal_get_icon_title (vte_terminal),
+ FALSE);
+}
+
+static void
+terminal_screen_child_exited (VteTerminal *terminal)
+{
+ TerminalScreen *screen = TERMINAL_SCREEN (terminal);
+ TerminalScreenPrivate *priv = screen->priv;
+ TerminalExitAction action;
+
+ /* 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;
+ priv->pty_fd = -1;
+
+ action = terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_EXIT_ACTION);
+
+ switch (action)
+ {
+ case TERMINAL_EXIT_CLOSE:
+ g_signal_emit (screen, signals[CLOSE_SCREEN], 0);
+ break;
+ case TERMINAL_EXIT_RESTART:
+ terminal_screen_launch_child_on_idle (screen);
+ break;
+ case TERMINAL_EXIT_HOLD: {
+ GtkWidget *info_bar;
+ int status;
+
+ status = vte_terminal_get_child_exit_status (terminal);
+
+ 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 terminated by signal %d."), WTERMSIG (status));
+ } else {
+ terminal_info_bar_format_text (TERMINAL_INFO_BAR (info_bar),
+ _("The child process was terminated."));
+ }
+ g_signal_connect (info_bar, "response",
+ G_CALLBACK (info_bar_response_cb), screen);
+
+ gtk_box_pack_start (GTK_BOX (terminal_screen_container_get_from_screen (screen)),
+ info_bar, FALSE, FALSE, 0);
+ gtk_info_bar_set_default_response (GTK_INFO_BAR (info_bar), RESPONSE_RELAUNCH);
+ gtk_widget_show (info_bar);
+ break;
+ }
+
+ default:
+ break;
+ }
+}
+
+void
+terminal_screen_set_user_title (TerminalScreen *screen,
+ const char *text)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+
+ /* The user set the title to nothing, let's understand that as a
+ request to revert to dynamically setting the title again. */
+ if (!text || !text[0])
+ priv->user_title = FALSE;
+ else
+ {
+ priv->user_title = TRUE;
+ terminal_screen_set_dynamic_title (screen, text, TRUE);
+ terminal_screen_set_dynamic_icon_title (screen, text, TRUE);
+ }
+}
+
+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))
+ {
+ char **uris;
+ char *text;
+ 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);
+ g_free (text);
+
+ g_strfreev (uris);
+ }
+ else if (gtk_targets_include_text (&selection_data_target, 1))
+ {
+ 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));
+ g_free (text);
+ }
+ else switch (info)
+ {
+ case TARGET_COLOR:
+ {
+ guint16 *data = (guint16 *)selection_data_data;
+ GdkColor 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 = data[0];
+ color.green = data[1];
+ color.blue = data[2];
+ /* FIXME: use opacity from data[3] */
+
+ g_object_set (priv->profile,
+ TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_SOLID,
+ TERMINAL_PROFILE_USE_THEME_COLORS, FALSE,
+ TERMINAL_PROFILE_BACKGROUND_COLOR, &color,
+ NULL);
+ }
+ break;
+
+ case TARGET_MOZ_URL:
+ {
+ char *utf8_data, *newline, *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.
+ */
+ 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;
+
+ 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_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_BGIMAGE:
+ {
+ char *utf8_data;
+ char **uris;
+
+ if (selection_data_length < 0 || selection_data_format != 8)
+ return;
+
+ utf8_data = g_strndup ((char *) selection_data_data, selection_data_length);
+ uris = g_uri_list_extract_uris (utf8_data);
+ g_free (utf8_data);
+
+ /* FIXME: use terminal_util_transform_uris_to_quoted_fuse_paths? */
+
+ if (uris && uris[0])
+ {
+ char *filename;
+
+ filename = g_filename_from_uri (uris[0], NULL, NULL);
+ if (filename)
+ {
+ g_object_set (priv->profile,
+ TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_IMAGE,
+ TERMINAL_PROFILE_BACKGROUND_IMAGE_FILE, filename,
+ NULL);
+ }
+
+ g_free (filename);
+ }
+
+ g_strfreev (uris);
+ }
+ break;
+
+ case TARGET_RESET_BG:
+ g_object_set (priv->profile,
+ TERMINAL_PROFILE_BACKGROUND_TYPE, TERMINAL_BACKGROUND_SOLID,
+ NULL);
+ break;
+
+ case TARGET_TAB:
+ {
+ GtkWidget *container;
+ TerminalScreen *moving_screen;
+ TerminalWindow *source_window;
+ TerminalWindow *dest_window;
+ GtkWidget *dest_notebook;
+ int page_num;
+
+ container = *(GtkWidget**) selection_data_data;
+ if (!GTK_IS_WIDGET (container))
+ return;
+
+ moving_screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
+ g_return_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);
+ dest_notebook = terminal_window_get_notebook (dest_window);
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (dest_notebook),
+ GTK_WIDGET (screen));
+ terminal_window_move_screen (source_window, dest_window, moving_screen, page_num + 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 policy = GTK_POLICY_ALWAYS;
+ GtkCornerType corner = GTK_CORNER_TOP_LEFT;
+
+ container = terminal_screen_container_get_from_screen (screen);
+ if (container == NULL)
+ return;
+
+ switch (terminal_profile_get_property_enum (priv->profile, TERMINAL_PROFILE_SCROLLBAR_POSITION))
+ {
+ case TERMINAL_SCROLLBAR_HIDDEN:
+ policy = GTK_POLICY_NEVER;
+ break;
+ case TERMINAL_SCROLLBAR_RIGHT:
+ policy = GTK_POLICY_ALWAYS;
+ corner = GTK_CORNER_TOP_LEFT;
+ break;
+ case TERMINAL_SCROLLBAR_LEFT:
+ policy = GTK_POLICY_ALWAYS;
+ corner = GTK_CORNER_TOP_RIGHT;
+ break;
+ default:
+ g_assert_not_reached ();
+ break;
+ }
+
+ terminal_screen_container_set_placement (container, corner);
+ terminal_screen_container_set_policy (container, GTK_POLICY_NEVER, policy);
+}
+
+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);
+}
+
+#ifdef ENABLE_SKEY
+static void
+terminal_screen_skey_match_remove (TerminalScreen *screen)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GSList *l, *next;
+
+ l = priv->match_tags;
+ while (l != NULL)
+ {
+ TagData *tag_data = (TagData *) l->data;
+
+ next = l->next;
+ if (tag_data->flavor == FLAVOR_SKEY)
+ {
+ vte_terminal_match_remove (VTE_TERMINAL (screen), tag_data->tag);
+ priv->match_tags = g_slist_delete_link (priv->match_tags, l);
+ }
+
+ l = next;
+ }
+}
+#endif /* ENABLE_SKEY */
+
+static char*
+terminal_screen_check_match (TerminalScreen *screen,
+ int column,
+ int row,
+ int *flavor)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ GSList *tags;
+ int tag;
+ char *match;
+
+ match = vte_terminal_match_check (VTE_TERMINAL (screen), column, row, &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;
+}
+
+void
+terminal_screen_save_config (TerminalScreen *screen,
+ GKeyFile *key_file,
+ const char *group)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ VteTerminal *terminal = VTE_TERMINAL (screen);
+ TerminalProfile *profile = priv->profile;
+ const char *profile_id;
+ char *working_directory;
+
+ profile_id = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_NAME);
+ g_key_file_set_string (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_PROFILE_ID, profile_id);
+
+ if (priv->override_command)
+ terminal_util_key_file_set_argv (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_COMMAND,
+ -1, priv->override_command);
+
+ if (priv->override_title)
+ g_key_file_set_string (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_TITLE, priv->override_title);
+
+ /* FIXMEchpe: use the initial_working_directory instead?? */
+ working_directory = terminal_screen_get_current_dir (screen);
+ if (working_directory)
+ terminal_util_key_file_set_string_escape (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_WORKING_DIRECTORY, working_directory);
+ g_free (working_directory);
+
+ g_key_file_set_double (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_ZOOM, priv->font_scale);
+
+ g_key_file_set_integer (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_WIDTH,
+ vte_terminal_get_column_count (terminal));
+ g_key_file_set_integer (key_file, group, TERMINAL_CONFIG_TERMINAL_PROP_HEIGHT,
+ vte_terminal_get_row_count (terminal));
+}
+
+/**
+ * terminal_screen_has_foreground_process:
+ * @screen:
+ *
+ * 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)
+{
+ TerminalScreenPrivate *priv = screen->priv;
+ int fgpid;
+
+ if (priv->pty_fd == -1)
+ return FALSE;
+
+ fgpid = tcgetpgrp (priv->pty_fd);
+ if (fgpid == -1 || fgpid == priv->child_pid)
+ return FALSE;
+
+ return TRUE;
+
+#if 0
+ char *cmdline, *basename, *name;
+ gsize len;
+ char filename[64];
+
+ g_snprintf (filename, sizeof (filename), "/proc/%d/cmdline", fgpid);
+ if (!g_file_get_contents (filename, &cmdline, &len, NULL))
+ return TRUE;
+
+ basename = g_path_get_basename (cmdline);
+ g_free (cmdline);
+ if (!basename)
+ return TRUE;
+
+ name = g_filename_to_utf8 (basename, -1, NULL, NULL, NULL);
+ g_free (basename);
+ if (!name)
+ return TRUE;
+
+ if (process_name)
+ *process_name = name;
+
+ return TRUE;
+#endif
+}
diff --git a/src/terminal-screen.h b/src/terminal-screen.h
new file mode 100644
index 0000000..885e7d2
--- /dev/null
+++ b/src/terminal-screen.h
@@ -0,0 +1,160 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2008 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_SCREEN_H
+#define TERMINAL_SCREEN_H
+
+#include <vte/vte.h>
+
+#include "terminal-profile.h"
+
+G_BEGIN_DECLS
+
+typedef enum {
+ FLAVOR_AS_IS,
+ FLAVOR_DEFAULT_TO_HTTP,
+ FLAVOR_VOIP_CALL,
+ FLAVOR_EMAIL,
+ FLAVOR_SKEY
+} TerminalURLFlavour;
+
+/* 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,
+ TerminalProfile *old_profile);
+ void (* show_popup_menu) (TerminalScreen *screen,
+ TerminalScreenPopupInfo *info);
+ gboolean (* match_clicked) (TerminalScreen *screen,
+ const char *url,
+ int flavour,
+ guint state);
+ void (* close_screen) (TerminalScreen *screen);
+};
+
+GType terminal_screen_get_type (void) G_GNUC_CONST;
+
+TerminalScreen *terminal_screen_new (TerminalProfile *profile,
+ char **override_command,
+ const char *title,
+ const char *working_dir,
+ char **child_env,
+ double zoom);
+
+void terminal_screen_set_profile (TerminalScreen *screen,
+ TerminalProfile *profile);
+TerminalProfile* terminal_screen_get_profile (TerminalScreen *screen);
+
+void terminal_screen_set_override_command (TerminalScreen *screen,
+ char **argv);
+const char** terminal_screen_get_override_command (TerminalScreen *screen);
+
+void terminal_screen_set_initial_environment (TerminalScreen *screen,
+ char **argv);
+char ** terminal_screen_get_initial_environment (TerminalScreen *screen);
+
+const char* terminal_screen_get_raw_title (TerminalScreen *screen);
+const char* terminal_screen_get_title (TerminalScreen *screen);
+const char* terminal_screen_get_icon_title (TerminalScreen *screen);
+gboolean terminal_screen_get_icon_title_set (TerminalScreen *screen);
+
+void terminal_screen_set_user_title (TerminalScreen *screen,
+ const char *text);
+
+void terminal_screen_set_override_title (TerminalScreen *screen,
+ const char *title);
+
+const char *terminal_screen_get_dynamic_title (TerminalScreen *screen);
+const char *terminal_screen_get_dynamic_icon_title (TerminalScreen *screen);
+
+char *terminal_screen_get_current_dir (TerminalScreen *screen);
+char *terminal_screen_get_current_dir_with_fallback (TerminalScreen *screen);
+
+void terminal_screen_set_font (TerminalScreen *screen);
+void terminal_screen_set_font_scale (TerminalScreen *screen,
+ double factor);
+double terminal_screen_get_font_scale (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);
+
+/* 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;
+ TerminalWindow *window;
+ TerminalScreen *screen;
+ char *string;
+ TerminalURLFlavour flavour;
+ 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-dialog.c b/src/terminal-search-dialog.c
new file mode 100644
index 0000000..81e3317
--- /dev/null
+++ b/src/terminal-search-dialog.c
@@ -0,0 +1,378 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#include "config.h"
+
+#include <string.h>
+
+#include "terminal-search-dialog.h"
+#include "terminal-util.h"
+
+#define HISTORY_MIN_ITEM_LEN 3
+#define HISTORY_LENGTH 10
+
+static GQuark
+get_quark (void)
+{
+ static GQuark quark = 0;
+
+ if (G_UNLIKELY (!quark))
+ quark = g_quark_from_static_string ("GT:data");
+
+ return quark;
+}
+
+
+#define TERMINAL_SEARCH_DIALOG_GET_PRIVATE(object) \
+ ((TerminalSearchDialogPrivate *) g_object_get_qdata (G_OBJECT (object), get_quark ()))
+
+#define GET_FLAG(widget) gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (priv->widget))
+
+typedef struct _TerminalSearchDialogPrivate
+{
+ GtkWidget *search_label;
+ GtkWidget *search_entry;
+ GtkWidget *search_text_entry;
+ GtkWidget *match_case_checkbutton;
+ GtkWidget *entire_word_checkbutton;
+ GtkWidget *regex_checkbutton;
+ GtkWidget *backwards_checkbutton;
+ GtkWidget *wrap_around_checkbutton;
+
+ GtkListStore *store;
+ GtkEntryCompletion *completion;
+
+ /* Cached regex */
+ GRegex *regex;
+ GRegexCompileFlags regex_compile_flags;
+} TerminalSearchDialogPrivate;
+
+
+static void update_sensitivity (void *unused,
+ GtkWidget *dialog);
+static void response_handler (GtkWidget *dialog,
+ gint response_id,
+ gpointer data);
+static void terminal_search_dialog_private_destroy (TerminalSearchDialogPrivate *priv);
+
+
+GtkWidget *
+terminal_search_dialog_new (GtkWindow *parent)
+{
+ GtkWidget *dialog;
+ TerminalSearchDialogPrivate *priv;
+ GtkListStore *store;
+ GtkEntryCompletion *completion;
+
+ priv = g_new0 (TerminalSearchDialogPrivate, 1);
+
+ if (!terminal_util_load_builder_file ("find-dialog.ui",
+ "find-dialog", &dialog,
+ "search-label", &priv->search_label,
+ "search-entry", &priv->search_entry,
+ "match-case-checkbutton", &priv->match_case_checkbutton,
+ "entire-word-checkbutton", &priv->entire_word_checkbutton,
+ "regex-checkbutton", &priv->regex_checkbutton,
+ "search-backwards-checkbutton", &priv->backwards_checkbutton,
+ "wrap-around-checkbutton", &priv->wrap_around_checkbutton,
+ NULL))
+ {
+ g_free (priv);
+ return NULL;
+ }
+
+ g_object_set_qdata_full (G_OBJECT (dialog), get_quark (), priv,
+ (GDestroyNotify) terminal_search_dialog_private_destroy);
+
+
+ priv->search_text_entry = gtk_bin_get_child (GTK_BIN (priv->search_entry));
+ gtk_widget_set_size_request (priv->search_entry, 300, -1);
+
+ priv->store = store = gtk_list_store_new (1, G_TYPE_STRING);
+ g_object_set (G_OBJECT (priv->search_entry),
+ "model", store,
+ "text-column", 0,
+ NULL);
+
+ priv->completion = completion = gtk_entry_completion_new ();
+ gtk_entry_completion_set_model (completion, GTK_TREE_MODEL (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_text_entry), completion);
+
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT);
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, FALSE);
+
+ gtk_entry_set_activates_default (GTK_ENTRY (priv->search_text_entry), TRUE);
+ g_signal_connect (priv->search_text_entry, "changed", G_CALLBACK (update_sensitivity), dialog);
+ g_signal_connect (priv->regex_checkbutton, "toggled", G_CALLBACK (update_sensitivity), dialog);
+
+ g_signal_connect (dialog, "response", G_CALLBACK (response_handler), NULL);
+
+ if (parent)
+ gtk_window_set_transient_for (GTK_WINDOW (dialog), parent);
+
+ return GTK_WIDGET (dialog);
+}
+
+void
+terminal_search_dialog_present (GtkWidget *dialog)
+{
+ TerminalSearchDialogPrivate *priv;
+
+ g_return_if_fail (GTK_IS_DIALOG (dialog));
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ g_return_if_fail (priv);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+ gtk_widget_grab_focus (priv->search_text_entry);
+}
+
+static void
+terminal_search_dialog_private_destroy (TerminalSearchDialogPrivate *priv)
+{
+
+ if (priv->regex)
+ g_regex_unref (priv->regex);
+
+ g_object_unref (priv->store);
+ g_object_unref (priv->completion);
+
+ g_free (priv);
+}
+
+
+static void
+update_sensitivity (void *unused, GtkWidget *dialog)
+{
+ TerminalSearchDialogPrivate *priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ const gchar *search_string;
+ gboolean valid;
+
+ if (priv->regex) {
+ g_regex_unref (priv->regex);
+ priv->regex = NULL;
+ }
+
+ search_string = gtk_entry_get_text (GTK_ENTRY (priv->search_text_entry));
+ g_return_if_fail (search_string != NULL);
+
+ valid = *search_string != '\0';
+
+ if (valid && GET_FLAG (regex_checkbutton)) {
+ /* Check that the regex is valid */
+ valid = NULL != terminal_search_dialog_get_regex (dialog);
+ /* TODO show the error message somewhere */
+ }
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog), GTK_RESPONSE_ACCEPT, valid);
+}
+
+static gboolean
+remove_item (GtkListStore *store,
+ const gchar *text)
+{
+ GtkTreeIter iter;
+
+ g_return_val_if_fail (text != NULL, FALSE);
+
+ if (!gtk_tree_model_get_iter_first (GTK_TREE_MODEL (store), &iter))
+ return FALSE;
+
+ do {
+ gchar *item_text;
+
+ gtk_tree_model_get (GTK_TREE_MODEL (store), &iter, 0, &item_text, -1);
+
+ if (item_text != NULL && strcmp (item_text, text) == 0) {
+ gtk_list_store_remove (store, &iter);
+ g_free (item_text);
+ return TRUE;
+ }
+
+ g_free (item_text);
+ } while (gtk_tree_model_iter_next (GTK_TREE_MODEL (store), &iter));
+
+ return FALSE;
+}
+
+static void
+clamp_list_store (GtkListStore *store,
+ guint 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 (store), &iter, path))
+ while (1)
+ if (!gtk_list_store_remove (store, &iter))
+ break;
+
+ gtk_tree_path_free (path);
+}
+
+static void
+history_entry_insert (GtkListStore *store,
+ const gchar *text)
+{
+ GtkTreeIter iter;
+
+ g_return_if_fail (text != NULL);
+
+ 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 (!remove_item (store, text))
+ clamp_list_store (store, HISTORY_LENGTH - 1);
+
+ gtk_list_store_insert (store, &iter, 0);
+ gtk_list_store_set (store, &iter, 0, text, -1);
+}
+
+static void
+response_handler (GtkWidget *dialog,
+ gint response_id,
+ gpointer data)
+{
+ TerminalSearchDialogPrivate *priv;
+ const gchar *str;
+
+ if (response_id != GTK_RESPONSE_ACCEPT) {
+ gtk_widget_hide (dialog);
+ return;
+ }
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+
+ str = gtk_entry_get_text (GTK_ENTRY (priv->search_text_entry));
+ if (*str != '\0')
+ history_entry_insert (priv->store, str);
+}
+
+
+void
+terminal_search_dialog_set_search_text (GtkWidget *dialog,
+ const gchar *text)
+{
+ TerminalSearchDialogPrivate *priv;
+
+ g_return_if_fail (GTK_IS_DIALOG (dialog));
+ g_return_if_fail (text != NULL);
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ g_return_if_fail (priv);
+
+ gtk_entry_set_text (GTK_ENTRY (priv->search_text_entry), text);
+
+ gtk_dialog_set_response_sensitive (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT,
+ (*text != '\0'));
+}
+
+const gchar *
+terminal_search_dialog_get_search_text (GtkWidget *dialog)
+{
+ TerminalSearchDialogPrivate *priv;
+
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ g_return_val_if_fail (priv, NULL);
+
+ return gtk_entry_get_text (GTK_ENTRY (priv->search_text_entry));
+}
+
+TerminalSearchFlags
+terminal_search_dialog_get_search_flags (GtkWidget *dialog)
+{
+ TerminalSearchDialogPrivate *priv;
+ TerminalSearchFlags flags = 0;
+
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), flags);
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ g_return_val_if_fail (priv, flags);
+
+ if (GET_FLAG (backwards_checkbutton))
+ flags |= TERMINAL_SEARCH_FLAG_BACKWARDS;
+
+ if (GET_FLAG (wrap_around_checkbutton))
+ flags |= TERMINAL_SEARCH_FLAG_WRAP_AROUND;
+
+ return flags;
+}
+
+GRegex *
+terminal_search_dialog_get_regex (GtkWidget *dialog)
+{
+ TerminalSearchDialogPrivate *priv;
+ GRegexCompileFlags compile_flags;
+ const char *text, *pattern;
+
+ g_return_val_if_fail (GTK_IS_DIALOG (dialog), NULL);
+
+ priv = TERMINAL_SEARCH_DIALOG_GET_PRIVATE (dialog);
+ g_return_val_if_fail (priv, NULL);
+
+ pattern = text = terminal_search_dialog_get_search_text (dialog);
+
+ compile_flags = G_REGEX_OPTIMIZE;
+
+ if (!GET_FLAG (match_case_checkbutton))
+ compile_flags |= G_REGEX_CASELESS;
+
+ if (GET_FLAG (regex_checkbutton))
+ compile_flags |= G_REGEX_MULTILINE;
+ else
+ pattern = g_regex_escape_string (text, -1);
+
+ if (GET_FLAG (entire_word_checkbutton)) {
+ const char *old_pattern = pattern;
+ pattern = g_strdup_printf ("\\b%s\\b", pattern);
+ if (old_pattern != text)
+ g_free ((char *) old_pattern);
+ }
+
+ if (!priv->regex || priv->regex_compile_flags != compile_flags) {
+ priv->regex_compile_flags = compile_flags;
+ if (priv->regex)
+ g_regex_unref (priv->regex);
+
+ /* TODO Error handling */
+ priv->regex = g_regex_new (pattern, compile_flags, 0, NULL);
+ }
+
+ if (pattern != text)
+ g_free ((char *) pattern);
+
+ return priv->regex;
+}
+
diff --git a/src/terminal-search-dialog.h b/src/terminal-search-dialog.h
new file mode 100644
index 0000000..e8911da
--- /dev/null
+++ b/src/terminal-search-dialog.h
@@ -0,0 +1,49 @@
+/*
+ * 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_SEARCH_DIALOG_H
+#define TERMINAL_SEARCH_DIALOG_H
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+typedef enum _TerminalSearchFlags {
+ TERMINAL_SEARCH_FLAG_BACKWARDS = 1 << 0,
+ TERMINAL_SEARCH_FLAG_WRAP_AROUND = 1 << 1
+} TerminalSearchFlags;
+
+
+GtkWidget *terminal_search_dialog_new (GtkWindow *parent);
+
+void terminal_search_dialog_present (GtkWidget *dialog);
+
+void terminal_search_dialog_set_search_text (GtkWidget *dialog,
+ const gchar *text);
+
+const gchar *terminal_search_dialog_get_search_text (GtkWidget *dialog);
+
+TerminalSearchFlags
+ terminal_search_dialog_get_search_flags(GtkWidget *dialog);
+GRegex *terminal_search_dialog_get_regex (GtkWidget *dialog);
+
+G_END_DECLS
+
+#endif /* TERMINAL_SEARCH_DIALOG_H */
diff --git a/src/terminal-tab-label.c b/src/terminal-tab-label.c
new file mode 100644
index 0000000..3a28504
--- /dev/null
+++ b/src/terminal-tab-label.c
@@ -0,0 +1,289 @@
+/*
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope tab_label 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#include <config.h>
+
+#include <gtk/gtk.h>
+
+#include "terminal-intl.h"
+#include "terminal-tab-label.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;
+};
+
+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_HBOX);
+
+/* 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;
+
+ title = terminal_screen_get_title (screen);
+ hbox = gtk_widget_get_parent (label);
+
+ gtk_label_set_text (GTK_LABEL (label), title);
+
+ gtk_widget_set_tooltip_text (hbox, title);
+}
+
+/* public functions */
+
+/* Class implementation */
+
+static void
+terminal_tab_label_parent_set (GtkWidget *widget,
+ GtkWidget *old_parent)
+{
+ void (* parent_set) (GtkWidget *, GtkWidget *) = GTK_WIDGET_CLASS (terminal_tab_label_parent_class)->parent_set;
+
+ if (parent_set)
+ parent_set (widget, old_parent);
+}
+
+static void
+terminal_tab_label_style_set (GtkWidget *widget,
+ GtkStyle *previous_style)
+{
+ TerminalTabLabel *tab_label = TERMINAL_TAB_LABEL (widget);
+ TerminalTabLabelPrivate *priv = tab_label->priv;
+ void (* style_set) (GtkWidget *, GtkStyle *) = GTK_WIDGET_CLASS (terminal_tab_label_parent_class)->style_set;
+ int h, w;
+
+ if (style_set)
+ style_set (widget, previous_style);
+
+ gtk_icon_size_lookup_for_settings (gtk_widget_get_settings (widget),
+ GTK_ICON_SIZE_MENU, &w, &h);
+ gtk_widget_set_size_request (priv->close_button, w + 2, h + 2);
+}
+
+static void
+terminal_tab_label_init (TerminalTabLabel *tab_label)
+{
+ tab_label->priv = TERMINAL_TAB_LABEL_GET_PRIVATE (tab_label);
+}
+
+static GObject *
+terminal_tab_label_constructor (GType type,
+ guint n_construct_properties,
+ GObjectConstructParam *construct_params)
+{
+ GObject *object;
+ TerminalTabLabel *tab_label;
+ TerminalTabLabelPrivate *priv;
+ GtkWidget *hbox, *label, *close_button, *image;
+
+ object = G_OBJECT_CLASS (terminal_tab_label_parent_class)->constructor
+ (type, n_construct_properties, construct_params);
+
+ tab_label = TERMINAL_TAB_LABEL (object);
+ hbox = GTK_WIDGET (tab_label);
+ priv = tab_label->priv;
+
+ g_assert (priv->screen != NULL);
+
+ gtk_box_set_spacing (GTK_BOX (hbox), SPACING);
+
+ priv->label = label = gtk_label_new (NULL);
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_misc_set_padding (GTK_MISC (label), 0, 0);
+ gtk_label_set_ellipsize (GTK_LABEL (label), PANGO_ELLIPSIZE_END);
+ gtk_label_set_single_line_mode (GTK_LABEL (label), TRUE);
+
+ gtk_box_pack_start (GTK_BOX (hbox), label, TRUE, TRUE, 0);
+
+ priv->close_button = close_button = gtk_button_new ();
+ gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ gtk_button_set_focus_on_click (GTK_BUTTON (close_button), FALSE);
+ gtk_button_set_relief (GTK_BUTTON (close_button), GTK_RELIEF_NONE);
+ gtk_widget_set_name (close_button, "mate-terminal-tab-close-button");
+ gtk_widget_set_tooltip_text (close_button, _("Close tab"));
+
+ image = gtk_image_new_from_stock (GTK_STOCK_CLOSE, GTK_ICON_SIZE_MENU);
+ gtk_container_add (GTK_CONTAINER (close_button), image);
+ 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);
+
+ return 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_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_get_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->constructor = terminal_tab_label_constructor;
+ gobject_class->finalize = terminal_tab_label_finalize;
+ gobject_class->set_property = terminal_tab_label_set_property;
+
+ widget_class->parent_set = terminal_tab_label_parent_set;
+ widget_class->style_set = terminal_tab_label_style_set;
+
+ 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_WRITABLE | 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,
+ "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);
+}
diff --git a/src/terminal-tab-label.h b/src/terminal-tab-label.h
new file mode 100644
index 0000000..d025e24
--- /dev/null
+++ b/src/terminal-tab-label.h
@@ -0,0 +1,64 @@
+/*
+ * 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, or (at your option)
+ * any later version.
+ *
+ * This program is distributed in the hope tab_label 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, write to the Free Software
+ * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_TAB_LABEL_H
+#define TERMINAL_TAB_LABEL_H
+
+#include <gtk/gtk.h>
+
+#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
+{
+ GtkHBox parent_instance;
+
+ /*< private >*/
+ TerminalTabLabelPrivate *priv;
+};
+
+struct _TerminalTabLabelClass
+{
+ GtkHBoxClass 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);
+
+G_END_DECLS
+
+#endif /* !TERMINAL_TAB_LABEL_H */
diff --git a/src/terminal-tabs-menu.c b/src/terminal-tabs-menu.c
new file mode 100644
index 0000000..2638a28
--- /dev/null
+++ b/src/terminal-tabs-menu.c
@@ -0,0 +1,487 @@
+/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*- */
+/*
+ * Copyright © 2003 David Bordoley
+ * Copyright © 2003-2004 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, 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+
+#include <gtk/gtk.h>
+
+#include "terminal-tabs-menu.h"
+#include "terminal-screen.h"
+#include "terminal-screen-container.h"
+#include "terminal-intl.h"
+
+#define TERMINAL_ACCELS_N_TABS_SWITCH (12)
+
+#define LABEL_WIDTH_CHARS 32
+#define ACTION_VERB_FORMAT_PREFIX "JmpTab"
+#define ACTION_VERB_FORMAT_PREFIX_LEN strlen (ACTION_VERB_FORMAT_PREFIX)
+#define ACTION_VERB_FORMAT ACTION_VERB_FORMAT_PREFIX "%x"
+#define ACTION_VERB_FORMAT_LENGTH strlen (ACTION_VERB_FORMAT) + 14 + 1
+#define ACTION_VERB_FORMAT_BASE (16) /* %x is hex */
+#define ACCEL_PATH_FORMAT "<Actions>/Main/TabsSwitch%u"
+#define ACCEL_PATH_FORMAT_LENGTH strlen (ACCEL_PATH_FORMAT) + 14 + 1
+#define DATA_KEY "TerminalTabsMenu::Action"
+
+#define UI_PATH "/menubar/Tabs"
+
+#define TERMINAL_TABS_MENU_GET_PRIVATE(object)(G_TYPE_INSTANCE_GET_PRIVATE ((object), TERMINAL_TYPE_TABS_MENU, TerminalTabsMenuPrivate))
+
+struct _TerminalTabsMenuPrivate
+{
+ TerminalWindow *window;
+ GtkActionGroup *action_group;
+ GtkAction *anchor_action;
+ guint ui_id;
+};
+
+enum
+{
+ PROP_0,
+ PROP_WINDOW
+};
+
+static void terminal_tabs_menu_update (TerminalTabsMenu *menu);
+
+/* FIXME: this can be severely optimised */
+static GByteArray *tabs_id_array = NULL;
+static guint n_tabs = 0;
+
+G_DEFINE_TYPE (TerminalTabsMenu, terminal_tabs_menu, G_TYPE_OBJECT)
+
+/* We need to assign unique IDs to tabs, otherwise accels get confused in the
+ * tabs menu (bug #339548). We could use a serial #, but the ID is used in the
+ * action name which is stored in a GQuark and so we should allocate them
+ * efficiently.
+ */
+static guint
+allocate_tab_id (void)
+{
+ int bit;
+ guint b, len;
+ guint8 *data;
+ guint8 byte, mask;
+
+ if (n_tabs++ == 0)
+ {
+ g_assert (tabs_id_array == NULL);
+ tabs_id_array = g_byte_array_sized_new (16);
+ }
+
+ /* Find a free ID */
+ len = tabs_id_array->len;
+ data = tabs_id_array->data;
+ for (b = 0; b < len; ++b)
+ {
+ if (data[b] != 0xff)
+ break;
+ }
+
+ /* Need to append a new byte */
+ if (b == len)
+ {
+ guint8 bytes[] = { 0 };
+ g_byte_array_append (tabs_id_array, bytes, G_N_ELEMENTS (bytes));
+ g_assert (tabs_id_array->len > b);
+ }
+
+ data = tabs_id_array->data + b;
+ byte = 0xff ^ *data;
+ /* Now find the first free bit */
+ bit = g_bit_nth_lsf (byte, -1);
+ mask = 1 << bit;
+ g_assert (bit >= 0 && bit <= 7);
+ g_assert ((*data & mask) == 0);
+ /* And mark it as allocated */
+ *data |= mask;
+
+ return b * 8 + bit;
+}
+
+static void
+free_tab_id (GtkAction *action)
+{
+ const char *name;
+ guint id;
+ guint8 *data;
+ guint b, bit;
+
+ name = gtk_action_get_name (action);
+ id = g_ascii_strtoull (name + ACTION_VERB_FORMAT_PREFIX_LEN, NULL,
+ ACTION_VERB_FORMAT_BASE);
+ g_assert (id < tabs_id_array->len * 8);
+
+ b = id >> 3;
+ bit = id & 0x7;
+ data = tabs_id_array->data + b;
+ *data &= ~(1 << bit);
+
+ g_assert (n_tabs > 0);
+ if (--n_tabs == 0)
+ {
+ g_assert (tabs_id_array != NULL);
+ g_byte_array_free (tabs_id_array, TRUE);
+ tabs_id_array = NULL;
+ }
+}
+
+static void
+tab_action_activate_cb (GtkToggleAction *action,
+ TerminalTabsMenu *menu)
+{
+ TerminalTabsMenuPrivate *priv = menu->priv;
+ TerminalScreen *screen;
+
+ if (gtk_toggle_action_get_active (action) == FALSE)
+ {
+ return;
+ }
+
+ screen = g_object_get_data (G_OBJECT (action), DATA_KEY);
+ g_return_if_fail (screen != NULL);
+
+ if (terminal_window_get_active (priv->window) != screen)
+ {
+ terminal_window_switch_screen (priv->window, screen);
+ }
+}
+
+static void
+sync_tab_title (TerminalScreen *screen,
+ GParamSpec *pspec,
+ GtkAction *action)
+{
+ const char *title;
+
+ title = terminal_screen_get_title (screen);
+
+ g_object_set (action, "label", title, NULL);
+}
+
+static void
+notebook_page_added_cb (GtkNotebook *notebook,
+ TerminalScreenContainer *container,
+ guint position,
+ TerminalTabsMenu *menu)
+{
+ TerminalTabsMenuPrivate *priv = menu->priv;
+ GtkAction *action;
+ char verb[ACTION_VERB_FORMAT_LENGTH];
+ GSList *group;
+ TerminalScreen *screen;
+
+ screen = terminal_screen_container_get_screen (container);
+
+ g_snprintf (verb, sizeof (verb), ACTION_VERB_FORMAT, allocate_tab_id ());
+
+ action = g_object_new (GTK_TYPE_RADIO_ACTION,
+ "name", verb,
+ "tooltip", _("Switch to this tab"),
+ NULL);
+
+ sync_tab_title (screen, NULL, action);
+ /* make sure the action is alive when handling the signal, see bug #169833 */
+ g_signal_connect_object (screen, "notify::title",
+ G_CALLBACK (sync_tab_title), action, 0);
+
+ gtk_action_group_add_action_with_accel (priv->action_group, action, NULL);
+
+ group = gtk_radio_action_get_group (GTK_RADIO_ACTION (priv->anchor_action));
+ gtk_radio_action_set_group (GTK_RADIO_ACTION (action), group);
+
+ /* set this here too, since tab-added comes after notify::active-child */
+ if (terminal_window_get_active (priv->window) == screen)
+ {
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+ }
+
+ g_object_set_data (G_OBJECT (screen), DATA_KEY, action);
+ g_object_set_data (G_OBJECT (action), DATA_KEY, screen);
+
+ g_signal_connect (action, "activate",
+ G_CALLBACK (tab_action_activate_cb), menu);
+
+ g_object_unref (action);
+
+ terminal_tabs_menu_update (menu);
+}
+
+static void
+notebook_page_removed_cb (GtkNotebook *notebook,
+ TerminalScreenContainer *container,
+ guint position,
+ TerminalTabsMenu *menu)
+{
+ TerminalTabsMenuPrivate *priv = menu->priv;
+ GtkAction *action;
+ TerminalScreen *screen;
+
+ screen = terminal_screen_container_get_screen (container);
+
+ action = g_object_get_data (G_OBJECT (screen), DATA_KEY);
+ g_return_if_fail (action != NULL);
+
+ free_tab_id (action);
+
+ g_signal_handlers_disconnect_by_func
+ (screen, G_CALLBACK (sync_tab_title), action);
+
+ g_signal_handlers_disconnect_by_func
+ (action, G_CALLBACK (tab_action_activate_cb), menu);
+
+ g_object_set_data (G_OBJECT (screen), DATA_KEY, NULL);
+ gtk_action_group_remove_action (priv->action_group, action);
+
+ terminal_tabs_menu_update (menu);
+}
+
+static void
+notebook_page_reordered_cb (GtkNotebook *notebook,
+ GtkBin *bin,
+ guint position,
+ TerminalTabsMenu *menu)
+{
+ terminal_tabs_menu_update (menu);
+}
+
+static void
+notebook_page_switch_cb (GtkNotebook *notebook,
+#if GTK_CHECK_VERSION (2, 90, 6)
+ GtkWidget *page,
+#else
+ gpointer page,
+#endif
+ guint position,
+ TerminalTabsMenu *menu)
+{
+ TerminalScreenContainer *container;
+ TerminalScreen *screen;
+ GtkAction *action;
+
+#if GTK_CHECK_VERSION (2, 90, 6)
+ container = TERMINAL_SCREEN_CONTAINER (page);
+#else
+ container = TERMINAL_SCREEN_CONTAINER (gtk_notebook_get_nth_page (notebook, position));
+#endif
+ screen = terminal_screen_container_get_screen (container);
+
+ action = g_object_get_data (G_OBJECT (screen), DATA_KEY);
+ g_signal_handlers_block_by_func (action, G_CALLBACK (tab_action_activate_cb), menu);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+ g_signal_handlers_unblock_by_func (action, G_CALLBACK (tab_action_activate_cb), menu);
+}
+
+static void
+connect_proxy_cb (GtkActionGroup *action_group,
+ GtkAction *action,
+ GtkWidget *proxy,
+ gpointer dummy)
+{
+ if (GTK_IS_MENU_ITEM (proxy))
+ {
+ GtkLabel *label;
+
+ label = GTK_LABEL (gtk_bin_get_child (GTK_BIN (proxy)));
+
+ gtk_label_set_use_underline (label, FALSE);
+ gtk_label_set_ellipsize (label, PANGO_ELLIPSIZE_END);
+ gtk_label_set_max_width_chars (label, LABEL_WIDTH_CHARS);
+ }
+}
+
+static void
+terminal_tabs_menu_set_window (TerminalTabsMenu *menu,
+ TerminalWindow *window)
+{
+ TerminalTabsMenuPrivate *priv = menu->priv;
+ GtkWidget *notebook;
+ GtkUIManager *manager;
+
+ priv->window = window;
+
+ manager = GTK_UI_MANAGER (terminal_window_get_ui_manager (window));
+ priv->action_group = gtk_action_group_new ("TabsActions");
+ gtk_ui_manager_insert_action_group (manager, priv->action_group, -1);
+ g_object_unref (priv->action_group);
+
+ priv->anchor_action = g_object_new (GTK_TYPE_RADIO_ACTION,
+ "name", "TabsMenuAnchorAction",
+ NULL);
+ gtk_action_group_add_action (priv->action_group, priv->anchor_action);
+ g_object_unref (priv->anchor_action);
+
+ g_signal_connect (priv->action_group, "connect-proxy",
+ G_CALLBACK (connect_proxy_cb), NULL);
+
+ notebook = terminal_window_get_notebook (window);
+ g_signal_connect_object (notebook, "page-added",
+ G_CALLBACK (notebook_page_added_cb), menu, 0);
+ g_signal_connect_object (notebook, "page-removed",
+ G_CALLBACK (notebook_page_removed_cb), menu, 0);
+ g_signal_connect_object (notebook, "page-reordered",
+ G_CALLBACK (notebook_page_reordered_cb), menu, 0);
+ g_signal_connect_object (notebook, "switch-page",
+ G_CALLBACK (notebook_page_switch_cb), menu, 0);
+}
+
+static void
+terminal_tabs_menu_set_property (GObject *object,
+ guint prop_id,
+ const GValue *value,
+ GParamSpec *pspec)
+{
+ TerminalTabsMenu *menu = TERMINAL_TABS_MENU (object);
+
+ switch (prop_id)
+ {
+ case PROP_WINDOW:
+ terminal_tabs_menu_set_window (menu, g_value_get_object (value));
+ break;
+ default:
+ G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
+ break;
+ }
+}
+
+static void
+terminal_tabs_menu_get_property (GObject *object,
+ guint prop_id,
+ GValue *value,
+ GParamSpec *pspec)
+{
+ /* no readable properties */
+ g_return_if_reached ();
+}
+
+static void
+terminal_tabs_menu_class_init (TerminalTabsMenuClass *klass)
+{
+ GObjectClass *object_class = G_OBJECT_CLASS (klass);
+
+ object_class->set_property = terminal_tabs_menu_set_property;
+ object_class->get_property = terminal_tabs_menu_get_property;
+
+ g_object_class_install_property (object_class,
+ PROP_WINDOW,
+ g_param_spec_object ("window", NULL, NULL,
+ TERMINAL_TYPE_WINDOW,
+ G_PARAM_WRITABLE | G_PARAM_STATIC_NAME | G_PARAM_STATIC_NICK | G_PARAM_STATIC_BLURB |
+ G_PARAM_CONSTRUCT_ONLY));
+
+ g_type_class_add_private (object_class, sizeof (TerminalTabsMenuPrivate));
+
+ /* We don't want to save accels, so skip them */
+ gtk_accel_map_add_filter ("<Actions>/Main/TabsSwitch*");
+}
+
+static void
+terminal_tabs_menu_init (TerminalTabsMenu *menu)
+{
+ menu->priv = TERMINAL_TABS_MENU_GET_PRIVATE (menu);
+}
+
+static void
+terminal_tabs_menu_clean (TerminalTabsMenu *menu)
+{
+ TerminalTabsMenuPrivate *p = menu->priv;
+ GtkUIManager *manager = GTK_UI_MANAGER (terminal_window_get_ui_manager (p->window));
+
+ if (p->ui_id != 0)
+ {
+ gtk_ui_manager_remove_ui (manager, p->ui_id);
+ gtk_ui_manager_ensure_update (manager);
+ p->ui_id = 0;
+ }
+}
+
+TerminalTabsMenu *
+terminal_tabs_menu_new (TerminalWindow *window)
+{
+ return TERMINAL_TABS_MENU (g_object_new (TERMINAL_TYPE_TABS_MENU,
+ "window", window,
+ NULL));
+}
+
+static void
+tab_set_action_accelerator (GtkActionGroup *action_group,
+ GtkAction *action,
+ guint tab_number,
+ gboolean is_single_tab)
+{
+ if (!is_single_tab &&
+ tab_number < TERMINAL_ACCELS_N_TABS_SWITCH)
+ {
+ char accel_path[ACCEL_PATH_FORMAT_LENGTH];
+
+ g_snprintf (accel_path, sizeof (accel_path), ACCEL_PATH_FORMAT, tab_number + 1);
+ gtk_action_set_accel_path (action, accel_path);
+ }
+ else
+ {
+ gtk_action_set_accel_path (action, NULL);
+ return;
+ }
+}
+
+static void
+terminal_tabs_menu_update (TerminalTabsMenu *menu)
+{
+ TerminalTabsMenuPrivate *p = menu->priv;
+ GtkUIManager *manager;
+ GtkAction *action;
+ GList *tabs = NULL, *l;
+ guint i = 0, n;
+ gboolean is_single_tab;
+ const char *verb;
+
+ terminal_tabs_menu_clean (menu);
+
+ tabs = terminal_window_list_screen_containers (p->window);
+
+ n = g_list_length (tabs);
+ if (n == 0) return;
+
+ is_single_tab = (n == 1);
+
+ manager = GTK_UI_MANAGER (terminal_window_get_ui_manager (p->window));
+ p->ui_id = gtk_ui_manager_new_merge_id (manager);
+
+ for (l = tabs; l != NULL; l = l->next)
+ {
+ TerminalScreenContainer *container = TERMINAL_SCREEN_CONTAINER (l->data);
+ GObject *screen = G_OBJECT (terminal_screen_container_get_screen (container));
+
+ action = g_object_get_data (screen, DATA_KEY);
+ g_return_if_fail (action != NULL);
+
+ verb = gtk_action_get_name (action);
+
+ tab_set_action_accelerator (p->action_group, action, i++, is_single_tab);
+
+ gtk_ui_manager_add_ui (manager, p->ui_id,
+ UI_PATH,
+ verb, verb,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+ }
+
+ g_list_free (tabs);
+}
diff --git a/src/terminal-tabs-menu.h b/src/terminal-tabs-menu.h
new file mode 100644
index 0000000..6e609e5
--- /dev/null
+++ b/src/terminal-tabs-menu.h
@@ -0,0 +1,56 @@
+/*
+ * Copyright © 2003 David Bordoley
+ *
+ * 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, 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, write to the Free Software
+ * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301, USA.
+ */
+
+#ifndef TERMINAL_TABS_MENU_H
+#define TERMINAL_TABS_MENU_H
+
+#include "terminal-window.h"
+
+G_BEGIN_DECLS
+
+#define TERMINAL_TYPE_TABS_MENU (terminal_tabs_menu_get_type ())
+#define TERMINAL_TABS_MENU(o) (G_TYPE_CHECK_INSTANCE_CAST ((o), TERMINAL_TYPE_TABS_MENU, TerminalTabsMenu))
+#define TERMINAL_TABS_MENU_CLASS(k) (G_TYPE_CHECK_CLASS_CAST((k), TERMINAL_TYPE_TABS_MENU, TerminalTabsMenuClass))
+#define TERMINAL_IS_TABS_MENU(o) (G_TYPE_CHECK_INSTANCE_TYPE ((o), TERMINAL_TYPE_TABS_MENU))
+#define TERMINAL_IS_TABS_MENU_CLASS(k) (G_TYPE_CHECK_CLASS_TYPE ((k), TERMINAL_TYPE_TABS_MENU))
+#define TERMINAL_TABS_MENU_GET_CLASS(o) (G_TYPE_INSTANCE_GET_CLASS ((o), TERMINAL_TYPE_TABS_MENU, TerminalTabsMenuClass))
+
+typedef struct _TerminalTabsMenu TerminalTabsMenu;
+typedef struct _TerminalTabsMenuClass TerminalTabsMenuClass;
+typedef struct _TerminalTabsMenuPrivate TerminalTabsMenuPrivate;
+
+struct _TerminalTabsMenuClass
+{
+ GObjectClass parent_class;
+};
+
+struct _TerminalTabsMenu
+{
+ GObject parent_object;
+
+ /*< private >*/
+ TerminalTabsMenuPrivate *priv;
+};
+
+GType terminal_tabs_menu_get_type (void);
+
+TerminalTabsMenu *terminal_tabs_menu_new (TerminalWindow *window);
+
+G_END_DECLS
+
+#endif
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 <config.h>
+
+#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 <glib-object.h>
+
+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..6bf6618
--- /dev/null
+++ b/src/terminal-util.c
@@ -0,0 +1,1213 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2002 Sun Microsystems
+ * Copyright © 2003 Mariano Suarez-Alvarez
+ * Copyright © 2008 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+#include <sys/types.h>
+
+#include <glib.h>
+
+#include <gio/gio.h>
+#include <gtk/gtk.h>
+
+#include <mateconf/mateconf.h>
+
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#include <X11/Xatom.h>
+#endif
+
+#include "terminal-accels.h"
+#include "terminal-app.h"
+#include "terminal-intl.h"
+#include "terminal-util.h"
+#include "terminal-window.h"
+
+void
+terminal_util_set_unique_role (GtkWindow *window, const char *prefix)
+{
+ char *role;
+
+ role = g_strdup_printf ("%s-%d-%d-%d", prefix, getpid (), g_random_int (), (int) time (NULL));
+ gtk_window_set_role (window, role);
+ g_free (role);
+}
+
+/**
+ * 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 <literal>*weap_ptr</literal> is #NULL
+ * (and in that * case, set @weap_ptr to be a weak pointer to the new dialog), otherwise just
+ * present <literal>*weak_ptr</literal>. Note that in this last case, the message <emph>will</emph>
+ * be changed.
+ */
+void
+terminal_util_show_error_dialog (GtkWindow *transient_parent,
+ GtkWidget **weak_ptr,
+ GError *error,
+ const char *message_format,
+ ...)
+{
+ 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));
+ }
+
+ g_free (message);
+}
+
+static gboolean
+open_url (GtkWindow *parent,
+ const char *uri,
+ guint32 user_time,
+ GError **error)
+{
+ GdkScreen *screen;
+
+ if (parent)
+ screen = gtk_widget_get_screen (GTK_WIDGET (parent));
+ else
+ screen = gdk_screen_get_default ();
+
+ return gtk_show_uri (screen, uri, user_time, error);
+}
+
+void
+terminal_util_show_help (const char *topic,
+ GtkWindow *parent)
+{
+ GError *error = NULL;
+ const char *lang;
+ char *uri = NULL, *url;
+ guint i;
+
+ const char * const * langs = g_get_language_names ();
+ for (i = 0; langs[i]; i++) {
+ lang = langs[i];
+ if (strchr (lang, '.')) {
+ continue;
+ }
+
+ uri = g_build_filename (TERM_HELPDIR,
+ "mate-terminal", /* DOC_MODULE */
+ lang,
+ "mate-terminal.xml",
+ NULL);
+
+ if (g_file_test (uri, G_FILE_TEST_EXISTS)) {
+ break;
+ }
+
+ g_free (uri);
+ uri = NULL;
+ }
+
+ if (!uri)
+ return;
+
+ if (topic) {
+ url = g_strdup_printf ("ghelp://%s?%s", uri, topic);
+ } else {
+ url = g_strdup_printf ("ghelp://%s", uri);
+ }
+
+ if (!open_url (GTK_WINDOW (parent), url, gtk_get_current_event_time (), &error))
+ {
+ terminal_util_show_error_dialog (GTK_WINDOW (parent), NULL, error,
+ _("There was an error displaying help"));
+ g_error_free (error);
+ }
+
+ g_free (uri);
+ g_free (url);
+}
+
+/* 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,
+ TerminalURLFlavour flavor,
+ guint32 user_time)
+{
+ GError *error = NULL;
+ char *uri;
+
+ 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;
+ case FLAVOR_SKEY:
+ /* shouldn't get this */
+ 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);
+
+ g_error_free (error);
+ }
+
+ g_free (uri);
+}
+
+/**
+ * terminal_util_resolve_relative_path:
+ * @path:
+ * @relative_path:
+ *
+ * Returns: a newly allocate string
+ */
+char *
+terminal_util_resolve_relative_path (const char *path,
+ const char *relative_path)
+{
+ GFile *file, *resolved_file;
+ char *resolved_path = NULL;
+
+ g_return_val_if_fail (relative_path != NULL, NULL);
+
+ if (path == NULL)
+ return g_strdup (relative_path);
+
+ file = g_file_new_for_path (path);
+ resolved_file = g_file_resolve_relative_path (file, relative_path);
+ g_object_unref (file);
+
+ if (resolved_file == NULL)
+ return NULL;
+
+ resolved_path = g_file_get_path (resolved_file);
+ g_object_unref (resolved_file);
+
+ return resolved_path;
+}
+
+/**
+ * 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)
+ {
+ GFile *file;
+ char *path;
+
+ file = g_file_new_for_uri (uris[i]);
+
+ if ((path = g_file_get_path (file)))
+ {
+ char *quoted;
+
+ quoted = g_shell_quote (path);
+ g_free (uris[i]);
+ g_free (path);
+
+ uris[i] = quoted;
+ }
+
+ g_object_unref (file);
+ }
+}
+
+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_("MATE 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_("MATE 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 MATE Terminal; if not, write to the Free Software Foundation, "
+ "Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA")
+ };
+
+ return g_strjoin ("\n\n", _(license[0]), _(license[1]), _(license[2]), NULL);
+}
+
+gboolean
+terminal_util_load_builder_file (const char *filename,
+ const char *object_name,
+ ...)
+{
+ char *path;
+ GtkBuilder *builder;
+ GError *error = NULL;
+ va_list args;
+
+ path = g_build_filename (TERM_PKGDATADIR, filename, NULL);
+ builder = gtk_builder_new ();
+ if (!gtk_builder_add_from_file (builder, path, &error)) {
+ g_warning ("Failed to load %s: %s\n", filename, error->message);
+ g_error_free (error);
+ g_free (path);
+ g_object_unref (builder);
+ return FALSE;
+ }
+ g_free (path);
+
+ 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_warning ("Failed to fetch object \"%s\"\n", object_name);
+ break;
+ }
+
+ object_name = va_arg (args, const char*);
+ }
+
+ va_end (args);
+
+ g_object_unref (builder);
+ return object_name == NULL;
+}
+
+gboolean
+terminal_util_dialog_response_on_delete (GtkWindow *widget)
+{
+ gtk_dialog_response (GTK_DIALOG (widget), GTK_RESPONSE_DELETE_EVENT);
+ return TRUE;
+}
+
+/* Like g_key_file_set_string, but escapes characters so that
+ * the stored string is ASCII. Use when the input string may not
+ * be UTF-8.
+ */
+void
+terminal_util_key_file_set_string_escape (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ const char *string)
+{
+ char *escaped;
+
+ /* FIXMEchpe: be more intelligent and only escape characters that aren't UTF-8 */
+ escaped = g_strescape (string, NULL);
+ g_key_file_set_string (key_file, group, key, escaped);
+ g_free (escaped);
+}
+
+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;
+}
+
+void
+terminal_util_key_file_set_argv (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ int argc,
+ char **argv)
+{
+ char **quoted_argv;
+ char *flat;
+ int i;
+
+ if (argc < 0)
+ argc = g_strv_length (argv);
+
+ quoted_argv = g_new (char*, argc + 1);
+ for (i = 0; i < argc; ++i)
+ quoted_argv[i] = g_shell_quote (argv[i]);
+ quoted_argv[argc] = NULL;
+
+ flat = g_strjoinv (" ", quoted_argv);
+ terminal_util_key_file_set_string_escape (key_file, group, key, flat);
+
+ g_free (flat);
+ g_strfreev (quoted_argv);
+}
+
+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;
+}
+
+/* Proxy stuff */
+
+static char *
+conf_get_string (MateConfClient *conf,
+ const char *key)
+{
+ char *value;
+ value = mateconf_client_get_string (conf, key, NULL);
+ if (G_UNLIKELY (value && *value == '\0'))
+ {
+ g_free (value);
+ value = NULL;
+ }
+ return value;
+}
+
+/*
+ * 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)
+{
+ 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_http_proxy_env (GHashTable *env_table,
+ MateConfClient *conf)
+{
+ gchar *host;
+ gint port;
+ GSList *ignore;
+
+ if (!mateconf_client_get_bool (conf, CONF_HTTP_PROXY_PREFIX "/use_http_proxy", NULL))
+ return;
+
+ host = conf_get_string (conf, CONF_HTTP_PROXY_PREFIX "/host");
+ port = mateconf_client_get_int (conf, CONF_HTTP_PROXY_PREFIX "/port", NULL);
+ if (host && port)
+ {
+ GString *buf = g_string_sized_new (64);
+ g_string_append (buf, "http://");
+
+ if (mateconf_client_get_bool (conf, CONF_HTTP_PROXY_PREFIX "/use_authentication", NULL))
+ {
+ char *user, *password;
+ user = conf_get_string (conf, CONF_HTTP_PROXY_PREFIX "/authentication_user");
+ if (user)
+ {
+ g_string_append_uri_escaped (buf, user, NULL, TRUE);
+ password = conf_get_string (conf, CONF_HTTP_PROXY_PREFIX "/authentication_password");
+ if (password)
+ {
+ g_string_append_c (buf, ':');
+ g_string_append_uri_escaped (buf, password, NULL, TRUE);
+ g_free (password);
+ }
+ g_free (user);
+ g_string_append_c (buf, '@');
+ }
+ }
+ g_string_append_printf (buf, "%s:%d/", host, port);
+ set_proxy_env (env_table, "http_proxy", g_string_free (buf, FALSE));
+ }
+ g_free (host);
+
+ ignore = mateconf_client_get_list (conf, CONF_HTTP_PROXY_PREFIX "/ignore_hosts", MATECONF_VALUE_STRING, NULL);
+ if (ignore)
+ {
+ GString *buf = g_string_sized_new (64);
+ while (ignore != NULL)
+ {
+ GSList *old;
+
+ if (buf->len)
+ g_string_append_c (buf, ',');
+ g_string_append (buf, ignore->data);
+
+ old = ignore;
+ ignore = g_slist_next (ignore);
+ g_free (old->data);
+ g_slist_free_1 (old);
+ }
+ set_proxy_env (env_table, "no_proxy", g_string_free (buf, FALSE));
+ }
+}
+
+static void
+setup_https_proxy_env (GHashTable *env_table,
+ MateConfClient *conf)
+{
+ gchar *host;
+ gint port;
+
+ host = conf_get_string (conf, CONF_PROXY_PREFIX "/secure_host");
+ port = mateconf_client_get_int (conf, CONF_PROXY_PREFIX "/secure_port", NULL);
+ if (host && port)
+ {
+ char *proxy;
+ /* Even though it's https, the proxy scheme is 'http'. See bug #624440. */
+ proxy = g_strdup_printf ("http://%s:%d/", host, port);
+ set_proxy_env (env_table, "https_proxy", proxy);
+ }
+ g_free (host);
+}
+
+static void
+setup_ftp_proxy_env (GHashTable *env_table,
+ MateConfClient *conf)
+{
+ gchar *host;
+ gint port;
+
+ host = conf_get_string (conf, CONF_PROXY_PREFIX "/ftp_host");
+ port = mateconf_client_get_int (conf, CONF_PROXY_PREFIX "/ftp_port", NULL);
+ if (host && port)
+ {
+ char *proxy;
+ /* Even though it's ftp, the proxy scheme is 'http'. See bug #624440. */
+ proxy = g_strdup_printf ("http://%s:%d/", host, port);
+ set_proxy_env (env_table, "ftp_proxy", proxy);
+ }
+ g_free (host);
+}
+
+static void
+setup_socks_proxy_env (GHashTable *env_table,
+ MateConfClient *conf)
+{
+ gchar *host;
+ gint port;
+
+ host = conf_get_string (conf, CONF_PROXY_PREFIX "/socks_host");
+ port = mateconf_client_get_int (conf, CONF_PROXY_PREFIX "/socks_port", NULL);
+ if (host && port)
+ {
+ char *proxy;
+ proxy = g_strdup_printf ("socks://%s:%d/", host, port);
+ set_proxy_env (env_table, "all_proxy", proxy);
+ }
+ g_free (host);
+}
+
+static void
+setup_autoconfig_proxy_env (GHashTable *env_table,
+ MateConfClient *conf)
+{
+ /* XXX Not sure what to do with this. See bug #596688.
+ gchar *url;
+
+ url = conf_get_string (conf, CONF_PROXY_PREFIX "/autoconfig_url");
+ if (url)
+ {
+ char *proxy;
+ proxy = g_strdup_printf ("pac+%s", url);
+ set_proxy_env (env_table, "http_proxy", proxy);
+ }
+ g_free (url);
+ */
+}
+
+/**
+ * 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)
+{
+ char *proxymode;
+
+ MateConfClient *conf;
+ conf = mateconf_client_get_default ();
+
+ /* If mode is not manual, nothing to set */
+ proxymode = conf_get_string (conf, CONF_PROXY_PREFIX "/mode");
+ if (proxymode && 0 == strcmp (proxymode, "manual"))
+ {
+ setup_http_proxy_env (env_table, conf);
+ setup_https_proxy_env (env_table, conf);
+ setup_ftp_proxy_env (env_table, conf);
+ setup_socks_proxy_env (env_table, conf);
+ }
+ else if (proxymode && 0 == strcmp (proxymode, "auto"))
+ {
+ setup_autoconfig_proxy_env (env_table, conf);
+ }
+
+ g_free (proxymode);
+ g_object_unref (conf);
+}
+
+/* Bidirectional object/widget binding */
+
+typedef struct {
+ GObject *object;
+ const char *object_prop;
+ GtkWidget *widget;
+ gulong object_notify_id;
+ gulong widget_notify_id;
+ PropertyChangeFlags flags;
+} PropertyChange;
+
+static void
+property_change_free (PropertyChange *change)
+{
+ g_signal_handler_disconnect (change->object, change->object_notify_id);
+
+ g_slice_free (PropertyChange, change);
+}
+
+static gboolean
+transform_boolean (gboolean input,
+ PropertyChangeFlags flags)
+{
+ if (flags & FLAG_INVERT_BOOL)
+ input = !input;
+
+ return input;
+}
+
+static void
+object_change_notify_cb (PropertyChange *change)
+{
+ GObject *object = change->object;
+ const char *object_prop = change->object_prop;
+ GtkWidget *widget = change->widget;
+
+ g_signal_handler_block (widget, change->widget_notify_id);
+
+ if (GTK_IS_RADIO_BUTTON (widget))
+ {
+ int ovalue, rvalue;
+
+ g_object_get (object, object_prop, &ovalue, NULL);
+ rvalue = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "enum-value"));
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget), ovalue == rvalue);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ {
+ gboolean enabled;
+
+ g_object_get (object, object_prop, &enabled, NULL);
+ gtk_toggle_button_set_active (GTK_TOGGLE_BUTTON (widget),
+ transform_boolean (enabled, change->flags));
+ }
+ else if (GTK_IS_SPIN_BUTTON (widget))
+ {
+ int value;
+
+ g_object_get (object, object_prop, &value, NULL);
+ gtk_spin_button_set_value (GTK_SPIN_BUTTON (widget), value);
+ }
+ else if (GTK_IS_ENTRY (widget))
+ {
+ char *text;
+
+ g_object_get (object, object_prop, &text, NULL);
+ gtk_entry_set_text (GTK_ENTRY (widget), text ? text : "");
+ g_free (text);
+ }
+ else if (GTK_IS_COMBO_BOX (widget))
+ {
+ int value;
+
+ g_object_get (object, object_prop, &value, NULL);
+ gtk_combo_box_set_active (GTK_COMBO_BOX (widget), value);
+ }
+ else if (GTK_IS_RANGE (widget))
+ {
+ double value;
+
+ g_object_get (object, object_prop, &value, NULL);
+ gtk_range_set_value (GTK_RANGE (widget), value);
+ }
+ else if (GTK_IS_COLOR_BUTTON (widget))
+ {
+ GdkColor *color;
+ GdkColor old_color;
+
+ g_object_get (object, object_prop, &color, NULL);
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (widget), &old_color);
+
+ if (color && !gdk_color_equal (color, &old_color))
+ gtk_color_button_set_color (GTK_COLOR_BUTTON (widget), color);
+ if (color)
+ gdk_color_free (color);
+ }
+ else if (GTK_IS_FONT_BUTTON (widget))
+ {
+ PangoFontDescription *font_desc;
+ char *font;
+
+ g_object_get (object, object_prop, &font_desc, NULL);
+ if (!font_desc)
+ goto out;
+
+ font = pango_font_description_to_string (font_desc);
+ gtk_font_button_set_font_name (GTK_FONT_BUTTON (widget), font);
+ g_free (font);
+ pango_font_description_free (font_desc);
+ }
+ else if (GTK_IS_FILE_CHOOSER (widget))
+ {
+ char *name = NULL, *filename = NULL;
+
+ g_object_get (object, object_prop, &name, NULL);
+ if (name)
+ filename = g_filename_from_utf8 (name, -1, NULL, NULL, NULL);
+
+ if (filename)
+ gtk_file_chooser_set_filename (GTK_FILE_CHOOSER (widget), filename);
+ else
+ gtk_file_chooser_unselect_all (GTK_FILE_CHOOSER (widget));
+ g_free (filename);
+ g_free (name);
+ }
+
+out:
+ g_signal_handler_unblock (widget, change->widget_notify_id);
+}
+
+static void
+widget_change_notify_cb (PropertyChange *change)
+{
+ GObject *object = change->object;
+ const char *object_prop = change->object_prop;
+ GtkWidget *widget = change->widget;
+
+ g_signal_handler_block (change->object, change->object_notify_id);
+
+ if (GTK_IS_RADIO_BUTTON (widget))
+ {
+ gboolean active;
+ int value;
+
+ active = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ if (!active)
+ goto out;
+
+ value = GPOINTER_TO_INT (g_object_get_data (G_OBJECT (widget), "enum-value"));
+ g_object_set (object, object_prop, value, NULL);
+ }
+ else if (GTK_IS_TOGGLE_BUTTON (widget))
+ {
+ gboolean enabled;
+
+ enabled = gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget));
+ g_object_set (object, object_prop, transform_boolean (enabled, change->flags), NULL);
+ }
+ else if (GTK_IS_SPIN_BUTTON (widget))
+ {
+ int value;
+
+ value = (int) gtk_spin_button_get_value (GTK_SPIN_BUTTON (widget));
+ g_object_set (object, object_prop, value, NULL);
+ }
+ else if (GTK_IS_ENTRY (widget))
+ {
+ const char *text;
+
+ text = gtk_entry_get_text (GTK_ENTRY (widget));
+ g_object_set (object, object_prop, text, NULL);
+ }
+ else if (GTK_IS_COMBO_BOX (widget))
+ {
+ int value;
+
+ value = gtk_combo_box_get_active (GTK_COMBO_BOX (widget));
+ g_object_set (object, object_prop, value, NULL);
+ }
+ else if (GTK_IS_COLOR_BUTTON (widget))
+ {
+ GdkColor color;
+
+ gtk_color_button_get_color (GTK_COLOR_BUTTON (widget), &color);
+ g_object_set (object, object_prop, &color, NULL);
+ }
+ else if (GTK_IS_FONT_BUTTON (widget))
+ {
+ PangoFontDescription *font_desc;
+ const char *font;
+
+ font = gtk_font_button_get_font_name (GTK_FONT_BUTTON (widget));
+ font_desc = pango_font_description_from_string (font);
+ g_object_set (object, object_prop, font_desc, NULL);
+ pango_font_description_free (font_desc);
+ }
+ else if (GTK_IS_RANGE (widget))
+ {
+ double value;
+
+ value = gtk_range_get_value (GTK_RANGE (widget));
+ g_object_set (object, object_prop, value, NULL);
+ }
+ else if (GTK_IS_FILE_CHOOSER (widget))
+ {
+ char *filename, *name = NULL;
+
+ filename = gtk_file_chooser_get_filename (GTK_FILE_CHOOSER (widget));
+ if (filename)
+ name = g_filename_to_utf8 (filename, -1, NULL, NULL, NULL);
+
+ g_object_set (object, object_prop, name, NULL);
+ g_free (filename);
+ g_free (name);
+ }
+
+out:
+ g_signal_handler_unblock (change->object, change->object_notify_id);
+}
+
+void
+terminal_util_bind_object_property_to_widget (GObject *object,
+ const char *object_prop,
+ GtkWidget *widget,
+ PropertyChangeFlags flags)
+{
+ PropertyChange *change;
+ const char *signal_name;
+ char notify_signal_name[64];
+
+ change = g_slice_new0 (PropertyChange);
+
+ change->widget = widget;
+ g_assert (g_object_get_data (G_OBJECT (widget), "GT:PCD") == NULL);
+ g_object_set_data_full (G_OBJECT (widget), "GT:PCD", change, (GDestroyNotify) property_change_free);
+
+ if (GTK_IS_TOGGLE_BUTTON (widget))
+ signal_name = "notify::active";
+ else if (GTK_IS_SPIN_BUTTON (widget))
+ signal_name = "notify::value";
+ else if (GTK_IS_ENTRY (widget))
+ signal_name = "notify::text";
+ else if (GTK_IS_COMBO_BOX (widget))
+ signal_name = "notify::active";
+ else if (GTK_IS_COLOR_BUTTON (widget))
+ signal_name = "notify::color";
+ else if (GTK_IS_FONT_BUTTON (widget))
+ signal_name = "notify::font-name";
+ else if (GTK_IS_RANGE (widget))
+ signal_name = "value-changed";
+ else if (GTK_IS_FILE_CHOOSER_BUTTON (widget))
+ signal_name = "file-set";
+ else if (GTK_IS_FILE_CHOOSER (widget))
+ signal_name = "selection-changed";
+ else
+ g_assert_not_reached ();
+
+ change->widget_notify_id = g_signal_connect_swapped (widget, signal_name, G_CALLBACK (widget_change_notify_cb), change);
+
+ change->object = object;
+ change->flags = flags;
+ change->object_prop = object_prop;
+
+ g_snprintf (notify_signal_name, sizeof (notify_signal_name), "notify::%s", object_prop);
+ object_change_notify_cb (change);
+ change->object_notify_id = g_signal_connect_swapped (object, notify_signal_name, G_CALLBACK (object_change_notify_cb), change);
+}
+
+#ifdef GDK_WINDOWING_X11
+
+/* We don't want to hop desktops when we unrealize/realize.
+ * So we need to save and restore the value of NET_WM_DESKTOP. This isn't
+ * exposed through GDK.
+ */
+gboolean
+terminal_util_x11_get_net_wm_desktop (GdkWindow *window,
+ guint32 *desktop)
+{
+ GdkDisplay *display = gdk_drawable_get_display (window);
+ Atom type;
+ int format;
+ guchar *data;
+ gulong n_items, bytes_after;
+ gboolean result = FALSE;
+
+ if (XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display),
+ GDK_DRAWABLE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_DESKTOP"),
+ 0, G_MAXLONG, False, AnyPropertyType,
+ &type, &format, &n_items, &bytes_after, &data) == Success &&
+ type != None)
+ {
+ if (type == XA_CARDINAL && format == 32 && n_items == 1)
+ {
+ *desktop = *(gulong *)data;
+ result = TRUE;
+ }
+
+ XFree (data);
+ }
+
+ return result;
+}
+
+void
+terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
+ guint32 desktop)
+{
+ /* We can't change the current desktop before mapping our window,
+ * because GDK has the annoying habit of clearing _NET_WM_DESKTOP
+ * before mapping a GdkWindow, So we we have to do it after instead.
+ *
+ * However, doing it after is different whether or not we have a
+ * window manager (if we don't have a window manager, we have to
+ * set the _NET_WM_DESKTOP property so that it picks it up when
+ * it starts)
+ *
+ * http://bugzilla.mate.org/show_bug.cgi?id=586311 asks for GTK+
+ * to just handle everything behind the scenes including the desktop.
+ */
+ GdkScreen *screen = gdk_drawable_get_screen (window);
+ GdkDisplay *display = gdk_screen_get_display (screen);
+ Display *xdisplay = GDK_DISPLAY_XDISPLAY (display);
+ char *wm_selection_name;
+ Atom wm_selection;
+ gboolean have_wm;
+
+ wm_selection_name = g_strdup_printf ("WM_S%d", gdk_screen_get_number (screen));
+ wm_selection = gdk_x11_get_xatom_by_name_for_display (display, wm_selection_name);
+ g_free(wm_selection_name);
+
+ XGrabServer (xdisplay);
+
+ have_wm = XGetSelectionOwner (xdisplay, wm_selection) != None;
+
+ if (have_wm)
+ {
+ /* code borrowed from GDK
+ */
+ XClientMessageEvent xclient;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.serial = 0;
+ xclient.send_event = True;
+ xclient.window = GDK_WINDOW_XWINDOW (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_DESKTOP");
+ xclient.format = 32;
+
+ xclient.data.l[0] = desktop;
+ xclient.data.l[1] = 0;
+ xclient.data.l[2] = 0;
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent (xdisplay,
+ GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+ }
+ else
+ {
+ gulong long_desktop = desktop;
+
+ XChangeProperty (xdisplay,
+ GDK_DRAWABLE_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display,
+ "_NET_WM_DESKTOP"),
+ XA_CARDINAL, 32, PropModeReplace,
+ (guchar *)&long_desktop, 1);
+ }
+
+ XUngrabServer (xdisplay);
+ XFlush (xdisplay);
+}
+
+/* Asks the window manager to turn off the "demands attention" state on the window.
+ *
+ * This only works for windows that are currently window managed; if the window
+ * is unmapped (in the withdrawn state) it would be necessary to change _NET_WM_STATE
+ * directly.
+ */
+void
+terminal_util_x11_clear_demands_attention (GdkWindow *window)
+{
+ GdkScreen *screen = gdk_drawable_get_screen (window);
+ GdkDisplay *display = gdk_screen_get_display (screen);
+ XClientMessageEvent xclient;
+
+ memset (&xclient, 0, sizeof (xclient));
+ xclient.type = ClientMessage;
+ xclient.serial = 0;
+ xclient.send_event = True;
+ xclient.window = GDK_WINDOW_XWINDOW (window);
+ xclient.message_type = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE");
+ xclient.format = 32;
+
+ xclient.data.l[0] = 0; /* _NET_WM_STATE_REMOVE */
+ xclient.data.l[1] = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_DEMANDS_ATTENTION");
+ xclient.data.l[2] = 0;
+ xclient.data.l[3] = 0;
+ xclient.data.l[4] = 0;
+
+ XSendEvent (GDK_DISPLAY_XDISPLAY (display),
+ GDK_WINDOW_XWINDOW (gdk_screen_get_root_window (screen)),
+ False,
+ SubstructureRedirectMask | SubstructureNotifyMask,
+ (XEvent *)&xclient);
+}
+
+/* Check if a GdkWindow is minimized. This is a workaround for a
+ * GDK bug/misfeature. gdk_window_get_state (window) has the
+ * GDK_WINDOW_STATE_ICONIFIED bit for all unmapped windows,
+ * even windows on another desktop.
+ *
+ * http://bugzilla.mate.org/show_bug.cgi?id=586664
+ *
+ * Code to read _NET_WM_STATE adapted from GDK
+ */
+gboolean
+terminal_util_x11_window_is_minimized (GdkWindow *window)
+{
+ GdkDisplay *display = gdk_drawable_get_display (window);
+
+ Atom type;
+ gint format;
+ gulong nitems;
+ gulong bytes_after;
+ guchar *data;
+ Atom *atoms = NULL;
+ gulong i;
+
+ gboolean minimized = FALSE;
+
+ type = None;
+ gdk_error_trap_push ();
+ XGetWindowProperty (GDK_DISPLAY_XDISPLAY (display), GDK_WINDOW_XID (window),
+ gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE"),
+ 0, G_MAXLONG, False, XA_ATOM, &type, &format, &nitems,
+ &bytes_after, &data);
+ gdk_error_trap_pop ();
+
+ if (type != None)
+ {
+ Atom hidden_atom = gdk_x11_get_xatom_by_name_for_display (display, "_NET_WM_STATE_HIDDEN");
+
+ atoms = (Atom *)data;
+
+ for (i = 0; i < nitems; i++)
+ {
+ if (atoms[i] == hidden_atom)
+ minimized = TRUE;
+
+ ++i;
+ }
+
+ XFree (atoms);
+ }
+
+ return minimized;
+}
+
+#endif /* GDK_WINDOWING_X11 */
diff --git a/src/terminal-util.h b/src/terminal-util.h
new file mode 100644
index 0000000..524d41c
--- /dev/null
+++ b/src/terminal-util.h
@@ -0,0 +1,112 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2008 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_UTIL_H
+#define TERMINAL_UTIL_H
+
+#include <gtk/gtk.h>
+#include <mateconf/mateconf-client.h>
+
+#include "terminal-screen.h"
+
+G_BEGIN_DECLS
+
+#define CONF_PROXY_PREFIX "/system/proxy"
+#define CONF_HTTP_PROXY_PREFIX "/system/http_proxy"
+
+void terminal_util_set_unique_role (GtkWindow *window, const char *prefix);
+
+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, GtkWindow *transient_parent);
+
+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,
+ TerminalURLFlavour flavor,
+ guint32 user_time);
+
+char *terminal_util_resolve_relative_path (const char *path,
+ const char *relative_path);
+
+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);
+
+gboolean terminal_util_load_builder_file (const char *filename,
+ const char *object_name,
+ ...);
+
+gboolean terminal_util_dialog_response_on_delete (GtkWindow *widget);
+
+void terminal_util_key_file_set_string_escape (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ const char *string);
+char *terminal_util_key_file_get_string_unescape (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ GError **error);
+
+void terminal_util_key_file_set_argv (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ int argc,
+ char **argv);
+char **terminal_util_key_file_get_argv (GKeyFile *key_file,
+ const char *group,
+ const char *key,
+ int *argc,
+ GError **error);
+
+void terminal_util_add_proxy_env (GHashTable *env_table);
+
+typedef enum {
+ FLAG_INVERT_BOOL = 1 << 0,
+} PropertyChangeFlags;
+
+void terminal_util_bind_object_property_to_widget (GObject *object,
+ const char *object_prop,
+ GtkWidget *widget,
+ PropertyChangeFlags flags);
+
+gboolean terminal_util_x11_get_net_wm_desktop (GdkWindow *window,
+ guint32 *desktop);
+void terminal_util_x11_set_net_wm_desktop (GdkWindow *window,
+ guint32 desktop);
+
+void terminal_util_x11_clear_demands_attention (GdkWindow *window);
+
+gboolean terminal_util_x11_window_is_minimized (GdkWindow *window);
+
+G_END_DECLS
+
+#endif /* TERMINAL_UTIL_H */
diff --git a/src/terminal-version.h.in b/src/terminal-version.h.in
new file mode 100644
index 0000000..5bc4f2d
--- /dev/null
+++ b/src/terminal-version.h.in
@@ -0,0 +1,35 @@
+/*
+ * Copyright © 2009 Christian Persch
+ *
+ * This library is free software; you can redistribute it and/or modify it
+ * under the terms of the GNU Lesser General Public License as published by the
+ * Free Software Foundation; either version 2.1 of the License, or (at your
+ * option) any later version.
+ *
+ * This library 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 Lesser General Public License along
+ * with this library; if not, write to the Free Software Foundation, Inc.,
+ * 59 Temple Place, Suite 330, Boston, MA 02110-1301 USA
+ */
+
+#if !defined (__TERMINAL_TERMINAL_H_INSIDE__) && !defined (TERMINAL_COMPILATION)
+#error "Only <terminal/terminal.h> 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..234d209
--- /dev/null
+++ b/src/terminal-window.c
@@ -0,0 +1,4026 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2007, 2008, 2009 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <string.h>
+#include <stdlib.h>
+#include <gtk/gtk.h>
+#ifdef GDK_WINDOWING_X11
+#include <gdk/gdkx.h>
+#endif
+#include <gdk/gdkkeysyms.h>
+
+#include "terminal-accels.h"
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-encoding.h"
+#include "terminal-intl.h"
+#include "terminal-screen-container.h"
+#include "terminal-search-dialog.h"
+#include "terminal-tab-label.h"
+#include "terminal-tabs-menu.h"
+#include "terminal-util.h"
+#include "terminal-window.h"
+
+#ifdef ENABLE_SKEY
+#include "skey-popup.h"
+#endif
+
+struct _TerminalWindowPrivate
+{
+ GtkActionGroup *action_group;
+ GtkUIManager *ui_manager;
+ guint ui_id;
+
+ GtkActionGroup *profiles_action_group;
+ guint profiles_ui_id;
+
+ GtkActionGroup *encodings_action_group;
+ guint encodings_ui_id;
+
+ TerminalTabsMenu *tabs_menu;
+
+ TerminalScreenPopupInfo *popup_info;
+ guint remove_popup_info_idle;
+
+ GtkActionGroup *new_terminal_action_group;
+ guint new_terminal_ui_id;
+
+ GtkWidget *menubar;
+ GtkWidget *notebook;
+ TerminalScreen *active_screen;
+ int old_char_width;
+ int old_char_height;
+ void *old_geometry_widget; /* only used for pointer value as it may be freed */
+
+ GtkWidget *confirm_close_dialog;
+ GtkWidget *search_find_dialog;
+
+ guint menubar_visible : 1;
+ guint use_default_menubar_visibility : 1;
+
+ /* Compositing manager integration */
+ guint have_argb_visual : 1;
+
+ /* Used to clear stray "demands attention" flashing on our window when we
+ * unmap and map it to switch to an ARGB visual.
+ */
+ guint clear_demands_attention : 1;
+
+ guint disposed : 1;
+ guint present_on_insert : 1;
+
+ /* Workaround until gtk+ bug #535557 is fixed */
+ guint icon_title_set : 1;
+};
+
+#define PROFILE_DATA_KEY "GT::Profile"
+
+#define FILE_NEW_TERMINAL_TAB_UI_PATH "/menubar/File/FileNewTabProfiles"
+#define FILE_NEW_TERMINAL_WINDOW_UI_PATH "/menubar/File/FileNewWindowProfiles"
+#define SET_ENCODING_UI_PATH "/menubar/Terminal/TerminalSetEncoding/EncodingsPH"
+#define SET_ENCODING_ACTION_NAME_PREFIX "TerminalSetEncoding"
+
+#define PROFILES_UI_PATH "/menubar/Terminal/TerminalProfiles"
+#define PROFILES_POPUP_UI_PATH "/Popup/PopupTerminalProfiles/ProfilesPH"
+
+#define SIZE_TO_UI_PATH "/menubar/Terminal/TerminalSizeToPH"
+#define SIZE_TO_ACTION_NAME_PREFIX "TerminalSizeTo"
+
+#define STOCK_NEW_WINDOW "window-new"
+#define STOCK_NEW_TAB "tab-new"
+
+#define ENCODING_DATA_KEY "encoding"
+
+#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
+
+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 notebook_page_selected_callback (GtkWidget *notebook,
+#if GTK_CHECK_VERSION (2, 90, 6)
+ GtkWidget *page,
+#else
+ gpointer page,
+#endif
+ guint page_num,
+ TerminalWindow *window);
+static void notebook_page_added_callback (GtkWidget *notebook,
+ GtkWidget *container,
+ guint page_num,
+ TerminalWindow *window);
+static void notebook_page_removed_callback (GtkWidget *notebook,
+ GtkWidget *container,
+ guint page_num,
+ TerminalWindow *window);
+
+/* Menu action callbacks */
+static void file_new_window_callback (GtkAction *action,
+ TerminalWindow *window);
+static void file_new_tab_callback (GtkAction *action,
+ TerminalWindow *window);
+static void file_new_profile_callback (GtkAction *action,
+ TerminalWindow *window);
+static void file_close_window_callback (GtkAction *action,
+ TerminalWindow *window);
+static void file_save_contents_callback (GtkAction *action,
+ TerminalWindow *window);
+static void file_close_tab_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_copy_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_paste_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_select_all_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_keybindings_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_profiles_callback (GtkAction *action,
+ TerminalWindow *window);
+static void edit_current_profile_callback (GtkAction *action,
+ TerminalWindow *window);
+static void view_menubar_toggled_callback (GtkToggleAction *action,
+ TerminalWindow *window);
+static void view_fullscreen_toggled_callback (GtkToggleAction *action,
+ TerminalWindow *window);
+static void view_zoom_in_callback (GtkAction *action,
+ TerminalWindow *window);
+static void view_zoom_out_callback (GtkAction *action,
+ TerminalWindow *window);
+static void view_zoom_normal_callback (GtkAction *action,
+ TerminalWindow *window);
+static void search_find_callback (GtkAction *action,
+ TerminalWindow *window);
+static void search_find_next_callback (GtkAction *action,
+ TerminalWindow *window);
+static void search_find_prev_callback (GtkAction *action,
+ TerminalWindow *window);
+static void search_clear_highlight_callback (GtkAction *action,
+ TerminalWindow *window);
+static void terminal_set_title_callback (GtkAction *action,
+ TerminalWindow *window);
+static void terminal_add_encoding_callback (GtkAction *action,
+ TerminalWindow *window);
+static void terminal_reset_callback (GtkAction *action,
+ TerminalWindow *window);
+static void terminal_reset_clear_callback (GtkAction *action,
+ TerminalWindow *window);
+static void tabs_next_or_previous_tab_cb (GtkAction *action,
+ TerminalWindow *window);
+static void tabs_move_left_callback (GtkAction *action,
+ TerminalWindow *window);
+static void tabs_move_right_callback (GtkAction *action,
+ TerminalWindow *window);
+static void tabs_detach_tab_callback (GtkAction *action,
+ TerminalWindow *window);
+static void help_contents_callback (GtkAction *action,
+ TerminalWindow *window);
+static void help_about_callback (GtkAction *action,
+ TerminalWindow *window);
+
+static gboolean find_larger_zoom_factor (double current,
+ double *found);
+static gboolean find_smaller_zoom_factor (double current,
+ double *found);
+
+static void terminal_window_show (GtkWidget *widget);
+
+static gboolean confirm_close_window_or_tab (TerminalWindow *window,
+ TerminalScreen *screen);
+
+static void
+profile_set_callback (TerminalScreen *screen,
+ TerminalProfile *old_profile,
+ TerminalWindow *window);
+static void
+sync_screen_icon_title (TerminalScreen *screen,
+ GParamSpec *psepc,
+ TerminalWindow *window);
+
+G_DEFINE_TYPE (TerminalWindow, terminal_window, GTK_TYPE_WINDOW)
+
+/* Menubar mnemonics & accel settings handling */
+
+static void
+app_setting_notify_cb (TerminalApp *app,
+ GParamSpec *pspec,
+ GdkScreen *screen)
+{
+ GtkSettings *settings;
+ const char *prop_name;
+
+ if (pspec)
+ prop_name = pspec->name;
+ else
+ prop_name = NULL;
+
+ settings = gtk_settings_get_for_screen (screen);
+
+ if (!prop_name || prop_name == I_(TERMINAL_APP_ENABLE_MNEMONICS))
+ {
+ gboolean enable_mnemonics;
+
+ g_object_get (app, TERMINAL_APP_ENABLE_MNEMONICS, &enable_mnemonics, NULL);
+ g_object_set (settings, "gtk-enable-mnemonics", enable_mnemonics, NULL);
+ }
+
+ if (!prop_name || prop_name == I_(TERMINAL_APP_ENABLE_MENU_BAR_ACCEL))
+ {
+ /* const */ char *saved_menubar_accel;
+ gboolean enable_menubar_accel;
+
+ /* FIXME: Once gtk+ bug 507398 is fixed, use that to reset the property instead */
+ /* Now this is a bad hack on so many levels. */
+ saved_menubar_accel = g_object_get_data (G_OBJECT (settings), "GT::gtk-menu-bar-accel");
+ if (!saved_menubar_accel)
+ {
+ g_object_get (settings, "gtk-menu-bar-accel", &saved_menubar_accel, NULL);
+ g_object_set_data_full (G_OBJECT (settings), "GT::gtk-menu-bar-accel",
+ saved_menubar_accel, (GDestroyNotify) g_free);
+ }
+
+ g_object_get (app, TERMINAL_APP_ENABLE_MENU_BAR_ACCEL, &enable_menubar_accel, NULL);
+ if (enable_menubar_accel)
+ g_object_set (settings, "gtk-menu-bar-accel", saved_menubar_accel, NULL);
+ else
+ g_object_set (settings, "gtk-menu-bar-accel", NULL, NULL);
+ }
+}
+
+static void
+app_setting_notify_destroy_cb (GdkScreen *screen)
+{
+ g_signal_handlers_disconnect_by_func (terminal_app_get (),
+ G_CALLBACK (app_setting_notify_cb),
+ screen);
+}
+
+/* utility functions */
+
+static char *
+escape_underscores (const char *name)
+{
+ GString *escaped_name;
+
+ g_assert (name != NULL);
+
+ /* Who'd use more that 4 underscores in a profile name... */
+ escaped_name = g_string_sized_new (strlen (name) + 4 + 1);
+
+ while (*name)
+ {
+ if (*name == '_')
+ g_string_append (escaped_name, "__");
+ else
+ g_string_append_c (escaped_name, *name);
+ name++;
+ }
+
+ return g_string_free (escaped_name, FALSE);
+}
+
+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
+position_menu_under_widget (GtkMenu *menu,
+ int *x,
+ int *y,
+ gboolean *push_in,
+ gpointer user_data)
+{
+ /* Adapted from gtktoolbar.c */
+ GtkWidget *widget = GTK_WIDGET (user_data);
+ GdkWindow *widget_window;
+ GtkWidget *container;
+ GtkRequisition req;
+ GtkRequisition menu_req;
+ GdkRectangle monitor;
+ int monitor_num;
+ GdkScreen *screen;
+ GtkAllocation widget_allocation;
+
+ widget_window = gtk_widget_get_window (widget);
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ container = gtk_widget_get_ancestor (widget, GTK_TYPE_CONTAINER);
+
+ gtk_widget_size_request (widget, &req);
+ gtk_widget_size_request (GTK_WIDGET (menu), &menu_req);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (menu));
+ monitor_num = gdk_screen_get_monitor_at_window (screen, widget_window);
+ if (monitor_num < 0)
+ monitor_num = 0;
+ gdk_screen_get_monitor_geometry (screen, monitor_num, &monitor);
+
+ gdk_window_get_origin (widget_window, x, y);
+ if (!gtk_widget_get_has_window (widget))
+ {
+ *x += widget_allocation.x;
+ *y += widget_allocation.y;
+ }
+ if (gtk_widget_get_direction (container) == GTK_TEXT_DIR_LTR)
+ *x += widget_allocation.width - req.width;
+ else
+ *x += req.width - menu_req.width;
+
+ if ((*y + widget_allocation.height + menu_req.height) <= monitor.y + monitor.height)
+ *y += widget_allocation.height;
+ else if ((*y - menu_req.height) >= monitor.y)
+ *y -= menu_req.height;
+ else if (monitor.y + monitor.height - (*y + widget_allocation.height) > *y)
+ *y += widget_allocation.height;
+ else
+ *y -= menu_req.height;
+
+ *push_in = FALSE;
+}
+
+static void
+terminal_set_profile_toggled_callback (GtkToggleAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalProfile *profile;
+
+ if (!gtk_toggle_action_get_active (action))
+ return;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
+ g_assert (profile);
+
+ if (_terminal_profile_get_forgotten (profile))
+ return;
+
+ g_signal_handlers_block_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
+ terminal_screen_set_profile (priv->active_screen, profile);
+ g_signal_handlers_unblock_by_func (priv->active_screen, G_CALLBACK (profile_set_callback), window);
+}
+
+static void
+profile_visible_name_notify_cb (TerminalProfile *profile,
+ GParamSpec *pspec,
+ GtkAction *action)
+{
+ const char *visible_name;
+ char *dot, *display_name;
+ guint num;
+
+ visible_name = terminal_profile_get_property_string (profile, TERMINAL_PROFILE_VISIBLE_NAME);
+ display_name = escape_underscores (visible_name);
+
+ dot = strchr (gtk_action_get_name (action), '.');
+ if (dot != NULL)
+ {
+ char *free_me;
+
+ num = g_ascii_strtoll (dot + 1, NULL, 10);
+
+ free_me = display_name;
+ if (num < 10)
+ /* Translators: This is the label of a menu item to choose a profile.
+ * _%d is used as the accelerator (with d between 1 and 9), and
+ * the %s is the name of the terminal profile.
+ */
+ display_name = g_strdup_printf (_("_%d. %s"), num, display_name);
+ else if (num < 36)
+ /* Translators: This is the label of a menu item to choose a profile.
+ * _%c is used as the accelerator (it will be a character between A and Z),
+ * and the %s is the name of the terminal profile.
+ */
+ display_name = g_strdup_printf (_("_%c. %s"), ('A' + num - 10), display_name);
+ else
+ free_me = NULL;
+
+ g_free (free_me);
+ }
+
+ g_object_set (action, "label", display_name, NULL);
+ g_free (display_name);
+}
+
+static void
+disconnect_profiles_from_actions_in_group (GtkActionGroup *action_group)
+{
+ GList *actions, *l;
+
+ actions = gtk_action_group_list_actions (action_group);
+ for (l = actions; l != NULL; l = l->next)
+ {
+ GObject *action = G_OBJECT (l->data);
+ TerminalProfile *profile;
+
+ profile = g_object_get_data (action, PROFILE_DATA_KEY);
+ if (!profile)
+ continue;
+
+ g_signal_handlers_disconnect_by_func (profile, G_CALLBACK (profile_visible_name_notify_cb), action);
+ }
+ g_list_free (actions);
+}
+
+static void
+terminal_window_update_set_profile_menu_active_profile (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalProfile *new_active_profile;
+ GList *actions, *l;
+
+ if (!priv->profiles_action_group)
+ return;
+
+ if (!priv->active_screen)
+ return;
+
+ new_active_profile = terminal_screen_get_profile (priv->active_screen);
+
+ actions = gtk_action_group_list_actions (priv->profiles_action_group);
+ for (l = actions; l != NULL; l = l->next)
+ {
+ GObject *action = G_OBJECT (l->data);
+ TerminalProfile *profile;
+
+ profile = g_object_get_data (action, PROFILE_DATA_KEY);
+ if (profile != new_active_profile)
+ continue;
+
+ g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+ g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_profile_toggled_callback), window);
+
+ break;
+ }
+ g_list_free (actions);
+}
+
+static void
+terminal_window_update_set_profile_menu (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalProfile *active_profile;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GList *profiles, *p;
+ GSList *group;
+ guint n;
+ gboolean single_profile;
+
+ /* Remove the old UI */
+ if (priv->profiles_ui_id != 0)
+ {
+ gtk_ui_manager_remove_ui (priv->ui_manager, priv->profiles_ui_id);
+ priv->profiles_ui_id = 0;
+ }
+
+ if (priv->profiles_action_group != NULL)
+ {
+ disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
+ gtk_ui_manager_remove_action_group (priv->ui_manager,
+ priv->profiles_action_group);
+ priv->profiles_action_group = NULL;
+ }
+
+ profiles = terminal_app_get_profile_list (terminal_app_get ());
+
+ action = gtk_action_group_get_action (priv->action_group, "TerminalProfiles");
+ single_profile = !profiles || profiles->next == NULL; /* list length <= 1 */
+ gtk_action_set_sensitive (action, !single_profile);
+ if (profiles == NULL)
+ return;
+
+ if (priv->active_screen)
+ active_profile = terminal_screen_get_profile (priv->active_screen);
+ else
+ active_profile = NULL;
+
+ action_group = priv->profiles_action_group = gtk_action_group_new ("Profiles");
+ gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
+ g_object_unref (action_group);
+
+ priv->profiles_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+
+ group = NULL;
+ n = 0;
+ for (p = profiles; p != NULL; p = p->next)
+ {
+ TerminalProfile *profile = (TerminalProfile *) p->data;
+ GtkRadioAction *profile_action;
+ char name[32];
+
+ g_snprintf (name, sizeof (name), "TerminalSetProfile%u", n++);
+
+ profile_action = gtk_radio_action_new (name,
+ NULL,
+ NULL,
+ NULL,
+ n);
+
+ gtk_radio_action_set_group (profile_action, group);
+ group = gtk_radio_action_get_group (profile_action);
+
+ if (profile == active_profile)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (profile_action), TRUE);
+
+ g_object_set_data_full (G_OBJECT (profile_action),
+ PROFILE_DATA_KEY,
+ g_object_ref (profile),
+ (GDestroyNotify) g_object_unref);
+ profile_visible_name_notify_cb (profile, NULL, GTK_ACTION (profile_action));
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_VISIBLE_NAME,
+ G_CALLBACK (profile_visible_name_notify_cb), profile_action);
+ g_signal_connect (profile_action, "toggled",
+ G_CALLBACK (terminal_set_profile_toggled_callback), window);
+
+ gtk_action_group_add_action (action_group, GTK_ACTION (profile_action));
+ g_object_unref (profile_action);
+
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
+ PROFILES_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->profiles_ui_id,
+ PROFILES_POPUP_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+ }
+
+ g_list_free (profiles);
+}
+
+static void
+terminal_window_create_new_terminal_action (TerminalWindow *window,
+ TerminalProfile *profile,
+ const char *name,
+ guint num,
+ GCallback callback)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+
+ action = gtk_action_new (name, NULL, NULL, NULL);
+
+ g_object_set_data_full (G_OBJECT (action),
+ PROFILE_DATA_KEY,
+ g_object_ref (profile),
+ (GDestroyNotify) g_object_unref);
+ profile_visible_name_notify_cb (profile, NULL, action);
+ g_signal_connect (profile, "notify::" TERMINAL_PROFILE_VISIBLE_NAME,
+ G_CALLBACK (profile_visible_name_notify_cb), action);
+ g_signal_connect (action, "activate", callback, window);
+
+ gtk_action_group_add_action (priv->new_terminal_action_group, action);
+ g_object_unref (action);
+}
+
+static void
+terminal_window_update_new_terminal_menus (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GList *profiles, *p;
+ guint n;
+ gboolean have_single_profile;
+
+ /* Remove the old UI */
+ if (priv->new_terminal_ui_id != 0)
+ {
+ gtk_ui_manager_remove_ui (priv->ui_manager, priv->new_terminal_ui_id);
+ priv->new_terminal_ui_id = 0;
+ }
+
+ if (priv->new_terminal_action_group != NULL)
+ {
+ disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
+ gtk_ui_manager_remove_action_group (priv->ui_manager,
+ priv->new_terminal_action_group);
+ priv->new_terminal_action_group = NULL;
+ }
+
+ profiles = terminal_app_get_profile_list (terminal_app_get ());
+ have_single_profile = !profiles || !profiles->next;
+
+ action = gtk_action_group_get_action (priv->action_group, "FileNewTab");
+ gtk_action_set_visible (action, have_single_profile);
+ action = gtk_action_group_get_action (priv->action_group, "FileNewWindow");
+ gtk_action_set_visible (action, have_single_profile);
+
+ if (have_single_profile)
+ {
+ g_list_free (profiles);
+ return;
+ }
+
+ /* Now build the submenus */
+
+ action_group = priv->new_terminal_action_group = gtk_action_group_new ("NewTerminal");
+ gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
+ g_object_unref (action_group);
+
+ priv->new_terminal_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+
+ n = 0;
+ for (p = profiles; p != NULL; p = p->next)
+ {
+ TerminalProfile *profile = (TerminalProfile *) p->data;
+ char name[32];
+
+ g_snprintf (name, sizeof (name), "FileNewTab.%u", n);
+ terminal_window_create_new_terminal_action (window,
+ profile,
+ name,
+ n,
+ G_CALLBACK (file_new_tab_callback));
+
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->new_terminal_ui_id,
+ FILE_NEW_TERMINAL_TAB_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+
+ g_snprintf (name, sizeof (name), "FileNewWindow.%u", n);
+ terminal_window_create_new_terminal_action (window,
+ profile,
+ name,
+ n,
+ G_CALLBACK (file_new_window_callback));
+
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->new_terminal_ui_id,
+ FILE_NEW_TERMINAL_WINDOW_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+
+ ++n;
+ }
+
+ g_list_free (profiles);
+}
+
+static void
+terminal_set_encoding_callback (GtkToggleAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalEncoding *encoding;
+
+ if (!gtk_toggle_action_get_active (action))
+ return;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ encoding = g_object_get_data (G_OBJECT (action), ENCODING_DATA_KEY);
+ g_assert (encoding);
+
+ vte_terminal_set_encoding (VTE_TERMINAL (priv->active_screen),
+ terminal_encoding_get_charset (encoding));
+}
+
+static void
+terminal_window_update_encoding_menu (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalApp *app;
+ GtkActionGroup *action_group;
+ GSList *group;
+ guint n;
+ GSList *encodings, *l;
+ const char *charset;
+ TerminalEncoding *active_encoding;
+
+ /* Remove the old UI */
+ if (priv->encodings_ui_id != 0)
+ {
+ gtk_ui_manager_remove_ui (priv->ui_manager, priv->encodings_ui_id);
+ priv->encodings_ui_id = 0;
+ }
+
+ if (priv->encodings_action_group != NULL)
+ {
+ gtk_ui_manager_remove_action_group (priv->ui_manager,
+ priv->encodings_action_group);
+ priv->encodings_action_group = NULL;
+ }
+
+ action_group = priv->encodings_action_group = gtk_action_group_new ("Encodings");
+ gtk_ui_manager_insert_action_group (priv->ui_manager, action_group, -1);
+ g_object_unref (action_group);
+
+ priv->encodings_ui_id = gtk_ui_manager_new_merge_id (priv->ui_manager);
+
+ if (priv->active_screen)
+ charset = vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen));
+ else
+ charset = "current";
+
+ app = terminal_app_get ();
+ active_encoding = terminal_app_ensure_encoding (app, charset);
+
+ encodings = terminal_app_get_active_encodings (app);
+
+ if (g_slist_find (encodings, active_encoding) == NULL)
+ encodings = g_slist_append (encodings, terminal_encoding_ref (active_encoding));
+
+ group = NULL;
+ n = 0;
+ for (l = encodings; l != NULL; l = l->next)
+ {
+ TerminalEncoding *e = (TerminalEncoding *) l->data;
+ GtkRadioAction *encoding_action;
+ char name[128];
+ char *display_name;
+
+ g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s", terminal_encoding_get_id (e));
+ display_name = g_strdup_printf ("%s (%s)", e->name, terminal_encoding_get_charset (e));
+
+ encoding_action = gtk_radio_action_new (name,
+ display_name,
+ NULL,
+ NULL,
+ n);
+ g_free (display_name);
+
+ gtk_radio_action_set_group (encoding_action, group);
+ group = gtk_radio_action_get_group (encoding_action);
+
+ if (charset && strcmp (terminal_encoding_get_id (e), charset) == 0)
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (encoding_action), TRUE);
+
+ g_signal_connect (encoding_action, "toggled",
+ G_CALLBACK (terminal_set_encoding_callback), window);
+
+ g_object_set_data_full (G_OBJECT (encoding_action), ENCODING_DATA_KEY,
+ terminal_encoding_ref (e),
+ (GDestroyNotify) terminal_encoding_unref);
+
+ gtk_action_group_add_action (action_group, GTK_ACTION (encoding_action));
+ g_object_unref (encoding_action);
+
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->encodings_ui_id,
+ SET_ENCODING_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+ }
+
+ g_slist_foreach (encodings, (GFunc) terminal_encoding_unref, NULL);
+ g_slist_free (encodings);
+}
+
+static void
+terminal_window_update_encoding_menu_active_encoding (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ char name[128];
+
+ if (!priv->active_screen)
+ return;
+ if (!priv->encodings_action_group)
+ return;
+
+ g_snprintf (name, sizeof (name), SET_ENCODING_ACTION_NAME_PREFIX "%s",
+ vte_terminal_get_encoding (VTE_TERMINAL (priv->active_screen)));
+ action = gtk_action_group_get_action (priv->encodings_action_group, name);
+ if (!action)
+ return;
+
+ g_signal_handlers_block_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), TRUE);
+ g_signal_handlers_unblock_by_func (action, G_CALLBACK (terminal_set_encoding_callback), window);
+}
+
+static void
+terminal_size_to_cb (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ const char *name;
+ char *end = NULL;
+ guint width, height;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ name = gtk_action_get_name (action) + strlen (SIZE_TO_ACTION_NAME_PREFIX);
+ width = g_ascii_strtoull (name, &end, 10);
+ g_assert (end && *end == 'x');
+ height = g_ascii_strtoull (end + 1, &end, 10);
+ g_assert (end && *end == '\0');
+
+ vte_terminal_set_size (VTE_TERMINAL (priv->active_screen), width, height);
+
+ terminal_window_set_size_force_grid (window, priv->active_screen, TRUE, -1, -1);
+}
+
+static void
+terminal_window_update_size_to_menu (TerminalWindow *window)
+{
+ static const struct {
+ guint grid_width;
+ guint grid_height;
+ } predefined_sizes[] = {
+ { 80, 24 },
+ { 80, 43 },
+ { 132, 24 },
+ { 132, 43 }
+ };
+ TerminalWindowPrivate *priv = window->priv;
+ guint i;
+
+ /* We only install this once, so there's no need for a separate action group
+ * and any cleanup + build-new-one action here.
+ */
+
+ for (i = 0; i < G_N_ELEMENTS (predefined_sizes); ++i)
+ {
+ guint grid_width = predefined_sizes[i].grid_width;
+ guint grid_height = predefined_sizes[i].grid_height;
+ GtkAction *action;
+ char name[40];
+ char *display_name;
+
+ g_snprintf (name, sizeof (name), SIZE_TO_ACTION_NAME_PREFIX "%ux%u",
+ grid_width, grid_height);
+
+ /* If there are ever more than 9 of these, extend this to use A..Z as mnemonics,
+ * like we do for the profiles menu.
+ */
+ display_name = g_strdup_printf ("_%u. %ux%u", i + 1, grid_width, grid_height);
+
+ action = gtk_action_new (name, display_name, NULL, NULL);
+ g_free (display_name);
+
+ g_signal_connect (action, "activate",
+ G_CALLBACK (terminal_size_to_cb), window);
+
+ gtk_action_group_add_action (priv->action_group, action);
+ g_object_unref (action);
+
+ gtk_ui_manager_add_ui (priv->ui_manager, priv->ui_id,
+ SIZE_TO_UI_PATH,
+ name, name,
+ GTK_UI_MANAGER_MENUITEM, FALSE);
+ }
+}
+
+/* Actions stuff */
+
+static void
+terminal_window_update_copy_sensitivity (TerminalScreen *screen,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ gboolean can_copy;
+
+ if (screen != priv->active_screen)
+ return;
+
+ can_copy = vte_terminal_get_has_selection (VTE_TERMINAL (screen));
+
+ action = gtk_action_group_get_action (priv->action_group, "EditCopy");
+ gtk_action_set_sensitive (action, can_copy);
+}
+
+static void
+terminal_window_update_zoom_sensitivity (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreen *screen;
+ GtkAction *action;
+ double current, zoom;
+
+ screen = priv->active_screen;
+ if (screen == NULL)
+ return;
+
+ current = terminal_screen_get_font_scale (screen);
+
+ action = gtk_action_group_get_action (priv->action_group, "ViewZoomOut");
+ gtk_action_set_sensitive (action, find_smaller_zoom_factor (current, &zoom));
+ action = gtk_action_group_get_action (priv->action_group, "ViewZoomIn");
+ gtk_action_set_sensitive (action, find_larger_zoom_factor (current, &zoom));
+}
+
+static void
+terminal_window_update_search_sensitivity (TerminalScreen *screen,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ gboolean can_search;
+
+ if (screen != priv->active_screen)
+ return;
+
+ can_search = vte_terminal_search_get_gregex (VTE_TERMINAL (screen)) != NULL;
+
+ action = gtk_action_group_get_action (priv->action_group, "SearchFindNext");
+ gtk_action_set_sensitive (action, can_search);
+ action = gtk_action_group_get_action (priv->action_group, "SearchFindPrevious");
+ gtk_action_set_sensitive (action, can_search);
+ action = gtk_action_group_get_action (priv->action_group, "SearchClearHighlight");
+ gtk_action_set_sensitive (action, can_search);
+}
+
+static void
+update_edit_menu_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ int n_targets,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ gboolean can_paste, can_paste_uris;
+
+ can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
+ can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
+
+ action = gtk_action_group_get_action (priv->action_group, "EditPaste");
+ gtk_action_set_sensitive (action, can_paste);
+ action = gtk_action_group_get_action (priv->action_group, "EditPasteURIPaths");
+ gtk_action_set_visible (action, can_paste_uris);
+ gtk_action_set_sensitive (action, can_paste_uris);
+
+ /* Ref was added in gtk_clipboard_request_targets below */
+ g_object_unref (window);
+}
+
+static void
+edit_menu_activate_callback (GtkMenuItem *menuitem,
+ gpointer user_data)
+{
+ TerminalWindow *window = (TerminalWindow *) user_data;
+ GtkClipboard *clipboard;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_request_targets (clipboard,
+ (GtkClipboardTargetsReceivedFunc) update_edit_menu_cb,
+ g_object_ref (window));
+}
+
+static void
+screen_resize_window_cb (TerminalScreen *screen,
+ guint width,
+ guint height,
+ TerminalWindow* window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ VteTerminal *terminal = VTE_TERMINAL (screen);
+ GtkWidget *widget = GTK_WIDGET (screen);
+ guint grid_width, grid_height;
+ int char_width, char_height;
+ GtkBorder *inner_border = NULL;
+ GtkAllocation widget_allocation;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ /* Don't do anything if we're maximised or fullscreened */
+ // FIXME: realized && ... instead?
+ if (!gtk_widget_get_realized (widget) ||
+ (gdk_window_get_state (gtk_widget_get_window (widget)) & (GDK_WINDOW_STATE_MAXIMIZED | GDK_WINDOW_STATE_FULLSCREEN)) != 0)
+ return;
+
+ /* NOTE: width and height already include the VteTerminal's padding! */
+
+ /* Short-circuit */
+ if (((int) width) == widget_allocation.width &&
+ ((int) height) == widget_allocation.height)
+ return;
+
+ /* The resize-window signal sucks. Re-compute grid widths */
+
+ char_width = vte_terminal_get_char_width (terminal);
+ char_height = vte_terminal_get_char_height (terminal);
+
+ gtk_widget_style_get (GTK_WIDGET (terminal), "inner-border", &inner_border, NULL);
+ grid_width = (width - (inner_border ? (inner_border->left + inner_border->right) : 0)) / char_width;
+ grid_height = (height - (inner_border ? (inner_border->top + inner_border->bottom) : 0)) / char_height;
+ gtk_border_free (inner_border);
+
+ vte_terminal_set_size (terminal, grid_width, grid_height);
+
+ if (screen != priv->active_screen)
+ return;
+
+ terminal_window_set_size_force_grid (window, screen, TRUE, -1, -1); //grid_width, grid_height);
+}
+
+static void
+terminal_window_update_tabs_menu_sensitivity (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
+ GtkActionGroup *action_group = priv->action_group;
+ GtkAction *action;
+ int num_pages, page_num;
+ gboolean not_first, not_last;
+
+ if (priv->disposed)
+ return;
+
+ num_pages = gtk_notebook_get_n_pages (notebook);
+ page_num = gtk_notebook_get_current_page (notebook);
+ not_first = page_num > 0;
+ not_last = page_num + 1 < num_pages;
+
+ /* Hide the tabs menu in single-tab windows */
+ action = gtk_action_group_get_action (action_group, "Tabs");
+ gtk_action_set_visible (action, num_pages > 1);
+
+#if 1
+ /* NOTE: We always make next/prev actions sensitive except in
+ * single-tab windows, so the corresponding shortcut key escape code
+ * isn't sent to the terminal. See bug #453193 and bug #138609.
+ * This also makes tab cycling work, bug #92139.
+ * FIXME: Find a better way to do this.
+ */
+ action = gtk_action_group_get_action (action_group, "TabsPrevious");
+ gtk_action_set_sensitive (action, num_pages > 1);
+ action = gtk_action_group_get_action (action_group, "TabsNext");
+ gtk_action_set_sensitive (action, num_pages > 1);
+#else
+ /* This would be correct, but see the comment above. */
+ action = gtk_action_group_get_action (action_group, "TabsPrevious");
+ gtk_action_set_sensitive (action, not_first);
+ action = gtk_action_group_get_action (action_group, "TabsNext");
+ gtk_action_set_sensitive (action, not_last);
+#endif
+
+ action = gtk_action_group_get_action (action_group, "TabsMoveLeft");
+ gtk_action_set_sensitive (action, not_first);
+ action = gtk_action_group_get_action (action_group, "TabsMoveRight");
+ gtk_action_set_sensitive (action, not_last);
+ action = gtk_action_group_get_action (action_group, "TabsDetach");
+ gtk_action_set_sensitive (action, num_pages > 1);
+ action = gtk_action_group_get_action (action_group, "FileCloseTab");
+ gtk_action_set_sensitive (action, num_pages > 1);
+}
+
+gboolean
+terminal_window_uses_argb_visual (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ return priv->have_argb_visual;
+}
+
+static void
+update_tab_visibility (TerminalWindow *window,
+ int change)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ gboolean show_tabs;
+ guint num;
+
+ num = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ show_tabs = (num + change) > 1;
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), show_tabs);
+}
+
+static GtkNotebook *
+handle_tab_droped_on_desktop (GtkNotebook *source_notebook,
+ GtkWidget *container,
+ gint x,
+ gint y,
+ gpointer data)
+{
+ TerminalScreen *screen;
+ TerminalWindow *source_window;
+ TerminalWindow *new_window;
+ TerminalWindowPrivate *new_priv;
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
+ 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_app_new_window (terminal_app_get (),
+ gtk_widget_get_screen (GTK_WIDGET (source_window)));
+ new_priv = new_window->priv;
+ new_priv->present_on_insert = TRUE;
+
+ update_tab_visibility (source_window, -1);
+ update_tab_visibility (new_window, +1);
+
+ return GTK_NOTEBOOK (new_priv->notebook);
+}
+
+/* Terminal screen popup menu handling */
+
+static void
+popup_open_url_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreenPopupInfo *info = priv->popup_info;
+
+ if (info == NULL)
+ return;
+
+ terminal_util_open_url (GTK_WIDGET (window), info->string, info->flavour,
+ gtk_get_current_event_time ());
+}
+
+static void
+popup_copy_url_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreenPopupInfo *info = priv->popup_info;
+ GtkClipboard *clipboard;
+
+ if (info == NULL)
+ return;
+
+ if (info->string == NULL)
+ return;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_set_text (clipboard, info->string, -1);
+}
+
+static void
+popup_leave_fullscreen_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+}
+
+static void
+remove_popup_info (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (priv->remove_popup_info_idle != 0)
+ {
+ g_source_remove (priv->remove_popup_info_idle);
+ priv->remove_popup_info_idle = 0;
+ }
+
+ if (priv->popup_info != NULL)
+ {
+ terminal_screen_popup_info_unref (priv->popup_info);
+ priv->popup_info = NULL;
+ }
+}
+
+static gboolean
+idle_remove_popup_info (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ priv->remove_popup_info_idle = 0;
+ remove_popup_info (window);
+ return FALSE;
+}
+
+static void
+unset_popup_info (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ /* Unref the event from idle since we still need it
+ * from the action callbacks which will run before idle.
+ */
+ if (priv->remove_popup_info_idle == 0 &&
+ priv->popup_info != NULL)
+ {
+ priv->remove_popup_info_idle =
+ g_idle_add ((GSourceFunc) idle_remove_popup_info, window);
+ }
+}
+
+static void
+popup_menu_deactivate_callback (GtkWidget *popup,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *im_menu_item;
+
+ g_signal_handlers_disconnect_by_func
+ (popup, G_CALLBACK (popup_menu_deactivate_callback), window);
+
+ im_menu_item = gtk_ui_manager_get_widget (priv->ui_manager,
+ "/Popup/PopupInputMethods");
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (im_menu_item), NULL);
+
+ unset_popup_info (window);
+}
+
+static void
+popup_clipboard_targets_received_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ int n_targets,
+ TerminalScreenPopupInfo *info)
+{
+ TerminalWindow *window = info->window;
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreen *screen = info->screen;
+ GtkWidget *popup_menu, *im_menu, *im_menu_item;
+ GtkAction *action;
+ gboolean can_paste, can_paste_uris, show_link, show_email_link, show_call_link, show_input_method_menu;
+ int n_pages;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (screen)))
+ {
+ terminal_screen_popup_info_unref (info);
+ return;
+ }
+
+ /* Now we know that the screen is realized, we know that the window is still alive */
+ remove_popup_info (window);
+
+ priv->popup_info = info; /* adopt the ref added when requesting the clipboard */
+
+ n_pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook));
+
+ can_paste = targets != NULL && gtk_targets_include_text (targets, n_targets);
+ can_paste_uris = targets != NULL && gtk_targets_include_uri (targets, n_targets);
+ show_link = info->string != NULL && (info->flavour == FLAVOR_AS_IS || info->flavour == FLAVOR_DEFAULT_TO_HTTP);
+ show_email_link = info->string != NULL && info->flavour == FLAVOR_EMAIL;
+ show_call_link = info->string != NULL && info->flavour == FLAVOR_VOIP_CALL;
+
+ action = gtk_action_group_get_action (priv->action_group, "PopupSendEmail");
+ gtk_action_set_visible (action, show_email_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupCopyEmailAddress");
+ gtk_action_set_visible (action, show_email_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupCall");
+ gtk_action_set_visible (action, show_call_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupCopyCallAddress");
+ gtk_action_set_visible (action, show_call_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupOpenLink");
+ gtk_action_set_visible (action, show_link);
+ action = gtk_action_group_get_action (priv->action_group, "PopupCopyLinkAddress");
+ gtk_action_set_visible (action, show_link);
+
+ action = gtk_action_group_get_action (priv->action_group, "PopupCloseWindow");
+ gtk_action_set_visible (action, n_pages <= 1);
+ action = gtk_action_group_get_action (priv->action_group, "PopupCloseTab");
+ gtk_action_set_visible (action, n_pages > 1);
+
+ action = gtk_action_group_get_action (priv->action_group, "PopupCopy");
+ gtk_action_set_sensitive (action, vte_terminal_get_has_selection (VTE_TERMINAL (screen)));
+ action = gtk_action_group_get_action (priv->action_group, "PopupPaste");
+ gtk_action_set_sensitive (action, can_paste);
+ action = gtk_action_group_get_action (priv->action_group, "PopupPasteURIPaths");
+ gtk_action_set_visible (action, can_paste_uris);
+
+ g_object_get (gtk_widget_get_settings (GTK_WIDGET (window)),
+ "gtk-show-input-method-menu", &show_input_method_menu,
+ NULL);
+
+ action = gtk_action_group_get_action (priv->action_group, "PopupInputMethods");
+ gtk_action_set_visible (action, show_input_method_menu);
+
+ im_menu_item = gtk_ui_manager_get_widget (priv->ui_manager,
+ "/Popup/PopupInputMethods");
+ /* FIXME: fix this when gtk+ bug #500065 is done, use vte_terminal_im_merge_ui */
+ if (show_input_method_menu)
+ {
+ im_menu = gtk_menu_new ();
+ vte_terminal_im_append_menuitems (VTE_TERMINAL (screen),
+ GTK_MENU_SHELL (im_menu));
+ gtk_widget_show (im_menu);
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (im_menu_item), im_menu);
+ }
+ else
+ {
+ gtk_menu_item_set_submenu (GTK_MENU_ITEM (im_menu_item), NULL);
+ }
+
+ popup_menu = gtk_ui_manager_get_widget (priv->ui_manager, "/Popup");
+ g_signal_connect (popup_menu, "deactivate",
+ G_CALLBACK (popup_menu_deactivate_callback), window);
+
+ /* Pseudo activation of the popup menu's action */
+ action = gtk_action_group_get_action (priv->action_group, "Popup");
+ gtk_action_activate (action);
+
+ if (info->button == 0)
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (popup_menu), FALSE);
+
+ gtk_menu_popup (GTK_MENU (popup_menu),
+ NULL, NULL,
+ NULL, NULL,
+ info->button,
+ info->timestamp);
+}
+
+static void
+screen_show_popup_menu_callback (TerminalScreen *screen,
+ TerminalScreenPopupInfo *info,
+ TerminalWindow *window)
+{
+ GtkClipboard *clipboard;
+
+ g_return_if_fail (info->window == window);
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+ gtk_clipboard_request_targets (clipboard,
+ (GtkClipboardTargetsReceivedFunc) popup_clipboard_targets_received_cb,
+ terminal_screen_popup_info_ref (info));
+}
+
+static gboolean
+screen_match_clicked_cb (TerminalScreen *screen,
+ const char *match,
+ int flavour,
+ guint state,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (screen != priv->active_screen)
+ return FALSE;
+
+ switch (flavour)
+ {
+#ifdef ENABLE_SKEY
+ case FLAVOR_SKEY:
+ terminal_skey_do_popup (GTK_WINDOW (window), screen, match);
+ break;
+#endif
+ default:
+ gtk_widget_grab_focus (GTK_WIDGET (screen));
+ terminal_util_open_url (GTK_WIDGET (window), match, flavour,
+ gtk_get_current_event_time ());
+ break;
+ }
+
+ return TRUE;
+}
+
+static void
+screen_close_cb (TerminalScreen *screen,
+ TerminalWindow *window)
+{
+ terminal_window_remove_screen (window, screen);
+}
+
+static gboolean
+terminal_window_accel_activate_cb (GtkAccelGroup *accel_group,
+ GObject *acceleratable,
+ guint keyval,
+ GdkModifierType modifier,
+ TerminalWindow *window)
+{
+ GtkAccelGroupEntry *entries;
+ guint n_entries;
+ gboolean retval = FALSE;
+
+ entries = gtk_accel_group_query (accel_group, keyval, modifier, &n_entries);
+ if (n_entries > 0)
+ {
+ const char *accel_path;
+
+ accel_path = g_quark_to_string (entries[0].accel_path_quark);
+
+ if (g_str_has_prefix (accel_path, "<Actions>/Main/"))
+ {
+ const char *action_name;
+
+ /* We want to always consume these 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.
+ * This also makes tab cycling work, bug #92139. (NOT!)
+ */
+
+ action_name = I_(accel_path + strlen ("<Actions>/Main/"));
+
+#if 0
+ if (gtk_notebook_get_n_pages (GTK_NOTEBOOK (priv->notebook)) > 1 &&
+ (action_name == I_("TabsPrevious") || action_name == I_("TabsNext")))
+ retval = TRUE;
+ else
+#endif
+ if (action_name == I_("EditCopy") ||
+ action_name == I_("PopupCopy") ||
+ action_name == I_("EditPaste") ||
+ action_name == I_("PopupPaste"))
+ retval = TRUE;
+ }
+ }
+
+ return retval;
+}
+
+/*****************************************/
+
+#ifdef MATE_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 /* MATE_ENABLE_DEBUG */
+
+static void
+terminal_window_realize (GtkWidget *widget)
+{
+ TerminalWindow *window = TERMINAL_WINDOW (widget);
+ TerminalWindowPrivate *priv = window->priv;
+#ifdef GDK_WINDOWING_X11
+ GdkScreen *screen;
+ GdkColormap *colormap;
+ GtkAllocation widget_allocation;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ screen = gtk_widget_get_screen (GTK_WIDGET (window));
+ if (gdk_screen_is_composited (screen) &&
+ (colormap = gdk_screen_get_rgba_colormap (screen)) != NULL)
+ {
+ /* Set RGBA colormap if possible so VTE can use real transparency */
+ gtk_widget_set_colormap (widget, colormap);
+ priv->have_argb_visual = TRUE;
+ }
+ else
+ {
+ gtk_widget_set_colormap (widget, gdk_screen_get_default_colormap (screen));
+ priv->have_argb_visual = FALSE;
+ }
+#endif
+
+ _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);
+
+ /* Need to do this now since this requires the window to be realized */
+ if (priv->active_screen != NULL)
+ sync_screen_icon_title (priv->active_screen, NULL, window);
+}
+
+static gboolean
+terminal_window_map_event (GtkWidget *widget,
+ GdkEventAny *event)
+{
+ TerminalWindow *window = TERMINAL_WINDOW (widget);
+ TerminalWindowPrivate *priv = window->priv;
+ gboolean (* map_event) (GtkWidget *, GdkEventAny *) =
+ GTK_WIDGET_CLASS (terminal_window_parent_class)->map_event;
+ GtkAllocation widget_allocation;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[window %p] map-event, size %d : %d at (%d, %d)\n",
+ widget,
+ widget_allocation.width, widget_allocation.height,
+ widget_allocation.x, widget_allocation.y);
+
+ if (priv->clear_demands_attention)
+ {
+#ifdef GDK_WINDOWING_X11
+ terminal_util_x11_clear_demands_attention (gtk_widget_get_window (widget));
+#endif
+
+ priv->clear_demands_attention = FALSE;
+ }
+
+ if (map_event)
+ return map_event (widget, event);
+
+ return FALSE;
+}
+
+
+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);
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ gboolean is_fullscreen;
+
+ is_fullscreen = (event->new_window_state & GDK_WINDOW_STATE_FULLSCREEN) != 0;
+
+ action = gtk_action_group_get_action (priv->action_group, "ViewFullscreen");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), is_fullscreen);
+
+ action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
+ gtk_action_set_visible (action, is_fullscreen);
+ }
+
+ if (window_state_event)
+ return window_state_event (widget, event);
+
+ return FALSE;
+}
+
+static void
+terminal_window_window_manager_changed_cb (GdkScreen *screen,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+ gboolean supports_fs;
+
+ supports_fs = gdk_x11_screen_supports_net_wm_hint (screen, gdk_atom_intern ("_NET_WM_STATE_FULLSCREEN", FALSE));
+
+ action = gtk_action_group_get_action (priv->action_group, "ViewFullscreen");
+ gtk_action_set_sensitive (action, supports_fs);
+}
+
+#ifdef GDK_WINDOWING_X11
+
+static void
+terminal_window_composited_changed_cb (GdkScreen *screen,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ gboolean composited;
+
+ composited = gdk_screen_is_composited (screen);
+ if ((composited != priv->have_argb_visual) &&
+ gtk_widget_get_realized (GTK_WIDGET (window)))
+ {
+ GtkWidget *widget = GTK_WIDGET (window);
+ GdkWindow *widget_window;
+ guint32 user_time;
+ gboolean have_desktop;
+ guint32 desktop = 0; /* Quiet GCC */
+ gboolean was_minimized;
+ int x, y;
+
+ widget_window = gtk_widget_get_window (widget);
+
+ user_time = gdk_x11_display_get_user_time (gtk_widget_get_display (widget));
+
+ /* If compositing changed, re-realize the window. Bug #563561 */
+
+ /* Save the position; this isn't perfect, because the position
+ * that gtk_window_get_position() returns is the position of the
+ * frame window, and we are racing with the new window manager
+ * framing our window, so we might see a funky intermediate state.
+ * But at worst, we'll be off by a few pixels (the frame size). */
+ gtk_window_get_position (GTK_WINDOW (window), &x, &y);
+
+ /* GtkWindow tries to save whether the window was iconified
+ * and restore it, but that doesn't work because of problems
+ * GDK_WINDOW_STATE_ICONIFIED. For details, see comment for
+ * terminal_util_x11_window_is_minimized()
+ */
+ was_minimized = terminal_util_x11_window_is_minimized (widget_window);
+
+ /* And the desktop */
+ have_desktop = terminal_util_x11_get_net_wm_desktop (widget_window, &desktop);
+
+ gtk_widget_hide (widget);
+ gtk_widget_unrealize (widget);
+
+ /* put the window back where it was before */
+ gtk_window_move (GTK_WINDOW (window), x, y);
+ gtk_widget_realize (widget);
+
+ /* Get new GdkWindow */
+ widget_window = gtk_widget_get_window (widget);
+
+ gdk_x11_window_set_user_time (widget_window, user_time);
+
+ if (was_minimized)
+ gtk_window_iconify (GTK_WINDOW (window));
+ else
+ gtk_window_deiconify (GTK_WINDOW (window));
+
+ gtk_widget_show (widget);
+ if (have_desktop)
+ terminal_util_x11_set_net_wm_desktop (widget_window, desktop);
+
+ /* Mapping the window is likely to have set the "demands-attention" state.
+ * In particular, Marco will always set the state if a window is mapped,
+ * is not given the focus (because of an old user time), and is covered
+ * by some other window. We have no way of preventing this, so we just
+ * wait for our window to be mapped, and then tell the window manager
+ * to turn off the bit. If it wasn't set, no harm.
+ */
+ priv->clear_demands_attention = TRUE;
+ }
+}
+
+#endif /* GDK_WINDOWING_X11 */
+
+static void
+terminal_window_screen_update (TerminalWindow *window,
+ GdkScreen *screen)
+{
+ TerminalApp *app;
+
+ terminal_window_window_manager_changed_cb (screen, window);
+ g_signal_connect (screen, "window-manager-changed",
+ G_CALLBACK (terminal_window_window_manager_changed_cb), window);
+#ifdef GDK_WINDOWING_X11
+ g_signal_connect (screen, "composited-changed",
+ G_CALLBACK (terminal_window_composited_changed_cb), window);
+#endif
+
+ if (GPOINTER_TO_INT (g_object_get_data (G_OBJECT (screen), "GT::HasSettingsConnection")))
+ return;
+
+ g_object_set_data_full (G_OBJECT (screen), "GT::HasSettingsConnection",
+ GINT_TO_POINTER (TRUE),
+ (GDestroyNotify) app_setting_notify_destroy_cb);
+
+ app = terminal_app_get ();
+ app_setting_notify_cb (app, NULL, screen);
+ g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MNEMONICS,
+ G_CALLBACK (app_setting_notify_cb), screen);
+ g_signal_connect (app, "notify::" TERMINAL_APP_ENABLE_MENU_BAR_ACCEL,
+ G_CALLBACK (app_setting_notify_cb), screen);
+}
+
+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 (previous_screen)
+ {
+ g_signal_handlers_disconnect_by_func (previous_screen,
+ G_CALLBACK (terminal_window_window_manager_changed_cb),
+ window);
+#ifdef GDK_WINDOWING_X11
+ g_signal_handlers_disconnect_by_func (previous_screen,
+ G_CALLBACK (terminal_window_composited_changed_cb),
+ window);
+#endif
+ }
+
+ if (!screen)
+ return;
+
+ terminal_window_screen_update (window, screen);
+}
+
+static void
+terminal_window_profile_list_changed_cb (TerminalApp *app,
+ TerminalWindow *window)
+{
+ terminal_window_update_set_profile_menu (window);
+ terminal_window_update_new_terminal_menus (window);
+}
+
+static void
+terminal_window_encoding_list_changed_cb (TerminalApp *app,
+ TerminalWindow *window)
+{
+ terminal_window_update_encoding_menu (window);
+}
+
+static void
+terminal_window_init (TerminalWindow *window)
+{
+ const GtkActionEntry menu_entries[] =
+ {
+ /* Toplevel */
+ { "File", NULL, N_("_File") },
+ { "FileNewWindowProfiles", STOCK_NEW_WINDOW, N_("Open _Terminal")},
+ { "FileNewTabProfiles", STOCK_NEW_TAB, N_("Open Ta_b") },
+ { "Edit", NULL, N_("_Edit") },
+ { "View", NULL, N_("_View") },
+ { "Search", NULL, N_("_Search") },
+ { "Terminal", NULL, N_("_Terminal") },
+ { "Tabs", NULL, N_("Ta_bs") },
+ { "Help", NULL, N_("_Help") },
+ { "Popup", NULL, NULL },
+ { "NotebookPopup", NULL, "" },
+
+ /* File menu */
+ { "FileNewWindow", STOCK_NEW_WINDOW, N_("Open _Terminal"), "<shift><control>N",
+ NULL,
+ G_CALLBACK (file_new_window_callback) },
+ { "FileNewTab", STOCK_NEW_TAB, N_("Open Ta_b"), "<shift><control>T",
+ NULL,
+ G_CALLBACK (file_new_tab_callback) },
+ { "FileNewProfile", GTK_STOCK_OPEN, N_("New _Profile…"), "",
+ NULL,
+ G_CALLBACK (file_new_profile_callback) },
+ { "FileSaveContents", GTK_STOCK_SAVE, N_("_Save Contents"), "",
+ NULL,
+ G_CALLBACK (file_save_contents_callback) },
+ { "FileCloseTab", GTK_STOCK_CLOSE, N_("C_lose Tab"), "<shift><control>W",
+ NULL,
+ G_CALLBACK (file_close_tab_callback) },
+ { "FileCloseWindow", GTK_STOCK_CLOSE, N_("_Close Window"), "<shift><control>Q",
+ NULL,
+ G_CALLBACK (file_close_window_callback) },
+
+ /* Edit menu */
+ { "EditCopy", GTK_STOCK_COPY, NULL, "<shift><control>C",
+ NULL,
+ G_CALLBACK (edit_copy_callback) },
+ { "EditPaste", GTK_STOCK_PASTE, NULL, "<shift><control>V",
+ NULL,
+ G_CALLBACK (edit_paste_callback) },
+ { "EditPasteURIPaths", GTK_STOCK_PASTE, N_("Paste _Filenames"), "",
+ NULL,
+ G_CALLBACK (edit_paste_callback) },
+ { "EditSelectAll", GTK_STOCK_SELECT_ALL, NULL, NULL,
+ NULL,
+ G_CALLBACK (edit_select_all_callback) },
+ { "EditProfiles", NULL, N_("P_rofiles…"), NULL,
+ NULL,
+ G_CALLBACK (edit_profiles_callback) },
+ { "EditKeybindings", NULL, N_("_Keyboard Shortcuts…"), NULL,
+ NULL,
+ G_CALLBACK (edit_keybindings_callback) },
+ { "EditCurrentProfile", NULL, N_("Pr_ofile Preferences"), NULL,
+ NULL,
+ G_CALLBACK (edit_current_profile_callback) },
+
+ /* View menu */
+ { "ViewZoomIn", GTK_STOCK_ZOOM_IN, NULL, "<control>plus",
+ NULL,
+ G_CALLBACK (view_zoom_in_callback) },
+ { "ViewZoomOut", GTK_STOCK_ZOOM_OUT, NULL, "<control>minus",
+ NULL,
+ G_CALLBACK (view_zoom_out_callback) },
+ { "ViewZoom100", GTK_STOCK_ZOOM_100, NULL, "<control>0",
+ NULL,
+ G_CALLBACK (view_zoom_normal_callback) },
+
+ /* Search menu */
+ { "SearchFind", GTK_STOCK_FIND, N_("_Find..."), "<shift><control>F",
+ NULL,
+ G_CALLBACK (search_find_callback) },
+ { "SearchFindNext", NULL, N_("Find Ne_xt"), "<shift><control>H",
+ NULL,
+ G_CALLBACK (search_find_next_callback) },
+ { "SearchFindPrevious", NULL, N_("Find Pre_vious"), "<shift><control>G",
+ NULL,
+ G_CALLBACK (search_find_prev_callback) },
+ { "SearchClearHighlight", NULL, N_("_Clear Highlight"), "<shift><control>J",
+ NULL,
+ G_CALLBACK (search_clear_highlight_callback) },
+#if 0
+ { "SearchGoToLine", GTK_STOCK_JUMP_TO, N_("Go to _Line..."), "<shift><control>I",
+ NULL,
+ G_CALLBACK (search_goto_line_callback) },
+ { "SearchIncrementalSearch", GTK_STOCK_FIND, N_("_Incremental Search..."), "<shift><control>K",
+ NULL,
+ G_CALLBACK (search_incremental_search_callback) },
+#endif
+
+ /* Terminal menu */
+ { "TerminalProfiles", NULL, N_("Change _Profile") },
+ { "TerminalSetTitle", NULL, N_("_Set Title…"), NULL,
+ NULL,
+ G_CALLBACK (terminal_set_title_callback) },
+ { "TerminalSetEncoding", NULL, N_("Set _Character Encoding") },
+ { "TerminalReset", NULL, N_("_Reset"), NULL,
+ NULL,
+ G_CALLBACK (terminal_reset_callback) },
+ { "TerminalResetClear", NULL, N_("Reset and C_lear"), NULL,
+ NULL,
+ G_CALLBACK (terminal_reset_clear_callback) },
+
+ /* Terminal/Encodings menu */
+ { "TerminalAddEncoding", NULL, N_("_Add or Remove…"), NULL,
+ NULL,
+ G_CALLBACK (terminal_add_encoding_callback) },
+
+ /* Tabs menu */
+ { "TabsPrevious", NULL, N_("_Previous Tab"), "<control>Page_Up",
+ NULL,
+ G_CALLBACK (tabs_next_or_previous_tab_cb) },
+ { "TabsNext", NULL, N_("_Next Tab"), "<control>Page_Down",
+ NULL,
+ G_CALLBACK (tabs_next_or_previous_tab_cb) },
+ { "TabsMoveLeft", NULL, N_("Move Tab _Left"), "<shift><control>Page_Up",
+ NULL,
+ G_CALLBACK (tabs_move_left_callback) },
+ { "TabsMoveRight", NULL, N_("Move Tab _Right"), "<shift><control>Page_Down",
+ NULL,
+ G_CALLBACK (tabs_move_right_callback) },
+ { "TabsDetach", NULL, N_("_Detach tab"), NULL,
+ NULL,
+ G_CALLBACK (tabs_detach_tab_callback) },
+
+ /* Help menu */
+ { "HelpContents", GTK_STOCK_HELP, N_("_Contents"), "F1",
+ NULL,
+ G_CALLBACK (help_contents_callback) },
+ { "HelpAbout", GTK_STOCK_ABOUT, N_("_About"), NULL,
+ NULL,
+ G_CALLBACK (help_about_callback) },
+
+ /* Popup menu */
+ { "PopupSendEmail", NULL, N_("_Send Mail To…"), NULL,
+ NULL,
+ G_CALLBACK (popup_open_url_callback) },
+ { "PopupCopyEmailAddress", NULL, N_("_Copy E-mail Address"), NULL,
+ NULL,
+ G_CALLBACK (popup_copy_url_callback) },
+ { "PopupCall", NULL, N_("C_all To…"), NULL,
+ NULL,
+ G_CALLBACK (popup_open_url_callback) },
+ { "PopupCopyCallAddress", NULL, N_("_Copy Call Address"), NULL,
+ NULL,
+ G_CALLBACK (popup_copy_url_callback) },
+ { "PopupOpenLink", NULL, N_("_Open Link"), NULL,
+ NULL,
+ G_CALLBACK (popup_open_url_callback) },
+ { "PopupCopyLinkAddress", NULL, N_("_Copy Link Address"), NULL,
+ NULL,
+ G_CALLBACK (popup_copy_url_callback) },
+ { "PopupTerminalProfiles", NULL, N_("P_rofiles") },
+ { "PopupCopy", GTK_STOCK_COPY, NULL, "",
+ NULL,
+ G_CALLBACK (edit_copy_callback) },
+ { "PopupPaste", GTK_STOCK_PASTE, NULL, "",
+ NULL,
+ G_CALLBACK (edit_paste_callback) },
+ { "PopupPasteURIPaths", GTK_STOCK_PASTE, N_("Paste _Filenames"), "",
+ NULL,
+ G_CALLBACK (edit_paste_callback) },
+ { "PopupNewTerminal", NULL, N_("Open _Terminal"), NULL,
+ NULL,
+ G_CALLBACK (file_new_window_callback) },
+ { "PopupNewTab", NULL, N_("Open Ta_b"), NULL,
+ NULL,
+ G_CALLBACK (file_new_tab_callback) },
+ { "PopupCloseWindow", NULL, N_("C_lose Window"), NULL,
+ NULL,
+ G_CALLBACK (file_close_window_callback) },
+ { "PopupCloseTab", NULL, N_("C_lose Tab"), NULL,
+ NULL,
+ G_CALLBACK (file_close_tab_callback) },
+ { "PopupLeaveFullscreen", NULL, N_("L_eave Full Screen"), NULL,
+ NULL,
+ G_CALLBACK (popup_leave_fullscreen_callback) },
+ { "PopupInputMethods", NULL, N_("_Input Methods") }
+ };
+
+ const GtkToggleActionEntry toggle_menu_entries[] =
+ {
+ /* View Menu */
+ { "ViewMenubar", NULL, N_("Show _Menubar"), NULL,
+ NULL,
+ G_CALLBACK (view_menubar_toggled_callback),
+ FALSE },
+ { "ViewFullscreen", NULL, N_("_Full Screen"), NULL,
+ NULL,
+ G_CALLBACK (view_fullscreen_toggled_callback),
+ FALSE }
+ };
+ TerminalWindowPrivate *priv;
+ TerminalApp *app;
+ GtkActionGroup *action_group;
+ GtkAction *action;
+ GtkUIManager *manager;
+ GtkWidget *main_vbox;
+ GError *error;
+ GtkWindowGroup *window_group;
+ GtkAccelGroup *accel_group;
+
+ priv = window->priv = G_TYPE_INSTANCE_GET_PRIVATE (window, TERMINAL_TYPE_WINDOW, TerminalWindowPrivate);
+
+ g_signal_connect (G_OBJECT (window), "delete_event",
+ G_CALLBACK(terminal_window_delete_event),
+ NULL);
+#ifdef MATE_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
+
+ gtk_window_set_title (GTK_WINDOW (window), _("Terminal"));
+
+ priv->active_screen = NULL;
+ priv->menubar_visible = FALSE;
+
+ main_vbox = gtk_vbox_new (FALSE, 0);
+ gtk_container_add (GTK_CONTAINER (window), main_vbox);
+ gtk_widget_show (main_vbox);
+
+ priv->notebook = gtk_notebook_new ();
+ gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook), TRUE);
+ gtk_notebook_set_show_border (GTK_NOTEBOOK (priv->notebook), FALSE);
+ gtk_notebook_set_show_tabs (GTK_NOTEBOOK (priv->notebook), FALSE);
+ gtk_notebook_set_group (GTK_NOTEBOOK (priv->notebook), GUINT_TO_POINTER (1));
+ gtk_notebook_set_scrollable (GTK_NOTEBOOK (priv->notebook),
+ TRUE);
+ g_signal_connect (priv->notebook, "button-press-event",
+ G_CALLBACK (notebook_button_press_cb), window);
+ g_signal_connect (priv->notebook, "popup-menu",
+ G_CALLBACK (notebook_popup_menu_cb), window);
+ g_signal_connect_after (priv->notebook, "switch-page",
+ G_CALLBACK (notebook_page_selected_callback), window);
+ g_signal_connect_after (priv->notebook, "page-added",
+ G_CALLBACK (notebook_page_added_callback), window);
+ g_signal_connect_after (priv->notebook, "page-removed",
+ G_CALLBACK (notebook_page_removed_callback), window);
+ g_signal_connect_data (priv->notebook, "page-reordered",
+ G_CALLBACK (terminal_window_update_tabs_menu_sensitivity),
+ window, NULL, G_CONNECT_SWAPPED | G_CONNECT_AFTER);
+
+ gtk_box_pack_end (GTK_BOX (main_vbox), priv->notebook, TRUE, TRUE, 0);
+ gtk_widget_show (priv->notebook);
+
+ priv->old_char_width = -1;
+ priv->old_char_height = -1;
+ priv->old_geometry_widget = NULL;
+
+ /* Create the UI manager */
+ manager = priv->ui_manager = gtk_ui_manager_new ();
+
+ accel_group = gtk_ui_manager_get_accel_group (manager);
+ gtk_window_add_accel_group (GTK_WINDOW (window), accel_group);
+ /* Workaround for bug #453193, bug #138609 and bug #559728 */
+ g_signal_connect_after (accel_group, "accel-activate",
+ G_CALLBACK (terminal_window_accel_activate_cb), window);
+
+ /* Create the actions */
+ /* Note that this action group name is used in terminal-accels.c; do not change it */
+ priv->action_group = action_group = gtk_action_group_new ("Main");
+ gtk_action_group_set_translation_domain (action_group, NULL);
+ gtk_action_group_add_actions (action_group, menu_entries,
+ G_N_ELEMENTS (menu_entries), window);
+ gtk_action_group_add_toggle_actions (action_group,
+ toggle_menu_entries,
+ G_N_ELEMENTS (toggle_menu_entries),
+ window);
+ gtk_ui_manager_insert_action_group (manager, action_group, 0);
+ g_object_unref (action_group);
+
+ action = gtk_action_group_get_action (action_group, "Edit");
+ g_signal_connect (action, "activate",
+ G_CALLBACK (edit_menu_activate_callback), window);
+
+ /* Set this action invisible so the Edit menu doesn't flash the first
+ * time it's shown and there's no text/uri-list on the clipboard.
+ */
+ action = gtk_action_group_get_action (priv->action_group, "EditPasteURIPaths");
+ gtk_action_set_visible (action, FALSE);
+
+ /* Idem for this action, since the window is not fullscreen. */
+ action = gtk_action_group_get_action (priv->action_group, "PopupLeaveFullscreen");
+ gtk_action_set_visible (action, FALSE);
+
+#ifndef ENABLE_SAVE
+ action = gtk_action_group_get_action (priv->action_group, "FileSaveContents");
+ gtk_action_set_visible (action, FALSE);
+#endif
+
+ /* Load the UI */
+ error = NULL;
+ priv->ui_id = gtk_ui_manager_add_ui_from_file (manager,
+ TERM_PKGDATADIR G_DIR_SEPARATOR_S "terminal.xml",
+ &error);
+ if (error)
+ {
+ g_printerr ("Failed to load UI: %s\n", error->message);
+ g_error_free (error);
+ }
+
+ priv->menubar = gtk_ui_manager_get_widget (manager, "/menubar");
+ gtk_box_pack_start (GTK_BOX (main_vbox),
+ priv->menubar,
+ FALSE, FALSE, 0);
+
+ /* Add tabs menu */
+ priv->tabs_menu = terminal_tabs_menu_new (window);
+
+ app = terminal_app_get ();
+ terminal_window_profile_list_changed_cb (app, window);
+ g_signal_connect (app, "profile-list-changed",
+ G_CALLBACK (terminal_window_profile_list_changed_cb), window);
+
+ terminal_window_encoding_list_changed_cb (app, window);
+ g_signal_connect (app, "encoding-list-changed",
+ G_CALLBACK (terminal_window_encoding_list_changed_cb), window);
+
+ terminal_window_set_menubar_visible (window, TRUE);
+ priv->use_default_menubar_visibility = TRUE;
+
+ terminal_window_update_size_to_menu (window);
+
+ /* 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);
+
+ terminal_util_set_unique_role (GTK_WINDOW (window), "mate-terminal-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->map_event = terminal_window_map_event;
+ widget_class->window_state_event = terminal_window_state_event;
+ widget_class->screen_changed = terminal_window_screen_changed;
+
+ g_type_class_add_private (object_class, sizeof (TerminalWindowPrivate));
+
+ gtk_rc_parse_string ("style \"mate-terminal-tab-close-button-style\"\n"
+ "{\n"
+ "GtkWidget::focus-padding = 0\n"
+ "GtkWidget::focus-line-width = 0\n"
+ "xthickness = 0\n"
+ "ythickness = 0\n"
+ "}\n"
+ "widget \"*.mate-terminal-tab-close-button\" style \"mate-terminal-tab-close-button-style\"");
+
+ gtk_notebook_set_window_creation_hook (handle_tab_droped_on_desktop, NULL, NULL);
+}
+
+static void
+terminal_window_dispose (GObject *object)
+{
+ TerminalWindow *window = TERMINAL_WINDOW (object);
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalApp *app;
+ GdkScreen *screen;
+
+ remove_popup_info (window);
+
+ priv->disposed = TRUE;
+
+ if (priv->tabs_menu)
+ {
+ g_object_unref (priv->tabs_menu);
+ priv->tabs_menu = NULL;
+ }
+
+ if (priv->profiles_action_group != NULL)
+ disconnect_profiles_from_actions_in_group (priv->profiles_action_group);
+ if (priv->new_terminal_action_group != NULL)
+ disconnect_profiles_from_actions_in_group (priv->new_terminal_action_group);
+
+ app = terminal_app_get ();
+ g_signal_handlers_disconnect_by_func (app,
+ G_CALLBACK (terminal_window_profile_list_changed_cb),
+ window);
+ g_signal_handlers_disconnect_by_func (app,
+ G_CALLBACK (terminal_window_encoding_list_changed_cb),
+ window);
+
+ screen = gtk_widget_get_screen (GTK_WIDGET (object));
+ if (screen)
+ {
+ g_signal_handlers_disconnect_by_func (screen,
+ G_CALLBACK (terminal_window_window_manager_changed_cb),
+ window);
+#ifdef GDK_WINDOWING_X11
+ g_signal_handlers_disconnect_by_func (screen,
+ G_CALLBACK (terminal_window_composited_changed_cb),
+ window);
+#endif
+ }
+
+ 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;
+
+ g_object_unref (priv->ui_manager);
+
+ if (priv->confirm_close_dialog)
+ gtk_dialog_response (GTK_DIALOG (priv->confirm_close_dialog),
+ GTK_RESPONSE_DELETE_EVENT);
+
+ if (priv->search_find_dialog)
+ gtk_dialog_response (GTK_DIALOG (priv->search_find_dialog),
+ GTK_RESPONSE_DELETE_EVENT);
+
+ 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);
+ GtkAllocation widget_allocation;
+
+ gtk_widget_get_allocation (widget, &widget_allocation);
+
+#if 0
+ TerminalWindowPrivate *priv = window->priv;
+
+ 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_set_size (window, priv->active_screen, FALSE);
+ }
+#endif
+
+ terminal_window_update_geometry (window);
+
+ _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);
+
+ GTK_WIDGET_CLASS (terminal_window_parent_class)->show (widget);
+}
+
+TerminalWindow*
+terminal_window_new (void)
+{
+ return g_object_new (TERMINAL_TYPE_WINDOW, NULL);
+}
+
+/**
+ * terminal_window_set_is_restored:
+ * @window:
+ *
+ * Marks the window as restored from session.
+ */
+void
+terminal_window_set_is_restored (TerminalWindow *window)
+{
+ g_return_if_fail (TERMINAL_IS_WINDOW (window));
+ g_return_if_fail (!gtk_widget_get_mapped (GTK_WIDGET (window)));
+
+ window->priv->clear_demands_attention = TRUE;
+}
+
+static void
+profile_set_callback (TerminalScreen *screen,
+ TerminalProfile *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;
+
+ if (screen != priv->active_screen)
+ return;
+
+ gtk_window_set_title (GTK_WINDOW (window), terminal_screen_get_title (screen));
+}
+
+static void
+sync_screen_icon_title (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;
+
+ if (!terminal_screen_get_icon_title_set (screen))
+ return;
+
+ gdk_window_set_icon_name (gtk_widget_get_window (GTK_WIDGET (window)), terminal_screen_get_icon_title (screen));
+
+ priv->icon_title_set = TRUE;
+}
+
+static void
+sync_screen_icon_title_set (TerminalScreen *screen,
+ GParamSpec *psepc,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (!gtk_widget_get_realized (GTK_WIDGET (window)))
+ return;
+
+ /* No need to restore the title if we never set an icon title */
+ if (!priv->icon_title_set)
+ return;
+
+ if (screen != priv->active_screen)
+ return;
+
+ if (terminal_screen_get_icon_title_set (screen))
+ return;
+
+ /* Need to reset the icon name */
+ /* FIXME: Once gtk+ bug 535557 is fixed, use that to unset the icon title. */
+
+ g_object_set_qdata (G_OBJECT (gtk_widget_get_window (GTK_WIDGET (window))),
+ g_quark_from_static_string ("gdk-icon-name-set"),
+ GUINT_TO_POINTER (FALSE));
+ priv->icon_title_set = FALSE;
+
+ /* Re-setting the right title will be done by the notify::title handler which comes after this one */
+}
+
+/* Notebook callbacks */
+
+static void
+close_button_clicked_cb (GtkWidget *tab_label,
+ GtkWidget *screen_container)
+{
+ GtkWidget *toplevel;
+ TerminalWindow *window;
+ TerminalWindowPrivate *priv;
+ TerminalScreen *screen;
+
+ toplevel = gtk_widget_get_toplevel (screen_container);
+ if (!gtk_widget_is_toplevel (toplevel))
+ return;
+
+ if (!TERMINAL_IS_WINDOW (toplevel))
+ return;
+
+ window = TERMINAL_WINDOW (toplevel);
+ priv = window->priv;
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (screen_container));
+ if (confirm_close_window_or_tab (window, screen))
+ return;
+
+ terminal_window_remove_screen (window, screen);
+}
+
+void
+terminal_window_add_screen (TerminalWindow *window,
+ TerminalScreen *screen,
+ int position)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *old_window;
+ GtkWidget *screen_container, *tab_label;
+
+ 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);
+
+ screen_container = terminal_screen_container_new (screen);
+ gtk_widget_show (screen_container);
+
+ update_tab_visibility (window, +1);
+
+ tab_label = terminal_tab_label_new (screen);
+ g_signal_connect (tab_label, "close-button-clicked",
+ G_CALLBACK (close_button_clicked_cb), screen_container);
+
+ gtk_notebook_insert_page (GTK_NOTEBOOK (priv->notebook),
+ screen_container,
+ tab_label,
+ position);
+ gtk_container_child_set (GTK_CONTAINER (priv->notebook),
+ screen_container,
+ "tab-expand", TRUE,
+ "tab-fill", TRUE,
+ NULL);
+ gtk_notebook_set_tab_reorderable (GTK_NOTEBOOK (priv->notebook),
+ screen_container,
+ TRUE);
+ gtk_notebook_set_tab_detachable (GTK_NOTEBOOK (priv->notebook),
+ screen_container,
+ TRUE);
+}
+
+void
+terminal_window_remove_screen (TerminalWindow *window,
+ TerminalScreen *screen)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreenContainer *screen_container;
+
+ g_return_if_fail (gtk_widget_get_toplevel (GTK_WIDGET (screen)) == GTK_WIDGET (window));
+
+ update_tab_visibility (window, -1);
+
+ screen_container = terminal_screen_container_get_from_screen (screen);
+ gtk_container_remove (GTK_CONTAINER (priv->notebook),
+ GTK_WIDGET (screen_container));
+}
+
+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);
+ g_object_unref (screen);
+}
+
+GList*
+terminal_window_list_screen_containers (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ /* We are trusting that GtkNotebook will return pages in order */
+ return gtk_container_get_children (GTK_CONTAINER (priv->notebook));
+}
+
+void
+terminal_window_set_menubar_visible (TerminalWindow *window,
+ gboolean setting)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkAction *action;
+
+ /* 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;
+
+ if (setting == priv->menubar_visible)
+ return;
+
+ priv->menubar_visible = setting;
+
+ action = gtk_action_group_get_action (priv->action_group, "ViewMenubar");
+ gtk_toggle_action_set_active (GTK_TOGGLE_ACTION (action), 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_set_size (window, priv->active_screen, TRUE);
+ }
+}
+
+gboolean
+terminal_window_get_menubar_visible (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ return priv->menubar_visible;
+}
+
+GtkWidget *
+terminal_window_get_notebook (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ g_return_val_if_fail (TERMINAL_IS_WINDOW (window), NULL);
+
+ return GTK_WIDGET (priv->notebook);
+}
+
+void
+terminal_window_set_size (TerminalWindow *window,
+ TerminalScreen *screen,
+ gboolean even_if_mapped)
+{
+ terminal_window_set_size_force_grid (window, screen, even_if_mapped, -1, -1);
+}
+
+void
+terminal_window_set_size_force_grid (TerminalWindow *window,
+ TerminalScreen *screen,
+ gboolean even_if_mapped,
+ int force_grid_width,
+ int force_grid_height)
+{
+ /* Owen's hack from mate-terminal */
+ GtkWidget *widget;
+ GtkWidget *app;
+ GtkRequisition toplevel_request;
+ GtkRequisition widget_request;
+ int w, h;
+ int char_width;
+ int char_height;
+ int grid_width;
+ int grid_height;
+ GtkBorder *inner_border = NULL;
+
+ /* be sure our geometry is up-to-date */
+ terminal_window_update_geometry (window);
+
+ widget = GTK_WIDGET (screen);
+
+ app = gtk_widget_get_toplevel (widget);
+ g_assert (app != NULL);
+
+ gtk_widget_size_request (app, &toplevel_request);
+ gtk_widget_size_request (widget, &widget_request);
+
+ terminal_screen_get_cell_size (screen, &char_width, &char_height);
+ terminal_screen_get_size (screen, &grid_width, &grid_height);
+
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[window %p] set size: toplevel %dx%d widget %dx%d grid %dx%d char-cell %dx%d\n",
+ window,
+ toplevel_request.width, toplevel_request.height,
+ widget_request.width, widget_request.height,
+ grid_width, grid_height, char_width, char_height);
+
+ w = toplevel_request.width - widget_request.width;
+ h = toplevel_request.height - widget_request.height;
+
+ if (force_grid_width >= 0)
+ grid_width = force_grid_width;
+ if (force_grid_height >= 0)
+ grid_height = force_grid_height;
+
+ gtk_widget_style_get (widget, "inner-border", &inner_border, NULL);
+ w += (inner_border ? (inner_border->left + inner_border->right) : 0) + char_width * grid_width;
+ h += (inner_border ? (inner_border->top + inner_border->bottom) : 0) + char_height * grid_height;
+ gtk_border_free (inner_border);
+
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[window %p] set size: grid %dx%d force %dx%d setting %dx%d pixels\n",
+ window,
+ grid_width, grid_height, force_grid_width, force_grid_height, w, h);
+
+ if (even_if_mapped && gtk_widget_get_mapped (app)) {
+ gtk_window_resize (GTK_WINDOW (app), w, h);
+ }
+ else {
+ gtk_window_set_default_size (GTK_WINDOW (app), w, h);
+ }
+}
+
+void
+terminal_window_switch_screen (TerminalWindow *window,
+ TerminalScreen *screen)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreenContainer *screen_container;
+ int page_num;
+
+ screen_container = terminal_screen_container_get_from_screen (screen);
+ g_assert (TERMINAL_IS_SCREEN_CONTAINER (screen_container));
+ page_num = gtk_notebook_page_num (GTK_NOTEBOOK (priv->notebook),
+ GTK_WIDGET (screen_container));
+ gtk_notebook_set_current_page (GTK_NOTEBOOK (priv->notebook), page_num);
+}
+
+TerminalScreen*
+terminal_window_get_active (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ return priv->active_screen;
+}
+
+static gboolean
+notebook_button_press_cb (GtkWidget *widget,
+ GdkEventButton *event,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebook *notebook = GTK_NOTEBOOK (widget);
+ GtkWidget *menu;
+ GtkAction *action;
+ int tab_clicked;
+
+ if (event->type != GDK_BUTTON_PRESS ||
+ event->button != 3 ||
+ (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);
+
+ action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
+ gtk_action_activate (action);
+
+ menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ NULL, NULL,
+ event->button, event->time);
+
+ return TRUE;
+}
+
+static gboolean
+notebook_popup_menu_cb (GtkWidget *widget,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
+ GtkWidget *focus_widget, *tab, *tab_label, *menu;
+ GtkAction *action;
+ int page_num;
+
+ focus_widget = gtk_window_get_focus (GTK_WINDOW (window));
+ /* Only respond if the notebook is the actual focus */
+ if (focus_widget != priv->notebook)
+ return FALSE;
+
+ page_num = gtk_notebook_get_current_page (notebook);
+ tab = gtk_notebook_get_nth_page (notebook, page_num);
+ tab_label = gtk_notebook_get_tab_label (notebook, tab);
+
+ action = gtk_action_group_get_action (priv->action_group, "NotebookPopup");
+ gtk_action_activate (action);
+
+ menu = gtk_ui_manager_get_widget (priv->ui_manager, "/NotebookPopup");
+ gtk_menu_popup (GTK_MENU (menu), NULL, NULL,
+ position_menu_under_widget, tab_label,
+ 0, gtk_get_current_event_time ());
+ gtk_menu_shell_select_first (GTK_MENU_SHELL (menu), FALSE);
+
+ return TRUE;
+}
+
+static void
+notebook_page_selected_callback (GtkWidget *notebook,
+#if GTK_CHECK_VERSION (2, 90, 6)
+ GtkWidget *page_widget,
+#else
+ gpointer useless_crap,
+#endif
+ guint page_num,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *widget;
+ TerminalScreen *screen;
+ TerminalProfile *profile;
+ int old_grid_width, old_grid_height;
+#if !GTK_CHECK_VERSION (2, 90, 6)
+ GtkWidget *page_widget;
+#endif
+
+ _terminal_debug_print (TERMINAL_DEBUG_MDI,
+ "[window %p] MDI: page-selected %d\n",
+ window, page_num);
+
+ if (priv->disposed)
+ return;
+
+#if !GTK_CHECK_VERSION (2, 90, 6)
+ page_widget = gtk_notebook_get_nth_page (GTK_NOTEBOOK (notebook), page_num);
+#endif
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (page_widget));
+ widget = GTK_WIDGET (screen);
+ g_assert (screen != NULL);
+
+ _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 (priv->active_screen == screen)
+ return;
+
+ if (priv->active_screen != NULL) {
+ terminal_screen_get_size (priv->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);
+ }
+
+ /* 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.
+ */
+ if (priv->active_screen)
+ gtk_widget_hide (GTK_WIDGET (priv->active_screen)); /* FIXME */
+
+ /* Make sure that the widget is no longer hidden due to the workaround */
+ gtk_widget_show (widget);
+
+ profile = terminal_screen_get_profile (screen);
+
+ priv->active_screen = screen;
+
+ /* Override menubar setting if it wasn't restored from session */
+ if (priv->use_default_menubar_visibility)
+ {
+ gboolean setting =
+ terminal_profile_get_property_boolean (terminal_screen_get_profile (screen), TERMINAL_PROFILE_DEFAULT_SHOW_MENUBAR);
+
+ terminal_window_set_menubar_visible (window, setting);
+ }
+
+ sync_screen_icon_title_set (screen, NULL, window);
+ sync_screen_icon_title (screen, NULL, window);
+ 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_set_size (window, screen, TRUE);
+
+ terminal_window_update_tabs_menu_sensitivity (window);
+ terminal_window_update_encoding_menu_active_encoding (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);
+}
+
+static void
+notebook_page_added_callback (GtkWidget *notebook,
+ GtkWidget *container,
+ guint page_num,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreen *screen;
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
+
+ _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_callback),
+ 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::icon-title",
+ G_CALLBACK (sync_screen_icon_title), window);
+ g_signal_connect (screen, "notify::icon-title-set",
+ G_CALLBACK (sync_screen_icon_title_set), window);
+ g_signal_connect (screen, "selection-changed",
+ G_CALLBACK (terminal_window_update_copy_sensitivity), window);
+
+ g_signal_connect (screen, "show-popup-menu",
+ G_CALLBACK (screen_show_popup_menu_callback), 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);
+
+ update_tab_visibility (window, 0);
+ terminal_window_update_tabs_menu_sensitivity (window);
+ terminal_window_update_search_sensitivity (screen, 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, &current_width, &current_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;
+ }
+}
+
+static void
+notebook_page_removed_callback (GtkWidget *notebook,
+ GtkWidget *container,
+ guint page_num,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreen *screen;
+ int pages;
+
+ if (priv->disposed)
+ return;
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (container));
+
+ _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_callback),
+ 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 (sync_screen_icon_title),
+ window);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
+ G_CALLBACK (sync_screen_icon_title_set),
+ window);
+
+ g_signal_handlers_disconnect_by_func (G_OBJECT (screen),
+ G_CALLBACK (terminal_window_update_copy_sensitivity),
+ window);
+
+ g_signal_handlers_disconnect_by_func (screen,
+ G_CALLBACK (screen_show_popup_menu_callback),
+ 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);
+
+ terminal_window_update_tabs_menu_sensitivity (window);
+ update_tab_visibility (window, 0);
+ terminal_window_update_search_sensitivity (screen, window);
+
+ pages = gtk_notebook_get_n_pages (GTK_NOTEBOOK (notebook));
+ if (pages == 1)
+ {
+ terminal_window_set_size (window, priv->active_screen, TRUE);
+ }
+ else if (pages == 0)
+ {
+ gtk_widget_destroy (GTK_WIDGET (window));
+ }
+}
+
+void
+terminal_window_update_geometry (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *widget;
+ GdkGeometry hints;
+ int char_width;
+ int char_height;
+
+ 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);
+
+ if (char_width != priv->old_char_width ||
+ char_height != priv->old_char_height ||
+ widget != (GtkWidget*) priv->old_geometry_widget)
+ {
+ GtkBorder *inner_border = NULL;
+
+ /* FIXME Since we're using xthickness/ythickness to compute
+ * padding we need to change the hints when the theme changes.
+ */
+
+ gtk_widget_style_get (widget, "inner-border", &inner_border, NULL);
+
+ hints.base_width = (inner_border ? (inner_border->left + inner_border->right) : 0);
+ hints.base_height = (inner_border ? (inner_border->top + inner_border->bottom) : 0);
+
+ gtk_border_free (inner_border);
+
+#define MIN_WIDTH_CHARS 4
+#define MIN_HEIGHT_CHARS 1
+
+ hints.width_inc = char_width;
+ hints.height_inc = char_height;
+
+ /* min size is min size of just the geometry widget, 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),
+ widget,
+ &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_char_width = hints.width_inc;
+ priv->old_char_height = hints.height_inc;
+ priv->old_geometry_widget = widget;
+ }
+ else
+ {
+ _terminal_debug_print (TERMINAL_DEBUG_GEOMETRY,
+ "[window %p] hints: increment unchanged, not setting\n",
+ window);
+ }
+}
+
+static void
+file_new_window_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalApp *app;
+ TerminalWindow *new_window;
+ TerminalProfile *profile;
+ char *new_working_directory;
+
+ app = terminal_app_get ();
+
+ profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
+ if (!profile)
+ profile = terminal_screen_get_profile (priv->active_screen);
+ if (!profile)
+ profile = terminal_app_get_profile_for_new_term (app);
+ if (!profile)
+ return;
+
+ if (_terminal_profile_get_forgotten (profile))
+ return;
+
+ new_window = terminal_app_new_window (app, gtk_widget_get_screen (GTK_WIDGET (window)));
+
+ new_working_directory = terminal_screen_get_current_dir_with_fallback (priv->active_screen);
+ terminal_app_new_terminal (app, new_window, profile,
+ NULL, NULL,
+ new_working_directory,
+ terminal_screen_get_initial_environment (priv->active_screen),
+ 1.0);
+ g_free (new_working_directory);
+
+ gtk_window_present (GTK_WINDOW (new_window));
+}
+
+static void
+file_new_tab_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalApp *app;
+ TerminalProfile *profile;
+ char *new_working_directory;
+
+ app = terminal_app_get ();
+ profile = g_object_get_data (G_OBJECT (action), PROFILE_DATA_KEY);
+ if (!profile)
+ profile = terminal_screen_get_profile (priv->active_screen);
+ if (!profile)
+ profile = terminal_app_get_profile_for_new_term (app);
+ if (!profile)
+ return;
+
+ if (_terminal_profile_get_forgotten (profile))
+ return;
+
+ new_working_directory = terminal_screen_get_current_dir_with_fallback (priv->active_screen);
+ terminal_app_new_terminal (app, window, profile,
+ NULL, NULL,
+ new_working_directory,
+ terminal_screen_get_initial_environment (priv->active_screen),
+ 1.0);
+ g_free (new_working_directory);
+}
+
+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;
+ MateConfClient *client;
+ 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);
+ }
+
+ client = mateconf_client_get_default ();
+ do_confirm = mateconf_client_get_bool (client, CONF_GLOBAL_PREFIX "/confirm_window_close", NULL);
+ g_object_unref (client);
+ if (!do_confirm)
+ return FALSE;
+
+ if (screen)
+ {
+ do_confirm = terminal_screen_has_foreground_process (screen);
+ 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))
+ {
+ 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);
+
+ gtk_dialog_set_alternative_button_order (GTK_DIALOG (dialog),
+ GTK_RESPONSE_ACCEPT,
+ GTK_RESPONSE_CANCEL,
+ -1);
+
+ 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;
+}
+
+static void
+file_close_window_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ if (confirm_close_window_or_tab (window, NULL))
+ return;
+
+ gtk_widget_destroy (GTK_WIDGET (window));
+}
+
+#ifdef ENABLE_SAVE
+static void
+save_contents_dialog_on_response (GtkDialog *dialog, gint response_id, gpointer terminal)
+{
+ GtkWindow *parent;
+ gchar *filename_uri = NULL;
+ GFile *file;
+ GOutputStream *stream;
+ 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 (terminal, stream,
+ VTE_TERMINAL_WRITE_DEFAULT,
+ NULL, &error);
+ g_object_unref (stream);
+ }
+
+ if (error)
+ {
+ terminal_util_show_error_dialog (parent, NULL, error,
+ "%s", _("Could not save contents"));
+ g_error_free (error);
+ }
+
+ g_object_unref(file);
+ g_free(filename_uri);
+}
+#endif /* ENABLE_SAVE */
+
+static void
+file_save_contents_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+#ifdef ENABLE_SAVE
+ GtkWidget *dialog = NULL;
+ TerminalWindowPrivate *priv = window->priv;
+ VteTerminal *terminal;
+
+ if (!priv->active_screen)
+ 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,
+ GTK_STOCK_CANCEL, GTK_RESPONSE_CANCEL,
+ GTK_STOCK_SAVE, GTK_RESPONSE_ACCEPT,
+ NULL);
+
+ gtk_file_chooser_set_do_overwrite_confirmation (GTK_FILE_CHOOSER (dialog), TRUE);
+ /* XXX where should we save to? */
+ gtk_file_chooser_set_current_folder (GTK_FILE_CHOOSER (dialog), g_get_user_special_dir (G_USER_DIRECTORY_DESKTOP));
+
+ 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 */
+}
+
+static void
+file_close_tab_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalScreen *active_screen = priv->active_screen;
+
+ if (!active_screen)
+ return;
+
+ if (confirm_close_window_or_tab (window, active_screen))
+ return;
+
+ terminal_window_remove_screen (window, active_screen);
+}
+
+static void
+edit_copy_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (!priv->active_screen)
+ return;
+
+ vte_terminal_copy_clipboard (VTE_TERMINAL (priv->active_screen));
+}
+
+typedef struct {
+ TerminalScreen *screen;
+ gboolean uris_as_paths;
+} PasteData;
+
+static void
+clipboard_uris_received_cb (GtkClipboard *clipboard,
+ /* const */ char **uris,
+ PasteData *data)
+{
+ char *text;
+ gsize len;
+
+ if (!uris) {
+ g_object_unref (data->screen);
+ g_slice_free (PasteData, data);
+ return;
+ }
+
+ /* This potentially modifies the strings in |uris| but that's ok */
+ if (data->uris_as_paths)
+ terminal_util_transform_uris_to_quoted_fuse_paths (uris);
+
+ text = terminal_util_concat_uris (uris, &len);
+ vte_terminal_feed_child (VTE_TERMINAL (data->screen), text, len);
+ g_free (text);
+
+ g_object_unref (data->screen);
+ g_slice_free (PasteData, data);
+}
+
+static void
+clipboard_targets_received_cb (GtkClipboard *clipboard,
+ GdkAtom *targets,
+ int n_targets,
+ PasteData *data)
+{
+ if (!targets) {
+ g_object_unref (data->screen);
+ g_slice_free (PasteData, data);
+ return;
+ }
+
+ if (gtk_targets_include_uri (targets, n_targets)) {
+ gtk_clipboard_request_uris (clipboard,
+ (GtkClipboardURIReceivedFunc) clipboard_uris_received_cb,
+ data);
+ return;
+ } else /* if (gtk_targets_include_text (targets, n_targets)) */ {
+ vte_terminal_paste_clipboard (VTE_TERMINAL (data->screen));
+ }
+
+ g_object_unref (data->screen);
+ g_slice_free (PasteData, data);
+}
+
+static void
+edit_paste_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkClipboard *clipboard;
+ PasteData *data;
+ const char *name;
+
+ if (!priv->active_screen)
+ return;
+
+ clipboard = gtk_widget_get_clipboard (GTK_WIDGET (window), GDK_SELECTION_CLIPBOARD);
+ name = gtk_action_get_name (action);
+
+ data = g_slice_new (PasteData);
+ data->screen = g_object_ref (priv->active_screen);
+ data->uris_as_paths = (name == I_("EditPasteURIPaths") || name == I_("PopupPasteURIPaths"));
+
+ gtk_clipboard_request_targets (clipboard,
+ (GtkClipboardTargetsReceivedFunc) clipboard_targets_received_cb,
+ data);
+}
+
+static void
+edit_select_all_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (!priv->active_screen)
+ return;
+
+ vte_terminal_select_all (VTE_TERMINAL (priv->active_screen));
+}
+
+static void
+edit_keybindings_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ terminal_app_edit_keybindings (terminal_app_get (),
+ GTK_WINDOW (window));
+}
+
+static void
+edit_current_profile_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ terminal_app_edit_profile (terminal_app_get (),
+ terminal_screen_get_profile (priv->active_screen),
+ GTK_WINDOW (window),
+ NULL);
+}
+
+static void
+file_new_profile_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ terminal_app_new_profile (terminal_app_get (),
+ terminal_screen_get_profile (priv->active_screen),
+ GTK_WINDOW (window));
+}
+
+static void
+edit_profiles_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ terminal_app_manage_profiles (terminal_app_get (),
+ GTK_WINDOW (window));
+}
+
+static void
+view_menubar_toggled_callback (GtkToggleAction *action,
+ TerminalWindow *window)
+{
+ terminal_window_set_menubar_visible (window, gtk_toggle_action_get_active (action));
+}
+
+static void
+view_fullscreen_toggled_callback (GtkToggleAction *action,
+ TerminalWindow *window)
+{
+ g_return_if_fail (gtk_widget_get_realized (GTK_WIDGET (window)));
+
+ if (gtk_toggle_action_get_active (action))
+ gtk_window_fullscreen (GTK_WINDOW (window));
+ else
+ gtk_window_unfullscreen (GTK_WINDOW (window));
+}
+
+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 current,
+ double *found)
+{
+ 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)
+ {
+ *found = zoom_factors[i];
+ return TRUE;
+ }
+ }
+
+ return FALSE;
+}
+
+static gboolean
+find_smaller_zoom_factor (double current,
+ double *found)
+{
+ 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)
+ {
+ *found = zoom_factors[i];
+ return TRUE;
+ }
+
+ --i;
+ }
+
+ return FALSE;
+}
+
+static void
+view_zoom_in_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ double current;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ current = terminal_screen_get_font_scale (priv->active_screen);
+ if (!find_larger_zoom_factor (current, &current))
+ return;
+
+ terminal_screen_set_font_scale (priv->active_screen, current);
+ terminal_window_update_zoom_sensitivity (window);
+}
+
+static void
+view_zoom_out_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ double current;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ current = terminal_screen_get_font_scale (priv->active_screen);
+ if (!find_smaller_zoom_factor (current, &current))
+ return;
+
+ terminal_screen_set_font_scale (priv->active_screen, current);
+ terminal_window_update_zoom_sensitivity (window);
+}
+
+static void
+view_zoom_normal_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ terminal_screen_set_font_scale (priv->active_screen, PANGO_SCALE_MEDIUM);
+ terminal_window_update_zoom_sensitivity (window);
+}
+
+
+static void
+search_find_response_callback (GtkWidget *dialog,
+ int response,
+ gpointer user_data)
+{
+ TerminalWindow *window = TERMINAL_WINDOW (user_data);
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalSearchFlags flags;
+ GRegex *regex;
+
+ if (response != GTK_RESPONSE_ACCEPT)
+ return;
+
+ if (G_UNLIKELY (!priv->active_screen))
+ return;
+
+ regex = terminal_search_dialog_get_regex (dialog);
+ g_return_if_fail (regex != NULL);
+
+ flags = terminal_search_dialog_get_search_flags (dialog);
+
+ vte_terminal_search_set_gregex (VTE_TERMINAL (priv->active_screen), regex);
+ vte_terminal_search_set_wrap_around (VTE_TERMINAL (priv->active_screen),
+ (flags & TERMINAL_SEARCH_FLAG_WRAP_AROUND));
+
+ if (flags & TERMINAL_SEARCH_FLAG_BACKWARDS)
+ vte_terminal_search_find_previous (VTE_TERMINAL (priv->active_screen));
+ else
+ vte_terminal_search_find_next (VTE_TERMINAL (priv->active_screen));
+
+ terminal_window_update_search_sensitivity (priv->active_screen, window);
+}
+
+static gboolean
+search_dialog_delete_event_cb (GtkWidget *widget,
+ GdkEventAny *event,
+ gpointer user_data)
+{
+ /* prevent destruction */
+ return TRUE;
+}
+
+static void
+search_find_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (!priv->search_find_dialog) {
+ GtkWidget *dialog;
+
+ dialog = priv->search_find_dialog = terminal_search_dialog_new (GTK_WINDOW (window));
+
+ g_signal_connect (dialog, "destroy",
+ G_CALLBACK (gtk_widget_destroyed), &priv->search_find_dialog);
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (search_find_response_callback), window);
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (search_dialog_delete_event_cb), NULL);
+ }
+
+ terminal_search_dialog_present (priv->search_find_dialog);
+}
+
+static void
+search_find_next_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ if (G_UNLIKELY (!window->priv->active_screen))
+ return;
+
+ vte_terminal_search_find_next (VTE_TERMINAL (window->priv->active_screen));
+}
+
+static void
+search_find_prev_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ if (G_UNLIKELY (!window->priv->active_screen))
+ return;
+
+ vte_terminal_search_find_previous (VTE_TERMINAL (window->priv->active_screen));
+}
+
+static void
+search_clear_highlight_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ if (G_UNLIKELY (!window->priv->active_screen))
+ return;
+
+ vte_terminal_search_set_gregex (VTE_TERMINAL (window->priv->active_screen), NULL);
+}
+
+static void
+terminal_set_title_dialog_response_cb (GtkWidget *dialog,
+ int response,
+ TerminalScreen *screen)
+{
+ if (response == GTK_RESPONSE_OK)
+ {
+ GtkEntry *entry;
+ const char *text;
+
+ entry = GTK_ENTRY (g_object_get_data (G_OBJECT (dialog), "title-entry"));
+ text = gtk_entry_get_text (entry);
+ terminal_screen_set_user_title (screen, text);
+ }
+
+ gtk_widget_destroy (dialog);
+}
+
+static void
+terminal_set_title_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkWidget *dialog, *message_area, *hbox, *label, *entry;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ /* FIXME: hook the screen up so this dialogue closes if the terminal screen closes */
+
+ dialog = gtk_message_dialog_new (GTK_WINDOW (window),
+ GTK_DIALOG_MODAL | GTK_DIALOG_DESTROY_WITH_PARENT,
+ GTK_MESSAGE_OTHER,
+ GTK_BUTTONS_OK_CANCEL,
+ "%s", "");
+
+ gtk_window_set_title (GTK_WINDOW (dialog), _("Set Title"));
+ gtk_window_set_resizable (GTK_WINDOW (dialog), FALSE);
+ gtk_window_set_role (GTK_WINDOW (dialog), "mate-terminal-change-title");
+ gtk_dialog_set_default_response (GTK_DIALOG (dialog), GTK_RESPONSE_OK);
+ /* Alternative button order was set automatically by GtkMessageDialog */
+
+ g_signal_connect (dialog, "response",
+ G_CALLBACK (terminal_set_title_dialog_response_cb), priv->active_screen);
+ g_signal_connect (dialog, "delete-event",
+ G_CALLBACK (terminal_util_dialog_response_on_delete), NULL);
+
+#if GTK_CHECK_VERSION (2, 90, 6)
+ message_area = gtk_message_dialog_get_message_area (GTK_MESSAGE_DIALOG (dialog));
+ gtk_container_foreach (GTK_CONTAINER (message_area), (GtkCallback) gtk_widget_hide, NULL);
+#else
+ label = GTK_MESSAGE_DIALOG (dialog)->label;
+ gtk_widget_hide (label);
+ message_area = gtk_widget_get_parent (label);
+#endif
+
+ hbox = gtk_hbox_new (FALSE, 12);
+ gtk_box_pack_start (GTK_BOX (message_area), hbox, FALSE, FALSE, 0);
+
+ label = gtk_label_new_with_mnemonic (_("_Title:"));
+ gtk_misc_set_alignment (GTK_MISC (label), 0.0, 0.5);
+ gtk_box_pack_start (GTK_BOX (hbox), label, FALSE, FALSE, 0);
+
+ entry = gtk_entry_new ();
+ gtk_entry_set_width_chars (GTK_ENTRY (entry), 32);
+ gtk_entry_set_activates_default (GTK_ENTRY (entry), TRUE);
+ gtk_label_set_mnemonic_widget (GTK_LABEL (label), entry);
+ gtk_box_pack_start (GTK_BOX (hbox), entry, TRUE, TRUE, 0);
+ gtk_widget_show_all (hbox);
+
+ gtk_widget_grab_focus (entry);
+ gtk_entry_set_text (GTK_ENTRY (entry), terminal_screen_get_raw_title (priv->active_screen));
+ gtk_editable_select_region (GTK_EDITABLE (entry), 0, -1);
+ g_object_set_data (G_OBJECT (dialog), "title-entry", entry);
+
+ gtk_window_present (GTK_WINDOW (dialog));
+}
+
+static void
+terminal_add_encoding_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ terminal_app_edit_encodings (terminal_app_get (),
+ GTK_WINDOW (window));
+}
+
+static void
+terminal_reset_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, FALSE);
+}
+
+static void
+terminal_reset_clear_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ if (priv->active_screen == NULL)
+ return;
+
+ vte_terminal_reset (VTE_TERMINAL (priv->active_screen), TRUE, TRUE);
+}
+
+static void
+tabs_next_or_previous_tab_cb (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebookClass *klass;
+ GtkBindingSet *binding_set;
+ const char *name;
+ guint keyval = 0;
+
+ name = gtk_action_get_name (action);
+ if (strcmp (name, "TabsNext") == 0) {
+ keyval = GDK_Page_Down;
+ } else if (strcmp (name, "TabsPrevious") == 0) {
+ keyval = GDK_Page_Up;
+ }
+
+ klass = GTK_NOTEBOOK_GET_CLASS (GTK_NOTEBOOK (priv->notebook));
+ binding_set = gtk_binding_set_by_class (klass);
+ gtk_binding_set_activate (gtk_binding_set_by_class (klass),
+ keyval,
+ GDK_CONTROL_MASK,
+ GTK_OBJECT (priv->notebook));
+}
+
+static void
+tabs_move_left_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
+ gint page_num,last_page;
+ GtkWidget *page;
+
+ page_num = gtk_notebook_get_current_page (notebook);
+ last_page = gtk_notebook_get_n_pages (notebook) - 1;
+ page = gtk_notebook_get_nth_page (notebook, page_num);
+
+ gtk_notebook_reorder_child (notebook, page, page_num == 0 ? last_page : page_num - 1);
+}
+
+static void
+tabs_move_right_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GtkNotebook *notebook = GTK_NOTEBOOK (priv->notebook);
+ gint page_num,last_page;
+ GtkWidget *page;
+
+ page_num = gtk_notebook_get_current_page (notebook);
+ last_page = gtk_notebook_get_n_pages (notebook) - 1;
+ page = gtk_notebook_get_nth_page (notebook, page_num);
+
+ gtk_notebook_reorder_child (notebook, page, page_num == last_page ? 0 : page_num + 1);
+}
+
+static void
+tabs_detach_tab_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ TerminalApp *app;
+ TerminalWindow *new_window;
+ TerminalScreen *screen;
+ char *geometry;
+ int width, height;
+
+ app = terminal_app_get ();
+
+ screen = priv->active_screen;
+
+ /* FIXME: this seems wrong if tabs are shown in the window */
+ terminal_screen_get_size (screen, &width, &height);
+ geometry = g_strdup_printf ("%dx%d", width, height);
+
+ new_window = terminal_app_new_window (app, gtk_widget_get_screen (GTK_WIDGET (window)));
+
+ terminal_window_move_screen (window, new_window, screen, -1);
+
+ gtk_window_parse_geometry (GTK_WINDOW (new_window), geometry);
+ g_free (geometry);
+
+ gtk_window_present_with_time (GTK_WINDOW (new_window), gtk_get_current_event_time ());
+}
+
+static void
+help_contents_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ terminal_util_show_help (NULL, GTK_WINDOW (window));
+}
+
+#define ABOUT_GROUP "About"
+#define EMAILIFY(string) (g_strdelimit ((string), "%", '@'))
+
+static void
+help_about_callback (GtkAction *action,
+ TerminalWindow *window)
+{
+ 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–2010 Christian Persch";
+ char *licence_text;
+ GKeyFile *key_file;
+ 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;
+
+ key_file = g_key_file_new ();
+ if (!g_key_file_load_from_file (key_file, TERM_PKGDATADIR G_DIR_SEPARATOR_S "terminal.about", 0, &error))
+ {
+ g_warning ("Couldn't load about data: %s\n", error->message);
+ g_error_free (error);
+ g_key_file_free (key_file);
+ return;
+ }
+
+ 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);
+
+ 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 ();
+
+ gtk_show_about_dialog (GTK_WINDOW (window),
+ "program-name", _("MATE Terminal"),
+ "copyright", copyright,
+ "comments", _("A terminal emulator for the MATE desktop"),
+ "version", VERSION,
+ "authors", array_strv,
+ "artists", artists,
+ "documenters", documenters,
+ "license", licence_text,
+ "wrap-license", TRUE,
+ "translator-credits", _("translator-credits"),
+ "logo-icon-name", MATE_TERMINAL_ICON_NAME,
+ NULL);
+
+ g_strfreev (array_strv);
+ g_strfreev (artists);
+ g_strfreev (documenters);
+ g_free (licence_text);
+}
+
+GtkUIManager *
+terminal_window_get_ui_manager (TerminalWindow *window)
+{
+ TerminalWindowPrivate *priv = window->priv;
+
+ return priv->ui_manager;
+}
+
+void
+terminal_window_save_state (TerminalWindow *window,
+ GKeyFile *key_file,
+ const char *group)
+{
+ TerminalWindowPrivate *priv = window->priv;
+ GList *tabs, *lt;
+ TerminalScreen *active_screen;
+ GdkWindowState state;
+ GPtrArray *tab_names_array;
+ char **tab_names;
+ gsize len;
+
+ //XXXif (priv->menub)//XXX
+ g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_MENUBAR_VISIBLE,
+ priv->menubar_visible);
+
+ g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_ROLE,
+ gtk_window_get_role (GTK_WINDOW (window)));
+
+ state = gdk_window_get_state (gtk_widget_get_window (GTK_WIDGET (window)));
+ if (state & GDK_WINDOW_STATE_MAXIMIZED)
+ g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_MAXIMIZED, TRUE);
+ if (state & GDK_WINDOW_STATE_FULLSCREEN)
+ g_key_file_set_boolean (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_FULLSCREEN, TRUE);
+
+ active_screen = terminal_window_get_active (window);
+ tabs = terminal_window_list_screen_containers (window);
+
+ tab_names_array = g_ptr_array_sized_new (g_list_length (tabs) + 1);
+
+ for (lt = tabs; lt != NULL; lt = lt->next)
+ {
+ TerminalScreen *screen;
+ char *tab_group;
+
+ screen = terminal_screen_container_get_screen (TERMINAL_SCREEN_CONTAINER (lt->data));
+
+ tab_group = g_strdup_printf ("Terminal%p", screen);
+ g_ptr_array_add (tab_names_array, tab_group);
+
+ terminal_screen_save_config (screen, key_file, tab_group);
+
+ if (screen == active_screen)
+ {
+ int w, h, x, y;
+ char *geometry;
+
+ g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_ACTIVE_TAB, tab_group);
+
+ /* FIXME saving the geometry is not great :-/ */
+ terminal_screen_get_size (screen, &w, &h);
+ gtk_window_get_position (GTK_WINDOW (window), &x, &y);
+ geometry = g_strdup_printf ("%dx%d+%d+%d", w, h, x, y);
+ g_key_file_set_string (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_GEOMETRY, geometry);
+ g_free (geometry);
+ }
+ }
+
+ g_list_free (tabs);
+
+ len = tab_names_array->len;
+ g_ptr_array_add (tab_names_array, NULL);
+ tab_names = (char **) g_ptr_array_free (tab_names_array, FALSE);
+ g_key_file_set_string_list (key_file, group, TERMINAL_CONFIG_WINDOW_PROP_TABS, (const char * const *) tab_names, len);
+ g_strfreev (tab_names);
+}
diff --git a/src/terminal-window.h b/src/terminal-window.h
new file mode 100644
index 0000000..b1a84b0
--- /dev/null
+++ b/src/terminal-window.h
@@ -0,0 +1,106 @@
+/*
+ * Copyright © 2001 Havoc Pennington
+ *
+ * This library is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU Library General Public
+ * License as published by the Free Software Foundation; either
+ * version 3 of the License, or (at your option) any later version.
+ *
+ * This library 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
+ * Library General Public License for more details.
+ *
+ * You should have received a copy of the GNU Library General Public
+ * License along with this library; if not, write to the
+ * Free Software Foundation, Inc., 59 Temple Place - Suite 330,
+ * Boston, MA 02111-1307, USA.
+ */
+
+#ifndef TERMINAL_WINDOW_H
+#define TERMINAL_WINDOW_H
+
+#include <gtk/gtk.h>
+
+#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
+{
+ GtkWindow parent_instance;
+
+ TerminalWindowPrivate *priv;
+};
+
+struct _TerminalWindowClass
+{
+ GtkWindowClass parent_class;
+
+};
+
+GType terminal_window_get_type (void) G_GNUC_CONST;
+
+TerminalWindow* terminal_window_new (void);
+
+void terminal_window_set_is_restored (TerminalWindow *window);
+
+GtkUIManager *terminal_window_get_ui_manager (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);
+gboolean terminal_window_get_menubar_visible (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);
+
+void terminal_window_update_geometry (TerminalWindow *window);
+void terminal_window_set_size (TerminalWindow *window,
+ TerminalScreen *screen,
+ gboolean even_if_mapped);
+void terminal_window_set_size_force_grid (TerminalWindow *window,
+ TerminalScreen *screen,
+ gboolean even_if_mapped,
+ int force_grid_width,
+ int force_grid_height);
+
+GtkWidget* terminal_window_get_notebook (TerminalWindow *window);
+
+gboolean terminal_window_uses_argb_visual (TerminalWindow *window);
+
+void terminal_window_save_state (TerminalWindow *window,
+ GKeyFile *key_file,
+ const char *group);
+
+G_END_DECLS
+
+#endif /* TERMINAL_WINDOW_H */
diff --git a/src/terminal.about b/src/terminal.about
new file mode 100644
index 0000000..1923fd9
--- /dev/null
+++ b/src/terminal.about
@@ -0,0 +1,5 @@
+[About]
+Authors=Behdad Esfahbod <behdad%mate.org>;Guilherme de S. Pastore <gpastore%mate.org>;Havoc Pennington <hp%redhat.com>;Christian Persch <chpe%mate.org>;Mariano Suárez-Alvarez <mariano%mate.org>;
+Contributors=
+;Artists=
+Documenters=MATE Documentation Team <mate-doc-list%mate.org>;
diff --git a/src/terminal.c b/src/terminal.c
new file mode 100644
index 0000000..03a619e
--- /dev/null
+++ b/src/terminal.c
@@ -0,0 +1,619 @@
+/*
+ * Copyright © 2001, 2002 Havoc Pennington
+ * Copyright © 2002 Red Hat, Inc.
+ * Copyright © 2002 Sun Microsystems
+ * Copyright © 2003 Mariano Suarez-Alvarez
+ * Copyright © 2008, 2010 Christian Persch
+ *
+ * Mate-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.
+ *
+ * Mate-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.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program. If not, see <http://www.gnu.org/licenses/>.
+ */
+
+#include <config.h>
+
+#include <errno.h>
+#include <locale.h>
+#include <stdlib.h>
+#include <time.h>
+#include <unistd.h>
+
+#include <glib.h>
+#include <glib/gstdio.h>
+#include <gio/gio.h>
+
+#include <gdk/gdkx.h>
+
+#ifdef WITH_SMCLIENT
+#include "eggsmclient.h"
+#endif
+
+#include "terminal-accels.h"
+#include "terminal-app.h"
+#include "terminal-debug.h"
+#include "terminal-intl.h"
+#include "terminal-options.h"
+#include "terminal-util.h"
+
+#define TERMINAL_FACTORY_SERVICE_NAME_PREFIX "org.mate.Terminal.Display"
+#define TERMINAL_FACTORY_SERVICE_PATH "/org/mate/Terminal/Factory"
+#define TERMINAL_FACTORY_INTERFACE_NAME "org.mate.Terminal.Factory"
+
+static char *
+ay_to_string (GVariant *variant,
+ GError **error)
+{
+ gsize len;
+ const char *data;
+
+ data = g_variant_get_fixed_array (variant, &len, sizeof (char));
+ if (len == 0)
+ return NULL;
+
+ /* Make sure there are no embedded NULs */
+ if (memchr (data, '\0', len) != NULL) {
+ g_set_error_literal (error, G_DBUS_ERROR, G_DBUS_ERROR_INVALID_ARGS,
+ "String is shorter than claimed");
+ return NULL;
+ }
+
+ return g_strndup (data, len);
+}
+
+static char **
+ay_to_strv (GVariant *variant,
+ int *argc)
+{
+ GPtrArray *argv;
+ const char *data, *nullbyte;
+ gsize data_len;
+ gssize len;
+
+ data = g_variant_get_fixed_array (variant, &data_len, sizeof (char));
+ if (data_len == 0 || data_len > G_MAXSSIZE) {
+ *argc = 0;
+ return NULL;
+ }
+
+ argv = g_ptr_array_new ();
+
+ len = data_len;
+ do {
+ gssize string_len;
+
+ nullbyte = memchr (data, '\0', len);
+
+ string_len = nullbyte ? (gssize) (nullbyte - data) : len;
+ g_ptr_array_add (argv, g_strndup (data, string_len));
+
+ len -= string_len + 1;
+ data += string_len + 1;
+ } while (len > 0);
+
+ if (argc)
+ *argc = argv->len;
+
+ /* NULL terminate */
+ g_ptr_array_add (argv, NULL);
+ return (char **) g_ptr_array_free (argv, FALSE);
+}
+
+static GVariant *
+string_to_ay (const char *string)
+{
+ gsize len;
+ char *data;
+
+ len = strlen (string);
+ data = g_strndup (string, len);
+
+ return g_variant_new_from_data (G_VARIANT_TYPE ("ay"), data, len, TRUE, g_free, data);
+}
+
+typedef struct {
+ char *factory_name;
+ TerminalOptions *options;
+ int exit_code;
+ char **argv;
+ int argc;
+} OwnData;
+
+static void
+method_call_cb (GDBusConnection *connection,
+ const char *sender,
+ const char *object_path,
+ const char *interface_name,
+ const char *method_name,
+ GVariant *parameters,
+ GDBusMethodInvocation *invocation,
+ gpointer user_data)
+{
+ if (g_strcmp0 (method_name, "HandleArguments") == 0) {
+ TerminalOptions *options = NULL;
+ GVariant *v_wd, *v_display, *v_sid, *v_envv, *v_argv;
+ char *working_directory = NULL, *display_name = NULL, *startup_id = NULL;
+ char **envv = NULL, **argv = NULL;
+ int argc;
+ GError *error = NULL;
+
+ g_variant_get (parameters, "(@ay@ay@ay@ay@ay)",
+ &v_wd, &v_display, &v_sid, &v_envv, &v_argv);
+
+ working_directory = ay_to_string (v_wd, &error);
+ if (error)
+ goto out;
+ display_name = ay_to_string (v_display, &error);
+ if (error)
+ goto out;
+ startup_id = ay_to_string (v_sid, &error);
+ if (error)
+ goto out;
+ envv = ay_to_strv (v_envv, NULL);
+ argv = ay_to_strv (v_argv, &argc);
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Factory invoked with working-dir='%s' display='%s' startup-id='%s'\n",
+ working_directory ? working_directory : "(null)",
+ display_name ? display_name : "(null)",
+ startup_id ? startup_id : "(null)");
+
+ options = terminal_options_parse (working_directory,
+ display_name,
+ startup_id,
+ envv,
+ TRUE,
+ TRUE,
+ &argc, &argv,
+ &error,
+ NULL);
+
+ if (options != NULL) {
+ terminal_app_handle_options (terminal_app_get (), options, FALSE /* no resume */, &error);
+ terminal_options_free (options);
+ }
+
+ out:
+ g_variant_unref (v_wd);
+ g_free (working_directory);
+ g_variant_unref (v_display);
+ g_free (display_name);
+ g_variant_unref (v_sid);
+ g_free (startup_id);
+ g_variant_unref (v_envv);
+ g_strfreev (envv);
+ g_variant_unref (v_argv);
+ g_strfreev (argv);
+
+ if (error == NULL) {
+ g_dbus_method_invocation_return_value (invocation, g_variant_new ("()"));
+ } else {
+ g_dbus_method_invocation_return_gerror (invocation, error);
+ g_error_free (error);
+ }
+ }
+}
+
+static void
+bus_acquired_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ static const char dbus_introspection_xml[] =
+ "<node name='/org/mate/Terminal'>"
+ "<interface name='org.mate.Terminal.Factory'>"
+ "<method name='HandleArguments'>"
+ "<arg type='ay' name='working_directory' direction='in' />"
+ "<arg type='ay' name='display_name' direction='in' />"
+ "<arg type='ay' name='startup_id' direction='in' />"
+ "<arg type='ay' name='environment' direction='in' />"
+ "<arg type='ay' name='arguments' direction='in' />"
+ "</method>"
+ "</interface>"
+ "</node>";
+
+ static const GDBusInterfaceVTable interface_vtable = {
+ method_call_cb,
+ NULL,
+ NULL,
+ };
+
+ OwnData *data = (OwnData *) user_data;
+ GDBusNodeInfo *introspection_data;
+ guint registration_id;
+ GError *error = NULL;
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Bus %s acquired\n", name);
+
+ introspection_data = g_dbus_node_info_new_for_xml (dbus_introspection_xml, NULL);
+ g_assert (introspection_data != NULL);
+
+ registration_id = g_dbus_connection_register_object (connection,
+ TERMINAL_FACTORY_SERVICE_PATH,
+ introspection_data->interfaces[0],
+ &interface_vtable,
+ NULL, NULL,
+ &error);
+ g_dbus_node_info_unref (introspection_data);
+
+ if (registration_id == 0) {
+ g_printerr ("Failed to register object: %s\n", error->message);
+ g_error_free (error);
+ data->exit_code = EXIT_FAILURE;
+ gtk_main_quit ();
+ }
+}
+
+static void
+name_acquired_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ OwnData *data = (OwnData *) user_data;
+ GError *error = NULL;
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Acquired the name %s on the session bus\n", name);
+
+ if (data->options == NULL) {
+ /* Name re-acquired!? */
+ g_assert_not_reached ();
+ }
+
+
+ if (!terminal_app_handle_options (terminal_app_get (), data->options, TRUE /* do resume */, &error)) {
+ g_printerr ("Failed to handle options: %s\n", error->message);
+ g_error_free (error);
+ data->exit_code = EXIT_FAILURE;
+ gtk_main_quit ();
+ }
+
+ terminal_options_free (data->options);
+ data->options = NULL;
+}
+
+static void
+name_lost_cb (GDBusConnection *connection,
+ const char *name,
+ gpointer user_data)
+{
+ OwnData *data = (OwnData *) user_data;
+ GError *error = NULL;
+ char **envv;
+ int envc, i;
+ GVariantBuilder builder;
+ GVariant *value;
+ GString *string;
+ char *s;
+ gsize len;
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Lost the name %s on the session bus\n", name);
+
+ /* Couldn't get the connection? No way to continue! */
+ if (connection == NULL) {
+ data->exit_code = EXIT_FAILURE;
+ gtk_main_quit ();
+ return;
+ }
+
+ if (data->options == NULL) {
+ /* Already handled */
+ data->exit_code = EXIT_SUCCESS;
+ gtk_main_quit ();
+ return;
+ }
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Forwarding arguments to existing instance\n");
+
+ g_variant_builder_init (&builder, G_VARIANT_TYPE ("(ayayayayay)"));
+
+ g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->default_working_dir));
+ g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->display_name));
+ g_variant_builder_add (&builder, "@ay", string_to_ay (data->options->startup_id));
+
+ string = g_string_new (NULL);
+ envv = g_listenv ();
+ envc = g_strv_length (envv);
+ for (i = 0; i < envc; ++i)
+ {
+ const char *value;
+
+ value = g_getenv (envv[i]);
+ if (value == NULL)
+ continue;
+
+ if (i > 0)
+ g_string_append_c (string, '\0');
+
+ g_string_append_printf (string, "%s=%s", envv[i], value);
+ }
+
+ len = string->len;
+ s = g_string_free (string, FALSE);
+ g_variant_builder_add (&builder, "@ay",
+ g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s));
+
+ string = g_string_new (NULL);
+
+ for (i = 0; i < data->argc; ++i)
+ {
+ if (i > 0)
+ g_string_append_c (string, '\0');
+ g_string_append (string, data->argv[i]);
+ }
+
+ len = string->len;
+ s = g_string_free (string, FALSE);
+ g_variant_builder_add (&builder, "@ay",
+ g_variant_new_from_data (G_VARIANT_TYPE ("ay"), s, len, TRUE, g_free, s));
+
+ value = g_dbus_connection_call_sync (connection,
+ data->factory_name,
+ TERMINAL_FACTORY_SERVICE_PATH,
+ TERMINAL_FACTORY_INTERFACE_NAME,
+ "HandleArguments",
+ g_variant_builder_end (&builder),
+ G_VARIANT_TYPE ("()"),
+ G_DBUS_CALL_FLAGS_NONE,
+ -1,
+ NULL,
+ &error);
+ if (value == NULL) {
+ g_printerr ("Failed to forward arguments: %s\n", error->message);
+ g_error_free (error);
+ data->exit_code = EXIT_FAILURE;
+ gtk_main_quit ();
+ } else {
+ g_variant_unref (value);
+ data->exit_code = EXIT_SUCCESS;
+ }
+
+ terminal_options_free (data->options);
+ data->options = NULL;
+
+ gtk_main_quit ();
+}
+
+/* Settings storage works as follows:
+ * /apps/mate-terminal/global/
+ * /apps/mate-terminal/profiles/Foo/
+ *
+ * It's somewhat tricky to manage the profiles/ dir since we need to track
+ * the list of profiles, but mateconf doesn't have a concept of notifying that
+ * a directory has appeared or disappeared.
+ *
+ * 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 mate-terminal 1.x for why.
+ *
+ * Don't use this code as an example of how to use MateConf - it's hugely
+ * overcomplicated due to the profiles stuff. Most apps should not
+ * have to do scary things of this nature, and should not have
+ * a profiles feature.
+ *
+ */
+
+/* Copied from libcaja/caja-program-choosing.c; Needed in case
+ * we have no DESKTOP_STARTUP_ID (with its accompanying timestamp).
+ */
+static Time
+slowly_and_stupidly_obtain_timestamp (Display *xdisplay)
+{
+ Window xwindow;
+ XEvent event;
+
+ {
+ 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 event.xproperty.time;
+}
+
+static char *
+get_factory_name_for_display (const char *display_name)
+{
+ GString *name;
+ const char *p;
+
+ name = g_string_sized_new (strlen (TERMINAL_FACTORY_SERVICE_NAME_PREFIX) + strlen (display_name) + 1 /* NUL */);
+ g_string_append (name, TERMINAL_FACTORY_SERVICE_NAME_PREFIX);
+
+ for (p = display_name; *p; ++p)
+ {
+ if (g_ascii_isalnum (*p))
+ g_string_append_c (name, *p);
+ else
+ g_string_append_c (name, '_');
+ }
+
+ _terminal_debug_print (TERMINAL_DEBUG_FACTORY,
+ "Factory name is \"%s\"\n", name->str);
+
+ return g_string_free (name, FALSE);
+}
+
+int
+main (int argc, char **argv)
+{
+ int i;
+ char **argv_copy;
+ int argc_copy;
+ const char *startup_id, *display_name, *home_dir;
+ GdkDisplay *display;
+ TerminalOptions *options;
+ GError *error = NULL;
+ char *working_directory;
+ int ret = EXIT_SUCCESS;
+
+ setlocale (LC_ALL, "");
+
+ bindtextdomain (GETTEXT_PACKAGE, TERM_LOCALEDIR);
+ bind_textdomain_codeset (GETTEXT_PACKAGE, "UTF-8");
+ textdomain (GETTEXT_PACKAGE);
+
+ /* MateConf uses MateCORBA2 which need GThread. See bug #565516 */
+ g_thread_init (NULL);
+
+ _terminal_debug_init ();
+
+ /* Make a NULL-terminated copy since we may need it later */
+ argv_copy = g_new (char *, argc + 1);
+ for (i = 0; i < argc; ++i)
+ argv_copy [i] = argv [i];
+ argv_copy [i] = NULL;
+ argc_copy = argc;
+
+ startup_id = g_getenv ("DESKTOP_STARTUP_ID");
+
+ working_directory = g_get_current_dir ();
+
+ /* Now change directory to $HOME so we don't prevent unmounting, e.g. if the
+ * factory is started by caja-open-terminal. See bug #565328.
+ * On failure back to /.
+ */
+ home_dir = g_get_home_dir ();
+ if (home_dir == NULL || chdir (home_dir) < 0)
+ (void) chdir ("/");
+
+ options = terminal_options_parse (working_directory,
+ NULL,
+ startup_id,
+ NULL,
+ FALSE,
+ FALSE,
+ &argc, &argv,
+ &error,
+ gtk_get_option_group (TRUE),
+#ifdef WITH_SMCLIENT
+ egg_sm_client_get_option_group (),
+#endif
+ NULL);
+
+ g_free (working_directory);
+
+ if (options == NULL) {
+ g_printerr (_("Failed to parse arguments: %s\n"), error->message);
+ g_error_free (error);
+ exit (EXIT_FAILURE);
+ }
+
+ g_set_application_name (_("Terminal"));
+
+ /* Unset the these env variables, so they doesn't end up
+ * in the factory's env and thus in the terminals' envs.
+ */
+ g_unsetenv ("DESKTOP_STARTUP_ID");
+ g_unsetenv ("GIO_LAUNCHED_DESKTOP_FILE_PID");
+ g_unsetenv ("GIO_LAUNCHED_DESKTOP_FILE");
+
+ /* Do this here so that gdk_display is initialized */
+ if (options->startup_id == NULL)
+ {
+ /* Create a fake one containing a timestamp that we can use */
+ Time timestamp;
+
+ timestamp = slowly_and_stupidly_obtain_timestamp (GDK_DISPLAY_XDISPLAY (gdk_display_get_default ()));
+
+ options->startup_id = g_strdup_printf ("_TIME%lu", timestamp);
+ }
+
+ display = gdk_display_get_default ();
+ display_name = gdk_display_get_name (display);
+ options->display_name = g_strdup (display_name);
+
+ if (options->use_factory) {
+ OwnData *data;
+ guint owner_id;
+
+ data = g_new (OwnData, 1);
+ data->factory_name = get_factory_name_for_display (display_name);
+ data->options = options;
+ data->exit_code = -1;
+ data->argv = argv_copy;
+ data->argc = argc_copy;
+
+ owner_id = g_bus_own_name (G_BUS_TYPE_SESSION,
+ data->factory_name,
+ G_BUS_NAME_OWNER_FLAGS_NONE,
+ bus_acquired_cb,
+ name_acquired_cb,
+ name_lost_cb,
+ data, NULL);
+
+ gtk_main ();
+
+ ret = data->exit_code;
+ g_bus_unown_name (owner_id);
+
+ g_free (data->factory_name);
+ g_free (data);
+
+ } else {
+
+ terminal_app_handle_options (terminal_app_get (), options, TRUE /* allow resume */, &error);
+ terminal_options_free (options);
+
+ if (error == NULL) {
+ gtk_main ();
+ } else {
+ g_printerr ("Error handling options: %s\n", error->message);
+ g_error_free (error);
+ ret = EXIT_FAILURE;
+ }
+ }
+
+ terminal_app_shutdown ();
+
+ g_free (argv_copy);
+
+ return ret;
+}
diff --git a/src/terminal.xml b/src/terminal.xml
new file mode 100644
index 0000000..3c9cbed
--- /dev/null
+++ b/src/terminal.xml
@@ -0,0 +1,116 @@
+<ui>
+ <menubar>
+ <menu action="File">
+ <menuitem action="FileNewWindow" />
+ <menu action="FileNewWindowProfiles" />
+ <menuitem action="FileNewTab" />
+ <menu action="FileNewTabProfiles" />
+ <separator />
+ <menuitem action="FileNewProfile" />
+ <menuitem action="FileSaveContents" />
+ <separator />
+ <menuitem action="FileCloseTab" />
+ <menuitem action="FileCloseWindow" />
+ </menu>
+ <menu action="Edit">
+ <menuitem action="EditCopy" />
+ <menuitem action="EditPaste" />
+ <menuitem action="EditPasteURIPaths" />
+ <separator />
+ <menuitem action="EditSelectAll" />
+ <separator />
+ <menuitem action="EditProfiles" />
+ <menuitem action="EditKeybindings" />
+ <menuitem action="EditCurrentProfile" />
+ </menu>
+ <menu action="View">
+ <menuitem action="ViewMenubar" />
+ <menuitem action="ViewFullscreen" />
+ <separator />
+ <menuitem action="ViewZoomIn" />
+ <menuitem action="ViewZoomOut" />
+ <menuitem action="ViewZoom100" />
+ </menu>
+ <menu action="Search">
+ <menuitem action="SearchFind"/>
+ <menuitem action="SearchFindNext"/>
+ <menuitem action="SearchFindPrevious"/>
+ <!--
+ <menuitem action="SearchIncrementalSearch"/>
+ -->
+ <!--
+ <separator/>
+ <menuitem name="SearchClearHighlight" action="SearchClearHighlight"/>
+ -->
+ <!--
+ <separator/>
+ <menuitem name="SearchGoToLineMenu" action="SearchGoToLine"/>
+ -->
+ </menu>
+ <menu action="Terminal">
+ <menu action="TerminalProfiles" />
+ <menuitem action="TerminalSetTitle" />
+ <menu action="TerminalSetEncoding" >
+ <placeholder name="EncodingsPH" />
+ <separator />
+ <menuitem action="TerminalAddEncoding" />
+ </menu>
+ <separator />
+ <menuitem action="TerminalReset" />
+ <menuitem action="TerminalResetClear" />
+ <separator />
+ <placeholder name="TerminalSizeToPH" />
+ </menu>
+ <menu action="Tabs">
+ <menuitem action="TabsNext" />
+ <menuitem action="TabsPrevious" />
+ <separator />
+ <menuitem action="TabsMoveLeft" />
+ <menuitem action="TabsMoveRight" />
+ <separator />
+ <menuitem action="TabsDetach" />
+ <separator />
+ </menu>
+ <menu action="Help">
+ <menuitem action="HelpContents" />
+ <menuitem action="HelpAbout" />
+ </menu>
+ </menubar>
+
+ <popup name="Popup" action="Popup">
+ <menuitem action="PopupSendEmail" />
+ <menuitem action="PopupCopyEmailAddress" />
+ <menuitem action="PopupCall" />
+ <menuitem action="PopupCopyCallAddress" />
+ <menuitem action="PopupOpenLink" />
+ <menuitem action="PopupCopyLinkAddress" />
+ <separator />
+ <menuitem action="PopupNewTerminal" />
+ <menuitem action="PopupNewTab" />
+ <separator />
+ <menuitem action="PopupCloseTab" />
+ <menuitem action="PopupCloseWindow" />
+ <separator />
+ <menuitem action="PopupCopy" />
+ <menuitem action="PopupPaste" />
+ <menuitem action="PopupPasteURIPaths" />
+ <separator />
+ <menu action="PopupTerminalProfiles">
+ <placeholder name="ProfilesPH" />
+ <separator />
+ <menuitem action="EditCurrentProfile" />
+ </menu>
+ <menuitem action="ViewMenubar" />
+ <menuitem action="PopupLeaveFullscreen" />
+ <separator />
+ <menuitem action="PopupInputMethods" />
+ </popup>
+ <popup name="NotebookPopup" action="NotebookPopup">
+ <menuitem action="TabsMoveLeft"/>
+ <menuitem action="TabsMoveRight"/>
+ <separator />
+ <menuitem action="TerminalSetTitle" />
+ <separator />
+ <menuitem action="FileCloseTab"/>
+ </popup>
+</ui>