Преглед изворни кода

Merge commit 'upstream/1.0'

Bradley Smith пре 15 година
родитељ
комит
a0156be035
18 измењених фајлова са 1394 додато и 172 уклоњено
  1. 32 0
      ChangeLog
  2. 12 0
      Makefile.am
  3. 70 11
      Makefile.in
  4. 45 0
      aclocal.m4
  5. 138 19
      configure
  6. 10 2
      configure.ac
  7. 82 0
      mssh.schemas
  8. 3 2
      src/Makefile.am
  9. 12 3
      src/Makefile.in
  10. 161 0
      src/mssh-gconf.c
  11. 30 0
      src/mssh-gconf.h
  12. 278 0
      src/mssh-pref.c
  13. 34 0
      src/mssh-pref.h
  14. 128 0
      src/mssh-terminal.c
  15. 52 0
      src/mssh-terminal.h
  16. 295 120
      src/mssh-window.c
  17. 11 14
      src/mssh-window.h
  18. 1 1
      src/mssh.c

+ 32 - 0
ChangeLog

@@ -1,3 +1,35 @@
+2009-09-02  Bradley Smith  <[email protected]>
+
+	Bump version to 1.0.
+
+	Hook up the rest of the preferences dialog.
+
+	Hook up columns spin button.
+
+2009-08-29  Bradley Smith  <[email protected]>
+
+	Add beginnings of columns preference.
+
+	Hook up colour preferences.
+
+2009-08-28  Bradley Smith  <[email protected]>
+
+	Reduce spacing between terminals.
+
+	Add initial gconf stuff, and hook up font preference.
+
+	Catch pastes into GtkEntry.
+
+2009-08-27  Bradley Smith  <[email protected]>
+
+	Remove menu item on session close.
+
+	Fixes to terminal class and add "add session" menuitem.
+
+	Add preferences dialog.
+
+	Split out terminals into seperate clase and make layout more dynamic.
+
 2009-08-25  Bradley Smith  <[email protected]>
 
 	Bump version to 0.2.

+ 12 - 0
Makefile.am

@@ -1 +1,13 @@
 SUBDIRS = src
+
+EXTRA_DIST = mssh.schemas
+
+SCHEMAS_FILE = mssh.schemas
+
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_DATA = $(SCHEMAS_FILE)
+
+if GCONF_SCHEMAS_INSTALL
+install-data-local:
+	GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/$(schema_DATA)
+endif

+ 70 - 11
Makefile.in

@@ -14,6 +14,7 @@
 # PARTICULAR PURPOSE.
 
 @SET_MAKE@
+
 VPATH = @srcdir@
 pkgdatadir = $(datadir)/@PACKAGE@
 pkgincludedir = $(includedir)/@PACKAGE@
@@ -55,6 +56,29 @@ RECURSIVE_TARGETS = all-recursive check-recursive dvi-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'
+am__installdirs = "$(DESTDIR)$(schemadir)"
+DATA = $(schema_DATA)
 RECURSIVE_CLEAN_TARGETS = mostlyclean-recursive clean-recursive	\
   distclean-recursive maintainer-clean-recursive
 AM_RECURSIVE_TARGETS = $(RECURSIVE_TARGETS:-recursive=) \
@@ -116,6 +140,9 @@ ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EXEEXT = @EXEEXT@
+GCONFTOOL = @GCONFTOOL@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -186,6 +213,10 @@ top_build_prefix = @top_build_prefix@
 top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 SUBDIRS = src
+EXTRA_DIST = mssh.schemas
+SCHEMAS_FILE = mssh.schemas
+schemadir = $(GCONF_SCHEMA_FILE_DIR)
+schema_DATA = $(SCHEMAS_FILE)
 all: config.h
 	$(MAKE) $(AM_MAKEFLAGS) all-recursive
 
@@ -241,6 +272,26 @@ $(srcdir)/config.h.in:  $(am__configure_deps)
 
 distclean-hdr:
 	-rm -f config.h stamp-h1
+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
 
 # This directory's subdirectories are mostly independent; you can cd
 # into them and run `make' without going through this Makefile.
@@ -553,9 +604,12 @@ distcleancheck: distclean
 	       exit 1; } >&2
 check-am: all-am
 check: check-recursive
-all-am: Makefile config.h
+all-am: Makefile $(DATA) config.h
 installdirs: installdirs-recursive
 installdirs-am:
+	for dir in "$(DESTDIR)$(schemadir)"; do \
+	  test -z "$$dir" || $(MKDIR_P) "$$dir"; \
+	done
 install: install-recursive
 install-exec: install-exec-recursive
 install-data: install-data-recursive
@@ -581,6 +635,7 @@ distclean-generic:
 maintainer-clean-generic:
 	@echo "This command is intended for maintainers to use"
 	@echo "it deletes files that may require special tools to rebuild."
+@GCONF_SCHEMAS_INSTALL_FALSE@install-data-local:
 clean: clean-recursive
 
 clean-am: clean-generic mostlyclean-am
@@ -602,7 +657,7 @@ info: info-recursive
 
 info-am:
 
-install-data-am:
+install-data-am: install-data-local install-schemaDATA
 
 install-dvi: install-dvi-recursive
 
@@ -648,7 +703,7 @@ ps: ps-recursive
 
 ps-am:
 
-uninstall-am:
+uninstall-am: uninstall-schemaDATA
 
 .MAKE: $(RECURSIVE_CLEAN_TARGETS) $(RECURSIVE_TARGETS) all \
 	ctags-recursive install-am install-strip tags-recursive
@@ -660,14 +715,18 @@ uninstall-am:
 	distclean distclean-generic distclean-hdr distclean-tags \
 	distcleancheck distdir distuninstallcheck 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 installdirs-am maintainer-clean \
-	maintainer-clean-generic mostlyclean mostlyclean-generic pdf \
-	pdf-am ps ps-am tags tags-recursive uninstall uninstall-am
-
+	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 installcheck installcheck-am installdirs \
+	installdirs-am maintainer-clean maintainer-clean-generic \
+	mostlyclean mostlyclean-generic pdf pdf-am ps ps-am tags \
+	tags-recursive uninstall uninstall-am uninstall-schemaDATA
+
+
+@GCONF_SCHEMAS_INSTALL_TRUE@install-data-local:
+@GCONF_SCHEMAS_INSTALL_TRUE@	GCONF_CONFIG_SOURCE=$(GCONF_SCHEMA_CONFIG_SOURCE) $(GCONFTOOL) --makefile-install-rule $(top_builddir)/$(schema_DATA)
 
 # 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.

+ 45 - 0
aclocal.m4

