From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / apple2-main.c
index 0e1508ff1ad514e1a0ca064ab9f58df78634df81..3063b58d787f720324f9d700d7948586d0f420b0 100644 (file)
@@ -1,4 +1,4 @@
-/* xscreensaver, Copyright (c) 1998-2012 Jamie Zawinski <jwz@jwz.org>
+/* xscreensaver, Copyright (c) 1998-2014 Jamie Zawinski <jwz@jwz.org>
  *
  * Permission to use, copy, modify, distribute, and sell this software and its
  * documentation for any purpose is hereby granted without fee, provided that
@@ -27,6 +27,7 @@
 #include "screenhack.h"
 #include "apple2.h"
 #include "textclient.h"
+#include "utf8wc.h"
 
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
@@ -34,8 +35,6 @@
 #define SCREEN_COLS 40
 #define SCREEN_ROWS 24
 
-#define DEBUG
-
 
 /* Given a bitmask, returns the position and width of the field.
  */
@@ -88,7 +87,7 @@ scale_image (Display *dpy, Window window, XImage *in,
   int x, y, i;
   unsigned int rpos=0, gpos=0, bpos=0; /* bitfield positions */
   unsigned int rsiz=0, gsiz=0, bsiz=0;
-  unsigned int rmsk=0, gmsk=0, bmsk=0;
+  unsigned long rmsk=0, gmsk=0, bmsk=0;
   unsigned char spread_map[3][256];
   XWindowAttributes xgwa;
   XColor *colors = 0;
@@ -113,9 +112,7 @@ scale_image (Display *dpy, Window window, XImage *in,
     }
   else
     {
-      rmsk = xgwa.visual->red_mask;
-      gmsk = xgwa.visual->green_mask;
-      bmsk = xgwa.visual->blue_mask;
+      visual_rgb_masks (xgwa.screen, xgwa.visual, &rmsk, &gmsk, &bmsk);
       decode_mask (rmsk, &rpos, &rsiz);
       decode_mask (gmsk, &gpos, &gsiz);
       decode_mask (bmsk, &bpos, &bsiz);
@@ -762,7 +759,21 @@ static void slideshow_controller(apple2_sim_t *sim, int *stepno,
     *stepno=10;
     break;
 
+  case 80:
+    /* Do nothing, just wait */
+    *next_actiontime += 2.0;
+    *stepno = A2CONTROLLER_FREE;
+    break;
+
   case A2CONTROLLER_FREE:
+    /* It is possible that still image is being loaded,
+       in that case mine cannot be freed, because
+       callback function tries to use it, so wait.
+    */
+    if (mine->image_loading_p) {
+      *stepno = 80;
+      break;
+    }
     free(mine->render_img);
     free(mine->img_filename);
     free(mine);
@@ -786,6 +797,7 @@ struct terminal_controller_data {
   int curparam;
   int cursor_x, cursor_y;
   int saved_x,  saved_y;
+  int unicruds; char unicrud[7];
   union {
     struct {
       unsigned int bold : 1;
@@ -887,6 +899,8 @@ a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state,
   int i;
   int start, end;
 
+  /* Mostly duplicated in phosphor.c */
+
   switch (state->escstate)
     {
     case 0:
@@ -950,6 +964,38 @@ a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state,
           state->curparam = 0;
           break;
         default:
+
+          /* states 102-106 are for UTF-8 decoding */
+
+          if ((c & 0xE0) == 0xC0) {        /* 110xxxxx - 11 bits, 2 bytes */
+            state->unicruds = 1;
+            state->unicrud[0] = c;
+            state->escstate = 102;
+            break;
+          } else if ((c & 0xF0) == 0xE0) { /* 1110xxxx - 16 bits, 3 bytes */
+            state->unicruds = 1;
+            state->unicrud[0] = c;
+            state->escstate = 103;
+            break;
+          } else if ((c & 0xF8) == 0xF0) { /* 11110xxx - 21 bits, 4 bytes */
+            state->unicruds = 1;
+            state->unicrud[0] = c;
+            state->escstate = 104;
+            break;
+          } else if ((c & 0xFC) == 0xF8) { /* 111110xx - 26 bits, 5 bytes */
+            state->unicruds = 1;
+            state->unicrud[0] = c;
+            state->escstate = 105;
+            break;
+          } else if ((c & 0xFE) == 0xFC) { /* 1111110x - 31 bits, 6 bytes */
+            state->unicruds = 1;
+            state->unicrud[0] = c;
+            state->escstate = 106;
+            break;
+          }
+
+        PRINT:
+
           /* If the cursor is in column 39 and we print a character, then
              that character shows up in column 39, and the cursor is no longer
              visible on the screen (it's in "column 40".)  If another character
@@ -1024,9 +1070,13 @@ a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state,
           state->curparam = 0;
           break;
         case '%': /* Select charset */
-          /* No, I don't support UTF-8, since the apple2 font
-             isn't even Unicode anyway. We must still catch the
-             last byte, though. */
+          /* @: Select default (ISO 646 / ISO 8859-1)
+             G: Select UTF-8
+             8: Select UTF-8 (obsolete)
+
+             We can just ignore this and always process UTF-8, I think?
+             We must still catch the last byte, though.
+           */
         case '(':
         case ')':
           /* I don't support different fonts either - see above
@@ -1236,6 +1286,39 @@ a2_vt100_printc (apple2_sim_t *sim, struct terminal_controller_data *state,
     case 3:
       state->escstate = 0;
       break;
+
+    case 102:
+    case 103:
+    case 104:
+    case 105:
+    case 106:
+      {
+        int total = state->escstate - 100;  /* see what I did there */
+        if (state->unicruds < total) {
+          /* Buffer more bytes of the UTF-8 sequence */
+          state->unicrud[state->unicruds++] = c;
+        }
+
+        if (state->unicruds >= total) {
+          /* Done! Convert it to ASCII and print that. */
+          char *s;
+          state->unicrud[state->unicruds] = 0;
+          s = utf8_to_latin1 ((const char *) state->unicrud, True);
+          state->unicruds = 0;
+          state->escstate = 0;
+          if (s) {
+            c = s[0];
+            free (s);
+            goto PRINT;
+          } else {
+            /* c = 0; */
+          }
+        }
+      }
+      break;
+
+    default:
+      abort();
     }
   a2_goto(st, state->cursor_y, state->cursor_x);
 }
@@ -1278,30 +1361,43 @@ terminal_controller(apple2_sim_t *sim, int *stepno, double *next_actiontime)
       mine->tc = textclient_open (mine->dpy);
       textclient_reshape (mine->tc,
                           SCREEN_COLS, SCREEN_ROWS,
-                          SCREEN_COLS, SCREEN_ROWS);
+                          SCREEN_COLS, SCREEN_ROWS,
+                          0);
     }
 
     if (! mine->fast_p)
       *next_actiontime += 4.0;
     *stepno = 10;
+
+    mine->last_emit_time = sim->curtime;
     break;
 
   case 10:
+  case 11:
     {
+      Bool first_line_p = (*stepno == 10);
       unsigned char buf[1024];
       int nr,nwant;
       double elapsed;
 
       elapsed=sim->curtime - mine->last_emit_time;
-      mine->last_emit_time=sim->curtime;
-      nwant=elapsed*25.0;
-      if (elapsed>1.0) nwant=1;
-      if (nwant<1) nwant=1;
-      if (nwant>4) nwant=4;
+
+      nwant = elapsed * 25.0;   /* characters per second */
+
+      if (first_line_p) {
+        *stepno = 11;
+        nwant = 1;
+      }
+
+      if (nwant > 40) nwant = 40;
 
       if (mine->fast_p)
         nwant = sizeof(buf)-1;
 
+      if (nwant <= 0) break;
+
+      mine->last_emit_time = sim->curtime;
+
       nr=terminal_read(mine, buf, nwant);
       for (i=0; i<nr; i++) {
         c=buf[i];
@@ -1770,7 +1866,11 @@ apple2_draw (Display *dpy, Window window, void *closure)
     st->sim = 0;
   }
 
-  return 10000;
+#ifdef HAVE_MOBILE
+  return 0;
+#else
+  return 5000;
+#endif
 }
 
 static void
@@ -1778,7 +1878,8 @@ apple2_reshape (Display *dpy, Window window, void *closure,
                  unsigned int w, unsigned int h)
 {
   struct state *st = (struct state *) closure;
-  analogtv_reconfigure (st->sim->dec);
+  if (st->sim)
+    analogtv_reconfigure (st->sim->dec);
 }
 
 static Bool
@@ -1786,7 +1887,8 @@ apple2_event (Display *dpy, Window window, void *closure, XEvent *event)
 {
   struct state *st = (struct state *) closure;
 
-  if (st->controller == terminal_controller &&
+  if (st->sim &&
+      st->controller == terminal_controller &&
       event->xany.type == KeyPress) {
     terminal_keypress_handler (dpy, event, st->sim->controller_data);
     return True;