Don't forget to call term_paste() when we get the chance, or big
[sgt/putty] / unix / pterm.c
index d258f9e..b18fc1f 100644 (file)
@@ -29,7 +29,7 @@ struct gui_data {
     GtkAdjustment *sbar_adjust;
     GdkPixmap *pixmap;
     GdkFont *fonts[2];                 /* normal and bold (for now!) */
-    GdkCursor *rawcursor, *textcursor;
+    GdkCursor *rawcursor, *textcursor, *blankcursor, *currcursor;
     GdkColor cols[NCOLOURS];
     GdkColormap *colmap;
     wchar_t *pastein_data;
@@ -68,7 +68,9 @@ int askappend(char *filename)
 void logevent(char *string)
 {
     /*
-     * FIXME: event log entries are currently ignored.
+     * This is not a very helpful function: events are logged
+     * pretty much exclusively by the back end, and our pty back
+     * end is self-contained. So we need do nothing.
      */
 }
 
@@ -170,11 +172,22 @@ char *get_window_title(int icon)
 gint delete_window(GtkWidget *widget, GdkEvent *event, gpointer data)
 {
     /*
-     * FIXME: warn on close?
+     * We could implement warn-on-close here if we really wanted
+     * to.
      */
     return FALSE;
 }
 
+void show_mouseptr(int show)
+{
+    if (!cfg.hide_mouseptr)
+       show = 1;
+    if (show)
+       gdk_window_set_cursor(inst->area->window, inst->currcursor);
+    else
+       gdk_window_set_cursor(inst->area->window, inst->blankcursor);
+}
+
 gint configure_area(GtkWidget *widget, GdkEventConfigure *event, gpointer data)
 {
     struct gui_data *inst = (struct gui_data *)data;
@@ -371,6 +384,32 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
        }
 
        /*
+        * NetHack keypad mode.
+        */
+       if (cfg.nethack_keypad) {
+           char *keys = NULL;
+           switch (event->keyval) {
+             case GDK_KP_1: case GDK_KP_End: keys = "bB"; break;
+             case GDK_KP_2: case GDK_KP_Down: keys = "jJ"; break;
+             case GDK_KP_3: case GDK_KP_Page_Down: keys = "nN"; break;
+             case GDK_KP_4: case GDK_KP_Left: keys = "hH"; break;
+             case GDK_KP_5: case GDK_KP_Begin: keys = ".."; break;
+             case GDK_KP_6: case GDK_KP_Right: keys = "lL"; break;
+             case GDK_KP_7: case GDK_KP_Home: keys = "yY"; break;
+             case GDK_KP_8: case GDK_KP_Up: keys = "kK"; break;
+             case GDK_KP_9: case GDK_KP_Page_Up: keys = "uU"; break;
+           }
+           if (keys) {
+               end = 2;
+               if (event->state & GDK_SHIFT_MASK)
+                   output[1] = keys[1];
+               else
+                   output[1] = keys[0];
+               goto done;
+           }
+       }
+
+       /*
         * Application keypad mode.
         */
        if (app_keypad_keys && !cfg.no_applic_k) {
@@ -638,8 +677,11 @@ gint key_event(GtkWidget *widget, GdkEventKey *event, gpointer data)
            printf("\n");
        }
 #endif
-       ldisc_send(output+start, end-start, 1);
-       term_out();
+       if (end-start > 0) {
+           ldisc_send(output+start, end-start, 1);
+           show_mouseptr(0);
+           term_out();
+       }
     }
 
     return TRUE;
@@ -650,6 +692,8 @@ gint button_event(GtkWidget *widget, GdkEventButton *event, gpointer data)
     struct gui_data *inst = (struct gui_data *)data;
     int shift, ctrl, alt, x, y, button, act;
 
+    show_mouseptr(1);
+
     shift = event->state & GDK_SHIFT_MASK;
     ctrl = event->state & GDK_CONTROL_MASK;
     alt = event->state & GDK_MOD1_MASK;
@@ -687,6 +731,8 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
     struct gui_data *inst = (struct gui_data *)data;
     int shift, ctrl, alt, x, y, button;
 
+    show_mouseptr(1);
+
     shift = event->state & GDK_SHIFT_MASK;
     ctrl = event->state & GDK_CONTROL_MASK;
     alt = event->state & GDK_MOD1_MASK;
@@ -710,11 +756,31 @@ gint motion_event(GtkWidget *widget, GdkEventMotion *event, gpointer data)
 gint timer_func(gpointer data)
 {
     /* struct gui_data *inst = (struct gui_data *)data; */
+    extern int pty_child_is_dead();  /* declared in pty.c */
+
+    if (pty_child_is_dead()) {
+       /*
+        * The primary child process died. We could keep the
+        * terminal open for remaining subprocesses to output to,
+        * but conventional wisdom seems to feel that that's the
+        * Wrong Thing for an xterm-alike, so we bail out now. This
+        * would be easy enough to change or make configurable if
+        * necessary.
+        */
+       exit(0);
+    }
 
     term_update();
     return TRUE;
 }
 
+gint idle_func(gpointer data)
+{
+    /* struct gui_data *inst = (struct gui_data *)data; */
+    term_paste();
+    return TRUE;
+}
+
 void pty_input_func(gpointer data, gint sourcefd, GdkInputCondition condition)
 {
     /* struct gui_data *inst = (struct gui_data *)data; */
@@ -751,6 +817,7 @@ gint focus_event(GtkWidget *widget, GdkEventFocus *event, gpointer data)
     has_focus = event->in;
     term_out();
     term_update();
+    show_mouseptr(1);
     return FALSE;
 }
 
@@ -762,9 +829,10 @@ void set_raw_mouse_mode(int activate)
     activate = activate && !cfg.no_mouse_rep;
     send_raw_mouse = activate;
     if (send_raw_mouse)
-       gdk_window_set_cursor(inst->area->window, inst->rawcursor);
+       inst->currcursor = inst->rawcursor;
     else
-       gdk_window_set_cursor(inst->area->window, inst->textcursor);
+       inst->currcursor = inst->textcursor;
+    show_mouseptr(1);
 }
 
 void request_resize(int w, int h)
@@ -936,10 +1004,9 @@ void do_text(Context ctx, int x, int y, char *text, int len,
 
     /*
      * NYI:
-     *  - ATTR_WIDE (is this for Unicode CJK? I hope so)
+     *  - Unicode, code pages, and ATTR_WIDE for CJK support.
      *  - LATTR_* (ESC # 4 double-width and double-height stuff)
      *  - cursor shapes other than block
-     *  - VT100 line drawing stuff; code pages in general!
      *  - shadow bolding
      */
 
@@ -1043,12 +1110,12 @@ GdkCursor *make_mouse_ptr(int cursor_val)
     gchar text[2];
     gint lb, rb, wid, asc, desc, w, h, x, y;
 
-    if (cursor_val < 0) {
+    if (cursor_val == -2) {
        gdk_font_unref(cursor_font);
        return NULL;
     }
 
-    if (!cursor_font)
+    if (cursor_val >= 0 && !cursor_font)
        cursor_font = gdk_font_load("cursor");
 
     /*
@@ -1056,10 +1123,15 @@ GdkCursor *make_mouse_ptr(int cursor_val)
      * mask character for this, because it's typically slightly
      * bigger than the main character.
      */
-    text[1] = '\0';
-    text[0] = (char)cursor_val + 1;
-    gdk_string_extents(cursor_font, text, &lb, &rb, &wid, &asc, &desc);
-    w = rb-lb; h = asc+desc; x = -lb; y = asc;
+    if (cursor_val >= 0) {
+       text[1] = '\0';
+       text[0] = (char)cursor_val + 1;
+       gdk_string_extents(cursor_font, text, &lb, &rb, &wid, &asc, &desc);
+       w = rb-lb; h = asc+desc; x = -lb; y = asc;
+    } else {
+       w = h = 1;
+       x = y = 0;
+    }
 
     source = gdk_pixmap_new(NULL, w, h, 1);
     mask = gdk_pixmap_new(NULL, w, h, 1);
@@ -1067,25 +1139,29 @@ GdkCursor *make_mouse_ptr(int cursor_val)
     /*
      * Draw the mask character on the mask pixmap.
      */
-    text[1] = '\0';
-    text[0] = (char)cursor_val + 1;
     gc = gdk_gc_new(mask);
     gdk_gc_set_foreground(gc, &dbg);
     gdk_draw_rectangle(mask, gc, 1, 0, 0, w, h);
-    gdk_gc_set_foreground(gc, &dfg);
-    gdk_draw_text(mask, cursor_font, gc, x, y, text, 1);
+    if (cursor_val >= 0) {
+       text[1] = '\0';
+       text[0] = (char)cursor_val + 1;
+       gdk_gc_set_foreground(gc, &dfg);
+       gdk_draw_text(mask, cursor_font, gc, x, y, text, 1);
+    }
     gdk_gc_unref(gc);
 
     /*
      * Draw the main character on the source pixmap.
      */
-    text[1] = '\0';
-    text[0] = (char)cursor_val;
     gc = gdk_gc_new(source);
     gdk_gc_set_foreground(gc, &dbg);
     gdk_draw_rectangle(source, gc, 1, 0, 0, w, h);
-    gdk_gc_set_foreground(gc, &dfg);
-    gdk_draw_text(source, cursor_font, gc, x, y, text, 1);
+    if (cursor_val >= 0) {
+       text[1] = '\0';
+       text[0] = (char)cursor_val;
+       gdk_gc_set_foreground(gc, &dfg);
+       gdk_draw_text(source, cursor_font, gc, x, y, text, 1);
+    }
     gdk_gc_unref(gc);
 
     /*
@@ -1151,6 +1227,12 @@ int main(int argc, char **argv)
            } else
                err = 1, fprintf(stderr, "pterm: -T expects an argument\n");
        }
+       if (!strcmp(p, "-hide")) {
+           cfg.hide_mouseptr = 1;
+       }
+       if (!strcmp(p, "-nethack")) {
+           cfg.nethack_keypad = 1;
+       }
     }
 
     inst->fonts[0] = gdk_font_load(cfg.font);
@@ -1227,12 +1309,13 @@ int main(int argc, char **argv)
                       GTK_SIGNAL_FUNC(selection_clear), inst);
     gtk_signal_connect(GTK_OBJECT(inst->sbar_adjust), "value_changed",
                       GTK_SIGNAL_FUNC(scrollbar_moved), inst);
+    gtk_idle_add(idle_func, inst);
     gtk_timeout_add(20, timer_func, inst);
     gdk_input_add(pty_master_fd, GDK_INPUT_READ, pty_input_func, inst);
     gtk_widget_add_events(GTK_WIDGET(inst->area),
                          GDK_KEY_PRESS_MASK | GDK_KEY_RELEASE_MASK |
                          GDK_BUTTON_PRESS_MASK | GDK_BUTTON_RELEASE_MASK |
-                         GDK_BUTTON_MOTION_MASK);
+                         GDK_POINTER_MOTION_MASK | GDK_BUTTON_MOTION_MASK);
 
     gtk_widget_show(inst->area);
     gtk_widget_show(inst->sbar);
@@ -1241,8 +1324,10 @@ int main(int argc, char **argv)
 
     inst->textcursor = make_mouse_ptr(GDK_XTERM);
     inst->rawcursor = make_mouse_ptr(GDK_LEFT_PTR);
-    make_mouse_ptr(-1);                       /* clean up cursor font */
-    gdk_window_set_cursor(inst->area->window, inst->textcursor);
+    inst->blankcursor = make_mouse_ptr(-1);
+    make_mouse_ptr(-2);                       /* clean up cursor font */
+    inst->currcursor = inst->textcursor;
+    show_mouseptr(1);
 
     term_init();
     term_size(24, 80, 2000);