@@ -19,6 +19,51 @@ You have another version of autoconf.  It may work, but is not guaranteed to.
 If you have problems, you may need to regenerate the build system entirely.
 To do so, use the procedure documented by the package, typically `autoreconf'.])])
 
+dnl AM_GCONF_SOURCE_2
+dnl Defines GCONF_SCHEMA_CONFIG_SOURCE which is where you should install schemas
+dnl  (i.e. pass to gconftool-2
+dnl Defines GCONF_SCHEMA_FILE_DIR which is a filesystem directory where
+dnl  you should install foo.schemas files
+dnl
+
+AC_DEFUN([AM_GCONF_SOURCE_2],
+[
+  if test "x$GCONF_SCHEMA_INSTALL_SOURCE" = "x"; then
+    GCONF_SCHEMA_CONFIG_SOURCE=`gconftool-2 --get-default-source`
+  else
+    GCONF_SCHEMA_CONFIG_SOURCE=$GCONF_SCHEMA_INSTALL_SOURCE
+  fi
+
+  AC_ARG_WITH([gconf-source],
+	      AC_HELP_STRING([--with-gconf-source=sourceaddress],
+			     [Config database for installing schema files.]),
+	      [GCONF_SCHEMA_CONFIG_SOURCE="$withval"],)
+
+  AC_SUBST(GCONF_SCHEMA_CONFIG_SOURCE)
+  AC_MSG_RESULT([Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation])
+
+  if test "x$GCONF_SCHEMA_FILE_DIR" = "x"; then
+    GCONF_SCHEMA_FILE_DIR='$(sysconfdir)/gconf/schemas'
+  fi
+
+  AC_ARG_WITH([gconf-schema-file-dir],
+	      AC_HELP_STRING([--with-gconf-schema-file-dir=dir],
+			     [Directory for installing schema files.]),
+	      [GCONF_SCHEMA_FILE_DIR="$withval"],)
+
+  AC_SUBST(GCONF_SCHEMA_FILE_DIR)
+  AC_MSG_RESULT([Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files])
+
+  AC_ARG_ENABLE(schemas-install,
+  	AC_HELP_STRING([--disable-schemas-install],
+		       [Disable the schemas installation]),
+     [case ${enableval} in
+       yes|no) ;;
+       *) AC_MSG_ERROR([bad value ${enableval} for --enable-schemas-install]) ;;
+      esac])
+  AM_CONDITIONAL([GCONF_SCHEMAS_INSTALL], [test "$enable_schemas_install" != no])
+])
+
 # pkg.m4 - Macros to locate and utilise pkg-config.            -*- Autoconf -*-
 # 
 # Copyright © 2004 Scott James Remnant <[email protected]>.

+ 138 - 19
configure

@@ -1,6 +1,6 @@
 #! /bin/sh
 # Guess values for system-dependent variables and create Makefiles.
-# Generated by GNU Autoconf 2.64 for MultiSSH 0.2.
+# Generated by GNU Autoconf 2.64 for MultiSSH 1.0.
 #
 # Report bugs to <[email protected]>.
 #
@@ -548,8 +548,8 @@ MAKEFLAGS=
 # Identity of this package.
 PACKAGE_NAME='MultiSSH'
 PACKAGE_TARNAME='mssh'
-PACKAGE_VERSION='0.2'
-PACKAGE_STRING='MultiSSH 0.2'
+PACKAGE_VERSION='1.0'
+PACKAGE_STRING='MultiSSH 1.0'
 PACKAGE_BUGREPORT='[email protected]'
 PACKAGE_URL=''
 
@@ -557,6 +557,11 @@ ac_subst_vars='am__EXEEXT_FALSE
 am__EXEEXT_TRUE
 LTLIBOBJS
 LIBOBJS
+GCONF_SCHEMAS_INSTALL_FALSE
+GCONF_SCHEMAS_INSTALL_TRUE
+GCONF_SCHEMA_FILE_DIR
+GCONF_SCHEMA_CONFIG_SOURCE
+GCONFTOOL
 MSSH_LIBS
 MSSH_CFLAGS
 PKG_CONFIG
@@ -641,6 +646,9 @@ ac_subst_files=''
 ac_user_opts='
 enable_option_checking
 enable_dependency_tracking
+with_gconf_source
+with_gconf_schema_file_dir
+enable_schemas_install
 '
       ac_precious_vars='build_alias
 host_alias
@@ -1194,7 +1202,7 @@ if test "$ac_init_help" = "long"; then
   # Omit some internal or obsolete options to make the list less imposing.
   # This message is too long to be a string in the A/UX 3.1 sh.
   cat <<_ACEOF
-\`configure' configures MultiSSH 0.2 to adapt to many kinds of systems.
+\`configure' configures MultiSSH 1.0 to adapt to many kinds of systems.
 
 Usage: $0 [OPTION]... [VAR=VALUE]...
 
@@ -1260,7 +1268,7 @@ fi
 
 if test -n "$ac_init_help"; then
   case $ac_init_help in
-     short | recursive ) echo "Configuration of MultiSSH 0.2:";;
+     short | recursive ) echo "Configuration of MultiSSH 1.0:";;
    esac
   cat <<\_ACEOF
 
@@ -1270,6 +1278,16 @@ Optional Features:
   --enable-FEATURE[=ARG]  include FEATURE [ARG=yes]
   --disable-dependency-tracking  speeds up one-time build
   --enable-dependency-tracking   do not reject slow dependency extractors
+  --disable-schemas-install
+                          Disable the schemas installation
+
+Optional Packages:
+  --with-PACKAGE[=ARG]    use PACKAGE [ARG=yes]
+  --without-PACKAGE       do not use PACKAGE (same as --with-PACKAGE=no)
+  --with-gconf-source=sourceaddress
+                          Config database for installing schema files.
+  --with-gconf-schema-file-dir=dir
+                          Directory for installing schema files.
 
 Some influential environment variables:
   CC          C compiler command
@@ -1349,7 +1367,7 @@ fi
 test -n "$ac_init_help" && exit $ac_status
 if $ac_init_version; then
   cat <<\_ACEOF
-MultiSSH configure 0.2
+MultiSSH configure 1.0
 generated by GNU Autoconf 2.64
 
 Copyright (C) 2009 Free Software Foundation, Inc.
@@ -1404,7 +1422,7 @@ cat >config.log <<_ACEOF
 This file contains any messages produced by compilers while
 running configure, to aid debugging if configure makes a mistake.
 
-It was created by MultiSSH $as_me 0.2, which was
+It was created by MultiSSH $as_me 1.0, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   $ $0 $@
@@ -2214,7 +2232,7 @@ fi
 
 # Define the identity of the package.
  PACKAGE='mssh'
- VERSION='0.2'
+ VERSION='1.0'
 
 
 cat >>confdefs.h <<_ACEOF
@@ -3338,12 +3356,12 @@ if test -n "$PKG_CONFIG"; then
         pkg_cv_MSSH_CFLAGS="$MSSH_CFLAGS"
     else
         if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 vte\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "gtk+-2.0 vte") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 vte gconf-2.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "gtk+-2.0 vte gconf-2.0") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_MSSH_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0 vte" 2>/dev/null`
+  pkg_cv_MSSH_CFLAGS=`$PKG_CONFIG --cflags "gtk+-2.0 vte gconf-2.0" 2>/dev/null`
 else
   pkg_failed=yes
 fi
@@ -3356,12 +3374,12 @@ if test -n "$PKG_CONFIG"; then
         pkg_cv_MSSH_LIBS="$MSSH_LIBS"
     else
         if test -n "$PKG_CONFIG" && \
-    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 vte\""; } >&5
-  ($PKG_CONFIG --exists --print-errors "gtk+-2.0 vte") 2>&5
+    { { $as_echo "$as_me:${as_lineno-$LINENO}: \$PKG_CONFIG --exists --print-errors \"gtk+-2.0 vte gconf-2.0\""; } >&5
+  ($PKG_CONFIG --exists --print-errors "gtk+-2.0 vte gconf-2.0") 2>&5
   ac_status=$?
   $as_echo "$as_me:${as_lineno-$LINENO}: \$? = $ac_status" >&5
   test $ac_status = 0; }; then
-  pkg_cv_MSSH_LIBS=`$PKG_CONFIG --libs "gtk+-2.0 vte" 2>/dev/null`
+  pkg_cv_MSSH_LIBS=`$PKG_CONFIG --libs "gtk+-2.0 vte gconf-2.0" 2>/dev/null`
 else
   pkg_failed=yes
 fi
@@ -3380,14 +3398,14 @@ else
         _pkg_short_errors_supported=no
 fi
         if test $_pkg_short_errors_supported = yes; then
-	        MSSH_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0 vte"`
+	        MSSH_PKG_ERRORS=`$PKG_CONFIG --short-errors --errors-to-stdout --print-errors "gtk+-2.0 vte gconf-2.0"`
         else
-	        MSSH_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0 vte"`
+	        MSSH_PKG_ERRORS=`$PKG_CONFIG --errors-to-stdout --print-errors "gtk+-2.0 vte gconf-2.0"`
         fi
 	# Put the nasty error message in config.log where it belongs
 	echo "$MSSH_PKG_ERRORS" >&5
 
-	as_fn_error "Package requirements (gtk+-2.0 vte) were not met:
+	as_fn_error "Package requirements (gtk+-2.0 vte gconf-2.0) were not met:
 
 $MSSH_PKG_ERRORS
 
@@ -3421,6 +3439,103 @@ fi
 
 
 
+# Extract the first word of "gconftool-2", so it can be a program name with args.
+set dummy gconftool-2; ac_word=$2
+{ $as_echo "$as_me:${as_lineno-$LINENO}: checking for $ac_word" >&5
+$as_echo_n "checking for $ac_word... " >&6; }
+if test "${ac_cv_path_GCONFTOOL+set}" = set; then :
+  $as_echo_n "(cached) " >&6
+else
+  case $GCONFTOOL in
+  [\\/]* | ?:[\\/]*)
+  ac_cv_path_GCONFTOOL="$GCONFTOOL" # Let the user override the test with a path.
+  ;;
+  *)
+  as_save_IFS=$IFS; IFS=$PATH_SEPARATOR
+for as_dir in $PATH
+do
+  IFS=$as_save_IFS
+  test -z "$as_dir" && as_dir=.
+    for ac_exec_ext in '' $ac_executable_extensions; do
+  if { test -f "$as_dir/$ac_word$ac_exec_ext" && $as_test_x "$as_dir/$ac_word$ac_exec_ext"; }; then
+    ac_cv_path_GCONFTOOL="$as_dir/$ac_word$ac_exec_ext"
+    $as_echo "$as_me:${as_lineno-$LINENO}: found $as_dir/$ac_word$ac_exec_ext" >&5
+    break 2
+  fi
+done
+  done
+IFS=$as_save_IFS
+
+  test -z "$ac_cv_path_GCONFTOOL" && ac_cv_path_GCONFTOOL="no"
+  ;;
+esac
+fi
+GCONFTOOL=$ac_cv_path_GCONFTOOL
+if test -n "$GCONFTOOL"; then
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: $GCONFTOOL" >&5
+$as_echo "$GCONFTOOL" >&6; }
+else
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: no" >&5
+$as_echo "no" >&6; }
+fi
+
+
+
+if test x"$GCONFTOOL" = xno; then
+  as_fn_error "gconftool-2 executable not found in your path - should be installed with GConf" "$LINENO" 5
+fi
+
+
+  if test "x$GCONF_SCHEMA_INSTALL_SOURCE" = "x"; then
+    GCONF_SCHEMA_CONFIG_SOURCE=`gconftool-2 --get-default-source`
+  else
+    GCONF_SCHEMA_CONFIG_SOURCE=$GCONF_SCHEMA_INSTALL_SOURCE
+  fi
+
+
+# Check whether --with-gconf-source was given.
+if test "${with_gconf_source+set}" = set; then :
+  withval=$with_gconf_source; GCONF_SCHEMA_CONFIG_SOURCE="$withval"
+fi
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation" >&5
+$as_echo "Using config source $GCONF_SCHEMA_CONFIG_SOURCE for schema installation" >&6; }
+
+  if test "x$GCONF_SCHEMA_FILE_DIR" = "x"; then
+    GCONF_SCHEMA_FILE_DIR='$(sysconfdir)/gconf/schemas'
+  fi
+
+
+# Check whether --with-gconf-schema-file-dir was given.
+if test "${with_gconf_schema_file_dir+set}" = set; then :
+  withval=$with_gconf_schema_file_dir; GCONF_SCHEMA_FILE_DIR="$withval"
+fi
+
+
+
+  { $as_echo "$as_me:${as_lineno-$LINENO}: result: Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files" >&5
+$as_echo "Using $GCONF_SCHEMA_FILE_DIR as install directory for schema files" >&6; }
+
+  # Check whether --enable-schemas-install was given.
+if test "${enable_schemas_install+set}" = set; then :
+  enableval=$enable_schemas_install; case ${enableval} in
+       yes|no) ;;
+       *) as_fn_error "bad value ${enableval} for --enable-schemas-install" "$LINENO" 5 ;;
+      esac
+fi
+
+   if test "$enable_schemas_install" != no; then
+  GCONF_SCHEMAS_INSTALL_TRUE=
+  GCONF_SCHEMAS_INSTALL_FALSE='#'
+else
+  GCONF_SCHEMAS_INSTALL_TRUE='#'
+  GCONF_SCHEMAS_INSTALL_FALSE=
+fi
+
+
+
 ac_config_files="$ac_config_files Makefile src/Makefile"
 
 cat >confcache <<\_ACEOF
