[Date Prev][Date Next] [Thread Prev][Thread Next] [Date Index] [Thread Index]

Re: [RFC] Add support for shells in the graphical installer



On Sat, Jul 19, 2008 at 01:47:17PM +0200, Frans Pop wrote:
> > > Why is the Continue button needed? Could an active <Go back> button
> > > be shown instead of the Continue that (after a warning) just kills
> > > the plug-in if it is clicked (the mouse is still active after all)?
> >
> > I need to think of a proper way to display a warning, but it sounds
> > like a better idea.
> 
> I had intended for the warning to be optional. I mainly feel that a 
> graphical alternative to typing "exit" would be useful, and certainly 
> more useful than a Continue button which only means "you have exited, 
> please confirm that you've already exited and we'll return to the 
> installer proper" (exaggerated).

Ok, the behaviour I have implemented today:
 * When the terminal process exits, the plugin exit as well.
 * The "Continue" button has been replaced with a "Go back" button.
 * When pressed, the "Go back" button displays a confirmation message,
   with "Cancel" (default) and "Continue" button.  Pressing the later
   exits.
 * Pressing Ctrl-Shift-Escape in the terminal is a shortcut result in
   the same behaviour as pressing the "Go back" button.

After some testing, it feels indeed better.

> You must have something different as in the normal rescue case it does 
> work correctly. I doubt including rescue in the initrd makes any 
> difference, although I have not checked that.

It really might make a difference.  I don't see how any changes that I
have done could affect the menu ordering!


On another topic, I have been able to fix the Home/End keys.  That was a
side effect while trying to see if I could remove the dependency on
ncurses completely.

VTE uses ncurses to read terminfo files, if they are not accessible it
falls back to its own internal termcap parser.  Good news is that I have
been able to completely remove the useless dependency on ncurses, as no
terminfo files were accessible in the installer anyway.

Fixing the Home/End keys was only a matter of tweaking the minimal
termcap file shipped in libvte9-udeb.

Current size numbers (with the last ttf-dejavu-mono-udeb):
 * initrd.gz:
     without:  13271k
        with:  13626k
           => +  355k

 * memory after boot:
     without:  49340k
        with:  49988k
           => +  648k
 
 * memory for the plugin:
       before the shell:  50424k
       during the shell:  51484k
                      => + 1060k

Last patchset attached.

