From http://www.jwz.org/xscreensaver/xscreensaver-5.37.tar.gz
[xscreensaver] / hacks / glx / fliptext.c
index b47bbb83edfd0c204c11c162145142f2a89db7df..d35706cb2a5ad0325c22c865f9341f72f2271c43 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * fliptext, Copyright (c) 2005-2011 Jamie Zawinski <jwz@jwz.org>
+ * fliptext, Copyright (c) 2005-2015 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
 # include "config.h"
 #endif /* HAVE_CONFIG_H */
 
-#include <ctype.h>
-#include <sys/stat.h>
-
-#ifndef HAVE_COCOA
-# include <X11/Intrinsic.h>
-#endif
-
-#ifdef HAVE_UNISTD_H
-# include <unistd.h>
-#endif
-
-#ifdef HAVE_UNAME
-# include <sys/utsname.h>
-#endif /* HAVE_UNAME */
-
-
-/* Utopia 800 needs 64 512x512 textures (4096x4096 bitmap).
-   Utopia 720 needs 16 512x512 textures (2048x2048 bitmap).
-   Utopia 480 needs 16 512x512 textures (2048x2048 bitmap).
-   Utopia 400 needs  4 512x512 textures (1024x1024 bitmap).
-   Utopia 180 needs  1 512x512 texture.
-   Times  240 needs  1 512x512 texture.
- */
-#define DEF_FONT       "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-iso8859-1"
+#define DEF_FONT       "-*-utopia-bold-r-normal-*-*-720-*-*-*-*-*-*"
 #define DEF_COLOR      "#00CCFF"
 
 #define DEFAULTS "*delay:        10000      \n" \
                 "*showFPS:      False      \n" \
                 "*wireframe:    False      \n" \
+                "*usePty:       False      \n" \
+                "*texFontCacheSize: 60     \n" \
                 "*font:       " DEF_FONT  "\n" \
                 ".foreground: " DEF_COLOR "\n" \
+                "*program: xscreensaver-text --cols 0"  /* don't wrap */
 
 # define refresh_fliptext 0
+# define release_fliptext 0
 # define fliptext_handle_event 0
 #undef countof
 #define countof(x) (sizeof((x))/sizeof((*x)))
@@ -56,6 +37,7 @@
 
 #include "xlockmore.h"
 #include "texfont.h"
+#include "textclient.h"
 
 #ifdef USE_GL /* whole file */
 
@@ -68,7 +50,6 @@
 # endif
 
 
-#define DEF_PROGRAM    "xscreensaver-text --cols 0"  /* don't wrap */
 #define DEF_LINES      "8"
 #define DEF_FONT_SIZE  "20"
 #define DEF_COLUMNS    "80"