@@ -3536,6 +3651,10 @@ if test -z "${am__fastdepCC_TRUE}" && test -z "${am__fastdepCC_FALSE}"; then
   as_fn_error "conditional \"am__fastdepCC\" was never defined.
 Usually this means the macro was only invoked conditionally." "$LINENO" 5
 fi
+if test -z "${GCONF_SCHEMAS_INSTALL_TRUE}" && test -z "${GCONF_SCHEMAS_INSTALL_FALSE}"; then
+  as_fn_error "conditional \"GCONF_SCHEMAS_INSTALL\" was never defined.
+Usually this means the macro was only invoked conditionally." "$LINENO" 5
+fi
 
 : ${CONFIG_STATUS=./config.status}
 ac_write_fail=0
@@ -3944,7 +4063,7 @@ cat >>$CONFIG_STATUS <<\_ACEOF || ac_write_fail=1
 # report actual input values of CONFIG_FILES etc. instead of their
 # values after options handling.
 ac_log="
-This file was extended by MultiSSH $as_me 0.2, which was
+This file was extended by MultiSSH $as_me 1.0, which was
 generated by GNU Autoconf 2.64.  Invocation command line was
 
   CONFIG_FILES    = $CONFIG_FILES
@@ -4008,7 +4127,7 @@ Report bugs to <[email protected]>."
 _ACEOF
 cat >>$CONFIG_STATUS <<_ACEOF || ac_write_fail=1
 ac_cs_version="\\
-MultiSSH config.status 0.2
+MultiSSH config.status 1.0
 configured by $0, generated by GNU Autoconf 2.64,
   with options \\"`$as_echo "$ac_configure_args" | sed 's/^ //; s/[\\""\`\$]/\\\\&/g'`\\"
 

+ 10 - 2
configure.ac

@@ -1,13 +1,21 @@
-AC_INIT([MultiSSH], [0.2], [[email protected]], [mssh])
+AC_INIT([MultiSSH], [1.0], [[email protected]], [mssh])
 AM_CONFIG_HEADER([config.h])
 AM_INIT_AUTOMAKE
 
 AC_PROG_CC
 
-PKG_CHECK_MODULES(MSSH, [gtk+-2.0 vte])
+PKG_CHECK_MODULES(MSSH, [gtk+-2.0 vte gconf-2.0])
 AC_SUBST(MSSH_CFLAGS)
 AC_SUBST(MSSH_LIBS)
 