Cheers,
-- 
Jérémy Bobbio                        .''`. 
lunar@debian.org                    : :Ⓐ  :  # apt-get install anarchism
                                    `. `'` 
                                      `-   
commit 220e2d3e7540dce4263ed8f6fda1f38157125e77
Author: Jérémy Bobbio <lunar@debian.org>
Date:   Sun Jul 6 20:54:58 2008 +0000

    Add cdebconf-terminal package
    
    cdebconf-terminal builds a plugin for the GTK+ frontend adding the
    possibility to display terminals as debconf questions.
    
    This will allow shells to be started inside the graphical installer like
    the other frontends.
    
    As the terminal widget is provided by VTE, the package depends on
    libvte9-udeb.  It also depends on ttf-dejavu-mono-udeb to display properly
    monospaced fonts.

diff --git a/packages/cdebconf-terminal/Makefile.in b/packages/cdebconf-terminal/Makefile.in
new file mode 100644
index 0000000..9d156b6
--- /dev/null
+++ b/packages/cdebconf-terminal/Makefile.in
@@ -0,0 +1,51 @@
+prefix=@prefix@
+etcdir=@sysconfdir@
+bindir=${prefix}/bin
+sbindir=${prefix}/sbin
+libdir=${prefix}/lib
+moddir=${libdir}/cdebconf/frontend
+sharedir=${prefix}/share/debconf
+mandir=${prefix}/share/man
+incdir=${prefix}/include/cdebconf
+
+PACKAGE=@PACKAGE@
+CC=@CC@
+CFLAGS=@CFLAGS@ -I.
+LDFLAGS=@LDFLAGS@
+GTK_CFLAGS=@GTK_CFLAGS@
+GTK_LIBS=@GTK_LIBS@
+
+CFLAGS += -funsigned-char -fstrict-aliasing -Wall -W -Werror -Wundef \
+	-Wwrite-strings -Wsign-compare -Wno-unused-parameter -Winit-self \
+	-Wpointer-arith -Wredundant-decls -Wno-format-zero-length \
+	-Wmissing-prototypes -Wmissing-format-attribute
+
+FRONTENDS=@FRONTENDS@
+PLUGIN_MODULES=$(addsuffix -plugin-$(PACKAGE).so,$(FRONTENDS))
+
+all: $(PLUGIN_MODULES)
+
+install: $(PLUGIN_MODULES)
+	for p in $(PLUGIN_MODULES); do \
+		install -m755 -d $(DESTDIR)/$(moddir)/$${p%%-*} ; \
+		install -m644 $$p $(DESTDIR)/$(moddir)/$${p%%-*}/$${p#*-} ; \
+	done
+
+gtk-plugin-$(PACKAGE).so: gtk-plugin-$(PACKAGE).opic
+	$(CC) $(LDFLAGS) -shared -o $@ $^ $(GTK_LIBS) -lvte
+
+clean:
+	rm -f $(PLUGIN_MODULES)
+	rm -f *.opic
+
+distclean: clean
+	rm -f config.log config.status
+	rm -f Makefile
+
+gtk-%.opic: gtk-%.c
+	@echo "Compiling $< to $@"
+	$(CC) $(CFLAGS) $(GTK_CFLAGS) -fPIC -o $@ -c $<
+
+%.opic: %.c
+	@echo "Compiling $< to $@"
+	$(CC) $(CFLAGS) -fPIC -o $@ -c $<
diff --git a/packages/cdebconf-terminal/configure.ac b/packages/cdebconf-terminal/configure.ac
new file mode 100644
index 0000000..2297f0f
--- /dev/null
+++ b/packages/cdebconf-terminal/configure.ac
@@ -0,0 +1,31 @@
+AC_INIT
+
+PACKAGE=terminal
+AC_DEFINE_UNQUOTED(PACKAGE,"$PACKAGE")
+
+AC_PROG_MAKE_SET
+AC_PROG_CC
+
+dnl Enable debugging?
+AC_ARG_WITH(debug,[  --without-debug         turn off debugging?])
+if test "$with_debug" == "yes"; then
+  AC_DEFINE(DODEBUG)
+  CFLAGS="$CFLAGS -g -D_DEBUG_"
+fi
+
+FRONTENDS=""
+
+PKG_CHECK_MODULES(GTK, [gtk+-directfb-2.0],
+ FRONTENDS="$FRONTENDS gtk",
+ echo "*** Cannot build GTK+ plugin ***")
+
+PKG_CHECK_MODULES(VTE, [vte])
+
+AC_SUBST(GTK_CFLAGS)
+AC_SUBST(GTK_LIBS)
+AC_SUBST(VTE_CFLAGS)
+AC_SUBST(FRONTENDS)
+AC_SUBST(PACKAGE)
+
+AC_OUTPUT(Makefile)
+
diff --git a/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.install b/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.install
new file mode 100644
index 0000000..3a7472e
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.install
@@ -0,0 +1 @@
+usr/lib/cdebconf/frontend/gtk
diff --git a/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.templates b/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.templates
new file mode 100644
index 0000000..4b9cf5b
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/cdebconf-gtk-terminal.templates
@@ -0,0 +1,7 @@
+Template: debconf/terminal/gtk/confirm-title
+Type: text
+_Description: Please confirm exit
+
+Template: debconf/terminal/gtk/confirm-message
+Type: text
+_Description: The terminal process is still running. If you press the "Continue" button, it will be killed before proceeding with the installation.
diff --git a/packages/cdebconf-terminal/debian/changelog b/packages/cdebconf-terminal/debian/changelog
new file mode 100644
index 0000000..51d6255
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/changelog
@@ -0,0 +1,5 @@
+cdebconf-terminal (0.1) UNRELEASED; urgency=low
+
+  * Initial release.
+
+ -- Jérémy Bobbio <lunar@debian.org>  Sun, 06 Jul 2008 20:49:52 +0000
diff --git a/packages/cdebconf-terminal/debian/compat b/packages/cdebconf-terminal/debian/compat
new file mode 100644
index 0000000..b8626c4
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/compat
@@ -0,0 +1 @@
+4
diff --git a/packages/cdebconf-terminal/debian/control b/packages/cdebconf-terminal/debian/control
new file mode 100644
index 0000000..217807a
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/control
@@ -0,0 +1,19 @@
+Source: cdebconf-terminal
+Priority: extra
+Section: debian-installer
+Maintainer: Debian Install System Team <debian-boot@lists.debian.org>
+Uploaders: Jérémy Bobbio <lunar@debian.org>
+Build-Depends: debhelper (>= 4.2), libdebconfclient0-dev (>= 0.130), libgtk-directfb-2.0-dev, libvte-dev (>> 0.16.14-1)
+Standards-Version: 3.8.0
+Vcs-Svn: svn://svn.debian.org/d-i/trunk/packages/cdebconf-terminal
+
+Package: cdebconf-gtk-terminal
+Architecture: any
+Section: debian-installer
+Depends: cdebconf-gtk-udeb, ttf-dejavu-mono-udeb, ${shlibs:Depends}
+Provides: cdebconf-entropy
+XC-Package-Type: udeb
+Description: cdebconf gtk plugin dislaying a terminal
+ cdebconf plugin to display a terminal inside the debian-installer graphical
+ frontend.
+
diff --git a/packages/cdebconf-terminal/debian/copyright b/packages/cdebconf-terminal/debian/copyright
new file mode 100644
index 0000000..48794a7
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/copyright
@@ -0,0 +1,30 @@
+cdebconf-entropy is Copyright 2008 Jérémy Bobbio <lunar@debian.org>
+
+Makefile.in, configure.ac and debian/rules were initially written by
+Tollef Fog Heen <tfheen@debian.org> for cdebconf-keystep. They were
+downloaded as part of cdebconf-keystep_0.3.tar.gz from
+http://ubuntu.cn99.com/ubuntu/pool/main/c/cdebconf-keystep/cdebconf-keystep_0.3.tar.gz
+
+License:
+
+Redistribution and use in source and binary forms, with or without
+modification, are permitted provided that the following conditions
+are met:
+1. Redistributions of source code must retain the above copyright
+   notice, this list of conditions and the following disclaimer.
+2. Redistributions in binary form must reproduce the above copyright
+   notice, this list of conditions and the following disclaimer in the
+   documentation and/or other materials provided with the distribution.
+
+THIS SOFTWARE IS PROVIDED BY THE AUTHORS AND CONTRIBUTORS ``AS IS'' AND
+ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
+IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
+ARE DISCLAIMED.  IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE
+FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
+OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
+HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
+LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
+OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+SUCH DAMAGE.
+
diff --git a/packages/cdebconf-terminal/debian/po/POTFILES.in b/packages/cdebconf-terminal/debian/po/POTFILES.in
new file mode 100644
index 0000000..a7b5184
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/po/POTFILES.in
@@ -0,0 +1 @@
+[type: gettext/rfc822deb] cdebconf-gtk-terminal.templates
diff --git a/packages/cdebconf-terminal/debian/po/templates.pot b/packages/cdebconf-terminal/debian/po/templates.pot
new file mode 100644
index 0000000..50e657f
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/po/templates.pot
@@ -0,0 +1,23 @@
+# SOME DESCRIPTIVE TITLE.
+# Copyright (C) YEAR THE PACKAGE'S COPYRIGHT HOLDER
+# This file is distributed under the same license as the PACKAGE package.
+# FIRST AUTHOR <EMAIL@ADDRESS>, YEAR.
+#
+#, fuzzy
+msgid ""
+msgstr ""
+"Project-Id-Version: PACKAGE VERSION\n"
+"Report-Msgid-Bugs-To: cdebconf-terminal@packages.debian.org\n"
+"POT-Creation-Date: 2008-07-08 13:02+0000\n"
+"PO-Revision-Date: YEAR-MO-DA HO:MI+ZONE\n"
+"Last-Translator: FULL NAME <EMAIL@ADDRESS>\n"
+"Language-Team: LANGUAGE <LL@li.org>\n"
+"MIME-Version: 1.0\n"
+"Content-Type: text/plain; charset=CHARSET\n"
+"Content-Transfer-Encoding: 8bit\n"
+
+#. Type: text
+#. Description
+#: ../cdebconf-gtk-terminal.templates:1001
+msgid "Shell process has exited."
+msgstr ""
diff --git a/packages/cdebconf-terminal/debian/rules b/packages/cdebconf-terminal/debian/rules
new file mode 100755
index 0000000..f7f6957
--- /dev/null
+++ b/packages/cdebconf-terminal/debian/rules
@@ -0,0 +1,78 @@
+#! /usr/bin/make -f
+# -*- makefile -*-
+
+# Uncomment this to turn on verbose mode.
+#export DH_VERBOSE=1
+
+DEB_HOST_GNU_TYPE   ?= $(shell dpkg-architecture -qDEB_HOST_GNU_TYPE)
+DEB_BUILD_GNU_TYPE  ?= $(shell dpkg-architecture -qDEB_BUILD_GNU_TYPE)
+
+CFLAGS = -Wall -g
+
+ifneq (,$(findstring noopt,$(DEB_BUILD_OPTIONS)))
+	CFLAGS += -O0
+else
+	CFLAGS += -O2
+endif
+
+ifeq ($(DEB_BUILD_GNU_TYPE), $(DEB_HOST_GNU_TYPE))
+	confflags += --build $(DEB_HOST_GNU_TYPE)
+else
+	confflags += --build $(DEB_BUILD_GNU_TYPE) --host $(DEB_HOST_GNU_TYPE)
+endif
+
+config.status: configure
+	dh_testdir
+	CFLAGS="$(CFLAGS)" LDFLAGS="-Wl,-z,syms" ./configure $(confflags) --prefix=/usr
+
+build: build-stamp
+build-stamp:  config.status
+	dh_testdir
+	$(MAKE)
+	touch build-stamp
+
+clean:
+	dh_testdir
+	dh_testroot
+	rm -f build-stamp
+
+	[ ! -f Makefile ] || $(MAKE) distclean
+ifneq "$(wildcard /usr/share/misc/config.sub)" ""
+	cp -f /usr/share/misc/config.sub config.sub
+endif
+ifneq "$(wildcard /usr/share/misc/config.guess)" ""
+	cp -f /usr/share/misc/config.guess config.guess
+endif
+	dh_clean
+
+install: build
+	dh_testdir
+	dh_testroot
+	dh_clean -k
+	dh_installdirs
+	$(MAKE) install DESTDIR=$(CURDIR)/debian/tmp
+
+# Build architecture-independent files here.
+binary-indep: build install
+# We have nothing to do by default.
+
+# Build architecture-dependent files here.
+binary-arch: build install
+	dh_testdir
+	dh_testroot
+	dh_installchangelogs
+	dh_installdocs
+	dh_installdebconf
+	dh_install --sourcedir=debian/tmp
+	dh_link
+	dh_strip
+	dh_compress
+	dh_fixperms
+	dh_installdeb
+	dh_shlibdeps
+	dh_gencontrol
+	dh_md5sums
+	dh_builddeb
+
+binary: binary-indep binary-arch
+.PHONY: build clean binary-indep binary-arch binary install
diff --git a/packages/cdebconf-terminal/gtk-plugin-terminal.c b/packages/cdebconf-terminal/gtk-plugin-terminal.c
new file mode 100644
index 0000000..3900cc1
--- /dev/null
+++ b/packages/cdebconf-terminal/gtk-plugin-terminal.c
@@ -0,0 +1,398 @@
+/*
+ * cdebconf gtk plugin to display a terminal
+ *
+ * Copyright © 2008 Jérémy Bobbio <lunar@debian.org>
+ * See debian/copyright for license.
+ *
+ */
+
+#include <cdebconf/frontend.h>
+#include <cdebconf/cdebconf_gtk.h>
+
+#include <gtk/gtk.h>
+#include <gdk/gdkkeysyms.h>
+#include <vte/vte.h>
+#include <string.h>
+
+extern char ** environ;
+
+#define DEFAULT_COMMAND_LINE "/bin/sh"
+
+/* Here's the plugin! */
+int cdebconf_gtk_handler_terminal(struct frontend * fe,
+                                  struct question * question,
+                                  GtkWidget * question_box);
+
+struct terminal {
+    struct frontend * fe;
+    GtkWidget * goback_button;
+    VteTerminal * terminal;
+    char * command;
+    char ** argv;
+    char ** environ;
+};
+
+static void destroy_terminal(struct terminal * terminal_data)
+{
+    if (NULL != terminal_data->command) {
+        g_free(terminal_data->command);
+    }
+    if (NULL != terminal_data->argv) {
+        g_strfreev(terminal_data->argv);
+    }
+    if (NULL != terminal_data->environ) {
+        g_strfreev(terminal_data->environ);
+    }
+    if (NULL != terminal_data->terminal) {
+        g_object_unref(G_OBJECT(terminal_data->terminal));
+    }
+    if (NULL != terminal_data->goback_button) {
+        g_object_unref(G_OBJECT(terminal_data->goback_button));
+    }
+    g_free(terminal_data);
+}
+
+static void cleanup(GtkWidget * widget, struct terminal * terminal_data)
+{
+    destroy_terminal(terminal_data);
+}
+
+static void handle_child_exit(GtkWidget * button,
+                              struct terminal * terminal_data)
+{
+    cdebconf_gtk_set_answer_ok(terminal_data->fe);
+}
+
+static struct terminal * init_terminal(struct frontend * fe,
+                                       struct question * question)
+{
+    struct terminal * terminal_data;
+
+    if (NULL == (terminal_data = g_malloc0(sizeof (struct terminal)))) {
+        g_critical("g_malloc0 failed.");
+        return NULL;
+    }
+    terminal_data->fe = fe;
+
+    return terminal_data;
+}
+
+static gboolean init_command(struct terminal * terminal_data,
+                             struct question * question)
+{
+    const char * command_line;
+
+    command_line = question_get_variable(question, "COMMAND_LINE");
+    if (NULL == command_line) {
+        command_line = DEFAULT_COMMAND_LINE;
+    }
+    terminal_data->argv = g_strsplit_set(
+        command_line, " \t\n" /* default IFS */,
+        4096 /* max number of arguments */
+        /* XXX: replace with the correct system macro */);
+    if (NULL == terminal_data->argv || NULL == terminal_data->argv[0]) {
+        g_critical("g_strsplit_set failed.");
+        return FALSE;
+    }
+    terminal_data->command = g_strdup(terminal_data->argv[0]);
+    if (NULL == terminal_data->command) {
+        g_critical("g_strplit_set failed.");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+/* XXX: mostly copied from ui.c */
+static GtkWidget * create_dialog_action_box(struct frontend * fe,
+                                            GtkWidget * dialog)
+{
+    GtkWidget * action_box;
+    GtkWidget * cancel_button;
+    GtkWidget * continue_button;
+    char * label;
+
+    /* check NULL! */
+    action_box = gtk_hbutton_box_new();
+    gtk_button_box_set_layout(GTK_BUTTON_BOX(action_box), GTK_BUTTONBOX_END);
+
+    label = cdebconf_gtk_get_text(fe, "debconf/button-cancel", "Cancel");
+    /* check NULL! */
+    cancel_button = gtk_button_new_with_label(label);
+    g_free(label);
+
+    GTK_WIDGET_SET_FLAGS(cancel_button, GTK_CAN_DEFAULT);
+    g_signal_connect_swapped(G_OBJECT(cancel_button), "clicked",
+                             G_CALLBACK(gtk_widget_destroy), dialog);
+    g_signal_connect(G_OBJECT(cancel_button), "realize",
+                     G_CALLBACK(gtk_widget_grab_focus), NULL /* no data */);
+
+    label = cdebconf_gtk_get_text(fe, "debconf/button-continue", "Continue");
+    continue_button = gtk_button_new_with_label(label);
+    g_free(label);
+
+    g_signal_connect_swapped(G_OBJECT(continue_button), "clicked",
+                             G_CALLBACK(cdebconf_gtk_set_answer_ok), fe);
+    g_signal_connect_swapped(G_OBJECT(continue_button), "clicked",
+                             G_CALLBACK(gtk_widget_destroy), dialog);
+
+    gtk_box_pack_start(GTK_BOX(action_box), cancel_button,
+                       TRUE /* expand */, TRUE /* fill */, DEFAULT_PADDING);
+    gtk_box_pack_start(GTK_BOX(action_box), continue_button,
+                       TRUE /* expand */, TRUE /* fill */, DEFAULT_PADDING);
+
+    gtk_button_box_set_child_secondary(GTK_BUTTON_BOX(action_box),
+                                       cancel_button, TRUE /* secondary */);
+    return action_box;
+}
+
+/* XXX: copied from ui.c */
+static GtkWidget * create_dialog_title_label(const gchar * title)
+{
+    GtkWidget * label;
+    gchar * markup;
+
+    /* check NULL! */
+    label = gtk_label_new(NULL /* no text */);
+    gtk_misc_set_alignment(GTK_MISC(label), 0 /* left aligned */,
+                           0 /* top aligned */);
+
+    markup = g_strdup_printf("<b>%s</b>", title);
+    gtk_label_set_markup(GTK_LABEL(label), markup);
+    g_free(markup);
+
+    return label;
+}
+
+/* XXX: mostly copied from cdebconf_gtk_run_message_dialog() */
+static gboolean run_confirm_dialog(struct terminal * terminal_data)
+{
+    GtkWidget * parent;
+    GtkWidget * dialog;
+    GtkWidget * vbox;
+    GtkWidget * label;
+    GtkWidget * frame;
+    gchar * text;
+
+    parent = gtk_widget_get_ancestor(terminal_data->goback_button,
+                                     GTK_TYPE_WINDOW);
+
+    dialog = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+    gtk_window_set_transient_for(GTK_WINDOW(dialog), GTK_WINDOW(parent));
+    gtk_window_set_modal(GTK_WINDOW(dialog), TRUE /* modal */);
+    gtk_window_set_resizable(GTK_WINDOW(dialog), FALSE /* not resizale */);
+    gtk_window_set_position(GTK_WINDOW(dialog), GTK_WIN_POS_CENTER);
+    gtk_window_set_decorated(GTK_WINDOW(dialog), FALSE /* no decoration */);
+    gtk_container_set_border_width(GTK_CONTAINER(dialog), 0 /* no border */);
+
+    vbox = gtk_vbox_new(FALSE /* don't make children equal */,
+                        DEFAULT_PADDING);
+    text = cdebconf_gtk_get_text(
+        terminal_data->fe, "debconf/terminal/gtk/confirm-title",
+        "Please confirm exit");
+    gtk_box_pack_start(GTK_BOX(vbox), create_dialog_title_label(text),
+                       FALSE /* don't expand */, FALSE /* don't fille */,
+                       0 /* no padding */);
+    g_free(text);
+    text = cdebconf_gtk_get_text(
+        terminal_data->fe, "debconf/terminal/gtk/confirm-message",
+        "The terminal process is still running. If you press the \"Continue\" "
+        "button, it will be killed before proceeding with the installation.");
+    label = gtk_label_new(text);
+    gtk_label_set_line_wrap(GTK_LABEL(label), TRUE);
+    g_free(text);
+    gtk_box_pack_start(GTK_BOX(vbox), label,
+                       FALSE /* don't expand */, FALSE /* don't fill */,
+                       DEFAULT_PADDING);
+    gtk_box_pack_start(GTK_BOX(vbox), gtk_hseparator_new(),
+                       FALSE /* don't expand */, FALSE /* don't fill */,
+                       0 /* no padding */);
+    gtk_box_pack_start(GTK_BOX(vbox),
+                       create_dialog_action_box(terminal_data->fe, dialog),
+                       FALSE /* don't expand */, FALSE /* don't fill */,
+                       0 /* no padding */);
+    cdebconf_gtk_center_widget(&vbox, DEFAULT_PADDING, DEFAULT_PADDING);
+
+    frame = gtk_frame_new(NULL /* no label */);
+    gtk_frame_set_shadow_type(GTK_FRAME(frame), GTK_SHADOW_OUT);
+    gtk_container_add(GTK_CONTAINER(frame), vbox);
+    gtk_container_add(GTK_CONTAINER(dialog), frame);
+
+    gtk_widget_show_all(dialog);
+    return TRUE;
+}
+
+static GtkWidget * create_goback_button(struct terminal * terminal_data)
+{
+    GtkWidget * button;
+    char * label;
+
+    label = cdebconf_gtk_get_text(terminal_data->fe, "debconf/button-goback", "Go Back");
+    /* XXX: check NULL! */
+    button = gtk_button_new_with_label(label);
+    g_free(label);
+
+    g_signal_connect_swapped(G_OBJECT(button), "clicked",
+                             G_CALLBACK(run_confirm_dialog), terminal_data);
+
+    cdebconf_gtk_add_button(terminal_data->fe, button);
+
+    return button;
+}
+
+static gboolean handle_goback_key(GtkWidget * widget, GdkEventKey * key,
+                                  struct terminal * terminal_data)
+{
+    if (GDK_Escape == key->keyval &&
+        (GDK_SHIFT_MASK | GDK_CONTROL_MASK) ==
+        (key->state & (GDK_SHIFT_MASK | GDK_CONTROL_MASK))) {
+        run_confirm_dialog(terminal_data);
+        return TRUE;
+    }
+    return FALSE;
+}
+
+static GtkWidget * create_widgets(struct terminal * terminal_data)
+{
+    GtkWidget * hbox;
+    VteTerminal * terminal;
+    GtkWidget * scrollbar;
+    GtkWidget * goback_button;
+
+    goback_button = create_goback_button(terminal_data);
+    if (NULL == goback_button) {
+        g_critical("create_goback_button failed.");
+        return NULL;
+    }
+    g_object_ref(G_OBJECT(goback_button));
+    terminal_data->goback_button = goback_button;
+
+    g_setenv("VTE_BACKEND", "pango", TRUE /* overwrite */);
+    if (NULL == (terminal = VTE_TERMINAL(vte_terminal_new()))) {
+        g_critical("vte_terminal_new failed.");
+        return NULL;
+    }
+    vte_terminal_set_font_from_string(terminal, "monospace");
+    g_signal_connect(terminal, "destroy", G_CALLBACK(cleanup), terminal_data);
+    g_signal_connect(terminal, "child-exited", G_CALLBACK(handle_child_exit),
+                     terminal_data);
+    g_signal_connect(terminal, "key_press_event", G_CALLBACK(handle_goback_key),
+                     terminal_data);
+    g_signal_connect(terminal, "realize", G_CALLBACK(gtk_widget_grab_focus),
+                     NULL);
+    g_object_ref(terminal);
+    terminal_data->terminal = terminal;
+
+    hbox = gtk_hbox_new(FALSE /* not homogeneous */, 0 /* no spacing */);
+    if (NULL == hbox) {
+        g_critical("gtk_hbox_new failed.");
+        return NULL;
+    }
+    gtk_box_pack_start(GTK_BOX(hbox), GTK_WIDGET(terminal), TRUE /* expand */,
+                       TRUE /* fill */, 0 /* no padding */);
+
+    scrollbar = gtk_vscrollbar_new(terminal->adjustment);
+    if (NULL == scrollbar) {
+        g_critical("gtk_vscrollbar_new failed.");
+        return NULL;
+    }
+    gtk_box_pack_start(GTK_BOX(hbox), scrollbar, FALSE /* don't expand */,
+                       FALSE /* don't fill */, 0 /* no padding */);
+    return hbox;
+}
+
+static void set_nothing(struct question * question, void * dummy)
+{
+    /* terminal questions do not put anything in the database */
+    return;
+}
+
+static gboolean prepare_environ(struct terminal * terminal_data)
+{
+    guint orig_index;
+    guint new_index;
+    const char * src;
+
+    terminal_data->environ = g_new0(char *, g_strv_length(environ) + 1);
+    if (NULL == terminal_data->environ) {
+        g_critical("g_malloc0 failed.");
+        return FALSE;
+    }
+    new_index = 0;
+    for (orig_index = 0; NULL != environ[orig_index]; orig_index++) {
+        if (g_str_has_prefix(environ[orig_index], "DEBIAN_HAS_FRONTEND=")) {
+            src = "DEBIAN_HAS_FRONTEND=";
+        } else if (g_str_has_prefix(environ[orig_index], "DEBIAN_FRONTEND=")) {
+            src = "DEBIAN_FRONTEND=newt";
+        } else {
+            src = environ[orig_index];
+        }
+        if (NULL == (terminal_data->environ[new_index] = g_strdup(src))) {
+            g_critical("g_strdup failed.");
+            return FALSE;
+        }
+        new_index++;
+    }
+    return TRUE;
+}
+
+static gboolean start_command(struct terminal * terminal_data)
+{
+    pid_t pid;
+
+    pid = vte_terminal_fork_command(
+        terminal_data->terminal, terminal_data->command,
+        terminal_data->argv, terminal_data->environ, "/",
+        FALSE /* no lastlog */, FALSE /* no utmp */, FALSE /* no wtmp */);
+    if (0 == pid) {
+        g_critical("vte_terminal_fork_command failed.");
+        return FALSE;
+    }
+    return TRUE;
+}
+
+int cdebconf_gtk_handler_terminal(struct frontend * fe,
+                                  struct question * question,
+                                  GtkWidget * question_box)
+{
+    struct terminal * terminal_data;
+    GtkWidget * widget;
+
+    if (!IS_QUESTION_SINGLE(question)) {
+        g_critical("entropy plugin does not work alongside other questions.");
+        return DC_NOTOK;
+    }
+    if (NULL == (terminal_data = init_terminal(fe, question))) {
+        g_critical("init_terminal failed.");
+        return DC_NOTOK;
+    }
+    if (NULL == (widget = create_widgets(terminal_data))) {
+        g_critical("create_widgets failed.");
+        goto failed;
+    }
+    if (!init_command(terminal_data, question)) {
+        g_critical("init_command failed.");
+        goto failed;
+    }
+    if (!prepare_environ(terminal_data)) {
+        g_critical("prepare_environ failed.");
+        goto failed;
+    }
+    if (!start_command(terminal_data)) {
+        g_critical("start_command failed.");
+        goto failed;
+    }
+
+    cdebconf_gtk_add_common_layout(fe, question, question_box, widget);
+
+    cdebconf_gtk_register_setter(fe, SETTER_FUNCTION(set_nothing), question,
+                                 NULL);
+
+    return DC_OK;
+
+failed:
+    destroy_terminal(terminal_data);
+    return DC_NOTOK;
+}
+
+/* vim: et sw=4 si
+ */

commit a345a27b258413a309e57d5986c9704c00b9f6fc
Author: Jérémy Bobbio <lunar@debian.org>
Date:   Sun Jul 6 21:42:28 2008 +0000

    Add tests in cdebconf for the terminal plugin

diff --git a/packages/cdebconf/debian/changelog b/packages/cdebconf/debian/changelog
index e11639d..8c72e99 100644
--- a/packages/cdebconf/debian/changelog
+++ b/packages/cdebconf/debian/changelog
@@ -1,8 +1,12 @@
 cdebconf (0.133) UNRELEASED; urgency=low
 
+  [ Frans Pop ]
   * Additional tuning of the dark theme in the newt frontend. Patch from
     Samuel Thibault.
 
+  [ Jérémy Bobbio ]
+  * Add tests for the new terminal plugin.
+
  -- Frans Pop <fjp@debian.org>  Fri, 18 Jul 2008 08:03:07 +0200
 
 cdebconf (0.132) unstable; urgency=low
diff --git a/packages/cdebconf/src/test/terminal.config b/packages/cdebconf/src/test/terminal.config
new file mode 100755
index 0000000..42cb83d
--- /dev/null
+++ b/packages/cdebconf/src/test/terminal.config
@@ -0,0 +1,17 @@
+#!/bin/sh
+
+. ../client/confmodule
+
+db_capb
+echo "capb: $RET"
+if ! echo "$RET" | grep -w plugin-terminal; then
+        echo "terminal plugin not available"
+        exit 1
+fi
+
+db_subst test/terminal COMMAND_LINE /bin/sh -x
+db_fset test/terminal seen false
+db_input high test/terminal
+db_go
+
+echo "$RET"
diff --git a/packages/cdebconf/src/test/terminal.templates b/packages/cdebconf/src/test/terminal.templates
new file mode 100644
index 0000000..0330cb5
--- /dev/null
+++ b/packages/cdebconf/src/test/terminal.templates
@@ -0,0 +1,7 @@
+Template: test/terminal
+Type: terminal
+Description: Feel free to rescue your system.
+
+Template: debconf/terminal/gtk/child-exit
+Type: text
+Description: Shell process has exited.

commit 0524d7023be4b644b17ffacb24bcba0dec9d9530
Author: Jérémy Bobbio <lunar@debian.org>
Date:   Sun Jul 6 23:15:13 2008 +0000

    Add start-shell in di-utils-shell
    
    di-utils-shell now ships a new script, start-shell, which will either use
    debconf-disconnect or the new cdebconf terminal plugin.
    
    di-utils-shell.postinst has been updated to use this new script.

diff --git a/packages/debian-installer-utils/debian/changelog b/packages/debian-installer-utils/debian/changelog
index 3bafa81..aa353d9 100644
--- a/packages/debian-installer-utils/debian/changelog
+++ b/packages/debian-installer-utils/debian/changelog
@@ -1,3 +1,13 @@
+debian-installer-utils (1.62) UNRELEASED; urgency=low
+
+  [ Jérémy Bobbio ]
+  * Ship start-shell in di-utils-shell.  It allows a shell to be started
+    either with debconf-disconnect or with the terminal plugin for the GTK+
+    frontend.
+  * Use start-shell in di-utils-shell.postinst.
+
+ -- Jérémy Bobbio <lunar@debian.org>  Fri, 18 Jul 2008 22:25:03 +0000
+
 debian-installer-utils (1.61) unstable; urgency=low
 
   * update-dev: remove obsolete fallbacks to udevtrigger and udevsettle.
diff --git a/packages/debian-installer-utils/debian/di-utils-shell.install b/packages/debian-installer-utils/debian/di-utils-shell.install
new file mode 100644
index 0000000..fa32586
--- /dev/null
+++ b/packages/debian-installer-utils/debian/di-utils-shell.install
@@ -0,0 +1 @@
+start-shell bin
diff --git a/packages/debian-installer-utils/debian/di-utils-shell.isinstallable b/packages/debian-installer-utils/debian/di-utils-shell.isinstallable
deleted file mode 100755
index 52cf82b..0000000
--- a/packages/debian-installer-utils/debian/di-utils-shell.isinstallable
+++ /dev/null
@@ -1,5 +0,0 @@
-#!/bin/sh
-if [ "$DEBIAN_FRONTEND" = gtk ]; then
-	exit 1
-fi
-exit 0
diff --git a/packages/debian-installer-utils/debian/di-utils-shell.postinst b/packages/debian-installer-utils/debian/di-utils-shell.postinst
index 6fbfad6..203bab7 100644
--- a/packages/debian-installer-utils/debian/di-utils-shell.postinst
+++ b/packages/debian-installer-utils/debian/di-utils-shell.postinst
@@ -6,4 +6,4 @@ db_capb backup
 db_input high di-utils-shell/do-shell
 db_go || exit 10
 
-debconf-disconnect /bin/sh || true
+start-shell di-utils-shell/do-shell /bin/sh || true
diff --git a/packages/debian-installer-utils/debian/di-utils-shell.templates b/packages/debian-installer-utils/debian/di-utils-shell.templates
index d84a942..fc05648 100644
--- a/packages/debian-installer-utils/debian/di-utils-shell.templates
+++ b/packages/debian-installer-utils/debian/di-utils-shell.templates
@@ -11,6 +11,33 @@ _Description: Interactive shell
  .
  Use the "exit" command to return to the installation menu.
 
+Template: di-utils-shell/shell-plugin
+Type: terminal
+Description: ${TITLE}
+
+Template: di-utils-shell/shell-plugin-default-title
+Type: text
+# :sl2:
+_Description: Interactive shell
+
+Template: di-utils-shell/terminal-plugin-unavailable
+Type: error
+# :sl2:
+_Description: Terminal plugin not available
+ This build of the debian-installer requires the terminal plugin in
+ order to display a shell. Unfortunately, this plugin is currently
+ unavailable.
+ .
+ It should be available after reaching the "Loading additional components"
+ installation step.
+ .
+ ${WORKAROUND}
+
+Template: di-utils-shell/workaround-gtk
+Type: text
+# :sl2:
+_Description: Alternatively, you can open a shell by pressing Ctrl+Alt+F2. Use Alt+F5 to get back to the installer.
+
 Template: debian-installer/di-utils-shell/title
 Type: text
 #  Main menu item
diff --git a/packages/debian-installer-utils/debian/rules b/packages/debian-installer-utils/debian/rules
index 49cda69..70ed8f2 100755
--- a/packages/debian-installer-utils/debian/rules
+++ b/packages/debian-installer-utils/debian/rules
@@ -22,6 +22,7 @@ binary-indep: build
 	dh_testdir
 	dh_testroot
 	dh_clean -k
+	dh_install -i
 	dh_installdebconf -i
 	dh_compress -i
 	dh_fixperms -i
@@ -31,7 +32,6 @@ binary-indep: build
 		cp -pL $$file debian/di-utils-terminfo/$$file; \
 		chmod 644 debian/di-utils-terminfo/$$file; \
 	done
-	cp debian/di-utils-shell.isinstallable debian/di-utils-shell/DEBIAN/isinstallable
 	dh_installdeb -i
 	dh_gencontrol -i
 	dh_builddeb -i
diff --git a/packages/debian-installer-utils/start-shell b/packages/debian-installer-utils/start-shell
new file mode 100755
index 0000000..0ef2dac
--- /dev/null
+++ b/packages/debian-installer-utils/start-shell
@@ -0,0 +1,56 @@
+#! /bin/sh -e
+
+. /usr/share/debconf/confmodule
+
+TITLE_TEMPLATE="$1"
+shift
+COMMAND_LINE="$@"
+
+have_terminal_plugin () {
+	db_capb
+	set -- $RET
+	for cap; do
+		if [ "$cap" = plugin-terminal ]; then
+			return 0
+		fi
+	done
+	return 1
+}
+
+show_unavailable_message () {
+	local workaround_template
+
+	workaround_template=di-utils-shell/workaround-$DEBIAN_FRONTEND
+	if ! db_metaget $workaround_template description; then
+		RET=""
+	fi
+	db_subst di-utils-shell/terminal-plugin-unavailable WORKAROUND "$RET"
+	db_fset di-utils-shell/terminal-plugin-unavailable seen false
+	db_input critical di-utils-shell/terminal-plugin-unavailable
+	db_go || true
+	db_capb backup
+}
+
+case $DEBIAN_FRONTEND in
+    text|newt)
+	debconf-disconnect $COMMAND_LINE || true
+	;;
+    *)
+	if ! have_terminal_plugin; then
+		anna-install cdebconf-$DEBIAN_FRONTEND-terminal
+		if ! have_terminal_plugin; then
+			show_unavailable_message
+			exit 1
+		fi
+	fi
+	if ! db_metaget $TITLE_TEMPLATE description; then
+		db_metaget di-utils-shell/shell-plugin-default-title description
+	fi
+	db_subst di-utils-shell/shell-plugin TITLE "$RET"
+	db_subst di-utils-shell/shell-plugin COMMAND_LINE $COMMAND_LINE
+	db_fset di-utils-shell/shell-plugin seen false
+	db_input critical di-utils-shell/shell-plugin
+	db_go || true
+	db_capb backup
+	;;
+esac

commit 51c30128e559eab9a5b6f5619d61cd81714cec43
Author: Jérémy Bobbio <lunar@debian.org>
Date:   Sun Jul 6 22:03:19 2008 +0000

    Use start-shell in rescue-mode
    
    rescue-mode now uses start-shell from di-utils-shell (>= 1.61).  This
    means that shells are now available in all installer frontends.

diff --git a/packages/rescue/debian/changelog b/packages/rescue/debian/changelog
index d07080c..5811c91 100644
--- a/packages/rescue/debian/changelog
+++ b/packages/rescue/debian/changelog
@@ -1,8 +1,13 @@
 rescue (1.16) UNRELEASED; urgency=low
 
+  [ Colin Watson ]
   * Explain the situation and offer a reduced rescue menu if no partitions
     were detected (closes: #318194, LP: #219012).
 
+  [ Jérémy Bobbio ]
+  * Use start-shell from di-utils-shell (>= 1.61) to start rescue shells.
+    This enables using shells in the graphical installer.
+
  -- Colin Watson <cjwatson@debian.org>  Sat, 12 Jul 2008 08:20:17 +0100
 
 rescue (1.15) unstable; urgency=low
diff --git a/packages/rescue/debian/control b/packages/rescue/debian/control
index 2ce24c2..af8e617 100644
--- a/packages/rescue/debian/control
+++ b/packages/rescue/debian/control
@@ -10,7 +10,7 @@ Package: rescue-check
 Architecture: all
 Priority: standard
 XC-Package-Type: udeb
-Depends: cdebconf-udeb (>= 0.75), main-menu (>= 1.03), di-utils (>= 1.18)
+Depends: cdebconf-udeb (>= 0.75), main-menu (>= 1.03), di-utils (>= 1.18), di-utils-shell (>= 1.61)
 Description: enter d-i rescue mode if requested
 
 Package: rescue-mode
diff --git a/packages/rescue/debian/rescue-mode.templates b/packages/rescue/debian/rescue-mode.templates
index e28706e..4b523b7 100644
--- a/packages/rescue/debian/rescue-mode.templates
+++ b/packages/rescue/debian/rescue-mode.templates
@@ -96,6 +96,11 @@ Type: error
 _Description: No shell found in /target
  No usable shell was found on your root file system (${DEVICE}).
 
+Template: rescue/shell/title
+Type: text
+# :sl2:
+_Description: Interactive shell on ${DEVICE}
+
 Template: rescue/initrd-shell/intro
 Type: text
 # :sl2:
@@ -114,6 +119,11 @@ _Description: Executing a shell
  Since the installer could not find any partitions, no file systems have
  been mounted for you.
 
+Template: rescue/initrd-shell/title
+Type: text
+# :sl2:
+_Description: Interactive shell in the installer environment
+
 Template: rescue/passphrase
 Type: password
 # :sl2:
diff --git a/packages/rescue/rescue.d/_numbers b/packages/rescue/rescue.d/_numbers
index 12f5ca9..f412e57 100644
--- a/packages/rescue/rescue.d/_numbers
+++ b/packages/rescue/rescue.d/_numbers
@@ -1,7 +1,6 @@
 10 shell
 10 shell.tst
 15 initrd-shell
-15 initrd-shell.tst
 98 change-root
 98 change-root.tst
 99 reboot
diff --git a/packages/rescue/rescue.d/initrd-shell b/packages/rescue/rescue.d/initrd-shell
index 545585a..fe72c2f 100755
--- a/packages/rescue/rescue.d/initrd-shell
+++ b/packages/rescue/rescue.d/initrd-shell
@@ -1,2 +1,2 @@
 #! /bin/sh
-debconf-disconnect /bin/sh -i
+start-shell rescue/initrd-shell/title /bin/sh -i
diff --git a/packages/rescue/rescue.d/initrd-shell.tst b/packages/rescue/rescue.d/initrd-shell.tst
deleted file mode 100755
index 46269b2..0000000
--- a/packages/rescue/rescue.d/initrd-shell.tst
+++ /dev/null
@@ -1,2 +0,0 @@
-#! /bin/sh -e
-[ "$DEBIAN_FRONTEND" != gtk ]
diff --git a/packages/rescue/rescue.d/shell b/packages/rescue/rescue.d/shell
index af125cf..ae67c82 100755
--- a/packages/rescue/rescue.d/shell
+++ b/packages/rescue/rescue.d/shell
@@ -7,7 +7,8 @@ chroot_has () {
 }
 
 chroot_run () {
-	debconf-disconnect chroot /target "$@"
+	db_subst rescue/shell/title DEVICE "$RESCUE_ROOTDEV"
+	start-shell rescue/shell/title chroot /target "$@"
 }
 
 # Work out a sensible $PATH with respect to /target.
diff --git a/packages/rescue/rescue.d/shell.tst b/packages/rescue/rescue.d/shell.tst
index e927779..85c1df9 100755
--- a/packages/rescue/rescue.d/shell.tst
+++ b/packages/rescue/rescue.d/shell.tst
@@ -1,2 +1,2 @@
 #! /bin/sh -e
-[ "$DEBIAN_FRONTEND" != gtk ] && [ "$RESCUE_ROOTDEV" ]
+[ "$RESCUE_ROOTDEV" ]

Attachment: signature.asc
Description: Digital signature


Reply to: