ftp://ftp.krokus.ru/pub/OpenBSD/distfiles/xscreensaver-4.06.tar.gz
[xscreensaver] / hacks / xmatrix.c
index 1a6bebf158c8b857a436e5298e4e20abd6d1ad41..1433527cadb98934f88187983c9180b880c0af45 100644 (file)
  */
 
 #include "screenhack.h"
+#include "xpm-pixmap.h"
 #include <stdio.h>
 #include <X11/Xutil.h>
 
-#ifdef HAVE_XPM
-# include <X11/xpm.h>
+#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
 # include "images/matrix0.xpm"
 # include "images/matrix1.xpm"
 # include "images/matrix2.xpm"
@@ -111,6 +111,8 @@ static unsigned char char_map[256] = {
   176,177,178,195,180,181,182,183,184,185,186,187,188,189,190,191   /* 240 */
 };
 
+#define CURSOR_GLYPH 97
+
 typedef enum { TRACE0, TRACE1, TRACE2,
                KNOCK0, KNOCK1, KNOCK2, KNOCK3,
                KNOCK4, KNOCK5, KNOCK6, KNOCK7,
@@ -124,8 +126,10 @@ typedef struct {
   int grid_width, grid_height;
   int char_width, char_height;
   m_cell *cells;
+  m_cell *cursor;
   m_feeder *feeders;
   int nspinners;
+  Bool knock_knock_p;
   Bool small_p;
   Bool insert_top_p, insert_bottom_p;
   m_mode mode;
@@ -144,47 +148,21 @@ typedef struct {
 static void
 load_images_1 (m_state *state, int which)
 {
-#ifdef HAVE_XPM
+#if defined(HAVE_GDK_PIXBUF) || defined(HAVE_XPM)
   if (!get_boolean_resource ("mono", "Boolean") &&
       state->xgwa.depth > 1)
     {
-      
-
-      XpmAttributes xpmattrs;
-      int result;
-      xpmattrs.valuemask = 0;
-
-# ifdef XpmCloseness
-      xpmattrs.valuemask |= XpmCloseness;
-      xpmattrs.closeness = 40000;
-# endif
-# ifdef XpmVisual
-      xpmattrs.valuemask |= XpmVisual;
-      xpmattrs.visual = state->xgwa.visual;
-# endif
-# ifdef XpmDepth
-      xpmattrs.valuemask |= XpmDepth;
-      xpmattrs.depth = state->xgwa.depth;
-# endif
-# ifdef XpmColormap
-      xpmattrs.valuemask |= XpmColormap;
-      xpmattrs.colormap = state->xgwa.colormap;
-# endif
-
-      result = XpmCreatePixmapFromData (state->dpy, state->window,
-                (which == 0 ? (state->small_p ? matrix0b_xpm : matrix0_xpm) :
-                 which == 1 ? (state->small_p ? matrix1b_xpm : matrix1_xpm) :
-                              (state->small_p ? matrix2b_xpm : matrix2_xpm)),
-                                        &state->images[which], 0 /* mask */,
-                                        &xpmattrs);
-      if (!state->images || (result != XpmSuccess && result != XpmColorError))
-        state->images[which] = 0;
-
-      state->image_width = xpmattrs.width;
-      state->image_height = xpmattrs.height;
+      char **bits =
+        (which == 0 ? (state->small_p ? matrix0b_xpm : matrix0_xpm) :
+         which == 1 ? (state->small_p ? matrix1b_xpm : matrix1_xpm) :
+         (state->small_p ? matrix2b_xpm : matrix2_xpm));
+
+      state->images[which] =
+        xpm_data_to_pixmap (state->dpy, state->window, bits,
+                            &state->image_width, &state->image_height, 0);
     }
   else
-#endif /* !HAVE_XPM */
+#endif /* !HAVE_XPM && !HAVE_GDK_PIXBUF */
     {
       unsigned long fg, bg;
       state->image_width  = (state->small_p ? matrix0b_width :matrix0_width);
@@ -357,6 +335,7 @@ init_matrix (Display *dpy, Window window)
 
   state->cells = (m_cell *)
     calloc (sizeof(m_cell), state->grid_width * state->grid_height);
+  state->cursor = NULL;
   state->feeders = (m_feeder *) calloc (sizeof(m_feeder), state->grid_width);
 
   state->density = get_integer_resource ("density", "Integer");
@@ -392,6 +371,8 @@ init_matrix (Display *dpy, Window window)
   if (insert)
     free (insert);
 
+  state->knock_knock_p = get_boolean_resource ("knockKnock", "KnockKnock");
+
   mode = get_string_resource ("mode", "Mode");
   if (mode && !strcasecmp(mode, "trace"))
     state->mode = TRACE0;
@@ -526,6 +507,97 @@ feed_matrix (m_state *state)
     }
 }
 
+
+static void
+redraw_cells (m_state *state, Bool active)
+{
+  int x, y;
+  int count = 0;
+
+  for (y = 0; y < state->grid_height; y++)
+    for (x = 0; x < state->grid_width; x++)
+      {
+        m_cell *cell = &state->cells[state->grid_width * y + x];
+
+        if (cell->glyph)
+          count++;
+
+        if (state->mode == TRACE2 && active)
+          {
+            int xx = x % strlen(state->tracing);
+            Bool dead_p = state->tracing[xx] > 0;
+
+            if (y == 0 && x == xx)
+              cell->glyph = (dead_p
+                             ? state->glyph_map[state->tracing[xx]-'0'] + 1
+                             : 0);
+            else if (y == 0)
+              cell->glyph = 0;
+            else
+              cell->glyph = (dead_p ? 0 :
+                             (state->glyph_map[(random()%state->nglyphs)]
+                              + 1));
+
+            cell->changed = 1;
+          }
+
+        if (!cell->changed)
+          continue;
+
+        if (cell->glyph == 0 && cell != state->cursor)
+          XFillRectangle (state->dpy, state->window, state->erase_gc,
+                          x * state->char_width,
+                          y * state->char_height,
+                          state->char_width,
+                          state->char_height);
+        else
+          {
+            int g = (cell == state->cursor ? CURSOR_GLYPH : cell->glyph);
+            int cx = (g - 1) % CHAR_COLS;
+            int cy = (g - 1) / CHAR_COLS;
+            int map = ((cell->glow > 0 || cell->spinner) ? GLOW_MAP :
+                       (cell->glow < 0) ? FADE_MAP :
+                       PLAIN_MAP);
+
+            XCopyArea (state->dpy, state->images[map],
+                       state->window, state->draw_gc,
+                       cx * state->char_width,
+                       cy * state->char_height,
+                       state->char_width,
+                       state->char_height,
+                       x * state->char_width,
+                       y * state->char_height);
+          }
+
+        cell->changed = 0;
+
+        if (cell->glow > 0)
+          {
+            cell->glow--;
+            cell->changed = 1;
+          }
+        else if (cell->glow < 0)
+          {
+            cell->glow++;
+            if (cell->glow == 0)
+              cell->glyph = 0;
+            cell->changed = 1;
+          }
+
+        if (cell->spinner && active)
+          {
+            cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1);
+            cell->changed = 1;
+          }
+      }
+
+  if (state->cursor)
+    {
+      state->cursor->changed = 1;
+    }
+}
+
+
 static int
 densitizer (m_state *state)
 {
@@ -554,19 +626,29 @@ hack_text (m_state *state)
   int i;
   int x = 0;
   const char *s;
+  Bool typing_delay = False;
+  Bool transmit_delay = False;
+  Bool visible_cursor = False;
   switch (state->mode)
     {
-    case TRACE0: s = "Call trans opt: received.\n"
-                     "2-19-98 13:24:18 REC:Log>_"; break;
-    case TRACE1: s = "Trace program: running_"; break;
-
+    case TRACE0: if (state->grid_width >= 52)
+                   s = "Call trans opt: received. 2-19-98 13:24:18 REC:Log>";
+                 else
+                   s = "Call trans opt: received.\n2-19-98 13:24:18 REC:Log>";
+                 transmit_delay = True;
+                 visible_cursor = True;
+                 break;
+    case TRACE1: s = "Trace program: running";
+                 transmit_delay = True;
+                 visible_cursor = True;
+                 break;
     case KNOCK0: s = "Wake up, Neo..."; break;
     case KNOCK1: s = ""; break;
-    case KNOCK2: s = "The Matrix has you..."; break;
+    case KNOCK2: s = "The Matrix has you..."; typing_delay = True; break;
     case KNOCK3: s = ""; break;
-    case KNOCK4: s = "Follow the white rabbit..."; break;
+    case KNOCK4: s = "Follow the white rabbit."; typing_delay = True; break;
     case KNOCK5: s = ""; break;
-    case KNOCK6: s = "Knock knock, Neo."; break;
+    case KNOCK6: s = "Knock, knock, Neo."; break;
     case KNOCK7: s = ""; break;
 
     default: abort(); break;
@@ -606,11 +688,31 @@ hack_text (m_state *state)
               cell->glyph = char_map[(unsigned char) *s] + 1;
               if (*s == ' ' || *s == '\t') cell->glyph = 0;
               cell->changed = 1;
+              if (visible_cursor)
+                {
+                  m_cell *next = &state->cells[i + 1];
+                  next->changed = 1;
+                  state->cursor = next;
+                }
               i++;
             }
           x++;
         }
       s++;
+      if (typing_delay || transmit_delay)
+        {
+          redraw_cells (state, False);
+          XSync (state->dpy, False);
+          screenhack_handle_events (state->dpy);
+          if (typing_delay)
+            {
+              usleep (50000);
+              if (typing_delay && 0 == random() % 3)
+                usleep (0xFFFFFF & ((random() % 250000) + 1));
+            }
+          else
+            usleep (20000);
+        }
     }
 }
 