+AC_PATH_PROG(GCONFTOOL, gconftool-2, no)
+
+if test x"$GCONFTOOL" = xno; then
+  AC_MSG_ERROR([gconftool-2 executable not found in your path - should be installed with GConf])
+fi
+
+AM_GCONF_SOURCE_2
+
 AC_OUTPUT(
     Makefile
     src/Makefile

+ 82 - 0
mssh.schemas

@@ -0,0 +1,82 @@
+<gconfschemafile>
+    <schemalist>
+        <schema>
+            <key>/schemas/apps/mssh/font</key>
+            <applyto>/apps/mssh/font</applyto>
+            <owner>mssh</owner>
+            <type>string</type>
+            <default>Monospace 10</default>
+            <locale name="C">
+                <short>Terminal font</short>
+                <long>Font to use for all MSSH terminals</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/fg_colour</key>
+            <applyto>/apps/mssh/fg_colour</applyto>
+            <owner>mssh</owner>
+            <type>string</type>
+            <default>#ffffffffffff</default>
+            <locale name="C">
+                <short>Terminal foreground colour</short>
+                <long>Foreground colour to use for all MSSH terminals</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/bg_colour</key>
+            <applyto>/apps/mssh/bg_colour</applyto>
+            <owner>mssh</owner>
+            <type>string</type>
+            <default>#000000000000</default>
+            <locale name="C">
+                <short>Terminal background colour</short>
+                <long>Background colour to use for all MSSH terminals</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/coloums</key>
+            <applyto>/apps/mssh/columns</applyto>
+            <owner>mssh</owner>
+            <type>int</type>
+            <default>2</default>
+            <locale name="C">
+                <short>Terminal columns</short>
+                <long>Number of columns of tiled terminals</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/timeout</key>
+            <applyto>/apps/mssh/timeout</applyto>
+            <owner>mssh</owner>
+            <type>int</type>
+            <default>2</default>
+            <locale name="C">
+                <short>Terminal close timeout</short>
+                <long>Timeout after which to close ended sessions</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/close_ended</key>
+            <applyto>/apps/mssh/close_ended</applyto>
+            <owner>mssh</owner>
+            <type>bool</type>
+            <default>true</default>
+            <locale name="C">
+                <short>Close ended sessions</short>
+                <long>Close ended ssh sessions</long>
+            </locale>
+        </schema>
+        <schema>
+            <key>/schemas/apps/mssh/quit_all_ended</key>
+            <applyto>/apps/mssh/quit_all_ended</applyto>
+            <owner>mssh</owner>
+            <type>bool</type>
+            <default>false</default>
+            <locale name="C">
+                <short>Quit after all sessions ended</short>
+                <long>Quit MSSH when all ssh sessions have ended</long>
+            </locale>
+        </schema>
+
+    </schemalist>
+</gconfschemafile>

+ 3 - 2
src/Makefile.am

@@ -4,7 +4,8 @@ INCLUDES = $(MSSH_CFLAGS)
 
 bin_PROGRAMS = mssh
 
-mssh_SOURCES = mssh.c mssh-window.c
+mssh_SOURCES = mssh.c mssh-terminal.c mssh-window.c mssh-pref.c \
+	mssh-gconf.c
 mssh_LDADD = $(MSSH_LIBS)
 
-EXTRA_DIST = mssh-window.h
+EXTRA_DIST = mssh-window.h mssh-terminal.h mssh-pref.h mssh-gconf.h

+ 12 - 3
src/Makefile.in

@@ -45,7 +45,8 @@ CONFIG_CLEAN_FILES =
 CONFIG_CLEAN_VPATH_FILES =
 am__installdirs = "$(DESTDIR)$(bindir)"
 PROGRAMS = $(bin_PROGRAMS)
-am_mssh_OBJECTS = mssh.$(OBJEXT) mssh-window.$(OBJEXT)
+am_mssh_OBJECTS = mssh.$(OBJEXT) mssh-terminal.$(OBJEXT) \
+	mssh-window.$(OBJEXT) mssh-pref.$(OBJEXT) mssh-gconf.$(OBJEXT)
 mssh_OBJECTS = $(am_mssh_OBJECTS)
 am__DEPENDENCIES_1 =
 mssh_DEPENDENCIES = $(am__DEPENDENCIES_1)
@@ -79,6 +80,9 @@ ECHO_C = @ECHO_C@
 ECHO_N = @ECHO_N@
 ECHO_T = @ECHO_T@
 EXEEXT = @EXEEXT@
+GCONFTOOL = @GCONFTOOL@
+GCONF_SCHEMA_CONFIG_SOURCE = @GCONF_SCHEMA_CONFIG_SOURCE@
+GCONF_SCHEMA_FILE_DIR = @GCONF_SCHEMA_FILE_DIR@
 INSTALL = @INSTALL@
 INSTALL_DATA = @INSTALL_DATA@
 INSTALL_PROGRAM = @INSTALL_PROGRAM@
@@ -150,9 +154,11 @@ top_builddir = @top_builddir@
 top_srcdir = @top_srcdir@
 AM_CFLAGS = -pedantic-errors -Werror -Wall -Wfatal-errors -Wwrite-strings
 INCLUDES = $(MSSH_CFLAGS)
-mssh_SOURCES = mssh.c mssh-window.c
+mssh_SOURCES = mssh.c mssh-terminal.c mssh-window.c mssh-pref.c \
+	mssh-gconf.c
+
 mssh_LDADD = $(MSSH_LIBS)
-EXTRA_DIST = mssh-window.h
+EXTRA_DIST = mssh-window.h mssh-terminal.h mssh-pref.h mssh-gconf.h
 all: all-am
 
 .SUFFIXES:
@@ -234,6 +240,9 @@ mostlyclean-compile:
 distclean-compile:
 	-rm -f *.tab.c
 
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mssh-gconf.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mssh-pref.Po@am__quote@
+@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mssh-terminal.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mssh-window.Po@am__quote@
 @AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/mssh.Po@am__quote@
 

+ 161 - 0
src/mssh-gconf.c

@@ -0,0 +1,161 @@
+#include <vte/vte.h>
+
+#include "mssh-gconf.h"
+#include "mssh-window.h"
+#include "mssh-terminal.h"
+
+void mssh_gconf_notify_font(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	const gchar *font;
+	int i;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	font = gconf_value_get_string(value);
+
+	for(i = 0; i < window->terminals->len; i++)
+	{
+		vte_terminal_set_font_from_string(VTE_TERMINAL(g_array_index(
+			window->terminals, MSSHTerminal*, i)), font);
+	}
+}
+
+void mssh_gconf_notify_fg_colour(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	const gchar *colour_s;
+	GdkVisual *visual = gdk_visual_get_system();
+	GdkColormap *colour_map;
+	GdkColor colour;
+	int i;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	colour_s = gconf_value_get_string(value);
+	colour_map = gdk_colormap_new(visual, TRUE);
+	gdk_colormap_alloc_color(colour_map, &colour, TRUE, TRUE);
+
+	gdk_color_parse(colour_s, &colour);
+
+	for(i = 0; i < window->terminals->len; i++)
+	{
+		vte_terminal_set_color_foreground(VTE_TERMINAL(g_array_index(
+			window->terminals, MSSHTerminal*, i)), &colour);
+	}
+}
+
+void mssh_gconf_notify_bg_colour(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	const gchar *colour_s;
+	GdkVisual *visual = gdk_visual_get_system();
+	GdkColormap *colour_map;
+	GdkColor colour;
+	int i;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	colour_s = gconf_value_get_string(value);
+	colour_map = gdk_colormap_new(visual, TRUE);
+	gdk_colormap_alloc_color(colour_map, &colour, TRUE, TRUE);
+
+	gdk_color_parse(colour_s, &colour);
+
+	for(i = 0; i < window->terminals->len; i++)
+	{
+		vte_terminal_set_color_background(VTE_TERMINAL(g_array_index(
+			window->terminals, MSSHTerminal*, i)), &colour);
+	}
+}
+
+void mssh_gconf_notify_columns(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	int columns;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	columns = gconf_value_get_int(value);
+
+	if(columns <= 0)
+	{
+		columns = 1;
+		gconf_client_set_int(client, MSSH_GCONF_KEY_COLUMNS, columns,
+			NULL);
+	}
+
+	window->columns = columns;
+	mssh_window_relayout(window);
+}
+
+void mssh_gconf_notify_timeout(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	int timeout;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	timeout = gconf_value_get_int(value);
+
+	if(timeout < 0)
+	{
+		timeout = 0;
+		gconf_client_set_int(client, MSSH_GCONF_KEY_TIMEOUT, timeout,
+			NULL);
+	}
+
+	window->timeout = timeout;
+	mssh_window_relayout(window);
+}
+
+void mssh_gconf_notify_close_ended(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+	gboolean close_ended;
+	int i;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+	close_ended = gconf_value_get_bool(value);
+
+	window->close_ended_sessions = close_ended;
+
+	if(close_ended)
+	{
+		for(i = 0; i < window->terminals->len; i++)
+		{
+			MSSHTerminal *terminal = g_array_index(window->terminals,
+				MSSHTerminal*, i);
+
+			if(terminal->ended)
+			{
+				mssh_window_session_closed(terminal, window);
+			}
+		}
+	}
+}
+
+void mssh_gconf_notify_quit_all_ended(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data)
+{
+	GConfValue *value;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	value = gconf_entry_get_value(entry);
+
+	window->exit_on_all_closed = gconf_value_get_bool(value);
+}

+ 30 - 0
src/mssh-gconf.h

@@ -0,0 +1,30 @@
+#ifndef __MSSH_GCONF__
+#define __MSSH_GCONF__
+
+#include <gconf/gconf-client.h>
+
+#define MSSH_GCONF_PATH					"/apps/mssh"
+#define MSSH_GCONF_KEY_FONT				MSSH_GCONF_PATH"/font"
+#define MSSH_GCONF_KEY_FG_COLOUR		MSSH_GCONF_PATH"/fg_colour"
+#define MSSH_GCONF_KEY_BG_COLOUR		MSSH_GCONF_PATH"/bg_colour"
+#define MSSH_GCONF_KEY_COLUMNS			MSSH_GCONF_PATH"/columns"
+#define MSSH_GCONF_KEY_TIMEOUT			MSSH_GCONF_PATH"/timeout"
+#define MSSH_GCONF_KEY_CLOSE_ENDED		MSSH_GCONF_PATH"/close_ended"
+#define MSSH_GCONF_KEY_QUIT_ALL_ENDED	MSSH_GCONF_PATH"/quit_all_ended"
+
+void mssh_gconf_notify_font(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_fg_colour(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_bg_colour(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_columns(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_timeout(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_close_ended(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+void mssh_gconf_notify_quit_all_ended(GConfClient *client, guint cnxn_id,
+	GConfEntry *entry, gpointer data);
+
+#endif

+ 278 - 0
src/mssh-pref.c

@@ -0,0 +1,278 @@
+#include <gconf/gconf-client.h>
+
+#include "mssh-gconf.h"
+
+#include "mssh-pref.h"
+
+static void mssh_pref_init(MSSHPref* pref);
+static void mssh_pref_class_init(MSSHPrefClass *klass);
+
+G_DEFINE_TYPE(MSSHPref, mssh_pref, GTK_TYPE_WINDOW)
+
+GtkWidget* mssh_pref_new(void)
+{
+	return g_object_new(MSSH_TYPE_PREF, NULL);
+}
+
+static void mssh_pref_close(GtkWidget *widget, gpointer data)
+{
+	MSSHPref *pref = MSSH_PREF(data);
+
+	gtk_widget_destroy(GTK_WIDGET(pref));
+}
+
+static void mssh_pref_font_select(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	const gchar *font;
+
+	client = gconf_client_get_default();
+
+	font = gtk_font_button_get_font_name(GTK_FONT_BUTTON(widget));
+
+	gconf_client_set_string(client, MSSH_GCONF_KEY_FONT, font, NULL);
+}
+
+static void mssh_pref_fg_colour_select(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	GdkColor colour;
+	const gchar *colour_s;
+
+	client = gconf_client_get_default();
+
+	gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), &colour);
+	colour_s = gdk_color_to_string(&colour);
+
+	gconf_client_set_string(client, MSSH_GCONF_KEY_FG_COLOUR, colour_s,
+		NULL);
+}
+
+static void mssh_pref_bg_colour_select(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	GdkColor colour;
+	const gchar *colour_s;
+
+	client = gconf_client_get_default();
+
+	gtk_color_button_get_color(GTK_COLOR_BUTTON(widget), &colour);
+	colour_s = gdk_color_to_string(&colour);
+
+	gconf_client_set_string(client, MSSH_GCONF_KEY_BG_COLOUR, colour_s,
+		NULL);
+}
+
+static void mssh_pref_columns_select(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	int columns;
+
+	client = gconf_client_get_default();
+
+	columns = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+
+	gconf_client_set_int(client, MSSH_GCONF_KEY_COLUMNS, columns, NULL);
+}
+
+static void mssh_pref_timeout_select(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	int timeout;
+
+	client = gconf_client_get_default();
+
+	timeout = gtk_spin_button_get_value_as_int(GTK_SPIN_BUTTON(widget));
+
+	gconf_client_set_int(client, MSSH_GCONF_KEY_TIMEOUT, timeout, NULL);
+}
+
+static void mssh_pref_close_check(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	gboolean close;
+
+	client = gconf_client_get_default();
+
+	close = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
+	gconf_client_set_bool(client, MSSH_GCONF_KEY_CLOSE_ENDED, close, NULL);
+}
+
+static void mssh_pref_exit_check(GtkWidget *widget, gpointer data)
+{
+	GConfClient *client;
+	gboolean close;
+
+	client = gconf_client_get_default();
+
+	close = gtk_toggle_button_get_active(GTK_TOGGLE_BUTTON(widget));
+
+	gconf_client_set_bool(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED, close,
+		NULL);
+}
+
+static void mssh_pref_init(MSSHPref* pref)
+{
+	GConfClient *client;
+	GConfEntry *entry;
+	GConfValue *value;
+	GdkVisual *visual = gdk_visual_get_system();
+	GdkColormap *colour_map = gdk_colormap_new(visual, TRUE);
+	GdkColor colour;
+	const gchar *colour_s;
+
+	GtkWidget *frame = gtk_vbox_new(FALSE, 5);
+	GtkWidget *notebook = gtk_notebook_new();
+	GtkWidget *content = gtk_vbox_new(FALSE, 4);
+
+	GtkWidget *font_hbox = gtk_hbox_new(FALSE, 10);
+	GtkWidget *font_label = gtk_label_new("Font:");
+	GtkWidget *font_select = gtk_font_button_new();
+
+	GtkWidget *colour_table = gtk_table_new(2, 2, FALSE);
+	GtkWidget *bg_colour_label = gtk_label_new("Background:");
+	GtkWidget *bg_colour_select = gtk_color_button_new();
+	GtkWidget *fg_colour_label = gtk_label_new("Foreground:");
+	GtkWidget *fg_colour_select = gtk_color_button_new();
+
+	GtkWidget *exit_check = gtk_check_button_new_with_label(
+		"Quit after all sessions have ended");
+	GtkWidget *close_check = gtk_check_button_new_with_label(
+		"Close ended sessions");
+
+	GtkWidget *timeout_hbox = gtk_hbox_new(FALSE, 10);
+	GtkWidget *timeout_label1 = gtk_label_new(
+		"Closed ended sessions after");
+	GtkObject *timeout_adj = gtk_adjustment_new(3, 0, 100, 1, 10, 0);
+	GtkWidget *timeout_select = gtk_spin_button_new(
+		GTK_ADJUSTMENT(timeout_adj), 1, 0);
+	GtkWidget *timeout_label2 = gtk_label_new("seconds");
+
+	GtkWidget *columns_hbox = gtk_hbox_new(FALSE, 10);
+	GtkWidget *columns_label = gtk_label_new("Columns:");
+	GtkObject *columns_adj = gtk_adjustment_new(2, 1, 10, 1, 10, 0);
+	GtkWidget *columns_select = gtk_spin_button_new(
+		GTK_ADJUSTMENT(columns_adj), 1, 0);
+
+	GtkWidget *close_hbox = gtk_hbox_new(FALSE, 0);
+	GtkWidget *close_button = gtk_button_new_from_stock(GTK_STOCK_CLOSE);
+
+	gtk_notebook_set_show_tabs(GTK_NOTEBOOK(notebook), FALSE);
+	gtk_notebook_append_page(GTK_NOTEBOOK(notebook), content, NULL);
+
+	gtk_box_pack_start(GTK_BOX(font_hbox), font_label, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(font_hbox), font_select, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(content), font_hbox, FALSE, TRUE, 0);
+
+	gtk_table_attach(GTK_TABLE(colour_table), bg_colour_label,
+		0, 1, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_table_attach(GTK_TABLE(colour_table), bg_colour_select,
+		1, 2, 0, 1, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_table_attach(GTK_TABLE(colour_table), fg_colour_label,
+		0, 1, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_table_attach(GTK_TABLE(colour_table), fg_colour_select,
+		1, 2, 1, 2, GTK_FILL, GTK_FILL, 0, 0);
+	gtk_box_pack_start(GTK_BOX(content), colour_table, FALSE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(content), exit_check, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(content), close_check, FALSE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(timeout_hbox), timeout_label1, FALSE,
+		TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(timeout_hbox), timeout_select, FALSE,
+		TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(timeout_hbox), timeout_label2, FALSE,
+		TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(content), timeout_hbox, FALSE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(columns_hbox), columns_label, FALSE,
+		TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(columns_hbox), columns_select, FALSE,
+		TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(content), columns_hbox, FALSE, TRUE, 0);
+
+	gtk_box_pack_end(GTK_BOX(close_hbox), close_button, FALSE, TRUE, 0);
+
+	gtk_box_pack_start(GTK_BOX(frame), notebook, TRUE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(frame), close_hbox, FALSE, TRUE, 0);
+
+	gtk_container_add(GTK_CONTAINER(pref), frame);
+
+	g_signal_connect(G_OBJECT(close_button), "clicked",
+		G_CALLBACK(mssh_pref_close), pref);
+
+	gtk_container_set_border_width(GTK_CONTAINER(content), 6);
+	gtk_container_set_border_width(GTK_CONTAINER(pref), 15);
+	gtk_window_set_title(GTK_WINDOW(pref), "Preferences");
+	gtk_window_set_resizable(GTK_WINDOW(pref), FALSE);
+
+	g_signal_connect(G_OBJECT(font_select), "font-set",
+		G_CALLBACK(mssh_pref_font_select), NULL);
+	g_signal_connect(G_OBJECT(fg_colour_select), "color-set",
+		G_CALLBACK(mssh_pref_fg_colour_select), NULL);
+	g_signal_connect(G_OBJECT(bg_colour_select), "color-set",
+		G_CALLBACK(mssh_pref_bg_colour_select), NULL);
+	g_signal_connect(G_OBJECT(columns_select), "value-changed",
+		G_CALLBACK(mssh_pref_columns_select), NULL);
+	g_signal_connect(G_OBJECT(timeout_select), "value-changed",
+		G_CALLBACK(mssh_pref_timeout_select), NULL);
+	g_signal_connect(G_OBJECT(close_check), "toggled",
+		G_CALLBACK(mssh_pref_close_check), NULL);
+	g_signal_connect(G_OBJECT(exit_check), "toggled",
+		G_CALLBACK(mssh_pref_exit_check), NULL);
+
+	client = gconf_client_get_default();
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FONT, NULL,
+		TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	gtk_font_button_set_font_name(GTK_FONT_BUTTON(font_select),
+		gconf_value_get_string(value));
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
+		TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	colour_s = gconf_value_get_string(value);
+	gdk_colormap_alloc_color(colour_map, &colour, TRUE, TRUE);
+	gdk_color_parse(colour_s, &colour);
+	gtk_color_button_set_color(GTK_COLOR_BUTTON(fg_colour_select),
+		&colour);
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
+		TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	colour_s = gconf_value_get_string(value);
+	gdk_colormap_alloc_color(colour_map, &colour, TRUE, TRUE);
+	gdk_color_parse(colour_s, &colour);
+	gtk_color_button_set_color(GTK_COLOR_BUTTON(bg_colour_select),
+		&colour);
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_COLUMNS, NULL,
+		TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(columns_select),
+		gconf_value_get_int(value));
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_TIMEOUT, NULL,
+		TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	gtk_spin_button_set_value(GTK_SPIN_BUTTON(timeout_select),
+		gconf_value_get_int(value));
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_CLOSE_ENDED,
+		NULL, TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(close_check),
+		gconf_value_get_bool(value));
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED,
+			NULL, TRUE, NULL);
+	value = gconf_entry_get_value(entry);
+	gtk_toggle_button_set_active(GTK_TOGGLE_BUTTON(exit_check),
+		gconf_value_get_bool(value));
+}
+
+static void mssh_pref_class_init(MSSHPrefClass *klass)
+{
+}

+ 34 - 0
src/mssh-pref.h

@@ -0,0 +1,34 @@
+#ifndef __MSSH_PREF_H__
+#define __MSSH_PREF_H__
+
+#include <gtk/gtk.h>
+
+G_BEGIN_DECLS
+
+#define MSSH_TYPE_PREF				mssh_pref_get_type()
+#define MSSH_PREF(obj)				G_TYPE_CHECK_INSTANCE_CAST(obj,\
+	MSSH_TYPE_PREF, MSSHPref)
+#define MSSH_PREF_CLASS(klass)		G_TYPE_CHECK_CLASS_CAST(klass,\
+	MSSH_PREF_TYPE, MSSHPrefClass)
+#define IS_MSSH_PREF(obj)			G_TYPE_CHECK_INSTANCE_TYPE(obj,\
+	MSSH_TYPE_PREF)
+#define IS_MSSH_PREF_CLASS(klass) G_TYPE_CHECK_CLASS_TYPE(klass,\
+	MSSH_TYPE_PREF)
+
+typedef struct
+{
+	GtkWindow widget;
+} MSSHPref;
+
+typedef struct
+{
+	GtkWindowClass parent_class;
+} MSSHPrefClass;
+
+GType mssh_pref_get_type(void) G_GNUC_CONST;
+
+GtkWidget* mssh_pref_new(void);
+
+G_END_DECLS
+
+#endif /* __MSSH_PREF_H__ */

+ 128 - 0
src/mssh-terminal.c

@@ -0,0 +1,128 @@
+#include <string.h>
+#include <stdlib.h>
+
+#include "mssh-terminal.h"
+
+G_DEFINE_TYPE(MSSHTerminal, mssh_terminal, VTE_TYPE_TERMINAL)
+
+static void mssh_terminal_init(MSSHTerminal* terminal);
+static void mssh_terminal_class_init(MSSHTerminalClass *klass);
+static void mssh_terminal_child_exited(VteTerminal *vte, gpointer data);
+static gboolean mssh_terminal_focused(GtkWidget *widget,
+	GtkDirectionType dir, gpointer data);
+
+GtkWidget* mssh_terminal_new()
+{
+	return g_object_new(MSSH_TYPE_TERMINAL, NULL);
+}
+
+void mssh_terminal_destroy(MSSHTerminal *terminal)
+{
+	free(terminal->hostname);
+}
+
+gboolean mssh_terminal_isactive(MSSHTerminal *terminal)
+{
+	return gtk_check_menu_item_get_active(
+		GTK_CHECK_MENU_ITEM(terminal->menu_item));
+}
+
+void mssh_terminal_init_session(MSSHTerminal *terminal, char *hostname)
+{
+	terminal->hostname = hostname;
+
+	terminal->menu_item = gtk_check_menu_item_new_with_label(
+		terminal->hostname);
+
+	gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
+		terminal->menu_item), TRUE);
+}
+
+void mssh_terminal_start_session(MSSHTerminal *terminal, char **env)
+{
+	char *args[3];
+
+	args[0] = strdup("ssh");
+	args[1] = terminal->hostname;
+	args[2] = NULL;
+
+	vte_terminal_fork_command(VTE_TERMINAL(terminal), "ssh", args,
+		env, NULL, FALSE, FALSE, FALSE);
+
+	free(args[0]);
+}
+
+void mssh_terminal_send_host(MSSHTerminal *terminal)
+{
+	if(mssh_terminal_isactive(terminal))
+	{
+		vte_terminal_feed_child(VTE_TERMINAL(terminal),
+			terminal->hostname, strlen(terminal->hostname));
+	}
+}
+
+void mssh_terminal_send_string(MSSHTerminal *terminal, gchar *string)
+{
+	if(mssh_terminal_isactive(terminal))
+	{
+		vte_terminal_feed_child(VTE_TERMINAL(terminal),	string,
+			strlen(string));
+	}
+}
+
+void mssh_terminal_send_data(MSSHTerminal *terminal, GdkEventKey *event)
+{
+	gboolean dummy;
+
+	if(mssh_terminal_isactive(terminal))
+	{
+		g_signal_emit_by_name(terminal, "key-press-event", event, &dummy);
+	}
+}
+
+static void mssh_terminal_init(MSSHTerminal* terminal)
+{
+	terminal->started = 0;
+	terminal->ended = 0;
+
+	g_signal_connect(G_OBJECT(terminal), "child-exited",
+		G_CALLBACK(mssh_terminal_child_exited), terminal);
+	g_signal_connect(G_OBJECT(terminal), "focus-in-event",
+		G_CALLBACK(mssh_terminal_focused), terminal);
+}
+
+static void mssh_terminal_class_init(MSSHTerminalClass *klass)
+{
+	klass->session_closed_signal = g_signal_new("session-closed",
+		G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET(MSSHTerminalClass, session_closed), NULL, NULL,
+		g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+
+	klass->session_focused_signal = g_signal_new("session-focused",
+		G_TYPE_FROM_CLASS(klass), G_SIGNAL_RUN_LAST,
+		G_STRUCT_OFFSET(MSSHTerminalClass, session_focused), NULL, NULL,
+		g_cclosure_marshal_VOID__VOID, G_TYPE_NONE, 0, NULL);
+}
+
+static void mssh_terminal_child_exited(VteTerminal *vte, gpointer data)
+{
+	char msg[] = "\r\n[Child Exited]\r\n";
+
+	MSSHTerminal *terminal = MSSH_TERMINAL(data);
+
+	terminal->ended = 1;
+
+	vte_terminal_feed(vte, msg, strlen(msg));
+
+	g_signal_emit_by_name(terminal, "session-closed");
+}
+
+static gboolean mssh_terminal_focused(GtkWidget *widget,
+	GtkDirectionType dir, gpointer data)
+{
+	MSSHTerminal *terminal = MSSH_TERMINAL(data);
+
+	g_signal_emit_by_name(terminal, "session-focused");
+
+	return FALSE;
+}

+ 52 - 0
src/mssh-terminal.h

@@ -0,0 +1,52 @@
+#ifndef __MSSH_TERMINAL_H__
+#define __MSSH_TERMINAL_H__
+
+#include <gtk/gtk.h>
+#include <vte/vte.h>
+
+G_BEGIN_DECLS
+
+#define MSSH_TYPE_TERMINAL				mssh_terminal_get_type()
+#define MSSH_TERMINAL(obj)				G_TYPE_CHECK_INSTANCE_CAST(obj, \
+	MSSH_TYPE_TERMINAL, MSSHTerminal)
+#define MSSH_TERMINAL_CLASS(klass)		G_TYPE_CHECK_CLASS_CAST(klass, \
+	MSSH_TERMINAL_TYPE, MSSHTerminalClass)
+#define IS_MSSH_TERMINAL(obj)			G_TYPE_CHECK_INSTANCE_TYPE(obj, \
+	MSSH_TYPE_TERMINAL)
+#define IS_MSSH_TERMINAL_CLASS(klass)	G_TYPE_CHECK_CLASS_TYPE(klass, \
+	MSSH_TYPE_TERMINAL)
+
+typedef struct
+{
+	VteTerminal vte;
+	GtkWidget *menu_item;
+	char *hostname;
+	int started;
+	int ended;
+} MSSHTerminal;
+
+typedef struct
+{
+	VteTerminalClass parent_class;
+
+	guint session_closed_signal;
+	guint session_focused_signal;
+
+	void (*session_closed)(MSSHTerminal *terminal);
+	void (*session_focused)(MSSHTerminal *terminal);
+} MSSHTerminalClass;
+
+GType mssh_terminal_get_type(void) G_GNUC_CONST;
+
+GtkWidget* mssh_terminal_new(void);
+void mssh_terminal_destroy(MSSHTerminal *terminal);
+gboolean mssh_terminal_isactive(MSSHTerminal *terminal);
+void mssh_terminal_init_session(MSSHTerminal *terminal, char *hostname);
+void mssh_terminal_start_session(MSSHTerminal *terminal, char **env);
+void mssh_terminal_send_host(MSSHTerminal *terminal);
+void mssh_terminal_send_string(MSSHTerminal *terminal, gchar *string);
+void mssh_terminal_send_data(MSSHTerminal *terminal, GdkEventKey *event);
+
+G_END_DECLS
+
+#endif /* __MSSH_TERMINAL_H__ */

