source: trunk/third/xscreensaver/hacks/phosphor.c @ 20148

Revision 20148, 21.8 KB checked in by ghudson, 21 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r20147, which included commits to RCS files with non-trunk default branches.
Line 
1/* xscreensaver, Copyright (c) 1999, 2000 Jamie Zawinski <jwz@jwz.org>
2 *
3 * Permission to use, copy, modify, distribute, and sell this software and its
4 * documentation for any purpose is hereby granted without fee, provided that
5 * the above copyright notice appear in all copies and that both that
6 * copyright notice and this permission notice appear in supporting
7 * documentation.  No representations are made about the suitability of this
8 * software for any purpose.  It is provided "as is" without express or
9 * implied warranty.
10 *
11 * Phosphor -- simulate a glass tty with long-sustain phosphor.
12 */
13
14#include "screenhack.h"
15#include <stdio.h>
16#include <X11/Xutil.h>
17#include <X11/Xatom.h>
18#include <X11/Intrinsic.h>
19
20extern XtAppContext app;
21
22#define FUZZY_BORDER
23
24#define MAX(a,b) ((a)>(b)?(a):(b))
25#define MIN(a,b) ((a)<(b)?(a):(b))
26
27#define BLANK  0
28#define FLARE  1
29#define NORMAL 2
30#define FADE   3
31#define STATE_MAX FADE
32
33#define CURSOR_INDEX 128
34
35typedef struct {
36  unsigned char name;
37  int width, height;
38  Pixmap pixmap;
39#ifdef FUZZY_BORDER
40  Pixmap pixmap2;
41#endif /* FUZZY_BORDER */
42  Bool blank_p;
43} p_char;
44
45typedef struct {
46  p_char *p_char;
47  int state;
48  Bool changed;
49} p_cell;
50
51typedef struct {
52  Display *dpy;
53  Window window;
54  XWindowAttributes xgwa;
55  XFontStruct *font;
56  int grid_width, grid_height;
57  int char_width, char_height;
58  int scale;
59  int ticks;
60  p_char **chars;
61  p_cell *cells;
62  XGCValues gcv;
63  GC gc0;
64  GC gc1;
65#ifdef FUZZY_BORDER
66  GC gc2;
67#endif /* FUZZY_BORDER */
68  GC *gcs;
69  XImage *font_bits;
70
71  int cursor_x, cursor_y;
72  XtIntervalId cursor_timer;
73  Time cursor_blink;
74
75  FILE *pipe;
76  XtInputId pipe_id;
77  Bool input_available_p;
78  Time subproc_relaunch_delay;
79
80} p_state;
81
82
83static void capture_font_bits (p_state *state);
84static p_char *make_character (p_state *state, int c);
85static void drain_input (p_state *state);
86static void char_to_pixmap (p_state *state, p_char *pc, int c);
87static void launch_text_generator (p_state *state);
88
89
90/* About font metrics:
91
92   "lbearing" is the distance from the leftmost pixel of a character to
93   the logical origin of that character.  That is, it is the number of
94   pixels of the character which are to the left of its logical origin.
95
96   "rbearing" is the distance from the logical origin of a character to
97   the rightmost pixel of a character.  That is, it is the number of
98   pixels of the character to the right of its logical origin.
99
100   "descent" is the distance from the bottommost pixel of a character to
101   the logical baseline.  That is, it is the number of pixels of the
102   character which are below the baseline.
103
104   "ascent" is the distance from the logical baseline to the topmost pixel.
105   That is, it is the number of pixels of the character above the baseline.
106
107   Therefore, the bounding box of the "ink" of a character is
108   lbearing + rbearing by ascent + descent;
109
110   "width" is the distance from the logical origin of this character to
111   the position where the logical orgin of the next character should be
112   placed.
113
114   For our purposes, we're only interested in the part of the character
115   lying inside the "width" box.  If the characters have ink outside of
116   that box (the "charcell" box) then we're going to lose it.  Alas.
117 */
118
119static p_state *
120init_phosphor (Display *dpy, Window window)
121{
122  int i;
123  unsigned long flags;
124  p_state *state = (p_state *) calloc (sizeof(*state), 1);
125  char *fontname = get_string_resource ("font", "Font");
126  XFontStruct *font;
127
128  state->dpy = dpy;
129  state->window = window;
130
131  XGetWindowAttributes (dpy, window, &state->xgwa);
132
133  state->font = XLoadQueryFont (dpy, fontname);
134
135  if (!state->font)
136    {
137      fprintf(stderr, "couldn't load font \"%s\"\n", fontname);
138      state->font = XLoadQueryFont (dpy, "fixed");
139    }
140  if (!state->font)
141    {
142      fprintf(stderr, "couldn't load font \"fixed\"");
143      exit(1);
144    }
145
146  font = state->font;
147  state->scale = get_integer_resource ("scale", "Integer");
148  state->ticks = STATE_MAX + get_integer_resource ("ticks", "Integer");
149
150#if 0
151  for (i = 0; i < font->n_properties; i++)
152    if (font->properties[i].name == XA_FONT)
153      printf ("font: %s\n", XGetAtomName(dpy, font->properties[i].card32));
154#endif /* 0 */
155
156  state->cursor_blink = get_integer_resource ("cursor", "Time");
157  state->subproc_relaunch_delay =
158    (1000 * get_integer_resource ("relaunch", "Time"));
159
160  state->char_width  = font->max_bounds.width;
161  state->char_height = font->max_bounds.ascent + font->max_bounds.descent;
162
163  state->grid_width = state->xgwa.width / (state->char_width * state->scale);
164  state->grid_height = state->xgwa.height /(state->char_height * state->scale);
165  state->cells = (p_cell *) calloc (sizeof(p_cell),
166                                    state->grid_width * state->grid_height);
167  state->chars = (p_char **) calloc (sizeof(p_char *), 256);
168
169  state->gcs = (GC *) calloc (sizeof(GC), state->ticks + 1);
170
171  {
172    int ncolors = MAX (0, state->ticks - 3);
173    XColor *colors = (XColor *) calloc (ncolors, sizeof(XColor));
174    int h1, h2;
175    double s1, s2, v1, v2;
176
177    unsigned long fg = get_pixel_resource ("foreground", "Foreground",
178                                           state->dpy, state->xgwa.colormap);
179    unsigned long bg = get_pixel_resource ("background", "Background",
180                                           state->dpy, state->xgwa.colormap);
181    unsigned long flare = get_pixel_resource ("flareForeground", "Foreground",
182                                              state->dpy,state->xgwa.colormap);
183    unsigned long fade = get_pixel_resource ("fadeForeground", "Foreground",
184                                             state->dpy,state->xgwa.colormap);
185
186    XColor start, end;
187
188    start.pixel = fade;
189    XQueryColor (state->dpy, state->xgwa.colormap, &start);
190
191    end.pixel = bg;
192    XQueryColor (state->dpy, state->xgwa.colormap, &end);
193
194    /* Now allocate a ramp of colors from the main color to the background. */
195    rgb_to_hsv (start.red, start.green, start.blue, &h1, &s1, &v1);
196    rgb_to_hsv (end.red, end.green, end.blue, &h2, &s2, &v2);
197    make_color_ramp (state->dpy, state->xgwa.colormap,
198                     h1, s1, v1,
199                     h2, s2, v2,
200                     colors, &ncolors,
201                     False, True, False);
202
203    /* Adjust to the number of colors we actually got. */
204    state->ticks = ncolors + STATE_MAX;
205
206    /* Now, GCs all around.
207     */
208    state->gcv.font = font->fid;
209    state->gcv.cap_style = CapRound;
210#ifdef FUZZY_BORDER
211    state->gcv.line_width = (int) (((long) state->scale) * 1.3);
212    if (state->gcv.line_width == state->scale)
213      state->gcv.line_width++;
214#else /* !FUZZY_BORDER */
215    state->gcv.line_width = (int) (((long) state->scale) * 0.9);
216    if (state->gcv.line_width >= state->scale)
217      state->gcv.line_width = state->scale - 1;
218    if (state->gcv.line_width < 1)
219      state->gcv.line_width = 1;
220#endif /* !FUZZY_BORDER */
221
222    flags = (GCForeground | GCBackground | GCCapStyle | GCLineWidth);
223
224    state->gcv.background = bg;
225    state->gcv.foreground = bg;
226    state->gcs[BLANK] = XCreateGC (state->dpy, state->window, flags,
227                                   &state->gcv);
228
229    state->gcv.foreground = flare;
230    state->gcs[FLARE] = XCreateGC (state->dpy, state->window, flags,
231                                   &state->gcv);
232
233    state->gcv.foreground = fg;
234    state->gcs[NORMAL] = XCreateGC (state->dpy, state->window, flags,
235                                    &state->gcv);
236
237    for (i = 0; i < ncolors; i++)
238      {
239        state->gcv.foreground = colors[i].pixel;
240        state->gcs[STATE_MAX + i] = XCreateGC (state->dpy, state->window,
241                                               flags, &state->gcv);
242      }
243  }
244
245  capture_font_bits (state);
246
247  launch_text_generator (state);
248
249  return state;
250}
251
252
253static void
254capture_font_bits (p_state *state)
255{
256  XFontStruct *font = state->font;
257  int safe_width = font->max_bounds.rbearing - font->min_bounds.lbearing;
258  int height = state->char_height;
259  unsigned char string[257];
260  int i;
261  Pixmap p = XCreatePixmap (state->dpy, state->window,
262                            (safe_width * 256), height, 1);
263
264  for (i = 0; i < 256; i++)
265    string[i] = (unsigned char) i;
266  string[256] = 0;
267
268  state->gcv.foreground = 0;
269  state->gcv.background = 0;
270  state->gc0 = XCreateGC (state->dpy, p,
271                          (GCForeground | GCBackground),
272                          &state->gcv);
273
274  state->gcv.foreground = 1;
275  state->gc1 = XCreateGC (state->dpy, p,
276                          (GCFont | GCForeground | GCBackground |
277                           GCCapStyle | GCLineWidth),
278                          &state->gcv);
279
280#ifdef FUZZY_BORDER
281  {
282    state->gcv.line_width = (int) (((long) state->scale) * 0.8);
283    if (state->gcv.line_width >= state->scale)
284      state->gcv.line_width = state->scale - 1;
285    if (state->gcv.line_width < 1)
286      state->gcv.line_width = 1;
287    state->gc2 = XCreateGC (state->dpy, p,
288                            (GCFont | GCForeground | GCBackground |
289                             GCCapStyle | GCLineWidth),
290                            &state->gcv);
291  }
292#endif /* FUZZY_BORDER */
293
294  XFillRectangle (state->dpy, p, state->gc0, 0, 0, (safe_width * 256), height);
295
296  for (i = 0; i < 256; i++)
297    {
298      if (string[i] < font->min_char_or_byte2 ||
299          string[i] > font->max_char_or_byte2)
300        continue;
301      XDrawString (state->dpy, p, state->gc1,
302                   i * safe_width, font->ascent,
303                   (char *) (string + i), 1);
304    }
305
306  /* Draw the cursor. */
307  XFillRectangle (state->dpy, p, state->gc1,
308                  (CURSOR_INDEX * safe_width), 1,
309                  (font->per_char
310                   ? font->per_char['n'-font->min_char_or_byte2].width
311                   : font->max_bounds.width),
312                  font->ascent - 1);
313
314#if 0
315  XCopyPlane (state->dpy, p, state->window, state->gcs[FLARE],
316              0, 0, (safe_width * 256), height, 0, 0, 1L);
317  XSync(state->dpy, False);
318#endif
319
320  XSync (state->dpy, False);
321  state->font_bits = XGetImage (state->dpy, p, 0, 0,
322                                (safe_width * 256), height, ~0L, XYPixmap);
323  XFreePixmap (state->dpy, p);
324
325  for (i = 0; i < 256; i++)
326    state->chars[i] = make_character (state, i);
327  state->chars[CURSOR_INDEX] = make_character (state, CURSOR_INDEX);
328}
329
330
331static p_char *
332make_character (p_state *state, int c)
333{
334  p_char *pc = (p_char *) malloc (sizeof (*pc));
335  pc->name = (unsigned char) c;
336  pc->width =  state->scale * state->char_width;
337  pc->height = state->scale * state->char_height;
338  char_to_pixmap (state, pc, c);
339  return pc;
340}
341
342
343static void
344char_to_pixmap (p_state *state, p_char *pc, int c)
345{
346  Pixmap p = 0;
347  GC gc;
348#ifdef FUZZY_BORDER
349  Pixmap p2 = 0;
350  GC gc2;
351#endif /* FUZZY_BORDER */
352  int from, to;
353  int x1, y;
354
355  XFontStruct *font = state->font;
356  int safe_width = font->max_bounds.rbearing - font->min_bounds.lbearing;
357
358  int width  = state->scale * state->char_width;
359  int height = state->scale * state->char_height;
360
361  if (c < font->min_char_or_byte2 ||
362      c > font->max_char_or_byte2)
363    goto DONE;
364
365  gc = state->gc1;
366  p = XCreatePixmap (state->dpy, state->window, width, height, 1);
367  XFillRectangle (state->dpy, p, state->gc0, 0, 0, width, height);
368#ifdef FUZZY_BORDER
369  gc2 = state->gc2;
370  p2 = XCreatePixmap (state->dpy, state->window, width, height, 1);
371  XFillRectangle (state->dpy, p2, state->gc0, 0, 0, width, height);
372#endif /* FUZZY_BORDER */
373
374  from = safe_width * c;
375  to =   safe_width * (c + 1);
376
377#if 0
378  if (c > 75 && c < 150)
379    {
380      printf ("\n=========== %d (%c)\n", c, c);
381      for (y = 0; y < state->char_height; y++)
382        {
383          for (x1 = from; x1 < to; x1++)
384            printf (XGetPixel (state->font_bits, x1, y) ? "* " : ". ");
385          printf ("\n");
386        }
387    }
388#endif
389
390  pc->blank_p = True;
391  for (y = 0; y < state->char_height; y++)
392    for (x1 = from; x1 < to; x1++)
393      if (XGetPixel (state->font_bits, x1, y))
394        {
395          int xoff = state->scale / 2;
396          int x2;
397          for (x2 = x1; x2 < to; x2++)
398            if (!XGetPixel (state->font_bits, x2, y))
399              break;
400          x2--;
401          XDrawLine (state->dpy, p, gc,
402                     (x1 - from) * state->scale + xoff, y * state->scale,
403                     (x2 - from) * state->scale + xoff, y * state->scale);
404#ifdef FUZZY_BORDER
405          XDrawLine (state->dpy, p2, gc2,
406                     (x1 - from) * state->scale + xoff, y * state->scale,
407                     (x2 - from) * state->scale + xoff, y * state->scale);
408#endif /* FUZZY_BORDER */
409          x1 = x2;
410          pc->blank_p = False;
411        }
412
413  /*  if (pc->blank_p && c == CURSOR_INDEX)
414    abort();*/
415
416 DONE:
417  pc->pixmap = p;
418#ifdef FUZZY_BORDER
419  pc->pixmap2 = p2;
420#endif /* FUZZY_BORDER */
421}
422
423
424/* Managing the display.
425 */
426
427static void cursor_on_timer (XtPointer closure, XtIntervalId *id);
428static void cursor_off_timer (XtPointer closure, XtIntervalId *id);
429
430static Bool
431set_cursor_1 (p_state *state, Bool on)
432{
433  p_cell *cell = &state->cells[state->grid_width * state->cursor_y
434                              + state->cursor_x];
435  p_char *cursor = state->chars[CURSOR_INDEX];
436  int new_state = (on ? NORMAL : FADE);
437
438  if (cell->p_char != cursor)
439    cell->changed = True;
440
441  if (cell->state != new_state)
442    cell->changed = True;
443
444  cell->p_char = cursor;
445  cell->state = new_state;
446  return cell->changed;
447}
448
449static void
450set_cursor (p_state *state, Bool on)
451{
452  if (set_cursor_1 (state, on))
453    {
454      if (state->cursor_timer)
455        XtRemoveTimeOut (state->cursor_timer);
456      state->cursor_timer = 0;
457      cursor_on_timer (state, 0);
458    }
459}
460
461
462
463
464static void
465cursor_off_timer (XtPointer closure, XtIntervalId *id)
466{
467  p_state *state = (p_state *) closure;
468  set_cursor_1 (state, False);
469  state->cursor_timer = XtAppAddTimeOut (app, state->cursor_blink,
470                                         cursor_on_timer, closure);
471}
472
473static void
474cursor_on_timer (XtPointer closure, XtIntervalId *id)
475{
476  p_state *state = (p_state *) closure;
477  set_cursor_1 (state, True);
478  state->cursor_timer = XtAppAddTimeOut (app, 2 * state->cursor_blink,
479                                         cursor_off_timer, closure);
480}
481
482
483static void
484clear (p_state *state)
485{
486  int x, y;
487  state->cursor_x = 0;
488  state->cursor_y = 0;
489  for (y = 0; y < state->grid_height; y++)
490    for (x = 0; x < state->grid_width; x++)
491      {
492        p_cell *cell = &state->cells[state->grid_width * y + x];
493        if (cell->state == FLARE || cell->state == NORMAL)
494          {
495            cell->state = FADE;
496            cell->changed = True;
497          }
498      }
499  set_cursor (state, True);
500}
501
502
503static void
504decay (p_state *state)
505{
506  int x, y;
507  for (y = 0; y < state->grid_height; y++)
508    for (x = 0; x < state->grid_width; x++)
509      {
510        p_cell *cell = &state->cells[state->grid_width * y + x];
511        if (cell->state == FLARE)
512          {
513            cell->state = NORMAL;
514            cell->changed = True;
515          }
516        else if (cell->state >= FADE)
517          {
518            cell->state++;
519            if (cell->state >= state->ticks)
520              cell->state = BLANK;
521            cell->changed = True;
522          }
523      }
524}
525
526
527static void
528scroll (p_state *state)
529{
530  int x, y;
531
532  for (x = 0; x < state->grid_width; x++)
533    {
534      p_cell *from = 0, *to = 0;
535      for (y = 1; y < state->grid_height; y++)
536        {
537          from = &state->cells[state->grid_width * y     + x];
538          to   = &state->cells[state->grid_width * (y-1) + x];
539
540          if ((from->state == FLARE || from->state == NORMAL) &&
541              !from->p_char->blank_p)
542            {
543              *to = *from;
544              to->state = NORMAL;  /* should be FLARE?  Looks bad... */
545            }
546          else
547            {
548              if (to->state == FLARE || to->state == NORMAL)
549                to->state = FADE;
550            }
551
552          to->changed = True;
553        }
554
555      to = from;
556      if (to && (to->state == FLARE || to->state == NORMAL))
557        {
558          to->state = FADE;
559          to->changed = True;
560        }
561    }
562  set_cursor (state, True);
563}
564
565
566static void
567print_char (p_state *state, int c)
568{
569  static char last_c = 0;
570
571  p_cell *cell = &state->cells[state->grid_width * state->cursor_y
572                              + state->cursor_x];
573
574  /* Start the cursor fading (in case we don't end up overwriting it.) */
575  if (cell->state == FLARE || cell->state == NORMAL)
576    {
577      cell->state = FADE;
578      cell->changed = True;
579    }
580
581  if (c == '\t') c = ' ';   /* blah. */
582
583  if (c == '\r' || c == '\n')
584    {
585      if (c == '\n' && last_c == '\r')
586        ;   /* CRLF -- do nothing */
587      else
588        {
589          state->cursor_x = 0;
590          if (state->cursor_y == state->grid_height - 1)
591            scroll (state);
592          else
593            state->cursor_y++;
594        }
595    }
596  else if (c == '\014')
597    {
598      clear (state);
599    }
600  else
601    {
602      cell->state = FLARE;
603      cell->p_char = state->chars[c];
604      cell->changed = True;
605      state->cursor_x++;
606
607      if (c != ' ' && cell->p_char->blank_p)
608        cell->p_char = state->chars[CURSOR_INDEX];
609
610      if (state->cursor_x >= state->grid_width - 1)
611        {
612          state->cursor_x = 0;
613          if (state->cursor_y >= state->grid_height - 1)
614            scroll (state);
615          else
616            state->cursor_y++;
617        }
618    }
619  set_cursor (state, True);
620
621  last_c = c;
622}
623
624
625static void
626update_display (p_state *state, Bool changed_only)
627{
628  int x, y;
629
630  for (y = 0; y < state->grid_height; y++)
631    for (x = 0; x < state->grid_width; x++)
632      {
633        p_cell *cell = &state->cells[state->grid_width * y + x];
634        int width, height, tx, ty;
635
636        if (changed_only && !cell->changed)
637          continue;
638
639        width = state->char_width * state->scale;
640        height = state->char_height * state->scale;
641        tx = x * width;
642        ty = y * height;
643
644        if (cell->state == BLANK || cell->p_char->blank_p)
645          {
646            XFillRectangle (state->dpy, state->window, state->gcs[BLANK],
647                            tx, ty, width, height);
648          }
649        else
650          {
651#ifdef FUZZY_BORDER
652            GC gc1 = state->gcs[cell->state];
653            GC gc2 = ((cell->state + 2) < state->ticks
654                      ? state->gcs[cell->state + 2]
655                      : 0);
656            GC gc3 = (gc2 ? gc2 : gc1);
657            if (gc3)
658              XCopyPlane (state->dpy, cell->p_char->pixmap, state->window, gc3,
659                          0, 0, width, height, tx, ty, 1L);
660            if (gc2)
661              {
662                XSetClipMask (state->dpy, gc1, cell->p_char->pixmap2);
663                XSetClipOrigin (state->dpy, gc1, tx, ty);
664                XFillRectangle (state->dpy, state->window, gc1,
665                                tx, ty, width, height);
666                XSetClipMask (state->dpy, gc1, None);
667              }
668#else /* !FUZZY_BORDER */
669
670            XCopyPlane (state->dpy,
671                        cell->p_char->pixmap, state->window,
672                        state->gcs[cell->state],
673                        0, 0, width, height, tx, ty, 1L);
674
675#endif /* !FUZZY_BORDER */
676          }
677
678        cell->changed = False;
679      }
680}
681
682
683static void
684run_phosphor (p_state *state)
685{
686  update_display (state, True);
687  decay (state);
688  drain_input (state);
689}
690
691
692/* Subprocess.
693 */
694
695static void
696subproc_cb (XtPointer closure, int *source, XtInputId *id)
697{
698  p_state *state = (p_state *) closure;
699  state->input_available_p = True;
700}
701
702
703static void
704launch_text_generator (p_state *state)
705{
706  char *oprogram = get_string_resource ("program", "Program");
707  char *program = (char *) malloc (strlen (oprogram) + 10);
708
709  strcpy (program, "( ");
710  strcat (program, oprogram);
711  strcat (program, " ) 2>&1");
712
713  if ((state->pipe = popen (program, "r")))
714    {
715      state->pipe_id =
716        XtAppAddInput (app, fileno (state->pipe),
717                       (XtPointer) (XtInputReadMask | XtInputExceptMask),
718                       subproc_cb, (XtPointer) state);
719    }
720  else
721    {
722      perror (program);
723    }
724}
725
726
727static void
728relaunch_generator_timer (XtPointer closure, XtIntervalId *id)
729{
730  p_state *state = (p_state *) closure;
731  launch_text_generator (state);
732}
733
734
735static void
736drain_input (p_state *state)
737{
738  if (state->input_available_p)
739    {
740      unsigned char s[2];
741      int n = read (fileno (state->pipe), (void *) s, 1);
742      if (n == 1)
743        {
744          print_char (state, s[0]);
745        }
746      else
747        {
748          XtRemoveInput (state->pipe_id);
749          state->pipe_id = 0;
750          pclose (state->pipe);
751          state->pipe = 0;
752
753          if (state->cursor_x != 0)     /* break line if unbroken */
754            print_char (state, '\n');   /* blank line */
755          print_char (state, '\n');
756
757          /* Set up a timer to re-launch the subproc in a bit. */
758          XtAppAddTimeOut (app, state->subproc_relaunch_delay,
759                           relaunch_generator_timer,
760                           (XtPointer) state);
761        }
762       
763      state->input_available_p = False;
764    }
765}
766
767
768
769char *progclass = "Phosphor";
770
771char *defaults [] = {
772  ".background:            Black",
773  ".foreground:            Green",
774  "*fadeForeground:        DarkGreen",
775  "*flareForeground:       White",
776  "*font:                  fixed",
777  "*scale:                 6",
778  "*ticks:                 20",
779  "*delay:                 50000",
780  "*cursor:                333",
781  "*program:             " FORTUNE_PROGRAM,
782  "*relaunch:              5",
783  0
784};
785
786XrmOptionDescRec options [] = {
787  { "-font",            ".font",                XrmoptionSepArg, 0 },
788  { "-scale",           ".scale",               XrmoptionSepArg, 0 },
789  { "-ticks",           ".ticks",               XrmoptionSepArg, 0 },
790  { "-delay",           ".delay",               XrmoptionSepArg, 0 },
791  { "-program",         ".program",             XrmoptionSepArg, 0 },
792  { 0, 0, 0, 0 }
793};
794
795
796void
797screenhack (Display *dpy, Window window)
798{
799  int delay = get_integer_resource ("delay", "Integer");
800  p_state *state = init_phosphor (dpy, window);
801
802  clear (state);
803
804  while (1)
805    {
806      run_phosphor (state);
807      XSync (dpy, False);
808      screenhack_handle_events (dpy);
809
810      if (XtAppPending (app) & (XtIMTimer|XtIMAlternateInput))
811        XtAppProcessEvent (app, XtIMTimer|XtIMAlternateInput);
812
813      if (delay) usleep (delay);
814    }
815}
Note: See TracBrowser for help on using the repository browser.