#! /bin/sh -e

# DP: Modified

if [ $# -ne 1 ]; then
    echo >&2 "$0: script expects -patch|-unpatch as argument"
    exit 1
fi
case "$1" in
    -patch) patch -f -p0 < $0;;
    -unpatch) patch -f -R -p0 < $0;;
    *)
        echo >&2 "$0: script expects -patch|-unpatch as argument"
        exit 1
esac
exit 0

--- zvt/zvtterm.c.orig	Thu Dec 27 01:57:13 2001
+++ zvt/zvtterm.c	Thu Dec 27 01:58:31 2001
@@ -39,6 +39,7 @@
 #include <gtk/gtkmain.h>
 #include <gtk/gtksignal.h>
 #include <gtk/gtkselection.h>
+#include <gtk/gtkwindow.h>
 
 #include "zvtterm.h"
 
@@ -88,6 +89,8 @@
 static void zvt_term_child_died (ZvtTerm *term);
 static void zvt_term_title_changed (ZvtTerm *term, VTTITLE_TYPE type, char *str);
 static void zvt_term_title_changed_raise (void *user_data, VTTITLE_TYPE type, char *str);
+static void zvt_term_dtterm_seq (void *term);
+static void zvt_term_dtterm_seq_event (ZvtTerm *term);
 static gint zvt_term_cursor_blink (gpointer data);
 static void zvt_term_scrollbar_moved (GtkAdjustment *adj, GtkWidget *widget);
 static void zvt_term_readdata (gpointer data, gint fd, GdkInputCondition condition);
@@ -142,6 +145,7 @@
 {
   CHILD_DIED,
   TITLE_CHANGED,
+  DTTERM_SEQ,
   LAST_SIGNAL
 };
 static guint term_signals[LAST_SIGNAL] = { 0 };
@@ -205,6 +209,14 @@
 		    GTK_TYPE_INT,
 		    GTK_TYPE_STRING);
 
+  term_signals[DTTERM_SEQ] =
+    gtk_signal_new ("dtterm_seq",
+		    GTK_RUN_FIRST,
+		    object_class->type,
+		    GTK_SIGNAL_OFFSET (ZvtTermClass, child_died),
+		    gtk_signal_default_marshaller,
+		    GTK_TYPE_NONE, 0);
+
   gtk_object_class_add_signals (object_class, term_signals, LAST_SIGNAL);
 
   object_class->destroy = zvt_term_destroy;
@@ -244,6 +256,7 @@
   term->vx = vtx_new (80, 24, term);
   term->vx->vt.ring_my_bell = zvt_term_bell;
   term->vx->vt.change_my_name = zvt_term_title_changed_raise;
+  term->vx->vt.dtterm_seq     = zvt_term_dtterm_seq;
 
   /* set rendering callbacks */
   term->vx->draw_text = vt_draw_text;
@@ -290,9 +303,13 @@
   term->scroll_on_output = 0;
   term->blink_enabled = 1;
   term->ic = NULL;
+  term->meta_modifiers = GDK_MOD1_MASK|GDK_MOD4_MASK;
   term->in_expose = 0;
   term->transparent = 0;
   term->shaded = 0;
+  term->swap_del_key = 0;
+  term->del_is_del = 0;
+  term->meta_use_hight_bit = 0;
 
   /* private data - set before calling functions */
   zp = g_malloc0(sizeof(*zp));
@@ -327,6 +344,11 @@
       "value_changed",
       GTK_SIGNAL_FUNC (zvt_term_scrollbar_moved),
       term);
+  gtk_signal_connect (
+      GTK_OBJECT (term),
+      "dtterm_seq",
+      GTK_SIGNAL_FUNC (zvt_term_dtterm_seq_event),
+      NULL);
 
   /* selection received */
   gtk_selection_add_target (
@@ -432,7 +454,6 @@
 static void
 term_force_size(ZvtTerm *term)
 {
-  struct _zvtprivate *zp = _ZVT_PRIVATE(term);
   if (GTK_WIDGET_REALIZED (term)) {
 
     /* ok, if we update the window hints ourselves, then we
@@ -2172,6 +2193,151 @@
     vt_free_match_blocks(term->vx);
 }
 
+/**
+ * zvt_term_dtterm_seq_event:
+ * @term:   An initialised &ZvtTerm widget
+ *          the term->vx->vt.arg.num.intargs member should be an
+ *          &int pointing to an array consisting of the 'Ps' parameters
+ *          from the CSI sequence (translated into ints, that is)
+ * @report: integer. (The 1st Ps from the CSI Ps [; Ps [; Ps ]] t sequence)
+ *
+ * handle a dtterm escape sequence: generate a report
+ * and write it back to the child's pty if necessary.
+ **/
+static void
+zvt_term_dtterm_seq_event (ZvtTerm *term)
+{
+#define DTTERM_2ITEM_REPORT() \
+  g_snprintf(rbuf, bufs, "%s%d;%d;%dt", CSI, (seqn - 10), ps[0], ps[1])
+#define DTTERM_TITLE_REPORT(c) \
+  g_snprintf(rbuf, bufs, "%s%c%s%s", OSC, c, ZVT_GTK_WINDOW(term)->title, ST)
+
+  static const char * CSI = "\x1b[";
+  static const char * OSC = "\x1b]";
+  static const char * ST  = "\x1b\\";
+  
+  char rbuf[128];
+  const int bufs = sizeof(rbuf); 
+
+  int   ps[2] = { 0, 0 }; /* 'Ps' parameters from/for dtterm sequence */
+  int   seqn  = *(term->vx->vt.arg.num.intargs);
+  int * arg   = term->vx->vt.arg.num.intargs + 1;
+  
+  d(printf("signal received and handed over\n"));
+
+  memset(rbuf, 0, sizeof(rbuf));
+
+  switch( seqn ) {
+#if GTK_MAJOR_VERSION < 2    
+  case 1:
+    /* de-iconify */
+    {
+      GdkWindow *g = ZVT_GDK_TOPWIN(term);
+      gdk_window_show (g);
+      gdk_window_raise(g);
+    }
+    break;
+  case 2:
+    /* iconify */
+    {
+      GdkWindow *g = ZVT_GDK_TOPWIN(term);
+      Window     w = GDK_WINDOW_XWINDOW (g);
+      Display   *d = GDK_WINDOW_XDISPLAY(g);
+      XWindowAttributes xwa;
+      XGetWindowAttributes(d, w, &xwa);
+      XIconifyWindow(d, w, XScreenNumberOfScreen(xwa.screen));
+    }
+    break;
+#else
+  case 1:
+    gtk_deiconify_window(ZVT_GTK_WINDOW(term));
+    break;    
+  case 2:
+    gtk_iconify_window(ZVT_GTK_WINDOW(term));
+    break;
+#endif
+    break;
+  case 3:
+    /* move to x, y */
+    ps[0] = *arg++;
+    ps[1] = *arg;
+    gdk_window_move(ZVT_GDK_TOPWIN(term), ps[0], ps[1]);
+    break;
+  case 4:
+    /* resize to h x w pixels (actually nearest possible char x char size) */
+    /* as this is what xterm appears to do. */
+    ps[0] = *arg++ / term->charheight;
+    ps[1] = *arg   / term->charwidth;
+    zvt_term_set_size(term, ps[1], ps[0]);
+    break;
+  case 5:
+    gdk_window_raise(ZVT_GDK_TOPWIN(term));
+    break;
+  case 6:
+    gdk_window_lower(ZVT_GDK_TOPWIN(term));
+    break;
+  case 7:
+    /* refresh */
+    vt_update(term->vx, UPDATE_REFRESH);
+    break;
+  case 8:
+    /* resize to h x w chars */
+    ps[0] = *arg++;
+    ps[1] = *arg;
+    zvt_term_set_size(term, ps[1], ps[0]);
+    break;
+  case 9:
+    /* (*arg == 0) ? unmaximise : maximise */
+    break;
+  case 11:
+    d(printf("determine if term is iconified, echo appropriate sequence\n"));
+    /* IMPLEMENTME : iconifiedp ? (CSI 2 t) : (CSI 1 t) */
+    break;
+  case 13:
+    /* report window position (pixels x,y) */
+    gdk_window_get_position(ZVT_GDK_TOPWIN(term), &ps[0], &ps[1]);
+    DTTERM_2ITEM_REPORT();
+    break;
+  case 14:
+    /* report window sixe (pixels h,w) */
+    gdk_window_get_size(ZVT_GDK_WINDOW(term), &ps[1], &ps[0]);
+    DTTERM_2ITEM_REPORT();
+    break;
+  case 18:
+    /* report window size (chars h,w) */
+    ps[1] = term->vx->vt.width;
+    ps[0] = term->vx->vt.height;
+    DTTERM_2ITEM_REPORT();
+    break;
+  case 19:
+    /* report screen size (chars h,w) */
+    ps[1] = gdk_screen_width()  / term->charwidth;
+    ps[0] = gdk_screen_height() / term->charheight;
+    DTTERM_2ITEM_REPORT();
+    break;
+  case 20:
+    /* report icon label */
+    DTTERM_TITLE_REPORT('L');
+    break;
+  case 21:
+    /* report window title */
+    DTTERM_TITLE_REPORT('l');
+    break;
+  default:
+    /* DECSLPP - resize to #seqn lines: */
+    if(seqn >= 24)
+      zvt_term_set_size(term, term->vx->vt.width, seqn);
+    else
+      d(printf("Unknown dtterm sequence %d\n", seqn));
+  }
+
+  /* have we collected a report? if so, write it back out... */
+  if(rbuf[0]) {
+    rbuf[sizeof(rbuf) - 1] = 0;
+    vt_writechild( &(term->vx->vt), rbuf, strlen(rbuf) );
+  }
+}
+
 /*
  * Callback for when the adjustment changes - i.e., the scrollbar
  * moves.
@@ -2350,6 +2516,8 @@
   int handled;
   char *cursor;
   int appl_keypad;
+  char pre_meta = '\0';
+  char or_meta = '\0';
   
   g_return_val_if_fail (widget != NULL, FALSE);
   g_return_val_if_fail (ZVT_IS_TERM (widget), FALSE);
@@ -2364,15 +2532,25 @@
   
   d(printf("keyval = %04x state = %x\n", event->keyval, event->state));
   handled = TRUE;
+  if (event->state & term->meta_modifiers) {
+    /* Metaified key */
+    if (term->meta_use_hight_bit)
+      or_meta = 0x80;
+    else
+      pre_meta = '\033';
+  }
+
+  /* This macro inserts an ESC or sets the high bit on a character to be
+     sent to the app depending on the meta state. */
+# define INSERT_AND_MAYBE_METAIFY_KEY(c) \
+    ( ( pre_meta ? (*p++ = pre_meta) : 0 ), *p++ = ((c)|or_meta) )
+  
   switch (event->keyval) {
   case GDK_BackSpace:
-    if (event->state & GDK_MOD1_MASK)
-      *p++ = '\033';
-
     if (term->swap_del_key)
-      *p++ = '\177';
+      INSERT_AND_MAYBE_METAIFY_KEY(8);
     else
-      *p++ = 8;
+      INSERT_AND_MAYBE_METAIFY_KEY('\177');
     break;
   case GDK_KP_Right:
   case GDK_Right:
@@ -2405,12 +2583,10 @@
     break;
   case GDK_Delete:
     if (term->del_is_del){
-      if (event->state & GDK_MOD1_MASK)
-	*p++ = '\033';
       if (term->swap_del_key)
-	*p++ = 8;
+	INSERT_AND_MAYBE_METAIFY_KEY('\177');
       else
-	*p++ = '\177';
+	INSERT_AND_MAYBE_METAIFY_KEY(8);
     } else {
       p+=sprintf (p, "\033[3~");
     }
@@ -2538,7 +2714,7 @@
     *p++ = gdk_keyval_from_name("Tab");
     break;
   case GDK_Tab:
-    *p++ = event->keyval;
+    INSERT_AND_MAYBE_METAIFY_KEY(event->keyval);
     break;
   case GDK_Menu:
     p+=sprintf (p, "\033[29~");
@@ -2546,24 +2722,26 @@
   case ' ':
     /* maps single characters to correct control and alt versions */
     if (event->state & GDK_CONTROL_MASK)
-      *p++=event->keyval & 0x1f;
-    else if (event->state & GDK_MOD1_MASK)
-      *p++=event->keyval + 0x80; /* this works for space at least */
+      INSERT_AND_MAYBE_METAIFY_KEY(event->keyval & 0x1f);
     else
-      *p++=event->keyval;
+      INSERT_AND_MAYBE_METAIFY_KEY(event->keyval);
     break;
   default:
       if (event->length > 0){
-	if (event->state & (GDK_MOD1_MASK | GDK_MOD4_MASK)){
-	   *p++ = '\033';
-        }
+	if (pre_meta)
+	  *p++ = pre_meta;
 	memcpy(p, event->string, event->length*sizeof(char));
+	p[0] |= or_meta; /* Only sets the first character with multibyte 
+			    character sets ? */
 	p += event->length;
       } else {
 	handled = FALSE;
       }
       d(printf ("[%s,%d,%d]\n", event->string, event->length, handled));
   }
+
+#undef INSERT_AND_MAYBE_METAIFY_KEY
+
   if (handled && p>buffer) {
     vt_writechild(&vx->vt, buffer, (p-buffer));
     if (term->scroll_on_keystroke) zvt_term_scroll (term, 0);
@@ -2582,6 +2760,25 @@
   /* perhaps we should do something here? */
 }
 
+/**
+ * zvt_term_dtterm_seq:
+ * @term: An initialised &ZvtTerm.
+ * @report: integer (The 1st Ps from the CSI Ps [; Ps [; Ps ]] t sequence)
+ *
+ * Catches a request for a report and dispatches it to the connected
+ * signal handler (default: zvt_term_dtterm_seq_event)
+ **/
+static void
+zvt_term_dtterm_seq (void *term)
+{
+  ZvtTerm *TERM = term;
+
+  g_return_if_fail (TERM != NULL);
+  g_return_if_fail (ZVT_IS_TERM (TERM));
+
+  gtk_signal_emit(GTK_OBJECT(TERM), term_signals[DTTERM_SEQ]);
+}
+
 /* dummy default signal handler for title_changed */
 static void
 zvt_term_title_changed (ZvtTerm *term, VTTITLE_TYPE type, char *str)
@@ -2590,6 +2787,7 @@
   g_return_if_fail (ZVT_IS_TERM (term));
 
   /* perhaps we should do something here? */
+  gtk_window_set_title(ZVT_GTK_WINDOW(term), str);
 }
 
 /**
@@ -3193,9 +3391,9 @@
   if (attr&VTATTR_UNDERLINE) {
     gdk_draw_line(widget->window, fgc,
 		  offx + x,
-		  offy + y + 1,
+		  offy + y,
 		  offx + (col + len) * term->charwidth - 1,
-		  offy + y + 1);
+		  offy + y);
   }
   
   if (overstrike && zp && zp->bold_save) {
@@ -3327,6 +3525,36 @@
   g_return_if_fail (ZVT_IS_TERM (term));
   
   term->del_is_del = state != 0;
+}
+
+/**
+ * zvt_term_set_meta_use_high_bit
+ * @term:  Terminal
+ * @state: If true, meta keys sends characters with their high bit set rather
+ *         than sending ESC+character
+ **/
+void
+zvt_term_set_meta_use_high_bit(ZvtTerm *term, int state)
+{
+  g_return_if_fail (term != NULL);
+  g_return_if_fail (ZVT_IS_TERM (term));
+
+  term->meta_use_hight_bit = state != 0;
+}
+
+/**
+ * zvt_term_set_meta_modifiers
+ * @term:      Terminal
+ * @modifiers: All the modifiers which should be used as Meta modifiers
+ *             (GDK_MODx_MASK) ored together.
+ *             (if set to zero, then no meta keys are used)
+ **/
+void
+zvt_term_set_meta_modifiers(ZvtTerm* term, guint modifiers)
+{
+  g_return_if_fail (term != NULL);
+
+  term->meta_modifiers = modifiers;
 }
 
 /*