+ 295 - 120
src/mssh-window.c

@@ -1,202 +1,377 @@
 #include <string.h>
 #include <stdlib.h>
 
+#include <gconf/gconf-client.h>
 #include <gdk/gdkkeysyms.h>
 
+#include "mssh-terminal.h"
+#include "mssh-pref.h"
+#include "mssh-gconf.h"
 #include "mssh-window.h"
 
+#include "config.h"
+
+static void mssh_window_sendhost(GtkWidget *widget, gpointer data);
+static void mssh_window_destroy(GtkWidget *widget, gpointer data);
+static void mssh_window_pref(GtkWidget *widget, gpointer data);
+static gboolean mssh_window_key_press(GtkWidget *widget,
+	GdkEventKey *event, gpointer data);
+static gboolean mssh_window_entry_focused(GtkWidget *widget,
+	GtkDirectionType dir, gpointer data);
+static gboolean mssh_window_session_close(gpointer data);
+static void mssh_window_session_focused(MSSHTerminal *terminal,
+	gpointer data);
+static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
+	gint new_text_length, gint *position, gpointer data);
+static void mssh_window_add_session(MSSHWindow *window, char *hostname);
+static void mssh_window_init(MSSHWindow* window);
+static void mssh_window_class_init(MSSHWindowClass *klass);
+
 G_DEFINE_TYPE(MSSHWindow, mssh_window, GTK_TYPE_WINDOW)
 
+struct WinTermPair
+{
+	MSSHWindow *window;
+	MSSHTerminal *terminal;
+};
+
+GtkWidget* mssh_window_new(void)
+{
+	return g_object_new(MSSH_TYPE_WINDOW, NULL);
+}
+
 static void mssh_window_sendhost(GtkWidget *widget, gpointer data)
 {
 	int i;
 
 	MSSHWindow *window = MSSH_WINDOW(data);
 
-	for(i = 0; i < window->num_servers; i++)
+	for(i = 0; i < window->terminals->len; i++)
 	{
-		if(window->terms[i] != NULL)
-		{
-			if(gtk_check_menu_item_get_active(
-				GTK_CHECK_MENU_ITEM(window->items[i])))
-			{
-				vte_terminal_feed_child(VTE_TERMINAL(window->terms[i]),
-					window->servers[i], strlen(window->servers[i]));
-			}
-		}
+		mssh_terminal_send_host(g_array_index(window->terminals,
+			MSSHTerminal*, i));
 	}
 }
 
 static void mssh_window_destroy(GtkWidget *widget, gpointer data)
+{
+	gtk_main_quit();
+}
+
+static void mssh_window_pref(GtkWidget *widget, gpointer data)
 {
 	MSSHWindow *window = MSSH_WINDOW(data);
+	GtkWidget *pref = mssh_pref_new();
 
-	free(window->terms);
-	free(window->items);
-	gtk_main_quit();
+	gtk_window_set_transient_for(GTK_WINDOW(pref), GTK_WINDOW(window));
+	gtk_window_set_modal(GTK_WINDOW(pref), TRUE);
+	gtk_window_set_position(GTK_WINDOW(pref),
+		GTK_WIN_POS_CENTER_ON_PARENT);
+
+	gtk_widget_show_all(pref);
 }
 