@@ -105,11 +86,9 @@ typedef struct {
   GLXContext *glx_context;
 
   texture_font_data *texfont;
+  text_data *tc;
 
-  FILE *pipe;
-  XtInputId pipe_id;
-  XtIntervalId pipe_timer;
-  Time subproc_relaunch_delay;
+  int alignment;
 
   char *buf;
   int buf_size;
@@ -138,16 +117,14 @@ typedef struct {
 
 static fliptext_configuration *scs = NULL;
 
-static char *program;
 static int max_lines, min_lines;
 static float font_size;
 static int target_columns;
 static char *alignment_str;
-static int alignment, alignment_random_p;
+static int alignment_random_p;
 static GLfloat speed;
 
 static XrmOptionDescRec opts[] = {
-  {"-program",     ".program",   XrmoptionSepArg, 0 },
   {"-lines",       ".lines",     XrmoptionSepArg, 0 },
   {"-size",       ".fontSize",  XrmoptionSepArg, 0 },
   {"-columns",    ".columns",   XrmoptionSepArg, 0 },
@@ -160,7 +137,6 @@ static XrmOptionDescRec opts[] = {
 };
 
 static argtype vars[] = {
-  {&program,        "program",   "Program",    DEF_PROGRAM,   t_String},
   {&max_lines,      "lines",     "Integer",    DEF_LINES,     t_Int},
   {&font_size,      "fontSize",  "Float",      DEF_FONT_SIZE, t_Float},
   {&target_columns, "columns",   "Integer",    DEF_COLUMNS,   t_Int},
@@ -233,113 +209,15 @@ strip (char *s, Bool leading, Bool trailing)
 }
 
 
-\f
-/* Subprocess.
-   (This bit mostly cribbed from phosphor.c)
- */
-
-static void drain_input (fliptext_configuration *sc);
-
-static void
-subproc_cb (XtPointer closure, int *source, XtInputId *id)
-{
-  fliptext_configuration *sc = (fliptext_configuration *) closure;
-  drain_input (sc);
-}
-
-
-static void
-launch_text_generator (fliptext_configuration *sc)
-{
-  XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
-  char *oprogram = get_string_resource (sc->dpy, "program", "Program");
-  char *program = (char *) malloc (strlen (oprogram) + 10);
-  strcpy (program, "( ");
-  strcat (program, oprogram);
-  strcat (program, " ) 2>&1");
-
-  if ((sc->pipe = popen (program, "r")))
-    {
-      sc->pipe_id =
-        XtAppAddInput (app, fileno (sc->pipe),
-                       (XtPointer) (XtInputReadMask | XtInputExceptMask),
-                       subproc_cb, (XtPointer) sc);
-    }
-  else
-    {
-      perror (program);
-    }
-}
-
-
-static void
-relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
-{
-  fliptext_configuration *sc = (fliptext_configuration *) closure;
-  if (!sc->pipe_timer) abort();
-  sc->pipe_timer = 0;
-  launch_text_generator (sc);
-}
-
-
-/* When the subprocess has generated some output, this reads as much as it
-   can into sc->buf at sc->buf_tail.
- */
-static void
-drain_input (fliptext_configuration *sc)
-{
-  XtAppContext app = XtDisplayToApplicationContext (sc->dpy);
-  if (sc->buf_tail < sc->buf_size - 2)
-    {
-      int target = sc->buf_size - sc->buf_tail - 2;
-      int n = (sc->pipe
-               ? read (fileno (sc->pipe),
-                       (void *) (sc->buf + sc->buf_tail),
-                       target)
-               : 0);
-      if (n > 0)
-        {
-          sc->buf_tail += n;
-          sc->buf[sc->buf_tail] = 0;
-        }
-      else
-        {
-          if (sc->pipe)
-            {
-              XtRemoveInput (sc->pipe_id);
-              sc->pipe_id = 0;
-              pclose (sc->pipe);
-              sc->pipe = 0;
-            }
-
-          /* If the process didn't print a terminating newline, add one. */
-          if (sc->buf_tail > 1 &&
-              sc->buf[sc->buf_tail-1] != '\n')
-            {
-              sc->buf[sc->buf_tail++] = '\n';
-              sc->buf[sc->buf_tail] = 0;
-            }
-
-          /* Then add one more, just for giggles. */
-          sc->buf[sc->buf_tail++] = '\n';
-          sc->buf[sc->buf_tail] = 0;
-
-          /* Set up a timer to re-launch the subproc in a bit. */
-          sc->pipe_timer = XtAppAddTimeOut (app, sc->subproc_relaunch_delay,
-                                            relaunch_generator_timer,
-                                            (XtPointer) sc);
-        }
-    }
-}
-
-
 static int
 char_width (fliptext_configuration *sc, char c)
 {
+  XCharStruct e;
   char s[2];
   s[0] = c;
   s[1] = 0;
-  return texture_string_width (sc->texfont, s, 0);
+  texture_string_metrics (sc->texfont, s, &e, 0, 0);
+  return e.width;
 }
 
 
@@ -354,8 +232,23 @@ get_one_line (fliptext_configuration *sc)
   int wrap_pix = sc->font_wrap_pixels;
   int col = 0;
   int col_pix = 0;
-
   char *s = sc->buf;
+  int target = sc->buf_size - sc->buf_tail - 2;
+
+  /* Fill as much as we can into sc->buf, but stop at newline.
+   */
+  while (target > 0)
+    {
+      int c = textclient_getc (sc->tc);
+      if (c <= 0)
+        break;
+      sc->buf[sc->buf_tail++] = (char) c;
+      sc->buf[sc->buf_tail] = 0;
+      target--;
+      if (c == '\r' || c == '\n')
+        break;
+    }
+
   while (!result)
     {
       int cw;
@@ -401,8 +294,8 @@ get_one_line (fliptext_configuration *sc)
           {
             char *t = result;
             char *ut = untabify (t);
-            strip (ut, (alignment == 0), 1); /* if centering, strip
-                                                leading whitespace too */
+            strip (ut, (sc->alignment == 0), 1); /* if centering, strip
+                                                    leading whitespace too */
             result = ut;
             free (t);
           }
@@ -461,6 +354,7 @@ blank_p (const char *s)
 static line *
 make_line (fliptext_configuration *sc, Bool skip_blanks_p)
 {
+  XCharStruct e;
   line *ln;
   char *s;
 
@@ -477,7 +371,8 @@ make_line (fliptext_configuration *sc, Bool skip_blanks_p)
   ln = (line *) calloc (1, sizeof(*ln));
   ln->text = s;
   ln->state = NEW;
-  ln->width = sc->font_scale * texture_string_width (sc->texfont, s, 0);
+  texture_string_metrics (sc->texfont, s, &e, 0, 0);
+  ln->width = sc->font_scale * e.width;
   ln->height = sc->font_scale * sc->line_height;
 
   memcpy (ln->color, sc->color, sizeof(ln->color));
@@ -536,9 +431,9 @@ draw_line (ModeInfo *mi, line *line)
 
   glRotatef (line->cth, 0, 1, 0);
 
-  if (alignment == 1)
+  if (sc->alignment == 1)
     glTranslatef (-line->width, 0, 0);
-  else if (alignment == 0)
+  else if (sc->alignment == 0)
     glTranslatef (-line->width/2, 0, 0);
 
   glScalef (sc->font_scale, sc->font_scale, sc->font_scale);
@@ -557,8 +452,11 @@ draw_line (ModeInfo *mi, line *line)
       glColor3f (0.4, 0.4, 0.4);
       while (*s)
         {
+          XCharStruct e;
           *c = *s++;
-          w = texture_string_width (sc->texfont, c, &h);
+          texture_string_metrics (sc->texfont, c, &e, 0, 0);
+          w = e.width;
+          h = e.ascent + e.descent;
           glBegin (GL_LINE_LOOP);
           glVertex3f (0, 0, 0);
           glVertex3f (w, 0, 0);
@@ -789,11 +687,11 @@ reset_lines (ModeInfo *mi)
     maxh = maxy - miny;
       
   if (alignment_random_p)
-    alignment = (random() % 3) - 1;
+    sc->alignment = (random() % 3) - 1;
 
-  if      (alignment == -1) maxx -= maxw;
-  else if (alignment ==  1) minx += maxw;
-  else                      minx += maxw/2, maxx -= maxw/2;
+  if      (sc->alignment == -1) maxx -= maxw;
+  else if (sc->alignment ==  1) minx += maxw;
+  else                          minx += maxw/2, maxx -= maxw/2;
 
   miny += maxh/2;
   maxy -= maxh/2;
@@ -890,6 +788,9 @@ reshape_fliptext (ModeInfo *mi, int width, int height)
 }
 
 
+static void free_fliptext (ModeInfo *mi);
+
+
 ENTRYPOINT void 
 init_fliptext (ModeInfo *mi)
 {
@@ -897,19 +798,11 @@ init_fliptext (ModeInfo *mi)
 
   fliptext_configuration *sc;
 
-  if (!scs) {
-    scs = (fliptext_configuration *)
-      calloc (MI_NUM_SCREENS(mi), sizeof (fliptext_configuration));
-    if (!scs) {
-      fprintf(stderr, "%s: out of memory\n", progname);
-      exit(1);
-    }
-
-    sc = &scs[MI_SCREEN(mi)];
-    sc->lines = (line **) calloc (max_lines+1, sizeof(char *));
-  }
+  MI_INIT(mi, scs, free_fliptext);
 
   sc = &scs[MI_SCREEN(mi)];
+  sc->lines = (line **) calloc (max_lines+1, sizeof(char *));
+
   sc->dpy = MI_DISPLAY(mi);
 
   if ((sc->glx_context = init_GL(mi)) != NULL) {
@@ -917,13 +810,14 @@ init_fliptext (ModeInfo *mi)
     clear_gl_error(); /* WTF? sometimes "invalid op" from glViewport! */
   }
 
-  program = get_string_resource (mi->dpy, "program", "Program");
-
   {
-    int cw, lh;
+    XCharStruct e;
+    int cw, lh, ascent, descent;
     sc->texfont = load_texture_font (MI_DISPLAY(mi), "font");
     check_gl_error ("loading font");
-    cw = texture_string_width (sc->texfont, "n", &lh);
+    texture_string_metrics (sc->texfont, "n", &e, &ascent, &descent);
+    cw = e.width;
+    lh = ascent + descent;
     sc->char_width = cw;
     sc->line_height = lh;
   }
@@ -973,19 +867,17 @@ init_fliptext (ModeInfo *mi)
   sc->buf_size = target_columns * max_lines;
   sc->buf = (char *) calloc (1, sc->buf_size);
 
-  sc->subproc_relaunch_delay = 2 * 1000;   /* 2 seconds */
-
   alignment_random_p = False;
   if (!alignment_str || !*alignment_str ||
       !strcasecmp(alignment_str, "left"))
-    alignment = -1;
+    sc->alignment = -1;
   else if (!strcasecmp(alignment_str, "center") ||
            !strcasecmp(alignment_str, "middle"))
-    alignment = 0;
+    sc->alignment = 0;
   else if (!strcasecmp(alignment_str, "right"))
-    alignment = 1;
+    sc->alignment = 1;
   else if (!strcasecmp(alignment_str, "random"))
-    alignment = -1, alignment_random_p = True;
+    sc->alignment = -1, alignment_random_p = True;
 
   else
     {
@@ -995,7 +887,7 @@ init_fliptext (ModeInfo *mi)
       exit (1);
     }
 
-  launch_text_generator (sc);
+  sc->tc = textclient_open (sc->dpy);
 
   if (max_lines < 1) max_lines = 1;
   min_lines = max_lines * 0.66;
@@ -1036,6 +928,7 @@ draw_fliptext (ModeInfo *mi)
   mi->polygon_count = 0;
 
   glPushMatrix();
+  glRotatef(current_device_rotation(), 0, 0, 1);
   {
     GLfloat s = 3.0 / (sc->top_margin - sc->bottom_margin);
     glScalef(s, s, s);
@@ -1089,26 +982,15 @@ draw_fliptext (ModeInfo *mi)
   glXSwapBuffers(dpy, window);
 }
 
-ENTRYPOINT void
-release_fliptext (ModeInfo *mi)
+static void
+free_fliptext (ModeInfo *mi)
 {
-  if (scs) {
-    int screen;
-    for (screen = 0; screen < MI_NUM_SCREENS(mi); screen++) {
-      fliptext_configuration *sc = &scs[screen];
-      if (sc->pipe_id)
-        XtRemoveInput (sc->pipe_id);
-      if (sc->pipe)
-        pclose (sc->pipe);
-      if (sc->pipe_timer)
-        XtRemoveTimeOut (sc->pipe_timer);
-
-      /* #### there's more to free here */
-    }
-    free (scs);
-    scs = 0;
-  }
-  FreeAllGL(mi);
+  fliptext_configuration *sc = &scs[MI_SCREEN(mi)];
+  if (sc->tc)
+    textclient_close (sc->tc);
+  free(sc->lines);
+
+  /* #### there's more to free here */
 }
 
 XSCREENSAVER_MODULE ("FlipText", fliptext)