Michael Cardenas wrote:

>Hello. Talking with moshez and walters on #debian-boot last night, I
>discovered that the cdebconf gtk frontend is still on the todo list.
>
>I'll be out of town this weekend, away from net access, and I'm
>looking for a project to work on.
>
>So, I began a gtk frontend for cdebconf. The beginning is attached. It
>sort of compiles with this line:
>
>gcc -Wall -g gtk.c -o gtk.so `pkg-config --cflags gtk+-2.0`
>\`pkg-config --libs gtk+-2.0`
>-I../../.. -I../../../../debian/build/src
>
>well, it compiles but doesn't link with the debconf stuff. I'll work on that.
>  
>

Since noone objected or suggested otherwise, I am continuing to add a 
gtk frontend to cdebconf.

Attached is another patch. The boolean handler is much improved and I 
added a multiselect handler.

This is early stuff, I still haven't tested it with the debconf tests yet.

michael

-- 
michael cardenas | lead software engineer | lindows.com | hyperpoem.net

"Be the change you want to see in the world"
-Mahatma Gandhi


diff -urN frontend.orig/gtk/CVS/Entries frontend/gtk/CVS/Entries
--- frontend.orig/gtk/CVS/Entries       Wed Dec 31 16:00:00 1969
+++ frontend/gtk/CVS/Entries    Wed Aug 28 23:24:55 2002
@@ -0,0 +1,3 @@
+/Makefile/1.4/Tue Jul  9 05:25:05 2002//
+/text.c/1.13/Wed Aug  7 16:19:51 2002//
+D
diff -urN frontend.orig/gtk/CVS/Repository frontend/gtk/CVS/Repository
--- frontend.orig/gtk/CVS/Repository    Wed Dec 31 16:00:00 1969
+++ frontend/gtk/CVS/Repository Wed Aug 28 23:24:55 2002
@@ -0,0 +1 @@
+debian-installer/tools/cdebconf/src/modules/frontend/text
diff -urN frontend.orig/gtk/CVS/Root frontend/gtk/CVS/Root
--- frontend.orig/gtk/CVS/Root  Wed Dec 31 16:00:00 1969
+++ frontend/gtk/CVS/Root       Wed Aug 28 23:24:55 2002
@@ -0,0 +1 @@
+:pserver:[EMAIL PROTECTED]:/cvs/debian-boot
diff -urN frontend.orig/gtk/Makefile frontend/gtk/Makefile
--- frontend.orig/gtk/Makefile  Wed Dec 31 16:00:00 1969
+++ frontend/gtk/Makefile       Wed Aug 28 23:26:16 2002
@@ -0,0 +1,5 @@
+MODULE=gtk
+SOBJ=gtk.so
+OBJS=gtk.opic
+
+include ../modules.mak
diff -urN frontend.orig/gtk/gtk.c frontend/gtk/gtk.c
--- frontend.orig/gtk/gtk.c     Wed Dec 31 16:00:00 1969
+++ frontend/gtk/gtk.c  Fri Aug 30 17:32:12 2002
@@ -0,0 +1,697 @@
+/***********************************************************************
+ *
+ * cdebconf - An implementation of the Debian Configuration Management
+ *            System
+ *
+ * File: gtk.c
+ *
+ * Description: gtk UI for cdebconf
+ * Some notes on the implementation - optimistic at best. 
+ *
+ * $Id: text.c,v 1.13 2002/08/07 16:19:51 tfheen Exp $
+ *
+ * cdebconf is (c) 2000-2001 Randolph Chung and others under the following
+ * 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.
+ *
+ ***********************************************************************/
+#include "common.h"
+#include "template.h"
+#include "question.h"
+#include "frontend.h"
+#include "database.h"
+#include "strutl.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <gtk/gtk.h>
+
+#ifndef _
+#define _(x) x
+#endif
+
+int gBool;
+int gSelectNum;
+
+/*
+ * Function: check_callback
+ * Input: none
+ * Output: none
+ * Description: continue to next question 
+ * Assumptions: 
+ */
+void check_callback( GtkWidget *widget,
+            gpointer   data )
+{
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
+    {
+      /* If control reaches here, the toggle button is down */
+      gBool = 1;
+    
+    } else {
+    
+      /* If control reaches here, the toggle button is up */
+      gBool = 0;
+    }
+}
+
+/*
+ * Function: choice_callback
+ * Input: none
+ * Output: none
+ * Description: respond to button press and determing which button was pressed
+ * Assumptions: 
+ */
+void choice_callback( GtkWidget *widget,
+            gpointer   data )
+{
+  int i; 
+  GtkWidget **choices;
+  gboolean done;
+
+  choices = (GtkWidget **)data;
+  i = 0;
+  done = FALSE;
+
+  while(*choices && !done)
+    {
+      if(*choices == widget)
+       {
+         gSelectNum = i;
+         done = TRUE;
+       }
+
+      i++;
+      choices++;
+    }
+
+}
+
+
+
+/*
+ * Function: next
+ * Input: none
+ * Output: none
+ * Description: continue to next question 
+ * Assumptions: 
+ */
+void next( GtkWidget *widget,
+            gpointer   data )
+{
+  g_print ("next\n");
+}
+
+/*
+ * Function: back
+ * Input: none
+ * Output: none
+ * Description: go back to previous question
+ * Assumptions: 
+ */
+void back( GtkWidget *widget,
+            gpointer   data )
+{
+  g_print ("back\n");
+}
+
+/*
+ * Function: delete_event
+ * Input: none
+ * Output: none
+ * Description: callback function for delete event
+ * Assumptions: 
+ */
+
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                  gpointer   data )
+{
+  /* If you return FALSE in the "delete_event" signal handler,
+   * GTK will emit the "destroy" signal. Returning TRUE means
+   * you don't want the window to be destroyed.
+   * This is useful for popping up 'are you sure you want to quit?'
+   * type dialogs. */
+
+  g_print ("delete event occurred\n");
+
+  /* Change TRUE to FALSE and the main window will be destroyed with
+   * a "delete_event". */
+
+  return TRUE;
+}
+
+/*
+ * Function: destroy
+ * Input: none
+ * Output: none
+ * Description: callback function for close button
+ * Assumptions: 
+ */
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+  gtk_main_quit ();
+}
+
+/*
+ * Function: getwidth
+ * Input: none
+ * Output: int - width of screen
+ * Description: get the width of the current terminal
+ * Assumptions: doesn't handle resizing; caches value on first call
+ */
+static const int getwidth(void)
+{
+       static int res = 80;
+       static int inited = 0;
+       int fd;
+       struct winsize ws;
+
+       if (inited == 0)
+       {
+               inited = 1;
+               if ((fd = open("/dev/tty", O_RDONLY)) > 0)
+               {
+                       if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
+                               res = ws.ws_col;
+                       close(fd);
+               }
+       }
+       return res;
+}
+
+/*
+ * Function: wrap_print
+ * Input: const char *str - string to display
+ * Output: none
+ * Description: prints a string to the screen with word wrapping 
+ * Assumptions: string fits in <500 lines
+ */
+static void wrap_print(const char *str)
+{
+       /* Simple greedy line-wrapper */
+       int i, lc;
+       char *lines[500];
+
+       lc = strwrap(str, getwidth() - 1, lines, DIM(lines));
+
+       for (i = 0; i < lc; i++)
+       {
+               printf("%s\n", lines[i]);
+               DELETE(lines[i]);
+       }
+}
+
+/*
+ * Function: texthandler_displaydesc
+ * Input: struct frontend *obj - UI object
+ *        struct question *q - question for which to display the description
+ * Output: none
+ * Description: displays the description for a given question 
+ * Assumptions: none
+ *
+static void texthandler_displaydesc(struct frontend *obj, struct question *q) 
+{
+       wrap_print(question_description(q));
+       wrap_print(question_extended_description(q));
+}*/
+
+/*
+ * Function: gtkhandler_boolean
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the boolean question type
+ * Assumptions: none
+ */
+static int gtkhandler_boolean(struct frontend *obj, struct question *q)
+{
+
+       char buf[30];
+       int ans = -1;
+       int def = -1;
+       const char *defval;
+       GtkWidget *window;
+       GtkWidget *nextButton, *backButton, *boolButton;
+       GtkWidget *hboxtop, *hboxbottom, *bigbox;
+
+       defval = question_defaultval(q);
+       if (defval)
+       {
+               if (strcmp(defval, "true") == 0)
+                       def = 1;
+               else 
+                       def = 0;
+       }
+
+
+       //create the window for the question
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+       bigbox = gtk_vbox_new(FALSE, 0);
+       hboxtop = gtk_hbox_new(0, 0);
+       hboxbottom = gtk_hbox_new(0, 0);
+
+       //add a checkbox for the boolean, we wouldn't really want a whole dialog for 
+one boolean,
+       // but this is a start
+
+       boolButton = gtk_check_button_new_with_label ( (gchar 
+*)question_description(q) );
+       g_signal_connect (G_OBJECT (boolButton), "clicked",
+                         G_CALLBACK (check_callback), NULL);
+       gtk_box_pack_start(GTK_BOX(hboxtop), boolButton, FALSE, 5, 5);
+       gtk_widget_show (boolButton);           gtk_widget_show (boolButton);   
+
+       //add the next and back buttons. need to factor this out into a function. 
+
+       g_signal_connect (G_OBJECT (window), "delete_event",
+                         G_CALLBACK (delete_event), NULL);
+       g_signal_connect (G_OBJECT (window), "destroy",
+                         G_CALLBACK (destroy), NULL);
+       gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+       nextButton = gtk_button_new_with_label ("Next");
+       backButton = gtk_button_new_with_label ("Back");
+       g_signal_connect (G_OBJECT (nextButton), "clicked",
+                         G_CALLBACK (next), NULL);
+       g_signal_connect (G_OBJECT (backButton), "clicked",
+                         G_CALLBACK (back), NULL);
+
+       //not sure how to make the layout prettier, revisit this later...
+       //gtk_misc_set_alignment (GTK_MISC (backButton), (gfloat)1.0, (gfloat)1.0);
+
+       gtk_box_pack_start(GTK_BOX(hboxbottom), backButton, FALSE, 5, 5);
+       gtk_widget_show (backButton);
+       gtk_box_pack_start(GTK_BOX(hboxbottom), nextButton, FALSE, 5, 5);
+       gtk_widget_show (nextButton);
+
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxtop, FALSE, 5, 5);
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxbottom, FALSE, 5, 5);
+
+       gtk_container_add(GTK_CONTAINER(window), bigbox);
+
+       //show the dialog containing the question
+       gtk_widget_show (hboxbottom);   
+       gtk_widget_show (hboxtop);              
+       gtk_widget_show (bigbox);               
+       gtk_widget_show (window);
+
+       gtk_main ();
+
+       if(gBool)
+         {
+           ans = 1;
+         }
+       else
+         {
+           ans = 0;
+         }
+
+       question_setvalue(q, (ans ? "true" : "false"));
+       return DC_OK;
+}
+
+/*
+ * Function: gtkhandler_multiselect
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the multiselect question type
+ * Assumptions: none
+ *
+ * TODO: factor common code with select
+ */
+static int gtkhandler_multiselect(struct frontend *obj, struct question *q)
+{
+       char *choices[100] = {0};
+       char *defaults[100] = {0};
+       char selected[100] = {0};
+       char answer[1024];
+       int i, j, count, dcount, choice;
+       GtkWidget *window;
+       GtkWidget *nextButton, *backButton;
+       GtkWidget hboxtop, *hboxbottom, *bigbox;
+       GtkWidget **choiceButtons;
+
+       count = strchoicesplit(question_choices(q), choices, DIM(choices));
+       dcount = strchoicesplit(question_defaultval(q), defaults, DIM(defaults));
+
+       choiceButtons = (GtkWidget **)malloc( (count * (sizeof(GtkWidget *)) + 1) );
+
+       for(i = 0; i < count; i++)
+         choiceButtons[i] = (GtkWidget *)malloc(sizeof(GtkWidget *));
+
+       choiceButtons[count + 1] = 0;
+
+       if (dcount > 0)
+               for (i = 0; i < count; i++)
+                       for (j = 0; j < dcount; j++)
+                               if (strcmp(choices[i], defaults[j]) == 0)
+                                       {
+                                         selected[i] = 1;
+                                         gSelectNum = i;
+                                       }
+
+       //create the window for the question
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       bigbox = gtk_vbox_new(FALSE, 0);
+       hboxbottom = gtk_hbox_new(0, 0);
+       hboxtop = gtk_vbox_new(0, 0);
+
+       //add the next and back buttons. need to factor this out into a function. 
+
+       g_signal_connect (G_OBJECT (window), "delete_event",
+                         G_CALLBACK (delete_event), NULL);
+       g_signal_connect (G_OBJECT (window), "destroy",
+                         G_CALLBACK (destroy), NULL);
+       gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+       nextButton = gtk_button_new_with_label ("Next");
+       backButton = gtk_button_new_with_label ("Back");
+       g_signal_connect (G_OBJECT (nextButton), "clicked",
+                         G_CALLBACK (next), NULL);
+       g_signal_connect (G_OBJECT (backButton), "clicked",
+                         G_CALLBACK (back), NULL);
+
+       //not sure how to make the layout prettier, revisit this later...
+       //gtk_misc_set_alignment (GTK_MISC (backButton), (gfloat)1.0, (gfloat)1.0);
+
+       gtk_box_pack_start(GTK_BOX(hboxbottom), backButton, FALSE, 5, 5);
+       gtk_widget_show (backButton);
+       gtk_box_pack_start(GTK_BOX(hboxbottom), nextButton, FALSE, 5, 5);
+       gtk_widget_show (nextButton);
+
+       for (i = 0; i < count; i++)
+         {
+           //create a button for each choice here
+           //printf("%3d. %s%s\n", i+1, choices[i], 
+           //(selected[i] ? _(" (selected)") : ""));
+
+           choiceButtons[i] = gtk_button_new_with_label (choices[i]);
+           g_signal_connect (G_OBJECT (choiceButtons[i]), "clicked",
+                             G_CALLBACK (choice_callback), choiceButtons);
+           gtk_box_pack_start(GTK_BOX(hboxtop), choiceButtons[i], FALSE, 5, 5);
+           gtk_widget_show (choiceButtons[i]);
+                       
+         }
+
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxtop, FALSE, 5, 5);
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxbottom, FALSE, 5, 5);
+
+       gtk_container_add(GTK_CONTAINER(window), bigbox);
+
+       //show the dialog containing the question
+       gtk_widget_show (hboxbottom);   
+       gtk_widget_show (hboxtop);              
+       gtk_widget_show (bigbox);               
+       gtk_widget_show (window);
+
+       gtk_main();
+
+       //once the dialog returns, handle the result
+
+       for (i = 0; i < count; i++)
+               free(choiceButtons[i]);
+
+       if(gSelectNum > 0 && gSelectNum < count)
+         {
+           strcat(answer, choices[gSelectNum]);
+         }
+
+       gprint("%s", choices[gSelectNum]);
+
+       question_setvalue(q, answer);
+       
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_note
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the note question type
+ * Assumptions: none
+ */
+static int texthandler_note(struct frontend *obj, struct question *q)
+{
+       int c;
+       printf("[Press enter to continue]\n");
+       do { c = fgetc(stdin); } while (c != '\r' && c != '\n');
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_password
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the password question type
+ * Assumptions: none
+ *
+ * TODO: this can be *MUCH* improved. no editing is possible right now
+ */
+static int texthandler_password(struct frontend *obj, struct question *q)
+{
+       struct termios oldt, newt;
+       char passwd[256] = {0};
+       int i = 0, c;
+
+       tcgetattr(0, &oldt);
+       memcpy(&newt, &oldt, sizeof(struct termios));
+       cfmakeraw(&newt);
+       tcsetattr(0, TCSANOW, &newt);
+       while ((c = fgetc(stdin)) != EOF)
+       {
+               fputc('*', stdout);
+               passwd[i++] = (char)c;
+               if (c == '\r' || c == '\n') break;
+
+       }
+       printf("\n");
+       passwd[i] = 0;
+       tcsetattr(0, TCSANOW, &oldt);
+       question_setvalue(q, passwd);
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_select
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the select question type
+ * Assumptions: none
+ *
+ * TODO: factor common code with multiselect
+ */
+static int texthandler_select(struct frontend *obj, struct question *q)
+{
+       char *choices[100] = {0};
+       char *choices_translated[100] = {0};
+       char answer[10];
+       int i, count, choice = 1, def = -1;
+       const char *defval = question_defaultval(q);
+
+       count = strchoicesplit(question_choices(q), choices, DIM(choices));
+       strchoicesplit(question_choices_translated(q), choices_translated, 
+DIM(choices_translated));
+        /* fprintf(stderr,"In texthandler_select, count is: %d\n", count);*/
+       if (count > 1)
+       {
+               if (defval != NULL)
+               {
+                       for (i = 0; i < count; i++)
+                               if (strcmp(choices[i], defval) == 0)
+                                       def = i + 1;
+               }
+
+               do
+               {
+                       for (i = 0; i < count; i++)
+                               printf("%3d. %s%s\n", i+1, choices_translated[i],
+                                       (def == i + 1 ? _(" (default)") : ""));
+
+                       printf(_("Prompt: 1 - %d> "), count);
+                       fgets(answer, sizeof(answer), stdin);
+                       if (answer[0] == '\n')
+                               choice = def;
+                       else
+                               choice = atoi(answer);
+               } while (choice <= 0 || choice > count);
+       }
+       /*      fprintf(stderr,"In %s, line: %d\n\tanswer: %s, choice[choice]: %s\n",
+               __FILE__,__LINE__,answer, choices[choice - 1]);*/
+       question_setvalue(q, choices[choice - 1]);
+       for (i = 0; i < count; i++) 
+       {
+               free(choices[i]);
+               free(choices_translated[i]);
+       }
+       
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_string
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the string question type
+ * Assumptions: none
+ */
+static int texthandler_string(struct frontend *obj, struct question *q)
+{
+       char buf[1024] = {0};
+       const char *defval = question_defaultval(q);
+       if (defval)
+               printf(_("[default = %s]"), defval);
+       printf("> "); fflush(stdout);
+       fgets(buf, sizeof(buf), stdin);
+       CHOMP(buf);
+       if (buf[0] == 0 && defval != 0)
+               question_setvalue(q, defval);
+       else
+               question_setvalue(q, buf);
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_text
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the text question type
+ * Assumptions: none
+ */
+static int texthandler_text(struct frontend *obj, struct question *q)
+{
+       char *out = 0;
+       char buf[1024];
+       int sz = 1;
+
+       printf(_("Enter . on a line by itself when you are done\n"));
+       while (fgets(buf, sizeof(buf), stdin))
+       {
+               if (strcmp(buf, ".\n") == 0) break;
+               sz += strlen(buf);
+               out = realloc(out, sz);
+               memcpy(out + sz - strlen(buf) - 1, buf, strlen(buf));
+       }
+       out[sz-1] = 0;
+       question_setvalue(q, out);
+       free(out);
+       return DC_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+struct question_handlers {
+       const char *type;
+       int (*handler)(struct frontend *obj, struct question *q);
+} question_handlers[] = {
+        { "boolean",   gtkhandler_boolean },
+       { "multiselect", gtkhandler_multiselect }
+       /*      { "note",       gtkhandler_note },
+       { "password",   gtkhandler_password },
+       { "select",     gtkhandler_select },
+       { "string",     gtkhandler_string },
+       { "text",       gtkhandler_text }*/
+};
+
+/*
+ * Function: gtk_intitialize
+ * Input: struct frontend *obj - frontend UI object
+ *        struct configuration *cfg - configuration parameters
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: initializes the gtk UI
+ * Assumptions: none
+ *
+ */
+static int gtk_initialize(struct frontend *obj, struct configuration *conf)
+{
+       obj->interactive = 1;
+       //signal(SIGINT, SIG_IGN);
+
+       gtk_init (0, "cdebconf");
+
+       return DC_OK;
+}
+
+/*
+ * Function: gtk_go
+ * Input: struct frontend *obj - frontend object
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: asks all pending questions
+ * Assumptions: none
+ */
+static int gtk_go(struct frontend *obj)
+{
+       struct question *q = obj->questions;
+       int i;
+       int ret;
+       /*      char *window_title;
+       int len;
+
+       //printf("%s\n\n", obj->title);
+
+       len = strlen(obj->title);
+       window_title = (char *)malloc(len+1);
+       strcpy(window_title, obj->title);
+       */
+
+       for (; q != 0; q = q->next)
+       {
+                struct template *t = obj->tdb->methods.get(obj->tdb, q->tag);
+                template_deref(q->template);
+                q->template = t;
+
+               for (i = 0; i < DIM(question_handlers); i++)
+                       if (strcmp(q->template->type, question_handlers[i].type) == 0)
+                       {
+
+                               //gtkhandler_displaydesc(obj, q);
+                               
+                               ret = question_handlers[i].handler(obj, q);
+                               if (ret == DC_OK)
+                                       obj->qdb->methods.set(obj->qdb, q);
+                               else
+                                       return ret;
+                               break;
+                       }
+       }
+
+       return DC_OK;
+}
+
+struct frontend_module debconf_frontend_module =
+{
+       initialize: gtk_initialize,
+       go: gtk_go,
+};
diff -urN frontend.orig/gtk/gtk.c~ frontend/gtk/gtk.c~
--- frontend.orig/gtk/gtk.c~    Wed Dec 31 16:00:00 1969
+++ frontend/gtk/gtk.c~ Fri Aug 30 17:29:18 2002
@@ -0,0 +1,697 @@
+/***********************************************************************
+ *
+ * cdebconf - An implementation of the Debian Configuration Management
+ *            System
+ *
+ * File: gtk.c
+ *
+ * Description: gtk UI for cdebconf
+ * Some notes on the implementation - optimistic at best. 
+ *
+ * $Id: text.c,v 1.13 2002/08/07 16:19:51 tfheen Exp $
+ *
+ * cdebconf is (c) 2000-2001 Randolph Chung and others under the following
+ * 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.
+ *
+ ***********************************************************************/
+#include "common.h"
+#include "template.h"
+#include "question.h"
+#include "frontend.h"
+#include "database.h"
+#include "strutl.h"
+
+#include <ctype.h>
+#include <fcntl.h>
+#include <signal.h>
+#include <string.h>
+#include <termios.h>
+#include <unistd.h>
+#include <sys/ioctl.h>
+#include <sys/stat.h>
+#include <sys/types.h>
+
+#include <gtk/gtk.h>
+
+#ifndef _
+#define _(x) x
+#endif
+
+int gBool;
+int gSelectNum;
+
+/*
+ * Function: check_callback
+ * Input: none
+ * Output: none
+ * Description: continue to next question 
+ * Assumptions: 
+ */
+void check_callback( GtkWidget *widget,
+            gpointer   data )
+{
+  if (gtk_toggle_button_get_active (GTK_TOGGLE_BUTTON (widget))) 
+    {
+      /* If control reaches here, the toggle button is down */
+      gBool = 1;
+    
+    } else {
+    
+      /* If control reaches here, the toggle button is up */
+      gBool = 0;
+    }
+}
+
+/*
+ * Function: choice_callback
+ * Input: none
+ * Output: none
+ * Description: respond to button press and determing which button was pressed
+ * Assumptions: 
+ */
+void choice_callback( GtkWidget *widget,
+            gpointer   data )
+{
+  int i; 
+  GtkWidget **choices;
+  gboolean done;
+
+  choices = (GtkWidget **)data;
+  i = 0;
+  done = FALSE;
+
+  while(*choices && !done)
+    {
+      if(*choices == widget)
+       {
+         gSelectNum = i;
+         done = TRUE;
+       }
+
+      i++;
+      choices++;
+    }
+
+}
+
+
+
+/*
+ * Function: next
+ * Input: none
+ * Output: none
+ * Description: continue to next question 
+ * Assumptions: 
+ */
+void next( GtkWidget *widget,
+            gpointer   data )
+{
+  g_print ("next\n");
+}
+
+/*
+ * Function: back
+ * Input: none
+ * Output: none
+ * Description: go back to previous question
+ * Assumptions: 
+ */
+void back( GtkWidget *widget,
+            gpointer   data )
+{
+  g_print ("back\n");
+}
+
+/*
+ * Function: delete_event
+ * Input: none
+ * Output: none
+ * Description: callback function for delete event
+ * Assumptions: 
+ */
+
+gint delete_event( GtkWidget *widget,
+                   GdkEvent  *event,
+                  gpointer   data )
+{
+  /* If you return FALSE in the "delete_event" signal handler,
+   * GTK will emit the "destroy" signal. Returning TRUE means
+   * you don't want the window to be destroyed.
+   * This is useful for popping up 'are you sure you want to quit?'
+   * type dialogs. */
+
+  g_print ("delete event occurred\n");
+
+  /* Change TRUE to FALSE and the main window will be destroyed with
+   * a "delete_event". */
+
+  return TRUE;
+}
+
+/*
+ * Function: destroy
+ * Input: none
+ * Output: none
+ * Description: callback function for close button
+ * Assumptions: 
+ */
+void destroy( GtkWidget *widget,
+              gpointer   data )
+{
+  gtk_main_quit ();
+}
+
+/*
+ * Function: getwidth
+ * Input: none
+ * Output: int - width of screen
+ * Description: get the width of the current terminal
+ * Assumptions: doesn't handle resizing; caches value on first call
+ */
+static const int getwidth(void)
+{
+       static int res = 80;
+       static int inited = 0;
+       int fd;
+       struct winsize ws;
+
+       if (inited == 0)
+       {
+               inited = 1;
+               if ((fd = open("/dev/tty", O_RDONLY)) > 0)
+               {
+                       if (ioctl(fd, TIOCGWINSZ, &ws) == 0)
+                               res = ws.ws_col;
+                       close(fd);
+               }
+       }
+       return res;
+}
+
+/*
+ * Function: wrap_print
+ * Input: const char *str - string to display
+ * Output: none
+ * Description: prints a string to the screen with word wrapping 
+ * Assumptions: string fits in <500 lines
+ */
+static void wrap_print(const char *str)
+{
+       /* Simple greedy line-wrapper */
+       int i, lc;
+       char *lines[500];
+
+       lc = strwrap(str, getwidth() - 1, lines, DIM(lines));
+
+       for (i = 0; i < lc; i++)
+       {
+               printf("%s\n", lines[i]);
+               DELETE(lines[i]);
+       }
+}
+
+/*
+ * Function: texthandler_displaydesc
+ * Input: struct frontend *obj - UI object
+ *        struct question *q - question for which to display the description
+ * Output: none
+ * Description: displays the description for a given question 
+ * Assumptions: none
+ *
+static void texthandler_displaydesc(struct frontend *obj, struct question *q) 
+{
+       wrap_print(question_description(q));
+       wrap_print(question_extended_description(q));
+}*/
+
+/*
+ * Function: gtkhandler_boolean
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the boolean question type
+ * Assumptions: none
+ */
+static int gtkhandler_boolean(struct frontend *obj, struct question *q)
+{
+
+       char buf[30];
+       int ans = -1;
+       int def = -1;
+       const char *defval;
+       GtkWidget *window;
+       GtkWidget *nextButton, *backButton, *boolButton;
+       GtkWidget *hboxtop, *hboxbottom, *bigbox;
+
+       defval = question_defaultval(q);
+       if (defval)
+       {
+               if (strcmp(defval, "true") == 0)
+                       def = 1;
+               else 
+                       def = 0;
+       }
+
+
+       //create the window for the question
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+
+       bigbox = gtk_vbox_new(FALSE, 0);
+       hboxtop = gtk_hbox_new(0, 0);
+       hboxbottom = gtk_hbox_new(0, 0);
+
+       //add a checkbox for the boolean, we wouldn't really want a whole dialog for 
+one boolean,
+       // but this is a start
+
+       boolButton = gtk_check_button_new_with_label ( (gchar 
+*)question_description(q) );
+       g_signal_connect (G_OBJECT (boolButton), "clicked",
+                         G_CALLBACK (check_callback), NULL);
+       gtk_box_pack_start(GTK_BOX(hboxtop), boolButton, FALSE, 5, 5);
+       gtk_widget_show (boolButton);           gtk_widget_show (boolButton);   
+
+       //add the next and back buttons. need to factor this out into a function. 
+
+       g_signal_connect (G_OBJECT (window), "delete_event",
+                         G_CALLBACK (delete_event), NULL);
+       g_signal_connect (G_OBJECT (window), "destroy",
+                         G_CALLBACK (destroy), NULL);
+       gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+       nextButton = gtk_button_new_with_label ("Next");
+       backButton = gtk_button_new_with_label ("Back");
+       g_signal_connect (G_OBJECT (nextButton), "clicked",
+                         G_CALLBACK (next), NULL);
+       g_signal_connect (G_OBJECT (backButton), "clicked",
+                         G_CALLBACK (back), NULL);
+
+       //not sure how to make the layout prettier, revisit this later...
+       //gtk_misc_set_alignment (GTK_MISC (backButton), (gfloat)1.0, (gfloat)1.0);
+
+       gtk_box_pack_start(GTK_BOX(hboxbottom), backButton, FALSE, 5, 5);
+       gtk_widget_show (backButton);
+       gtk_box_pack_start(GTK_BOX(hboxbottom), nextButton, FALSE, 5, 5);
+       gtk_widget_show (nextButton);
+
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxtop, FALSE, 5, 5);
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxbottom, FALSE, 5, 5);
+
+       gtk_container_add(GTK_CONTAINER(window), bigbox);
+
+       //show the dialog containing the question
+       gtk_widget_show (hboxbottom);   
+       gtk_widget_show (hboxtop);              
+       gtk_widget_show (bigbox);               
+       gtk_widget_show (window);
+
+       gtk_main ();
+
+       if(gBool)
+         {
+           ans = 1;
+         }
+       else
+         {
+           ans = 0;
+         }
+
+       question_setvalue(q, (ans ? "true" : "false"));
+       return DC_OK;
+}
+
+/*
+ * Function: gtkhandler_multiselect
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the multiselect question type
+ * Assumptions: none
+ *
+ * TODO: factor common code with select
+ */
+static int gtkhandler_multiselect(struct frontend *obj, struct question *q)
+{
+       char *choices[100] = {0};
+       char *defaults[100] = {0};
+       char selected[100] = {0};
+       char answer[1024];
+       int i, j, count, dcount, choice;
+       GtkWidget *window;
+       GtkWidget *nextButton, *backButton;
+       GtkWidget hboxtop, *hboxbottom, *bigbox;
+       GtkWidget **choiceButtons;
+
+       count = strchoicesplit(question_choices(q), choices, DIM(choices));
+       dcount = strchoicesplit(question_defaultval(q), defaults, DIM(defaults));
+
+       choiceButtons = (GtkWidget **)malloc( (count * (sizeof(GtkWidget *)) + 1) );
+
+       for(i = 0; i < count; i++)
+         choiceButtons[i] = (GtkWidget *)malloc(sizeof(GtkWidget *));
+
+       choiceButtons[count + 1] = 0;
+
+       if (dcount > 0)
+               for (i = 0; i < count; i++)
+                       for (j = 0; j < dcount; j++)
+                               if (strcmp(choices[i], defaults[j]) == 0)
+                                       {
+                                         selected[i] = 1;
+                                         gSelectNum = i;
+                                       }
+
+       //create the window for the question
+       window = gtk_window_new (GTK_WINDOW_TOPLEVEL);
+       bigbox = gtk_vbox_new(FALSE, 0);
+       hboxbottom = gtk_hbox_new(0, 0);
+       hboxtop = gtk_vbox_new(0, 0);
+
+       //add the next and back buttons. need to factor this out into a function. 
+
+       g_signal_connect (G_OBJECT (window), "delete_event",
+                         G_CALLBACK (delete_event), NULL);
+       g_signal_connect (G_OBJECT (window), "destroy",
+                         G_CALLBACK (destroy), NULL);
+       gtk_container_set_border_width (GTK_CONTAINER (window), 10);
+       nextButton = gtk_button_new_with_label ("Next");
+       backButton = gtk_button_new_with_label ("Back");
+       g_signal_connect (G_OBJECT (nextButton), "clicked",
+                         G_CALLBACK (next), NULL);
+       g_signal_connect (G_OBJECT (backButton), "clicked",
+                         G_CALLBACK (back), NULL);
+
+       //not sure how to make the layout prettier, revisit this later...
+       //gtk_misc_set_alignment (GTK_MISC (backButton), (gfloat)1.0, (gfloat)1.0);
+
+       gtk_box_pack_start(GTK_BOX(hboxbottom), backButton, FALSE, 5, 5);
+       gtk_widget_show (backButton);
+       gtk_box_pack_start(GTK_BOX(hboxbottom), nextButton, FALSE, 5, 5);
+       gtk_widget_show (nextButton);
+
+       for (i = 0; i < count; i++)
+         {
+           //create a button for each choice here
+           //printf("%3d. %s%s\n", i+1, choices[i], 
+           //(selected[i] ? _(" (selected)") : ""));
+
+           choiceButtons[i] = gtk_button_new_with_label (choices[i]);
+           g_signal_connect (G_OBJECT (choiceButtons[i]), "clicked",
+                             G_CALLBACK (choice_callback), choiceButtons);
+           gtk_box_pack_start(GTK_BOX(hboxtop), choiceButtons[i], FALSE, 5, 5);
+           gtk_widget_show (choiceButtons[i]);
+                       
+         }
+
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxtop, FALSE, 5, 5);
+       gtk_box_pack_start(GTK_BOX(bigbox), hboxbottom, FALSE, 5, 5);
+
+       gtk_container_add(GTK_CONTAINER(window), bigbox);
+
+       //show the dialog containing the question
+       gtk_widget_show (hboxbottom);   
+       gtk_widget_show (hboxtop);              
+       gtk_widget_show (bigbox);               
+       gtk_widget_show (window);
+
+       gtk_main();
+
+       //once the dialog returns, handle the result
+
+       for (i = 0; i < count; i++)
+               free(choiceButtons[i]);
+
+       if(gSelectNum > 0 && gSelectNum < count)
+         {
+           strcat(answer, choices[gSelectNum]);
+         }
+
+       gprint("%s", choices[gSelectNum]);
+
+       question_setvalue(q, answer);
+       
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_note
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the note question type
+ * Assumptions: none
+ */
+static int texthandler_note(struct frontend *obj, struct question *q)
+{
+       int c;
+       printf("[Press enter to continue]\n");
+       do { c = fgetc(stdin); } while (c != '\r' && c != '\n');
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_password
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the password question type
+ * Assumptions: none
+ *
+ * TODO: this can be *MUCH* improved. no editing is possible right now
+ */
+static int texthandler_password(struct frontend *obj, struct question *q)
+{
+       struct termios oldt, newt;
+       char passwd[256] = {0};
+       int i = 0, c;
+
+       tcgetattr(0, &oldt);
+       memcpy(&newt, &oldt, sizeof(struct termios));
+       cfmakeraw(&newt);
+       tcsetattr(0, TCSANOW, &newt);
+       while ((c = fgetc(stdin)) != EOF)
+       {
+               fputc('*', stdout);
+               passwd[i++] = (char)c;
+               if (c == '\r' || c == '\n') break;
+
+       }
+       printf("\n");
+       passwd[i] = 0;
+       tcsetattr(0, TCSANOW, &oldt);
+       question_setvalue(q, passwd);
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_select
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the select question type
+ * Assumptions: none
+ *
+ * TODO: factor common code with multiselect
+ */
+static int texthandler_select(struct frontend *obj, struct question *q)
+{
+       char *choices[100] = {0};
+       char *choices_translated[100] = {0};
+       char answer[10];
+       int i, count, choice = 1, def = -1;
+       const char *defval = question_defaultval(q);
+
+       count = strchoicesplit(question_choices(q), choices, DIM(choices));
+       strchoicesplit(question_choices_translated(q), choices_translated, 
+DIM(choices_translated));
+        /* fprintf(stderr,"In texthandler_select, count is: %d\n", count);*/
+       if (count > 1)
+       {
+               if (defval != NULL)
+               {
+                       for (i = 0; i < count; i++)
+                               if (strcmp(choices[i], defval) == 0)
+                                       def = i + 1;
+               }
+
+               do
+               {
+                       for (i = 0; i < count; i++)
+                               printf("%3d. %s%s\n", i+1, choices_translated[i],
+                                       (def == i + 1 ? _(" (default)") : ""));
+
+                       printf(_("Prompt: 1 - %d> "), count);
+                       fgets(answer, sizeof(answer), stdin);
+                       if (answer[0] == '\n')
+                               choice = def;
+                       else
+                               choice = atoi(answer);
+               } while (choice <= 0 || choice > count);
+       }
+       /*      fprintf(stderr,"In %s, line: %d\n\tanswer: %s, choice[choice]: %s\n",
+               __FILE__,__LINE__,answer, choices[choice - 1]);*/
+       question_setvalue(q, choices[choice - 1]);
+       for (i = 0; i < count; i++) 
+       {
+               free(choices[i]);
+               free(choices_translated[i]);
+       }
+       
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_string
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the string question type
+ * Assumptions: none
+ */
+static int texthandler_string(struct frontend *obj, struct question *q)
+{
+       char buf[1024] = {0};
+       const char *defval = question_defaultval(q);
+       if (defval)
+               printf(_("[default = %s]"), defval);
+       printf("> "); fflush(stdout);
+       fgets(buf, sizeof(buf), stdin);
+       CHOMP(buf);
+       if (buf[0] == 0 && defval != 0)
+               question_setvalue(q, defval);
+       else
+               question_setvalue(q, buf);
+       return DC_OK;
+}
+
+/*
+ * Function: texthandler_text
+ * Input: struct frontend *obj - frontend object
+ *        struct question *q - question to ask
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: handler for the text question type
+ * Assumptions: none
+ */
+static int texthandler_text(struct frontend *obj, struct question *q)
+{
+       char *out = 0;
+       char buf[1024];
+       int sz = 1;
+
+       printf(_("Enter . on a line by itself when you are done\n"));
+       while (fgets(buf, sizeof(buf), stdin))
+       {
+               if (strcmp(buf, ".\n") == 0) break;
+               sz += strlen(buf);
+               out = realloc(out, sz);
+               memcpy(out + sz - strlen(buf) - 1, buf, strlen(buf));
+       }
+       out[sz-1] = 0;
+       question_setvalue(q, out);
+       free(out);
+       return DC_OK;
+}
+
+/* ----------------------------------------------------------------------- */
+struct question_handlers {
+       const char *type;
+       int (*handler)(struct frontend *obj, struct question *q);
+} question_handlers[] = {
+        { "boolean",   gtkhandler_boolean },
+       { "multiselect", gtkhandler_multiselect }
+       { "note",       gtkhandler_note },
+       { "password",   gtkhandler_password },
+       { "select",     gtkhandler_select },
+       { "string",     gtkhandler_string },
+       { "text",       gtkhandler_text }*/
+};
+
+/*
+ * Function: gtk_intitialize
+ * Input: struct frontend *obj - frontend UI object
+ *        struct configuration *cfg - configuration parameters
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: initializes the gtk UI
+ * Assumptions: none
+ *
+ */
+static int gtk_initialize(struct frontend *obj, struct configuration *conf)
+{
+       obj->interactive = 1;
+       //signal(SIGINT, SIG_IGN);
+
+       gtk_init (0, "cdebconf");
+
+       return DC_OK;
+}
+
+/*
+ * Function: gtk_go
+ * Input: struct frontend *obj - frontend object
+ * Output: int - DC_OK, DC_NOTOK
+ * Description: asks all pending questions
+ * Assumptions: none
+ */
+static int gtk_go(struct frontend *obj)
+{
+       struct question *q = obj->questions;
+       int i;
+       int ret;
+       /*      char *window_title;
+       int len;
+
+       //printf("%s\n\n", obj->title);
+
+       len = strlen(obj->title);
+       window_title = (char *)malloc(len+1);
+       strcpy(window_title, obj->title);
+       */
+
+       for (; q != 0; q = q->next)
+       {
+                struct template *t = obj->tdb->methods.get(obj->tdb, q->tag);
+                template_deref(q->template);
+                q->template = t;
+
+               for (i = 0; i < DIM(question_handlers); i++)
+                       if (strcmp(q->template->type, question_handlers[i].type) == 0)
+                       {
+
+                               //gtkhandler_displaydesc(obj, q);
+                               
+                               ret = question_handlers[i].handler(obj, q);
+                               if (ret == DC_OK)
+                                       obj->qdb->methods.set(obj->qdb, q);
+                               else
+                                       return ret;
+                               break;
+                       }
+       }
+
+       return DC_OK;
+}
+
+struct frontend_module debconf_frontend_module =
+{
+       initialize: gtk_initialize,
+       go: gtk_go,
+};

Reply via email to