-GtkWidget* mssh_window_new(void)
+static void mssh_window_insert(GtkWidget *widget, gchar *new_text,
+	gint new_text_length, gint *position, gpointer data)
 {
-	return g_object_new(MSSH_TYPE_WINDOW, NULL);
+	int i;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	for(i = 0; i < window->terminals->len; i++)
+	{
+		mssh_terminal_send_string(g_array_index(window->terminals,
+			MSSHTerminal*, i), new_text);
+	}
+
+	g_signal_stop_emission_by_name(G_OBJECT(widget), "insert-text");
 }
 
-gboolean key_press(GtkWidget *widget, GdkEventKey *event,
-	gpointer user_data)
+static gboolean mssh_window_key_press(GtkWidget *widget,
+	GdkEventKey *event, gpointer data)
 {
 	int i;
-	gboolean dummy;
 
-	MSSHWindow *window = MSSH_WINDOW(user_data);
+	MSSHWindow *window = MSSH_WINDOW(data);
 
-	for(i = 0; i < window->num_servers; i++)
+	for(i = 0; i < window->terminals->len; i++)
 	{
-		if(window->terms[i] != NULL)
-		{
-			if(gtk_check_menu_item_get_active(
-				GTK_CHECK_MENU_ITEM(window->items[i])))
-			{
-				g_signal_emit_by_name(window->terms[i], "key-press-event",
-					event, &dummy);
-			}
-		}
+		mssh_terminal_send_data(g_array_index(window->terminals,
+			MSSHTerminal*, i), event);
 	}
 
 	return TRUE;
 }
 
-void vte_child_exited(VteTerminal *vte, gpointer user_data)
+static gboolean mssh_window_entry_focused(GtkWidget *widget,
+	GtkDirectionType dir, gpointer data)
 {
-	int i;
-	char data[] = "\n[Child Exited]";
-	MSSHWindow *window = MSSH_WINDOW(user_data);
-	vte_terminal_feed(vte, data, strlen(data));
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME" - All");
+
+	return FALSE;
+}
+
+static gboolean mssh_window_session_close(gpointer data)
+{
+	int i, idx = -1;
+
+	struct WinTermPair *data_pair = (struct WinTermPair*)data;
 
-	for(i = 0; i < window->num_servers; i++)
+	for(i = 0; i < data_pair->window->terminals->len; i++)
 	{
-		if(window->terms[i] == GTK_WIDGET(vte))
+		if(data_pair->terminal == g_array_index(
+			data_pair->window->terminals, MSSHTerminal*, i))
 		{
-			window->terms[i] = NULL;
+			idx = i;
 			break;
 		}
 	}
+
+	if(idx == -1)
+	{
+		fprintf(stderr,
+			"mssh: Fatal Error: Can't find terminal to remove!\n");
+	}
+	else
+	{
+		gtk_widget_destroy(data_pair->terminal->menu_item);
+
+		gtk_container_remove(GTK_CONTAINER(data_pair->window->table),
+			GTK_WIDGET(data_pair->terminal));
+
+		g_array_remove_index(data_pair->window->terminals, idx);
+
+		mssh_window_relayout(data_pair->window);
+	}
+
+	if(data_pair->window->terminals->len == 0 &&
+		data_pair->window->exit_on_all_closed)
+	{
+		mssh_window_destroy(NULL, (void*)data_pair->window);
+	}
+
+	free(data_pair);
+
+	return FALSE;
+}
+
+void mssh_window_session_closed(MSSHTerminal *terminal, gpointer data)
+{
+	struct WinTermPair *data_pair = malloc(sizeof(struct WinTermPair));
+	data_pair->terminal = terminal;
+	data_pair->window = MSSH_WINDOW(data);
+
+	if(data_pair->window->close_ended_sessions)
+	{
+		g_timeout_add_seconds(data_pair->window->timeout,
+			mssh_window_session_close, data_pair);
+	}
+}
+
+static void mssh_window_session_focused(MSSHTerminal *terminal,
+	gpointer data)
+{
+	char *title;
+	size_t len;
+
+	MSSHWindow *window = MSSH_WINDOW(data);
+
+	len = strlen(PACKAGE_NAME" - ") + strlen(terminal->hostname) + 1;
+	title = malloc(len);
+
+	snprintf(title, len, PACKAGE_NAME" - %s", terminal->hostname);
+
+	gtk_window_set_title(GTK_WINDOW(window), title);
+
+	free(title);
+}
+
+void mssh_window_relayout(MSSHWindow *window)
+{
+	GConfClient *client;
+	GConfEntry *entry;
+	int i, len = window->terminals->len;
+	int cols = (len < window->columns) ? len : window->columns;
+	int rows = (len + 0.5) / cols;
+
+	for(i = 0; i < len; i++)
+	{
+		MSSHTerminal *terminal = g_array_index(window->terminals,
+			MSSHTerminal*, i);
+
+		g_object_ref(terminal);
+		if(GTK_WIDGET(terminal)->parent == GTK_WIDGET(window->table))
+		{
+			gtk_container_remove(GTK_CONTAINER(window->table),
+				GTK_WIDGET(terminal));
+		}
+
+		gtk_table_attach(GTK_TABLE(window->table), GTK_WIDGET(terminal),
+			(i % cols), (i == len - 1) ? cols : (i % cols) + 1, i / cols,
+			(i / cols) + 1,
+			GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 1, 1);
+		g_object_unref(terminal);
+
+		if(!terminal->started)
+		{
+			mssh_terminal_start_session(terminal, window->env);
+			terminal->started = 1;
+		}
+	}
+
+	if(len > 0)
+	{
+		gtk_table_resize(GTK_TABLE(window->table), rows, cols);
+	}
+
+	client = gconf_client_get_default();
+
+	gtk_widget_show_all(GTK_WIDGET(window));
+
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FONT, NULL,
+		TRUE, NULL);
+	mssh_gconf_notify_font(client, 0, entry, window);
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_FG_COLOUR, NULL,
+		TRUE, NULL);
+	mssh_gconf_notify_fg_colour(client, 0, entry, window);
+	entry = gconf_client_get_entry(client, MSSH_GCONF_KEY_BG_COLOUR, NULL,
+		TRUE, NULL);
+	mssh_gconf_notify_bg_colour(client, 0, entry, window);
+}
+
+static void mssh_window_add_session(MSSHWindow *window, char *hostname)
+{
+	MSSHTerminal *terminal = MSSH_TERMINAL(mssh_terminal_new());
+
+	g_array_append_val(window->terminals, terminal);
+
+	g_signal_connect(G_OBJECT(terminal), "session-closed",
+		G_CALLBACK(mssh_window_session_closed), window);
+	g_signal_connect(G_OBJECT(terminal), "session-focused",
+		G_CALLBACK(mssh_window_session_focused), window);
+
+	mssh_terminal_init_session(terminal, hostname);
+
+	gtk_menu_shell_append(GTK_MENU_SHELL(window->server_menu),
+		terminal->menu_item);
 }
 
 static void mssh_window_init(MSSHWindow* window)
 {
-	GtkAccelGroup *accel_group;
+	GConfClient *client;
 
-	accel_group = gtk_accel_group_new();
-	window->vbox = gtk_vbox_new(FALSE, 0);
-	window->entry = gtk_entry_new();
-	window->menu_bar = gtk_menu_bar_new();
-	window->server_menu = gtk_menu_new();
-	window->file_menu = gtk_menu_new();
-	window->server_item = gtk_menu_item_new_with_label("Servers");
-	window->file_item = gtk_menu_item_new_with_label("File");
-	window->file_quit = gtk_image_menu_item_new_from_stock(GTK_STOCK_QUIT,
-		NULL);
-	window->file_sendhost = gtk_image_menu_item_new_with_label(
+	GtkWidget *vbox = gtk_vbox_new(FALSE, 0);
+	GtkWidget *entry = gtk_entry_new();
+
+	GtkWidget *menu_bar = gtk_menu_bar_new();
+	GtkWidget *file_menu = gtk_menu_new();
+	GtkWidget *edit_menu = gtk_menu_new();
+
+	GtkWidget *file_item = gtk_menu_item_new_with_label("File");
+	GtkWidget *edit_item = gtk_menu_item_new_with_label("Edit");
+	GtkWidget *server_item = gtk_menu_item_new_with_label("Servers");
+
+	GtkWidget *file_quit = gtk_image_menu_item_new_from_stock(
+		GTK_STOCK_QUIT, NULL);
+	GtkWidget *file_sendhost = gtk_image_menu_item_new_with_label(
 		"Send hostname");
+/*	GtkWidget *file_add = gtk_image_menu_item_new_with_label(
+		"Add session");*/
+
+	GtkWidget *edit_pref = gtk_image_menu_item_new_from_stock(
+		GTK_STOCK_PREFERENCES, NULL);
 
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(window->file_item),
-		window->file_menu);
-	gtk_menu_item_set_submenu(GTK_MENU_ITEM(window->server_item),
+	window->server_menu = gtk_menu_new();
+
+	window->terminals = g_array_new(FALSE, TRUE, sizeof(MSSHTerminal*));
+
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(file_item), file_menu);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(edit_item), edit_menu);
+	gtk_menu_item_set_submenu(GTK_MENU_ITEM(server_item),
 		window->server_menu);
 
-	gtk_menu_shell_append(GTK_MENU_SHELL(window->file_menu),
-		window->file_sendhost);
-	gtk_menu_shell_append(GTK_MENU_SHELL(window->file_menu),
-		window->file_quit);
-	g_signal_connect(G_OBJECT(window->file_sendhost), "activate",
+/*	gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_add);*/
+	gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_sendhost);
+	gtk_menu_shell_append(GTK_MENU_SHELL(file_menu), file_quit);
+	gtk_menu_shell_append(GTK_MENU_SHELL(edit_menu), edit_pref);
+	g_signal_connect(G_OBJECT(file_sendhost), "activate",
 		G_CALLBACK(mssh_window_sendhost), window);
-	g_signal_connect(G_OBJECT(window->file_quit), "activate",
+	g_signal_connect(G_OBJECT(file_quit), "activate",
 		G_CALLBACK(mssh_window_destroy), window);
-	gtk_widget_add_accelerator(window->file_quit, "activate", accel_group,
-		GDK_W, GDK_CONTROL_MASK, GTK_ACCEL_VISIBLE);
-	gtk_window_add_accel_group(GTK_WINDOW(window), accel_group);
+	g_signal_connect(G_OBJECT(edit_pref), "activate",
+		G_CALLBACK(mssh_window_pref), window);
+
+	gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), file_item);
+	gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), edit_item);
+	gtk_menu_bar_append(GTK_MENU_BAR(menu_bar), server_item);
 
-	gtk_menu_bar_append(GTK_MENU_BAR(window->menu_bar),
-		window->file_item);
-	gtk_menu_bar_append(GTK_MENU_BAR(window->menu_bar),
-		window->server_item);
+	g_signal_connect(G_OBJECT(entry), "key-press-event",
+		G_CALLBACK(mssh_window_key_press), window);
+	g_signal_connect(G_OBJECT(entry), "insert-text",
+		G_CALLBACK(mssh_window_insert), window);
+	g_signal_connect(G_OBJECT(entry), "focus-in-event",
+		G_CALLBACK(mssh_window_entry_focused), window);
 
-	g_signal_connect(G_OBJECT(window->entry), "key-press-event",
-		G_CALLBACK(key_press), window);
+	gtk_box_pack_start(GTK_BOX(vbox), menu_bar, FALSE, TRUE, 0);
+	gtk_box_pack_start(GTK_BOX(vbox), entry, FALSE, TRUE, 2);
 
-	gtk_box_pack_start(GTK_BOX(window->vbox), window->menu_bar,
-		FALSE, TRUE, 0);
-	gtk_box_pack_start(GTK_BOX(window->vbox), window->entry,
-		FALSE, TRUE, 2);
+	window->table = gtk_table_new(1, 1, TRUE);
+	gtk_box_pack_start(GTK_BOX(vbox), window->table, TRUE, TRUE, 0);
 
-	gtk_container_add(GTK_CONTAINER(window), window->vbox);
+	gtk_container_add(GTK_CONTAINER(window), vbox);
 
 	gtk_widget_set_size_request(GTK_WIDGET(window), 1024, 768);
-	gtk_window_set_title(GTK_WINDOW(window), "MSSH");
+	gtk_window_set_title(GTK_WINDOW(window), PACKAGE_NAME);
+
+	client = gconf_client_get_default();
+
+	gconf_client_add_dir(client, MSSH_GCONF_PATH,
+		GCONF_CLIENT_PRELOAD_RECURSIVE, NULL);
+
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_FONT,
+		mssh_gconf_notify_font, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_FG_COLOUR,
+		mssh_gconf_notify_fg_colour, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_BG_COLOUR,
+		mssh_gconf_notify_bg_colour, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_COLUMNS,
+		mssh_gconf_notify_columns, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_TIMEOUT,
+		mssh_gconf_notify_timeout, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_CLOSE_ENDED,
+		mssh_gconf_notify_close_ended, window, NULL, NULL);
+	gconf_client_notify_add(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED,
+		mssh_gconf_notify_quit_all_ended, window, NULL, NULL);
+
+	gconf_client_notify(client, MSSH_GCONF_KEY_COLUMNS);
+	gconf_client_notify(client, MSSH_GCONF_KEY_TIMEOUT);
+	gconf_client_notify(client, MSSH_GCONF_KEY_CLOSE_ENDED);
+	gconf_client_notify(client, MSSH_GCONF_KEY_QUIT_ALL_ENDED);
 }
 
-void mssh_window_new_session(MSSHWindow* window, char **env,
-	int num_servers, char **servers)
+void mssh_window_start_session(MSSHWindow* window, char **env, int nhosts,
+	char **servers)
 {
-	char *args[3] = { NULL, NULL, NULL };
 	int i, j, k;
-	int rows = num_servers/2 + num_servers%2;
+	int rows = (nhosts / 2) + (nhosts % 2);
 
 	window->env = env;
-	window->num_servers = num_servers;
-	window->servers = servers;
-
-	window->items = malloc(sizeof(GtkWidget) * num_servers);
-	window->terms = malloc(sizeof(GtkWidget) * num_servers);
-	memset(window->items, 0, sizeof(GtkWidget) * num_servers);
-	memset(window->terms, 0, sizeof(GtkWidget) * num_servers);
-
-	args[0] = strdup("ssh");
-
-	window->table = gtk_table_new(rows, 2, TRUE);
-	gtk_box_pack_start(GTK_BOX(window->vbox), window->table,
-		TRUE, TRUE, 0);
 
 	for(i = 0; i < rows; i++)
 	{
 		for(j = 0; j < 2; j++)
 		{
 			k = j + i*2;
-			if(k < num_servers)
+			if(k < nhosts)
 			{
-				args[1] = window->servers[k];
-				window->terms[k] = vte_terminal_new();
-				g_signal_connect(G_OBJECT(window->terms[k]),
-					"child-exited", G_CALLBACK(vte_child_exited), window);
-				vte_terminal_fork_command(VTE_TERMINAL(window->terms[k]),
-					"ssh", args, window->env, NULL, FALSE, FALSE,
-					FALSE);
-				if((k == num_servers - 1) && (num_servers % 2 == 1))
-				{
-					gtk_table_attach(GTK_TABLE(window->table),
-						window->terms[k], j, j+2, i, i+1,
-						GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2,
-						2);
-				}
-				else
-				{
-					gtk_table_attach(GTK_TABLE(window->table),
-						window->terms[k], j, j+1, i, i+1,
-						GTK_FILL | GTK_EXPAND, GTK_FILL | GTK_EXPAND, 2,
-						2);
-				}
-
-				window->items[k] = gtk_check_menu_item_new_with_label(
-					window->servers[k]);
-				gtk_check_menu_item_set_active(GTK_CHECK_MENU_ITEM(
-					window->items[k]), TRUE);
-				gtk_menu_shell_append(GTK_MENU_SHELL(window->server_menu),
-					window->items[k]);
+				mssh_window_add_session(window, servers[k]);
 			}
 		}
 	}
 
-	free(args[0]);
+	mssh_window_relayout(window);
 }
 
 static void mssh_window_class_init(MSSHWindowClass *klass)

+ 11 - 14
src/mssh-window.h

@@ -4,6 +4,8 @@
 #include <gtk/gtk.h>
 #include <vte/vte.h>
 
+#include "mssh-terminal.h"
+
 G_BEGIN_DECLS
 
 #define MSSH_TYPE_WINDOW			mssh_window_get_type()
@@ -19,21 +21,14 @@ G_BEGIN_DECLS
 typedef struct
 {
 	GtkWindow widget;
-	GtkWidget *vbox;
-	GtkWidget *entry;
 	GtkWidget *table;
-	GtkWidget *menu_bar;
 	GtkWidget *server_menu;
-	GtkWidget *file_menu;
-	GtkWidget *server_item;
-	GtkWidget *file_item;
-	GtkWidget *file_sendhost;
-	GtkWidget *file_quit;
+	GArray *terminals;
 	char **env;
-	char **servers;
-	int num_servers;
-	GtkWidget **items;
-	GtkWidget **terms;
+	int columns;
+	int timeout;
+	gboolean close_ended_sessions;
+	gboolean exit_on_all_closed;
 } MSSHWindow;
 
 typedef struct
@@ -44,8 +39,10 @@ typedef struct
 GType mssh_window_get_type(void) G_GNUC_CONST;
 
 GtkWidget* mssh_window_new(void);
-void mssh_window_new_session(MSSHWindow* window, char **env,
-	int num_servers, char **servers);
+void mssh_window_start_session(MSSHWindow* window, char **env, int nhosts,
+	char **servers);
+void mssh_window_relayout(MSSHWindow *window);
+void mssh_window_session_closed(MSSHTerminal *terminal, gpointer data);
 
 G_END_DECLS
 

+ 1 - 1
src/mssh.c

@@ -116,7 +116,7 @@ int main(int argc, char* argv[], char* env[])
 	g_signal_connect(G_OBJECT(window), "destroy",
 		G_CALLBACK(on_mssh_destroy), NULL);
 
-	mssh_window_new_session(MSSH_WINDOW(window), env, nhosts, hosts);
+	mssh_window_start_session(MSSH_WINDOW(window), env, nhosts, hosts);
 
 	gtk_widget_show_all(window);
 	gtk_main();