~ubuntu-branches/ubuntu/dapper/xscreensaver/dapper

« back to all changes in this revision

Viewing changes to hacks/xmatrix.c

  • Committer: Bazaar Package Importer
  • Author(s): Oliver Grawert
  • Date: 2005-10-11 21:00:42 UTC
  • mfrom: (2.1.1 sarge)
  • Revision ID: james.westby@ubuntu.com-20051011210042-u7q6zslgevdxspr3
Tags: 4.21-4ubuntu17
updated pt_BR again, fixed to UTF-8 

Show diffs side-by-side

added added

removed removed

Lines of Context:
1
 
/* xscreensaver, Copyright (c) 1999 Jamie Zawinski <jwz@jwz.org>
 
1
/* xscreensaver, Copyright (c) 1999, 2001 Jamie Zawinski <jwz@jwz.org>
2
2
 *
3
3
 * Permission to use, copy, modify, distribute, and sell this software and its
4
4
 * documentation for any purpose is hereby granted without fee, provided that
12
12
 *
13
13
 * The movie people distribute their own Windows/Mac screensaver that does
14
14
 * a similar thing, so I wrote one for Unix.  However, that version (the
15
 
 * Windows/Mac version at http://www.whatisthematrix.com/) doesn't match my
16
 
 * memory of what the screens in the movie looked like, so my `xmatrix'
17
 
 * does things differently.
 
15
 * Windows/Mac version at http://www.whatisthematrix.com/) doesn't match
 
16
 * what the computer screens in the movie looked like, so my `xmatrix' does
 
17
 * things differently.
 
18
 *
 
19
 * See also my `glmatrix' program, which does a 3D rendering of the similar
 
20
 * effect that appeared in the title sequence of the movies.
18
21
 *
19
22
 *
20
23
 *     ==========================================================
37
40
 *         washed out.  They also definitely scrolled a
38
41
 *         character at a time, not a pixel at a time.
39
42
 *
 
43
 *         And keep in mind that this program emulates the
 
44
 *         behavior of the computer screens that were visible
 
45
 *         in the movies -- not the behavior of the effects in
 
46
 *         the title sequences.
 
47
 *
40
48
 *     ==========================================================
41
49
 *
42
 
 * One thing I would like to add (to "-trace" mode) is an intro like at the
43
 
 * beginning of the movie, where it printed
44
 
 *
45
 
 *        Call trans opt: received. 2-19-98 13:24:18 REC:Log>_
46
 
 *
47
 
 * then cleared, then
48
 
 *
49
 
 *        Trace program: running_
50
 
 *
51
 
 * then did the trace.
52
 
 *
53
 
 * I was also thinking of sometimes making the screen go blank and say
54
 
 * "Knock, knock."  
55
 
 *
56
 
 * However, the problem with both of these ideas is, I made the number images
57
 
 * by tooling around in GIMP until I got something that looked good (blurring
58
 
 * and unblurring and enlarging and shrinking and blurring some more...) and I
59
 
 * couldn't reproduce it if my life depended on it.  And to add anything other
60
 
 * than roman digits/katakana, I'd need to matrixify a whole font...
61
50
 */
62
51
 
63
52
#include "screenhack.h"
 
53
#include "xpm-pixmap.h"
64
54
#include <stdio.h>
65
55
#include <X11/Xutil.h>
66
56
 
67
 
#ifdef HAVE_XPM
68
 
# include <X11/xpm.h>
69
 
# include "images/matrix.xpm"
 
57
#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
 
58
# include "images/matrix1.xpm"
70
59
# include "images/matrix2.xpm"
 
60
# include "images/matrix1b.xpm"
 
61
# include "images/matrix2b.xpm"
71
62
#endif
72
63
 
73
 
#include "images/matrix.xbm"
 
64
#include "images/matrix1.xbm"
74
65
#include "images/matrix2.xbm"
 
66
#include "images/matrix1b.xbm"
 
67
#include "images/matrix2b.xbm"
75
68
 
76
 
#define CHAR_ROWS 27
77
 
#define CHAR_COLS 3
78
 
#define FADE_COL  0
79
 
#define PLAIN_COL 1
80
 
#define GLOW_COL  2
 
69
#define CHAR_COLS 16
 
70
#define CHAR_ROWS 13
 
71
#define CHAR_MAPS 3
 
72
#define PLAIN_MAP 1
 
73
#define GLOW_MAP  2
81
74
 
82
75
typedef struct {
83
 
  unsigned int glyph   : 8;
84
76
           int glow    : 8;
 
77
  unsigned int glyph   : 9;  /* note: 9 bit characters! */
85
78
  unsigned int changed : 1;
86
79
  unsigned int spinner : 1;
87
80
} m_cell;
92
85
  int y;
93
86
} m_feeder;
94
87
 
 
88
#define countof(x) (sizeof(x)/sizeof(*(x)))
 
89
 
 
90
static int matrix_encoding[] = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
 
91
                                 192, 193, 194, 195, 196, 197, 198, 199,
 
92
                                 200, 201, 202, 203, 204, 205, 206, 207 };
 
93
static int decimal_encoding[]  = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25 };
 
94
static int hex_encoding[]      = { 16, 17, 18, 19, 20, 21, 22, 23, 24, 25,
 
95
                                   33, 34, 35, 36, 37, 38 };
 
96
static int binary_encoding[] = { 16, 17 };
 
97
static int dna_encoding[]    = { 33, 35, 39, 52 };
 
98
static unsigned char char_map[256] = {
 
99
    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  /*   0 */
 
100
    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  /*  16 */
 
101
    0,  1,  2,  3,  4,  5,  6,  7,  8,  9, 10, 11, 12, 13, 14, 15,  /*  32 */
 
102
   16, 17, 18, 19, 20, 21, 22, 23, 24, 25, 26, 27, 28, 29, 30, 31,  /*  48 */
 
103
   32, 33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44, 45, 46, 47,  /*  64 */
 
104
   48, 49, 50, 51, 52, 53, 54, 55, 56, 57, 58, 59, 60, 61, 62, 63,  /*  80 */
 
105
   64, 65, 66, 67, 68, 69, 70, 71, 72, 73, 74, 75, 76, 77, 78, 79,  /*  96 */
 
106
   80, 81, 82, 83, 84, 85, 86, 87, 88, 89, 90, 91, 92, 93, 94, 95,  /* 112 */
 
107
    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  /* 128 */
 
108
    3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  3,  /* 144 */
 
109
   96, 97, 98, 99,100,101,102,103,104,105,106,107,108,109,110,111,  /* 160 */
 
110
  112,113,114,115,116,117,118,119,120,121,122,123,124,125,126,127,  /* 176 */
 
111
  128,129,130,131,132,133,134,135,136,137,138,139,140,141,142,143,  /* 192 */
 
112
  144,145,146,147,148,149,150,151,152,153,154,155,156,157,158,159,  /* 208 */
 
113
  160,161,162,163,164,165,166,167,168,169,170,171,172,173,174,175,  /* 224 */
 
114
  176,177,178,195,180,181,182,183,184,185,186,187,188,189,190,191   /* 240 */
 
115
};
 
116
 
 
117
#define CURSOR_GLYPH 97
 
118
 
 
119
typedef enum { TRACEA1, TRACEA2,
 
120
               TRACEB1, TRACEB2, SYSTEMFAILURE,
 
121
               KNOCK, NMAP, MATRIX, DNA, BINARY, DEC, HEX } m_mode;
 
122
 
95
123
typedef struct {
96
124
  Display *dpy;
97
125
  Window window;
98
126
  XWindowAttributes xgwa;
99
 
  GC draw_gc, erase_gc;
 
127
  GC draw_gc, erase_gc, scratch_gc;
100
128
  int grid_width, grid_height;
101
129
  int char_width, char_height;
102
130
  m_cell *cells;
 
131
  m_cell *cursor;
103
132
  m_feeder *feeders;
104
133
  int nspinners;
 
134
  Bool knock_knock_p;
105
135
  Bool small_p;
106
136
  Bool insert_top_p, insert_bottom_p;
107
 
  Bool trace_p;
 
137
  m_mode mode;
108
138
  signed char *tracing;
109
139
  int density;
110
140
 
111
 
  Pixmap images;
 
141
  Pixmap images[CHAR_MAPS];
112
142
  int image_width, image_height;
 
143
 
113
144
  int nglyphs;
 
145
  int *glyph_map;
114
146
 
 
147
  unsigned long colors[5];
115
148
} m_state;
116
149
 
117
150
 
118
151
static void
119
 
load_images (m_state *state)
 
152
load_images_1 (m_state *state, int which)
120
153
{
121
 
#ifdef HAVE_XPM
 
154
#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
122
155
  if (!get_boolean_resource ("mono", "Boolean") &&
123
156
      state->xgwa.depth > 1)
124
157
    {
125
 
      XpmAttributes xpmattrs;
126
 
      int result;
127
 
      xpmattrs.valuemask = 0;
128
 
 
129
 
# ifdef XpmCloseness
130
 
      xpmattrs.valuemask |= XpmCloseness;
131
 
      xpmattrs.closeness = 40000;
132
 
# endif
133
 
# ifdef XpmVisual
134
 
      xpmattrs.valuemask |= XpmVisual;
135
 
      xpmattrs.visual = state->xgwa.visual;
136
 
# endif
137
 
# ifdef XpmDepth
138
 
      xpmattrs.valuemask |= XpmDepth;
139
 
      xpmattrs.depth = state->xgwa.depth;
140
 
# endif
141
 
# ifdef XpmColormap
142
 
      xpmattrs.valuemask |= XpmColormap;
143
 
      xpmattrs.colormap = state->xgwa.colormap;
144
 
# endif
145
 
 
146
 
      result = XpmCreatePixmapFromData (state->dpy, state->window,
147
 
                                        (state->small_p
148
 
                                         ? matrix2_xpm
149
 
                                         : matrix_xpm),
150
 
                                        &state->images, 0 /* mask */,
151
 
                                        &xpmattrs);
152
 
      if (!state->images || (result != XpmSuccess && result != XpmColorError))
153
 
        state->images = 0;
154
 
 
155
 
      state->image_width = xpmattrs.width;
156
 
      state->image_height = xpmattrs.height;
157
 
      state->nglyphs = CHAR_ROWS;
 
158
      char **bits =
 
159
        (which == 1 ? (state->small_p ? matrix1b_xpm : matrix1_xpm) :
 
160
         (state->small_p ? matrix2b_xpm : matrix2_xpm));
 
161
 
 
162
      state->images[which] =
 
163
        xpm_data_to_pixmap (state->dpy, state->window, bits,
 
164
                            &state->image_width, &state->image_height, 0);
158
165
    }
159
166
  else
160
 
#endif /* !HAVE_XPM */
 
167
#endif /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
161
168
    {
162
169
      unsigned long fg, bg;
163
 
      state->image_width =  (state->small_p ? matrix2_width  : matrix_width);
164
 
      state->image_height = (state->small_p ? matrix2_height : matrix_height);
165
 
      state->nglyphs = CHAR_ROWS;
166
 
 
 
170
      state->image_width  = (state->small_p ? matrix1b_width :matrix1_width);
 
171
      state->image_height = (state->small_p ? matrix1b_height:matrix1_height);
167
172
      fg = get_pixel_resource("foreground", "Foreground",
168
173
                              state->dpy, state->xgwa.colormap);
169
174
      bg = get_pixel_resource("background", "Background",
170
175
                              state->dpy, state->xgwa.colormap);
171
 
      state->images =
172
 
        XCreatePixmapFromBitmapData (state->dpy, state->window,
173
 
                                     (state->small_p
174
 
                                      ? (char *) matrix2_bits
175
 
                                      : (char *) matrix_bits),
 
176
      state->images[which] =
 
177
        XCreatePixmapFromBitmapData (state->dpy, state->window, (char *)
 
178
                (which == 1 ? (state->small_p ? matrix1b_bits :matrix1_bits) :
 
179
                              (state->small_p ? matrix2b_bits :matrix2_bits)),
176
180
                                     state->image_width, state->image_height,
177
181
                                     bg, fg, state->xgwa.depth);
178
182
    }
180
184
 
181
185
 
182
186
static void
183
 
flip_images (m_state *state)
184
 
{
185
 
  XImage *im = XGetImage (state->dpy, state->images, 0, 0,
 
187
load_images (m_state *state)
 
188
{
 
189
  load_images_1 (state, 1);
 
190
  load_images_1 (state, 2);
 
191
}
 
192
 
 
193
 
 
194
static void
 
195
flip_images_1 (m_state *state, int which)
 
196
{
 
197
  XImage *im = XGetImage (state->dpy, state->images[which], 0, 0,
186
198
                          state->image_width, state->image_height,
187
199
                          ~0L, (state->xgwa.depth > 1 ? ZPixmap : XYPixmap));
188
 
  int x, y, i;
189
 
  int w = state->image_width / CHAR_COLS;
190
 
  unsigned long *row = (unsigned long *) malloc (sizeof(*row) * w);
 
200
  int x, y, xx;
 
201
  int ww = state->char_width;
 
202
  unsigned long *row = (unsigned long *) malloc (sizeof(*row) * ww);
191
203
 
192
204
  for (y = 0; y < state->image_height; y++)
193
 
    for (i = 0; i < CHAR_COLS; i++)
194
 
      {
195
 
        for (x = 0; x < w; x++)
196
 
          row[x] = XGetPixel (im, (i * w) + x, y);
197
 
        for (x = 0; x < w; x++)
198
 
          XPutPixel (im, (i * w) + x, y, row[w - x - 1]);
199
 
      }
 
205
    {
 
206
      for (x = 0; x < CHAR_COLS; x++)
 
207
        {
 
208
          for (xx = 0; xx < ww; xx++)
 
209
            row[xx] = XGetPixel (im, (x * ww) + xx, y);
 
210
          for (xx = 0; xx < ww; xx++)
 
211
            XPutPixel (im, (x * ww) + xx, y, row[ww - xx - 1]);
 
212
        }
 
213
    }
200
214
 
201
 
  XPutImage (state->dpy, state->images, state->draw_gc, im, 0, 0, 0, 0,
 
215
  XPutImage (state->dpy, state->images[which], state->draw_gc, im, 0, 0, 0, 0,
202
216
             state->image_width, state->image_height);
203
217
  XDestroyImage (im);
204
218
  free (row);
205
219
}
206
220
 
 
221
static void
 
222
flip_images (m_state *state)
 
223
{
 
224
  flip_images_1 (state, 1);
 
225
  flip_images_1 (state, 2);
 
226
}
 
227
 
207
228
 
208
229
static void
209
230
init_spinners (m_state *state)
238
259
  if (!s)
239
260
    goto FAIL;
240
261
 
241
 
  state->tracing = (char *) malloc (strlen (s) + 1);
242
 
  s3 = state->tracing;
 
262
  state->tracing = (signed char *) malloc (strlen (s) + 1);
 
263
  s3 = (char *) state->tracing;
243
264
 
244
265
  for (s2 = s; *s2; s2++)
245
266
    if (*s2 >= '0' && *s2 <= '9')
249
270
  if (s3 == (char *) state->tracing)
250
271
    goto FAIL;
251
272
 
252
 
  for (i = 0; i < strlen(state->tracing); i++)
 
273
  for (i = 0; i < strlen((char *) state->tracing); i++)
253
274
    state->tracing[i] = -state->tracing[i];
254
 
  state->nglyphs = 10;
255
 
  flip_images (state);
 
275
 
 
276
  state->glyph_map = decimal_encoding;
 
277
  state->nglyphs = countof(decimal_encoding);
256
278
 
257
279
  return;
258
280
 
263
285
  if (s) free (s);
264
286
  if (state->tracing) free (state->tracing);
265
287
  state->tracing = 0;
266
 
  state->trace_p = False;
 
288
  state->mode = MATRIX;
267
289
}
268
290
 
269
291
 
271
293
init_matrix (Display *dpy, Window window)
272
294
{
273
295
  XGCValues gcv;
274
 
  char *insert;
 
296
  char *insert, *mode;
 
297
  int i;
275
298
  m_state *state = (m_state *) calloc (sizeof(*state), 1);
 
299
 
276
300
  state->dpy = dpy;
277
301
  state->window = window;
278
302
 
279
303
  XGetWindowAttributes (dpy, window, &state->xgwa);
280
304
 
281
 
  state->small_p = get_boolean_resource ("small", "Boolean");
 
305
  {
 
306
    const char *s = get_string_resource ("small", "Boolean");
 
307
    if (s && *s)
 
308
      state->small_p = get_boolean_resource ("small", "Boolean");
 
309
    else
 
310
      state->small_p = (state->xgwa.width < 300);
 
311
  }
 
312
 
282
313
  load_images (state);
283
314
 
284
315
  gcv.foreground = get_pixel_resource("foreground", "Foreground",
291
322
  state->erase_gc = XCreateGC (state->dpy, state->window,
292
323
                               GCForeground|GCBackground, &gcv);
293
324
 
 
325
  state->scratch_gc = XCreateGC (state->dpy, state->window, 0, &gcv);
 
326
 
 
327
  /* Allocate colors for SYSTEM FAILURE box */
 
328
  {
 
329
    XColor boxcolors[] = {
 
330
      { 0, 0x0808, 0x1E1E, 0x0808, DoRed|DoGreen|DoBlue, 0 },
 
331
      { 0, 0x5A5A, 0xD2D2, 0x5A5A, DoRed|DoGreen|DoBlue, 0 },
 
332
      { 0, 0xE0E0, 0xF7F7, 0xE0E0, DoRed|DoGreen|DoBlue, 0 },
 
333
      { 0, 0x5A5A, 0xD2D2, 0x5A5A, DoRed|DoGreen|DoBlue, 0 },
 
334
      { 0, 0x0808, 0x1E1E, 0x0808, DoRed|DoGreen|DoBlue, 0 },
 
335
    };
 
336
  for (i = 0; i < countof(boxcolors); i++)
 
337
    {
 
338
      if (XAllocColor (state->dpy, state->xgwa.colormap, &boxcolors[i]))
 
339
        state->colors[i] = boxcolors[i].pixel;
 
340
      else
 
341
        state->colors[i] = gcv.foreground;  /* default black */
 
342
    }
 
343
  }
 
344
 
294
345
  state->char_width =  state->image_width  / CHAR_COLS;
295
346
  state->char_height = state->image_height / CHAR_ROWS;
296
347
 
298
349
  state->grid_height = state->xgwa.height / state->char_height;
299
350
  state->grid_width++;
300
351
  state->grid_height++;
 
352
  if (state->grid_width  < 5) state->grid_width  = 5;
 
353
  if (state->grid_height < 5) state->grid_height = 5;
 
354
 
 
355
  state->glyph_map = matrix_encoding;
 
356
  state->nglyphs = countof(matrix_encoding);
301
357
 
302
358
  state->cells = (m_cell *)
303
359
    calloc (sizeof(m_cell), state->grid_width * state->grid_height);
 
360
  state->cursor = NULL;
304
361
  state->feeders = (m_feeder *) calloc (sizeof(m_feeder), state->grid_width);
305
362
 
306
363
  state->density = get_integer_resource ("density", "Integer");
336
393
  if (insert)
337
394
    free (insert);
338
395
 
339
 
  state->trace_p = get_boolean_resource ("trace", "Trace");
340
 
  if (state->trace_p)
341
 
    init_trace (state);
 
396
  state->knock_knock_p = get_boolean_resource ("knockKnock", "KnockKnock");
 
397
 
 
398
  mode = get_string_resource ("mode", "Mode");
 
399
  if (mode && !strcasecmp(mode, "trace"))
 
400
    state->mode = (((random() % 3) == 0) ? TRACEB1 : TRACEA1);
 
401
  else if (mode && !strcasecmp(mode, "crack"))
 
402
    state->mode = NMAP;
 
403
  else if (mode && !strcasecmp(mode, "dna"))
 
404
    state->mode = DNA;
 
405
  else if (mode && (!strcasecmp(mode, "bin") ||
 
406
                    !strcasecmp(mode, "binary")))
 
407
    state->mode = BINARY;
 
408
  else if (mode && (!strcasecmp(mode, "hex") ||
 
409
                    !strcasecmp(mode, "hexadecimal")))
 
410
    state->mode = HEX;
 
411
  else if (mode && (!strcasecmp(mode, "dec") ||
 
412
                    !strcasecmp(mode, "decimal")))
 
413
    state->mode = DEC;
 
414
  else if (!mode || !*mode || !strcasecmp(mode, "matrix"))
 
415
    state->mode = MATRIX;
342
416
  else
343
 
    init_spinners (state);
 
417
    {
 
418
      fprintf (stderr,
 
419
           "%s: `mode' must be matrix, trace, dna, binary, or hex: not `%s'\n",
 
420
               progname, mode);
 
421
      state->mode = MATRIX;
 
422
    }
 
423
 
 
424
  switch (state->mode)
 
425
    {
 
426
    case DNA:
 
427
      state->glyph_map = dna_encoding;
 
428
      state->nglyphs = countof(dna_encoding);
 
429
      break;
 
430
    case BINARY:
 
431
      state->glyph_map = binary_encoding;
 
432
      state->nglyphs = countof(binary_encoding);
 
433
      break;
 
434
    case DEC:
 
435
      state->glyph_map = decimal_encoding;
 
436
      state->nglyphs = countof(decimal_encoding);
 
437
      break;
 
438
    case HEX:
 
439
      state->glyph_map = hex_encoding;
 
440
      state->nglyphs = countof(hex_encoding);
 
441
      break;
 
442
    case TRACEA1: case TRACEB1:
 
443
      init_trace (state);
 
444
      break;
 
445
    case NMAP:
 
446
      break;
 
447
    case MATRIX:
 
448
      flip_images (state);
 
449
      init_spinners (state);
 
450
      break;
 
451
    default:
 
452
      abort();
 
453
    }
344
454
 
345
455
  return state;
346
456
}
378
488
  if (!to->glyph)
379
489
    ;
380
490
  else if (bottom_feeder_p)
381
 
    to->glow = 1 + (random() % 2);
 
491
    to->glow = 1 + (random() % (state->tracing ? 4 : 2));
382
492
  else
383
493
    to->glow = 0;
384
494
}
389
499
{
390
500
  int x;
391
501
 
 
502
  switch (state->mode)
 
503
    {
 
504
    case TRACEA2: case TRACEB2:
 
505
    case MATRIX: case DNA: case BINARY: case DEC: case HEX:
 
506
      break;
 
507
    default:
 
508
      return;
 
509
    }
 
510
 
392
511
  /* Update according to current feeders. */
393
512
  for (x = 0; x < state->grid_width; x++)
394
513
    {
400
519
        }
401
520
      else if (f->remaining > 0)        /* how many items are in the pipe */
402
521
        {
403
 
          int g = (random() % state->nglyphs) + 1;
 
522
          int g = state->glyph_map[(random() % state->nglyphs)] + 1;
404
523
          insert_glyph (state, g, x, f->y);
405
524
          f->remaining--;
406
525
          if (f->y >= 0)  /* bottom_feeder_p */
420
539
    }
421
540
}
422
541
 
 
542
 
 
543
static void
 
544
redraw_cells (m_state *state, Bool active)
 
545
{
 
546
  int x, y;
 
547
  int count = 0;
 
548
 
 
549
  for (y = 0; y < state->grid_height; y++)
 
550
    for (x = 0; x < state->grid_width; x++)
 
551
      {
 
552
        m_cell *cell = &state->cells[state->grid_width * y + x];
 
553
 
 
554
        if (cell->glyph)
 
555
          count++;
 
556
 
 
557
        if ((state->mode == TRACEA2 || state->mode == TRACEB2) && active)
 
558
          {
 
559
            int xx = x % strlen((char *) state->tracing);
 
560
            Bool dead_p = state->tracing[xx] > 0;
 
561
 
 
562
            if (y == 0 && x == xx)
 
563
              cell->glyph = (dead_p
 
564
                             ? state->glyph_map[state->tracing[xx]-'0'] + 1
 
565
                             : 0);
 
566
            else if (y == 0)
 
567
              cell->glyph = 0;
 
568
            else
 
569
              cell->glyph = (dead_p ? 0 :
 
570
                             (state->glyph_map[(random()%state->nglyphs)]
 
571
                              + 1));
 
572
 
 
573
            cell->changed = 1;
 
574
          }
 
575
 
 
576
        if (!cell->changed)
 
577
          continue;
 
578
 
 
579
        if (cell->glyph == 0 && cell != state->cursor)
 
580
          XFillRectangle (state->dpy, state->window, state->erase_gc,
 
581
                          x * state->char_width,
 
582
                          y * state->char_height,
 
583
                          state->char_width,
 
584
                          state->char_height);
 
585
        else
 
586
          {
 
587
            int g = (cell == state->cursor ? CURSOR_GLYPH : cell->glyph);
 
588
            int cx = (g - 1) % CHAR_COLS;
 
589
            int cy = (g - 1) / CHAR_COLS;
 
590
            int map = ((cell->glow != 0 || cell->spinner) ? GLOW_MAP :
 
591
                       PLAIN_MAP);
 
592
 
 
593
            XCopyArea (state->dpy, state->images[map],
 
594
                       state->window, state->draw_gc,
 
595
                       cx * state->char_width,
 
596
                       cy * state->char_height,
 
597
                       state->char_width,
 
598
                       state->char_height,
 
599
                       x * state->char_width,
 
600
                       y * state->char_height);
 
601
          }
 
602
 
 
603
        cell->changed = 0;
 
604
 
 
605
        if (cell->glow > 0)
 
606
          {
 
607
            cell->glow--;
 
608
            cell->changed = 1;
 
609
          }
 
610
        else if (cell->glow < 0)
 
611
          abort();
 
612
 
 
613
        if (cell->spinner && active)
 
614
          {
 
615
            cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1);
 
616
            cell->changed = 1;
 
617
          }
 
618
      }
 
619
 
 
620
  if (state->cursor)
 
621
    {
 
622
      state->cursor->changed = 1;
 
623
    }
 
624
}
 
625
 
 
626
 
423
627
static int
424
628
densitizer (m_state *state)
425
629
{
442
646
}
443
647
 
444
648
 
 
649
static void drain_matrix (m_state *);
 
650
 
 
651
static void
 
652
handle_events (m_state *state)
 
653
{
 
654
  XSync (state->dpy, False);
 
655
  while (XPending (state->dpy))
 
656
    {
 
657
      XEvent event;
 
658
      XNextEvent (state->dpy, &event);
 
659
 
 
660
      if (event.xany.type == ConfigureNotify)
 
661
        {
 
662
          int ow = state->grid_width;
 
663
          int oh = state->grid_height;
 
664
          XGetWindowAttributes (state->dpy, state->window, &state->xgwa);
 
665
          state->grid_width  = state->xgwa.width  / state->char_width;
 
666
          state->grid_height = state->xgwa.height / state->char_height;
 
667
          state->grid_width++;
 
668
          state->grid_height++;
 
669
          if (state->grid_width  < 5) state->grid_width  = 5;
 
670
          if (state->grid_height < 5) state->grid_height = 5;
 
671
 
 
672
          if (ow != state->grid_width ||
 
673
              oh != state->grid_height)
 
674
            {
 
675
              m_cell *ncells = (m_cell *)
 
676
                calloc (sizeof(m_cell),
 
677
                        state->grid_width * state->grid_height);
 
678
              m_feeder *nfeeders = (m_feeder *)
 
679
                calloc (sizeof(m_feeder), state->grid_width);
 
680
              int x, y, i;
 
681
 
 
682
              /* fprintf(stderr, "resize: %d x %d  ==>  %d x %d\n",
 
683
                        ow, oh, state->grid_width, state->grid_height); */
 
684
 
 
685
              for (y = 0; y < oh; y++)
 
686
                for (x = 0; x < ow; x++)
 
687
                  if (x < ow && x < state->grid_width &&
 
688
                      y < oh && y < state->grid_height)
 
689
                    ncells[y * state->grid_width + x] =
 
690
                      state->cells[y * ow + x];
 
691
              free (state->cells);
 
692
              state->cells = ncells;
 
693
 
 
694
              x = (ow < state->grid_width ? ow : state->grid_width);
 
695
              for (i = 0; i < x; i++)
 
696
                nfeeders[i] = state->feeders[i];
 
697
              free (state->feeders);
 
698
              state->feeders = nfeeders;
 
699
            }
 
700
        }
 
701
      else if (event.xany.type == KeyPress)
 
702
        {
 
703
          KeySym keysym;
 
704
          char c = 0;
 
705
          XLookupString (&event.xkey, &c, 1, &keysym, 0);
 
706
          if (c == '0' && !state->tracing)
 
707
            {
 
708
              drain_matrix (state);
 
709
              return;
 
710
            }
 
711
          else if (c == '+' || c == '=' || c == '>' || c == '.')
 
712
            {
 
713
              state->density += 10;
 
714
              if (state->density > 100)
 
715
                state->density = 100;
 
716
              else
 
717
                return;
 
718
            }
 
719
          else if (c == '-' || c == '_' || c == '<' || c == ',')
 
720
            {
 
721
              state->density -= 10;
 
722
              if (state->density < 0)
 
723
                state->density = 0;
 
724
              else
 
725
                return;
 
726
            }
 
727
          else if (c == '[' || c == '(' || c == '{')
 
728
            {
 
729
              state->insert_top_p    = True;
 
730
              state->insert_bottom_p = False;
 
731
              return;
 
732
            }
 
733
          else if (c == ']' || c == ')' || c == '}')
 
734
            {
 
735
              state->insert_top_p    = False;
 
736
              state->insert_bottom_p = True;
 
737
              return;
 
738
            }
 
739
          else if (c == '\\' || c == '|')
 
740
            {
 
741
              state->insert_top_p    = True;
 
742
              state->insert_bottom_p = True;
 
743
              return;
 
744
            }
 
745
          else if ((c == 't' || c == 'T') && state->mode == MATRIX)
 
746
            {
 
747
              state->mode = (c == 't' ? TRACEA1 : TRACEB1);
 
748
              flip_images (state);
 
749
              init_trace (state);
 
750
              return;
 
751
            }
 
752
          else if ((c == 'c' || c == 'k') && state->mode == MATRIX)
 
753
            {
 
754
              drain_matrix (state);
 
755
              state->mode = (c == 'c' ? NMAP : KNOCK);
 
756
              flip_images (state);
 
757
              return;
 
758
            }
 
759
        }
 
760
 
 
761
      screenhack_handle_event (state->dpy, &event);
 
762
    }
 
763
}
 
764
 
 
765
 
 
766
static void
 
767
matrix_usleep (m_state *state, unsigned long delay)
 
768
{
 
769
  if (!delay) return;
 
770
 
 
771
  if (state->cursor)
 
772
    {
 
773
      int blink_delay = 333000;
 
774
      int tot_delay = 0;
 
775
      m_cell *cursor = state->cursor;
 
776
      while (tot_delay < delay)
 
777
        {
 
778
          if (state->cursor)
 
779
            {
 
780
              usleep (blink_delay * 2);
 
781
              tot_delay += (2 * blink_delay);
 
782
              state->cursor = NULL;
 
783
            }
 
784
          else
 
785
            {
 
786
              usleep (blink_delay);
 
787
              tot_delay += blink_delay;
 
788
              state->cursor = cursor;
 
789
            }
 
790
          cursor->changed = 1;
 
791
          redraw_cells (state, False);
 
792
          XSync (state->dpy, False);
 
793
          handle_events (state);
 
794
        }
 
795
    }
 
796
  else
 
797
    {
 
798
      XSync (state->dpy, False);
 
799
      handle_events (state);
 
800
      usleep (delay);
 
801
    }
 
802
}
 
803
 
 
804
 
 
805
static void
 
806
hack_text_1 (m_state *state,
 
807
             int *xP, int *yP,
 
808
             const char *s,
 
809
             Bool typing_delay,
 
810
             Bool transmit_delay,
 
811
             Bool long_delay,
 
812
             Bool visible_cursor,
 
813
             Bool scroll_p)
 
814
{
 
815
  int x = *xP;
 
816
  int y = *yP;
 
817
  int i = state->grid_width * y + x;
 
818
  Bool glow_p = False;
 
819
  int long_delay_usecs = 1000000;
 
820
 
 
821
  if (long_delay == -1)
 
822
    long_delay = 0, long_delay_usecs /= 6;
 
823
 
 
824
  if (y >= state->grid_height-1) return;
 
825
 
 
826
  while (*s)
 
827
    {
 
828
      m_cell *cell;
 
829
      Bool done_p = s[1] == '\000';
 
830
 
 
831
      long_delay = done_p;
 
832
              
 
833
      if (*s == '\n' || x >= state->grid_width - 1)
 
834
        {
 
835
          if (*s != '\n')
 
836
            s--;
 
837
          x = 0;
 
838
          y++;
 
839
          i = state->grid_width * y + x;
 
840
 
 
841
          if (scroll_p)
 
842
            {
 
843
              int xx, yy;
 
844
              for (yy = 0; yy < state->grid_height-1; yy++)
 
845
                for (xx = 0; xx < state->grid_width; xx++)
 
846
                  {
 
847
                    int ii = yy     * state->grid_width + xx;
 
848
                    int jj = (yy+1) * state->grid_width + xx;
 
849
                    state->cells[ii] = state->cells[jj];
 
850
                    state->cells[ii].changed = 1;
 
851
                  }
 
852
              /* clear bottom row */
 
853
              for (xx = 0; xx < state->grid_width; xx++)
 
854
                {
 
855
                  int ii = yy * state->grid_width + xx;
 
856
                  state->cells[ii].glyph   = 0;
 
857
                  state->cells[ii].changed = 1;
 
858
                }
 
859
              y--;  /* move it back */
 
860
              i = state->grid_width * y + x;
 
861
            }
 
862
 
 
863
          if (y >= state->grid_height) return;
 
864
 
 
865
          cell = &state->cells[i];
 
866
          if (visible_cursor)
 
867
            {
 
868
              cell->changed = 1;
 
869
              state->cursor = cell;
 
870
            }
 
871
        }
 
872
      else if (*s == '\010')
 
873
        ;
 
874
      else if (*s == '\002')
 
875
        glow_p = True;
 
876
      else
 
877
        {
 
878
          cell = &state->cells[i];
 
879
          if (x < state->grid_width-1)
 
880
            {
 
881
              cell->glyph = char_map[(unsigned char) *s] + 1;
 
882
              if (*s == ' ' || *s == '\t') cell->glyph = 0;
 
883
              cell->changed = 1;
 
884
              cell->glow = (glow_p ? 100 : 0);
 
885
              if (visible_cursor)
 
886
                {
 
887
                  m_cell *next = &state->cells[i + 1];
 
888
                  next->changed = 1;
 
889
                  state->cursor = next;
 
890
                }
 
891
              i++;
 
892
            }
 
893
          x++;
 
894
        }
 
895
      s++;
 
896
      if (typing_delay || transmit_delay || long_delay)
 
897
        {
 
898
          redraw_cells (state, False);
 
899
          XSync (state->dpy, False);
 
900
          handle_events (state);
 
901
          if (typing_delay)
 
902
            {
 
903
              usleep (50000);
 
904
              if (typing_delay && 0 == random() % 3)
 
905
                usleep (0xFFFFFF & ((random() % 250000) + 1));
 
906
            }
 
907
          else
 
908
            if (long_delay)
 
909
              matrix_usleep (state, long_delay_usecs);
 
910
            else
 
911
              usleep (20000);
 
912
        }
 
913
    }
 
914
 
 
915
  *xP = x;
 
916
  *yP = y;
 
917
}
 
918
 
 
919
 
 
920
static void
 
921
zero_cells (m_state *state)
 
922
{
 
923
  int i;
 
924
  for (i = 0; i < state->grid_height * state->grid_width; i++)
 
925
    {
 
926
      m_cell *cell = &state->cells[i];
 
927
      cell->changed = (cell->glyph != 0);
 
928
      cell->glyph   = 0;
 
929
      cell->glow    = 0;
 
930
      cell->spinner = 0;
 
931
    }
 
932
}
 
933
 
 
934
 
 
935
static void
 
936
hack_text (m_state *state)
 
937
{
 
938
  Bool typing_delay = False;
 
939
  Bool transmit_delay = False;
 
940
  Bool long_delay = False;
 
941
  Bool visible_cursor = False;
 
942
 
 
943
  switch (state->mode)
 
944
    {
 
945
    case KNOCK:
 
946
      {
 
947
        const char *blocks[] = {
 
948
          "Wake up, Neo...",
 
949
          "The Matrix has you...",
 
950
          "Follow the white rabbit.",
 
951
          " ",
 
952
          "Knock, knock, Neo."
 
953
        };
 
954
        int nblocks = countof(blocks);
 
955
        int j;
 
956
        typing_delay = True;
 
957
        transmit_delay = False;
 
958
        long_delay = False;
 
959
        visible_cursor = True;
 
960
        for (j = 0; j < nblocks; j++)
 
961
          {
 
962
            int x = 3;
 
963
            int y = 2;
 
964
            const char *s = blocks[j];
 
965
            if (!s[0] || !s[1]) typing_delay = False;
 
966
            zero_cells (state);
 
967
            hack_text_1 (state, &x, &y, s,
 
968
                         typing_delay, transmit_delay, -1,
 
969
                         visible_cursor, True);
 
970
            matrix_usleep (state, 2000000);
 
971
          }
 
972
      }
 
973
      break;
 
974
 
 
975
    case TRACEA1: case TRACEB1:
 
976
      {
 
977
        const char *blocks[10];
 
978
        int j, n = 0;
 
979
 
 
980
        if (state->mode == TRACEA1)
 
981
          blocks[n++] =
 
982
            (state->grid_width >= 52
 
983
             ?  "Call trans opt: received. 2-19-98 13:24:18 REC:Log>"
 
984
             : "Call trans opt: received.\n2-19-98 13:24:18 REC:Log>");
 
985
        else
 
986
          blocks[n++] =
 
987
            (state->grid_width >= 52
 
988
             ?  "Call trans opt: received. 9-18-99 14:32:21 REC:Log>"
 
989
             : "Call trans opt: received.\n9-18-99 14:32:21 REC:Log>");
 
990
 
 
991
        if (state->mode == TRACEB1)
 
992
          blocks[n++] = "WARNING: carrier anomaly";
 
993
        blocks[n++] = "Trace program: running";
 
994
 
 
995
        typing_delay = False;
 
996
        transmit_delay = True;
 
997
        long_delay = True;
 
998
        visible_cursor = True;
 
999
        for (j = 0; j < n; j++)
 
1000
          {
 
1001
            const char *s = blocks[j];
 
1002
            int x = 0;
 
1003
            int y = 0;
 
1004
            zero_cells (state);
 
1005
            hack_text_1 (state, &x, &y, s,
 
1006
                         typing_delay, transmit_delay, long_delay,
 
1007
                         visible_cursor, True);
 
1008
          }
 
1009
        matrix_usleep (state, 1000000);
 
1010
      }
 
1011
      break;
 
1012
 
 
1013
    case SYSTEMFAILURE:
 
1014
      {
 
1015
        const char *s = "SYSTEM FAILURE";
 
1016
        int i;
 
1017
        float cx = ((int)state->grid_width - (int)strlen(s)) / 2 - 0.5;
 
1018
        float cy = (state->grid_height / 2) - 1.3;
 
1019
        int x, y;
 
1020
 
 
1021
        if (cy < 0) cy = 0;
 
1022
        if (cx < 0) cx = 0;
 
1023
 
 
1024
        XFillRectangle (state->dpy, state->window, state->erase_gc,
 
1025
                        cx * state->char_width,
 
1026
                        cy * state->char_height,
 
1027
                        (strlen(s) + 1) * state->char_width,
 
1028
                        state->char_height * 1.6);
 
1029
 
 
1030
        for (i = -2; i < 3; i++)
 
1031
          {
 
1032
            XGCValues gcv;
 
1033
            gcv.foreground = state->colors[i + 2];
 
1034
            XChangeGC (state->dpy, state->scratch_gc, GCForeground, &gcv);
 
1035
            XDrawRectangle (state->dpy, state->window, state->scratch_gc,
 
1036
                            cx * state->char_width - i,
 
1037
                            cy * state->char_height - i,
 
1038
                            (strlen(s) + 1) * state->char_width + (2 * i),
 
1039
                            (state->char_height * 1.6) + (2 * i));
 
1040
          }
 
1041
 
 
1042
        /* If we don't clear these out, part of the box may get overwritten */
 
1043
        for (i = 0; i < state->grid_height * state->grid_width; i++)
 
1044
          {
 
1045
            m_cell *cell = &state->cells[i];
 
1046
            cell->changed = 0;
 
1047
          }
 
1048
 
 
1049
        x = ((int)state->grid_width - (int)strlen(s)) / 2;
 
1050
        y = (state->grid_height / 2) - 1;
 
1051
        if (y < 0) y = 0;
 
1052
        if (x < 0) x = 0;
 
1053
        hack_text_1 (state, &x, &y, s,
 
1054
                     typing_delay, transmit_delay, long_delay,
 
1055
                     visible_cursor, False);
 
1056
      }
 
1057
    break;
 
1058
 
 
1059
    case NMAP:
 
1060
      {
 
1061
        /* Note that what Trinity is using here is moderately accurate:
 
1062
           She runs nmap (http://www.insecure.org/nmap/) then breaks in
 
1063
           with a (hypothetical) program called "sshnuke" that exploits
 
1064
           the (very real) SSHv1 CRC32 compensation attack detector bug
 
1065
           (http://staff.washington.edu/dittrich/misc/ssh-analysis.txt).
 
1066
 
 
1067
           The command syntax of the power grid control software looks a
 
1068
           lot like Cisco IOS to me.  (IOS is a descendant of VMS.)
 
1069
        */
 
1070
        const char *blocks[] = {
 
1071
          "# ",
 
1072
 
 
1073
          "\001nmap 10.2.2.2\n",
 
1074
          "Starting nmap V. 2.54BETA25\n"
 
1075
 
 
1076
          "\010", "\010", "\010",
 
1077
 
 
1078
          "Insufficient responses for TCP sequencing (3), OS detection "
 
1079
          "may be less accurate\n"
 
1080
          "Interesting ports on 10.2.2.2:\n"
 
1081
          "(The 1538 ports scanned but not shown below are in state: "
 
1082
          "filtered)\n"
 
1083
          "Port       state       service\n"
 
1084
          "22/tcp     open        ssh\n"
 
1085
          "\n"
 
1086
          "No exact OS matches for host\n"
 
1087
          "\n"
 
1088
          "Nmap run completed -- 1 IP address (1 host up) scanned\n"
 
1089
          "# ",
 
1090
 
 
1091
          "\001sshnuke 10.2.2.2 -rootpw=\"Z1ON0101\"\n",
 
1092
 
 
1093
          "Connecting to 10.2.2.2:ssh ... ",
 
1094
 
 
1095
          "successful.\n"
 
1096
          "Attempting to exploit SSHv1 CRC32 ... ",
 
1097
 
 
1098
          "successful.\n"
 
1099
          "Resetting root password to \"Z1ON0101\".\n",
 
1100
 
 
1101
          "System open: Access Level <9>\n"
 
1102
          "# ",
 
1103
 
 
1104
          "\001ssh 10.2.2.2 -l root\n",
 
1105
 
 
1106
          "root@10.2.2.2's password: ",
 
1107
 
 
1108
          "\001\010\010\010\010\010\010\010\010\n",
 
1109
 
 
1110
          "\n"
 
1111
          "RRF-CONTROL> ",
 
1112
 
 
1113
          "\001disable grid nodes 21 - 48\n",
 
1114
 
 
1115
          "\002Warning: Disabling nodes 21-48 will disconnect sector 11 "
 
1116
          "(27 nodes)\n"
 
1117
          "\n"
 
1118
          "\002         ARE YOU SURE? (y/n) ",
 
1119
 
 
1120
          "\001\010\010y\n",
 
1121
          "\n"
 
1122
        };
 
1123
 
 
1124
        int nblocks = countof(blocks);
 
1125
        int y = state->grid_height - 2;
 
1126
        int x, j;
 
1127
 
 
1128
        visible_cursor = True;
 
1129
        x = 0;
 
1130
        zero_cells (state);
 
1131
        for (j = 0; j < nblocks; j++)
 
1132
          {
 
1133
            const char *s = blocks[j];
 
1134
            typing_delay = (*s == '\001');
 
1135
            if (typing_delay) s++;
 
1136
 
 
1137
            long_delay = False;
 
1138
            hack_text_1 (state, &x, &y, s,
 
1139
                         typing_delay, transmit_delay, long_delay,
 
1140
                         visible_cursor, True);
 
1141
          }
 
1142
 
 
1143
        typing_delay = False;
 
1144
        long_delay = False;
 
1145
        for (j = 21; j <= 48; j++)
 
1146
          {
 
1147
            char buf[100];
 
1148
            sprintf (buf, "\002Grid Node %d offline...\n", j);
 
1149
            hack_text_1 (state, &x, &y, buf,
 
1150
                         typing_delay, transmit_delay, -1,
 
1151
                         visible_cursor, True);
 
1152
 
 
1153
          }
 
1154
        long_delay = True;
 
1155
        hack_text_1 (state, &x, &y, "\nRRF-CONTROL> ",
 
1156
                     typing_delay, transmit_delay, long_delay,
 
1157
                     visible_cursor, True);
 
1158
 
 
1159
        /* De-glow all cells before draining them... */
 
1160
        for (j = 0; j < state->grid_height * state->grid_width; j++)
 
1161
          {
 
1162
            m_cell *cell = &state->cells[j];
 
1163
            cell->changed = (cell->glow != 0);
 
1164
            cell->glow = 0;
 
1165
          }
 
1166
      }
 
1167
    break;
 
1168
 
 
1169
  default:
 
1170
    abort();
 
1171
    break;
 
1172
  }
 
1173
}
 
1174
 
 
1175
 
 
1176
static void
 
1177
drain_matrix (m_state *state)
 
1178
{
 
1179
  int delay = get_integer_resource ("delay", "Integer");
 
1180
  int i;
 
1181
 
 
1182
  /* Fill the top row with empty top-feeders, to clear the screen. */
 
1183
  for (i = 0; i < state->grid_width; i++)
 
1184
    {
 
1185
      m_feeder *f = &state->feeders[i];
 
1186
      f->y = -1;
 
1187
      f->remaining = 0;
 
1188
      f->throttle = 0;
 
1189
    }
 
1190
 
 
1191
  /* Turn off all the spinners, else they never go away. */
 
1192
  for (i = 0; i < state->grid_width * state->grid_height; i++)
 
1193
    if (state->cells[i].spinner)
 
1194
      {
 
1195
        state->cells[i].spinner = 0;
 
1196
        state->cells[i].changed = 1;
 
1197
      }
 
1198
 
 
1199
  /* Run the machine until there are no live cells left. */
 
1200
  while (1)
 
1201
    {
 
1202
      Bool any_cells_p = False;
 
1203
      for (i = 0; i < state->grid_width * state->grid_height; i++)
 
1204
        if (state->cells[i].glyph)
 
1205
          {
 
1206
            any_cells_p = True;
 
1207
            goto FOUND;
 
1208
          }
 
1209
    FOUND:
 
1210
      if (! any_cells_p)
 
1211
        return;
 
1212
 
 
1213
      feed_matrix (state);
 
1214
      redraw_cells (state, True);
 
1215
      XSync (state->dpy, False);
 
1216
      handle_events (state);
 
1217
      if (delay) usleep (delay);
 
1218
    }
 
1219
}
 
1220
 
 
1221
 
 
1222
static void
 
1223
roll_state (m_state *state)
 
1224
{
 
1225
  int delay = 0;
 
1226
  switch (state->mode)
 
1227
    {
 
1228
    case TRACEA1:
 
1229
      state->mode = TRACEA2;
 
1230
      break;
 
1231
    case TRACEB1:
 
1232
      state->mode = TRACEB2;
 
1233
      break;
 
1234
 
 
1235
    case TRACEA2:
 
1236
      {
 
1237
        Bool any = False;
 
1238
        int i;
 
1239
        for (i = 0; i < strlen((char *) state->tracing); i++)
 
1240
          if (state->tracing[i] < 0) any = True;
 
1241
 
 
1242
        if (!any)
 
1243
          {
 
1244
            XSync (state->dpy, False);
 
1245
            matrix_usleep (state, 3000000);
 
1246
            state->mode = MATRIX;
 
1247
            state->glyph_map = matrix_encoding;
 
1248
            state->nglyphs = countof(matrix_encoding);
 
1249
            flip_images (state);
 
1250
            free (state->tracing);
 
1251
            state->tracing = 0;
 
1252
          }
 
1253
        else if ((random() % 20) == 0)  /* how fast numbers are discovered */
 
1254
          {
 
1255
            int x = random() % strlen((char *) state->tracing);
 
1256
            if (state->tracing[x] < 0)
 
1257
              state->tracing[x] = -state->tracing[x];
 
1258
          }
 
1259
        break;
 
1260
      }
 
1261
 
 
1262
    case TRACEB2:
 
1263
      {
 
1264
        /* reversed logic from TRACEA2 */
 
1265
        Bool any = False;
 
1266
        int i;
 
1267
        for (i = 0; i < strlen((char *) state->tracing); i++)
 
1268
          if (state->tracing[i] > 0) any = True;
 
1269
 
 
1270
        if ((random() % 15) == 0) {
 
1271
          if (any)
 
1272
            state->mode = SYSTEMFAILURE;
 
1273
          else
 
1274
            {
 
1275
              int x = random() % strlen((char *) state->tracing);
 
1276
              if (state->tracing[x] < 0)
 
1277
                state->tracing[x] = -state->tracing[x];
 
1278
            }
 
1279
        }
 
1280
        break;
 
1281
      }
 
1282
 
 
1283
    case SYSTEMFAILURE:
 
1284
      XSync (state->dpy, False);
 
1285
      matrix_usleep (state, 6000000);
 
1286
      state->mode = MATRIX;
 
1287
      state->glyph_map = matrix_encoding;
 
1288
      state->nglyphs = countof(matrix_encoding);
 
1289
      flip_images (state);
 
1290
      drain_matrix (state);
 
1291
      matrix_usleep (state, 2000000);
 
1292
      if (state->tracing) {
 
1293
        free (state->tracing);
 
1294
        state->tracing = 0;
 
1295
      }
 
1296
      break;
 
1297
 
 
1298
    case KNOCK:
 
1299
    case NMAP:
 
1300
      state->mode = MATRIX;
 
1301
      state->glyph_map = matrix_encoding;
 
1302
      state->nglyphs = countof(matrix_encoding);
 
1303
      flip_images (state);
 
1304
      break;
 
1305
 
 
1306
    case MATRIX:
 
1307
      if (state->knock_knock_p && (! (random() % 3500)))
 
1308
        {
 
1309
          drain_matrix (state);
 
1310
          if (! (random() % 5))
 
1311
            state->mode = NMAP;
 
1312
          else
 
1313
            state->mode = KNOCK;
 
1314
 
 
1315
          flip_images (state);
 
1316
        }
 
1317
      break;
 
1318
 
 
1319
    case DNA: case BINARY: case DEC: case HEX:
 
1320
      break;
 
1321
 
 
1322
    default:
 
1323
      abort();
 
1324
      break;
 
1325
    }
 
1326
 
 
1327
  matrix_usleep (state, delay * 1000000);
 
1328
  state->cursor = NULL;
 
1329
}
 
1330
 
 
1331
 
445
1332
static void
446
1333
hack_matrix (m_state *state)
447
1334
{
448
1335
  int x;
449
1336
 
 
1337
  switch (state->mode)
 
1338
    {
 
1339
    case TRACEA1: case TRACEB1: case SYSTEMFAILURE:
 
1340
    case KNOCK: case NMAP:
 
1341
      hack_text (state);
 
1342
      return;
 
1343
    case TRACEA2: case TRACEB2:
 
1344
    case MATRIX: case DNA: case BINARY: case DEC: case HEX:
 
1345
      break;
 
1346
    default:
 
1347
      abort(); break;
 
1348
    }
 
1349
 
450
1350
  /* Glow some characters. */
451
1351
  if (!state->insert_bottom_p)
452
1352
    {
453
1353
      int i = random() % (state->grid_width / 2);
454
1354
      while (--i > 0)
455
1355
        {
456
 
          int x = random() % state->grid_width;
457
 
          int y = random() % state->grid_height;
458
 
          m_cell *cell = &state->cells[state->grid_width * y + x];
 
1356
          int yy = random() % state->grid_height;
 
1357
          int xx = random() % state->grid_width;
 
1358
          m_cell *cell = &state->cells[state->grid_width * yy + xx];
459
1359
          if (cell->glyph && cell->glow == 0)
460
1360
            {
461
1361
              cell->glow = random() % 10;
482
1382
      if ((random() % 4) != 0)
483
1383
        f->remaining = 0;
484
1384
 
485
 
      if (state->trace_p)
 
1385
      if (state->mode == TRACEA2 || state->mode == TRACEB2)
486
1386
        bottom_feeder_p = True;
487
1387
      if (state->insert_top_p && state->insert_bottom_p)
488
1388
        bottom_feeder_p = (random() & 1);
495
1395
        f->y = -1;
496
1396
    }
497
1397
 
498
 
  if (!state->trace_p &&
 
1398
  if (!state->mode == TRACEA2 && !state->mode == TRACEB2 &&
499
1399
      ! (random() % 500))
500
1400
    init_spinners (state);
501
1401
}
504
1404
static void
505
1405
draw_matrix (m_state *state)
506
1406
{
507
 
  int x, y;
508
 
  int count = 0;
509
 
 
510
1407
  feed_matrix (state);
511
1408
  hack_matrix (state);
512
 
 
513
 
  for (y = 0; y < state->grid_height; y++)
514
 
    for (x = 0; x < state->grid_width; x++)
515
 
      {
516
 
        m_cell *cell = &state->cells[state->grid_width * y + x];
517
 
 
518
 
        if (cell->glyph)
519
 
          count++;
520
 
 
521
 
        if (state->trace_p)
522
 
          {
523
 
            int xx = x % strlen(state->tracing);
524
 
            Bool dead_p = state->tracing[xx] > 0;
525
 
 
526
 
            if (y == 0 && x == xx)
527
 
              cell->glyph = (dead_p ? (state->tracing[xx]-'0'+1) : 0);
528
 
            else if (y == 0)
529
 
              cell->glyph = 0;
530
 
            else
531
 
              cell->glyph = (dead_p ? 0 : (random() % state->nglyphs) + 1);
532
 
 
533
 
            cell->changed = 1;
534
 
          }
535
 
 
536
 
        if (!cell->changed)
537
 
          continue;
538
 
 
539
 
        if (cell->glyph == 0)
540
 
          XFillRectangle (state->dpy, state->window, state->erase_gc,
541
 
                          x * state->char_width,
542
 
                          y * state->char_height,
543
 
                          state->char_width,
544
 
                          state->char_height);
545
 
        else
546
 
          XCopyArea (state->dpy, state->images, state->window, state->draw_gc,
547
 
                     ((cell->glow > 0 || cell->spinner)
548
 
                      ? (state->char_width * GLOW_COL)
549
 
                      : (cell->glow == 0
550
 
                         ? (state->char_width * PLAIN_COL)
551
 
                         : (state->char_width * FADE_COL))),
552
 
                     (cell->glyph - 1) * state->char_height,
553
 
                     state->char_width, state->char_height,
554
 
                     x * state->char_width,
555
 
                     y * state->char_height);
556
 
 
557
 
        cell->changed = 0;
558
 
 
559
 
        if (cell->glow > 0)
560
 
          {
561
 
            cell->glow--;
562
 
            cell->changed = 1;
563
 
          }
564
 
        else if (cell->glow < 0)
565
 
          {
566
 
            cell->glow++;
567
 
            if (cell->glow == 0)
568
 
              cell->glyph = 0;
569
 
            cell->changed = 1;
570
 
          }
571
 
 
572
 
        if (cell->spinner)
573
 
          {
574
 
            cell->glyph = random() % CHAR_ROWS;
575
 
            cell->changed = 1;
576
 
          }
577
 
      }
578
 
 
579
 
  if (state->trace_p)
580
 
    {
581
 
      Bool any = False;
582
 
      int i;
583
 
      for (i = 0; i < strlen(state->tracing); i++)
584
 
        if (state->tracing[i] < 0) any = True;
585
 
 
586
 
      if (!any)
587
 
        {
588
 
          XSync (state->dpy, False);
589
 
          sleep (3);
590
 
          state->trace_p = False;
591
 
          state->nglyphs = CHAR_ROWS;
592
 
          flip_images (state);
593
 
          free (state->tracing);
594
 
          state->tracing = 0;
595
 
        }
596
 
      else if ((random() % 10) == 0)
597
 
        {
598
 
          int x = random() % strlen(state->tracing);
599
 
          if (state->tracing[x] < 0)
600
 
            state->tracing[x] = -state->tracing[x];
601
 
        }
602
 
    }
 
1409
  redraw_cells (state, True);
 
1410
  roll_state (state);
603
1411
 
604
1412
#if 0
605
1413
  {
627
1435
 
628
1436
char *defaults [] = {
629
1437
  ".background:            black",
630
 
  ".foreground:            green",
631
 
  "*small:                 False",
 
1438
  ".foreground:            #00AA00",
 
1439
  "*small:                 ",
632
1440
  "*delay:                 10000",
633
1441
  "*insert:                both",
634
 
  "*trace:                 false",
635
 
  "*tracePhone:            (212) 555-0690",
 
1442
  "*mode:                  Matrix",
 
1443
  "*tracePhone:            (312) 555-0690",
636
1444
  "*spinners:              5",
637
1445
  "*density:               75",
 
1446
  "*knockKnock:            False",
 
1447
  "*geometry:              800x600",
638
1448
  0
639
1449
};
640
1450
 
646
1456
  { "-bottom",          ".insert",              XrmoptionNoArg, "bottom" },
647
1457
  { "-both",            ".insert",              XrmoptionNoArg, "both" },
648
1458
  { "-density",         ".density",             XrmoptionSepArg, 0 },
649
 
  { "-trace",           ".trace",               XrmoptionNoArg, "True" },
 
1459
  { "-trace",           ".mode",                XrmoptionNoArg, "trace" },
 
1460
  { "-crack",           ".mode",                XrmoptionNoArg, "crack"},
650
1461
  { "-phone",           ".tracePhone",          XrmoptionSepArg, 0 },
 
1462
  { "-dna",             ".mode",                XrmoptionNoArg, "DNA" },
 
1463
  { "-binary",          ".mode",                XrmoptionNoArg, "binary" },
 
1464
  { "-hexadecimal",     ".mode",                XrmoptionNoArg, "hexadecimal"},
 
1465
  { "-decimal",         ".mode",                XrmoptionNoArg, "decimal"},
 
1466
  { "-knock-knock",     ".knockKnock",          XrmoptionNoArg, "True" },
651
1467
  { 0, 0, 0, 0 }
652
1468
};
653
1469
 
661
1477
    {
662
1478
      draw_matrix (state);
663
1479
      XSync (dpy, False);
664
 
      screenhack_handle_events (dpy);
 
1480
      handle_events (state);
665
1481
      if (delay) usleep (delay);
666
1482
    }
667
1483
}