@@ -672,7 +774,7 @@ roll_state (m_state *state)
       break;
 
     case MATRIX:
-      if (! (random() % 5000))
+      if (state->knock_knock_p && (! (random() % 5000)))
         {
           state->mode = KNOCK0;
           flip_images (state);
@@ -689,9 +791,38 @@ roll_state (m_state *state)
 
   if (delay)
     {
-      XSync (state->dpy, False);
-      sleep (delay);
+      if (state->cursor)
+        {
+          int blink_delay = 333000;
+          int tot_delay = 0;
+          m_cell *cursor = state->cursor;
+          while (tot_delay < delay * 1000000)
+            {
+              if (state->cursor)
+                {
+                  usleep (blink_delay * 2);
+                  tot_delay += (2 * blink_delay);
+                  state->cursor = NULL;
+                }
+              else
+                {
+                  usleep (blink_delay);
+                  tot_delay += blink_delay;
+                  state->cursor = cursor;
+                }
+              cursor->changed = 1;
+              redraw_cells (state, False);
+              XSync (state->dpy, False);
+              screenhack_handle_events (state->dpy);
+            }
+        }
+      else
+        {
+          XSync (state->dpy, False);
+          sleep (delay);
+        }
     }
+  state->cursor = NULL;
 }
 
 
@@ -770,88 +901,9 @@ hack_matrix (m_state *state)
 static void
 draw_matrix (m_state *state)
 {
-  int x, y;
-  int count = 0;
-
   feed_matrix (state);
   hack_matrix (state);
-
-  for (y = 0; y < state->grid_height; y++)
-    for (x = 0; x < state->grid_width; x++)
-      {
-        m_cell *cell = &state->cells[state->grid_width * y + x];
-
-        if (cell->glyph)
-          count++;
-
-        if (state->mode == TRACE2)
-          {
-            int xx = x % strlen(state->tracing);
-            Bool dead_p = state->tracing[xx] > 0;
-
-            if (y == 0 && x == xx)
-              cell->glyph = (dead_p
-                             ? state->glyph_map[state->tracing[xx]-'0'] + 1
-                             : 0);
-            else if (y == 0)
-              cell->glyph = 0;
-            else
-              cell->glyph = (dead_p ? 0 :
-                             (state->glyph_map[(random()%state->nglyphs)]
-                              + 1));
-
-            cell->changed = 1;
-          }
-
-        if (!cell->changed)
-          continue;
-
-        if (cell->glyph == 0)
-          XFillRectangle (state->dpy, state->window, state->erase_gc,
-                          x * state->char_width,
-                          y * state->char_height,
-                          state->char_width,
-                          state->char_height);
-        else
-          {
-            int cx = (cell->glyph - 1) % CHAR_COLS;
-            int cy = (cell->glyph - 1) / CHAR_COLS;
-            int map = ((cell->glow > 0 || cell->spinner) ? GLOW_MAP :
-                       (cell->glow == 0) ? PLAIN_MAP :
-                       GLOW_MAP);
-
-            XCopyArea (state->dpy, state->images[map],
-                       state->window, state->draw_gc,
-                       cx * state->char_width,
-                       cy * state->char_height,
-                       state->char_width,
-                       state->char_height,
-                       x * state->char_width,
-                       y * state->char_height);
-          }
-
-        cell->changed = 0;
-
-        if (cell->glow > 0)
-          {
-            cell->glow--;
-            cell->changed = 1;
-          }
-        else if (cell->glow < 0)
-          {
-            cell->glow++;
-            if (cell->glow == 0)
-              cell->glyph = 0;
-            cell->changed = 1;
-          }
-
-        if (cell->spinner)
-          {
-            cell->glyph = (state->glyph_map[(random()%state->nglyphs)] + 1);
-            cell->changed = 1;
-          }
-      }
-
+  redraw_cells (state, True);
   roll_state (state);
 
 #if 0
@@ -880,7 +932,7 @@ char *progclass = "XMatrix";
 
 char *defaults [] = {
   ".background:                   black",
-  ".foreground:                   green",
+  ".foreground:                   #00AA00",
   "*small:                ",
   "*delay:                10000",
   "*insert:               both",
@@ -888,6 +940,7 @@ char *defaults [] = {
   "*tracePhone:            (212) 555-0690",
   "*spinners:             5",
   "*density:              75",
+  "*knockKnock:                   False",
   0
 };
 
@@ -904,6 +957,7 @@ XrmOptionDescRec options [] = {
   { "-dna",            ".mode",                XrmoptionNoArg, "DNA" },
   { "-binary",         ".mode",                XrmoptionNoArg, "binary" },
   { "-hexadecimal",    ".mode",                XrmoptionNoArg, "hexadecimal"},
+  { "-knock-knock",    ".knockKnock",          XrmoptionNoArg, "True" },
   { 0, 0, 0, 0 }
 };