-/* xanalogtv, Copyright (c) 2003 Trevor Blackwell <tlb@tlb.org>
+/* xanalogtv, Copyright (c) 2003-2018 Trevor Blackwell <tlb@tlb.org>
*
* Permission to use, copy, modify, distribute, and sell this software and its
* documentation for any purpose is hereby granted without fee, provided that
* pictures from your images directory, some show color bars, and some
* just have static. Some channels receive two stations simultaneously
* so you see a ghostly, misaligned image.
- *
- * It's easy to add some test patterns by compiling in an XPM, but I
- * can't find any that are clearly freely redistributable.
- *
*/
+#ifdef HAVE_CONFIG_H
+# include "config.h"
+#endif /* HAVE_CONFIG_H */
+
#include <math.h>
+
+#ifdef HAVE_UNISTD_H
+# include <unistd.h>
+#endif
+
+#ifndef HAVE_JWXYZ
+# include <X11/Intrinsic.h> /* for XtDatabase in hack_resources() */
+#endif
+
#include "screenhack.h"
-#include "xpm-pixmap.h"
+#include "ximage-loader.h"
#include "analogtv.h"
-#include <stdio.h>
-#include <time.h>
-#include <sys/time.h>
-#include <X11/Xutil.h>
-#include <X11/Intrinsic.h>
-#include "images/logo-50.xpm"
+#define USE_TEST_PATTERNS
+
+#include "images/gen/logo-180_png.h"
+
+#ifdef USE_TEST_PATTERNS
+# include "images/gen/testcard_rca_png.h"
+# include "images/gen/testcard_pm5544_png.h"
+# include "images/gen/testcard_bbcf_png.h"
+#endif
-/* #define DEBUG 1 */
-/* #define USE_TEST_PATTERNS */
#define countof(x) (sizeof((x))/sizeof((*x)))
-static analogtv *tv=NULL;
+enum {
+ N_CHANNELS=12, /* Channels 2 through 13 on VHF */
+ MAX_MULTICHAN=2,
+ MAX_STATIONS=6
+};
+
+typedef struct chansetting_s {
+
+ analogtv_reception recs[MAX_MULTICHAN];
+ double noise_level;
+ Bool image_loaded_p;
+/* char *filename; was only used for diagnostics */
+ int dur;
+} chansetting;
+
+
+struct state {
+ Display *dpy;
+ Window window;
+ analogtv *tv;
+ analogtv_font ugly_font;
+ struct timeval basetime;
+
+ int n_stations;
+ analogtv_input *stations[MAX_STATIONS];
+ Bool image_loading_p;
+ XImage *logo, *logo_mask;
+# ifdef USE_TEST_PATTERNS
+ XImage *test_patterns[MAX_STATIONS];
+# endif
+
+ int curinputi;
+ int change_ticks;
+ chansetting chansettings[N_CHANNELS];
+ chansetting *cs;
+
+ int change_now;
+ int colorbars_only_p;
+};
-analogtv_font ugly_font;
static void
update_smpte_colorbars(analogtv_input *input)
{
+ struct state *st = (struct state *) input->client_data;
int col;
int xpos, ypos;
int black_ntsc[4];
ypos=ANALOGTV_V/5;
xpos=ANALOGTV_VIS_START + ANALOGTV_VIS_LEN/2;
+ /* if (! st->colorbars_only_p) */
{
char localname[256];
if (gethostname (localname, sizeof (localname))==0) {
+ int L;
localname[sizeof(localname)-1]=0; /* "The returned name is null-
terminated unless insufficient
space is provided" */
+ L = strlen(localname);
+ if (L > 6 && !strcmp(".local", localname+L-6))
+ localname[L-6] = 0;
+
localname[24]=0; /* limit length */
- analogtv_draw_string_centered(input, &ugly_font, localname,
+ analogtv_draw_string_centered(input, &st->ugly_font, localname,
xpos, ypos, black_ntsc);
}
}
- ypos += ugly_font.char_h*5/2;
-
- analogtv_draw_xpm(tv, input,
- logo_50_xpm, xpos - 100, ypos);
+ ypos += st->ugly_font.char_h*5/2;
+
+ if (st->logo)
+ {
+ int w2 = st->tv->xgwa.width * 0.2;
+ int h2 = st->tv->xgwa.height * 0.2;
+ analogtv_load_ximage (st->tv, input, st->logo, st->logo_mask,
+ (st->tv->xgwa.width - w2) / 2,
+ st->tv->xgwa.height * 0.28,
+ w2, h2);
+ }
ypos += 58;
#if 0
- analogtv_draw_string_centered(input, &ugly_font, "Please Stand By", xpos, ypos);
- ypos += ugly_font.char_h*4;
+ analogtv_draw_string_centered(input, &st->ugly_font,
+ "Please Stand By", xpos, ypos);
+ ypos += st->ugly_font.char_h*4;
#endif
+ /* if (! st->colorbars_only_p) */
{
char timestamp[256];
time_t t = time ((time_t *) 0);
/* Y2K: It is OK for this to use a 2-digit year because it's simulating a
TV display and is purely decorative. */
strftime(timestamp, sizeof(timestamp)-1, "%y.%m.%d %H:%M:%S ", tm);
- analogtv_draw_string_centered(input, &ugly_font, timestamp,
+ analogtv_draw_string_centered(input, &st->ugly_font, timestamp,
xpos, ypos, black_ntsc);
}
input->next_update_time += 1.0;
}
-#if 0
-static void
-draw_color_square(analogtv_input *input)
+static int
+getticks(struct state *st)
{
- double xs,ys;
-
- analogtv_draw_solid_rel_lcp(input, 0.0, 1.0, 0.0, 1.0,
- 30.0, 0.0, 0.0);
-
- for (xs=0.0; xs<0.9999; xs+=1.0/15.0) {
- analogtv_draw_solid_rel_lcp(input, xs, xs, 0.0, 1.0,
- 100.0, 0.0, 0.0);
- }
-
- for (ys=0.0; ys<0.9999; ys+=1.0/11.0) {
- analogtv_draw_solid_rel_lcp(input, 0.0, 1.0, ys, ys,
- 100.0, 0.0, 0.0);
- }
-
- for (ys=0.0; ys<0.9999; ys+=0.01) {
-
- analogtv_draw_solid_rel_lcp(input, 0.0/15, 1.0/15, ys, ys+0.01,
- 40.0, 45.0, 103.5*(1.0-ys) + 347.0*ys);
-
- analogtv_draw_solid_rel_lcp(input, 14.0/15, 15.0/15, ys, ys+0.01,
- 40.0, 45.0, 103.5*(ys) + 347.0*(1.0-ys));
- }
-
- for (ys=0.0; ys<0.9999; ys+=0.02) {
- analogtv_draw_solid_rel_lcp(input, 1.0/15, 2.0/15, ys*2.0/11.0+1.0/11.0,
- (ys+0.01)*2.0/11.0+1.0/11.0,
- 100.0*(1.0-ys), 0.0, 0.0);
- }
+ struct timeval tv;
+ gettimeofday(&tv,NULL);
+ return ((tv.tv_sec - st->basetime.tv_sec)*1000 +
+ (tv.tv_usec - st->basetime.tv_usec)/1000);
+}
+/* The first time we grab an image, do it the default way.
+ The second and subsequent times, add "-no-desktop" to the command.
+ That way we don't have to watch the window un-map 5+ times in a row.
+ Also, we end up with the desktop on only one channel, and pictures
+ on all the others (or colorbars, if no imageDirectory is set.)
+ */
+static void
+hack_resources (Display *dpy)
+{
+#ifndef HAVE_JWXYZ
+ static int count = -1;
+ count++;
+
+ if (count == 0)
+ return;
+ else if (count == 1)
+ {
+ XrmDatabase db = XtDatabase (dpy);
+ char *res = "desktopGrabber";
+ char *val = get_string_resource (dpy, res, "DesktopGrabber");
+ char buf1[255];
+ char buf2[255];
+ XrmValue value;
+ sprintf (buf1, "%.100s.%.100s", progname, res);
+ sprintf (buf2, "%.200s -no-desktop", val);
+ value.addr = buf2;
+ value.size = strlen(buf2);
+ XrmPutResource (&db, buf1, "String", &value);
+ }
+#endif /* HAVE_JWXYZ */
}
-#endif
-
-char *progclass = "XAnalogTV";
-char *defaults [] = {
- "*delay: 5",
- ANALOGTV_DEFAULTS
- 0,
-};
-XrmOptionDescRec options [] = {
- { "-delay", ".delay", XrmoptionSepArg, 0 },
- ANALOGTV_OPTIONS
- { 0, 0, 0, 0 }
-};
+static void analogtv_load_random_image(struct state *);
-#ifdef USE_TEST_PATTERNS
+static void image_loaded_cb (Screen *screen, Window window, Drawable pixmap,
+ const char *name, XRectangle *geometry,
+ void *closure)
+{
+ /* When an image has just been loaded, store it into the first available
+ channel. If there are other unloaded channels, then start loading
+ another image.
+ */
+ struct state *st = (struct state *) closure;
+ int i;
+ int this = -1;
+ int next = -1;
-#include "images/earth.xpm"
+ if (!st->image_loading_p) abort(); /* only one at a time... */
+ st->image_loading_p = False;
-char **test_patterns[] = {
- earth_xpm,
-};
+ for (i = 0; i < MAX_STATIONS; i++) {
+ if (! st->chansettings[i].image_loaded_p) {
+ if (this == -1) this = i;
+ else if (next == -1) next = i;
+ }
+ }
+ if (this == -1) abort(); /* no unloaded stations? */
+ /* Load this image into the next channel. */
+ {
+ analogtv_input *input = st->stations[this];
+ int width=ANALOGTV_PIC_LEN;
+ int height=width*3/4;
+ XImage *image = XGetImage (st->dpy, pixmap, 0, 0,
+ width, height, ~0L, ZPixmap);
+ XFreePixmap(st->dpy, pixmap);
+
+ analogtv_setup_sync(input, 1, (random()%20)==0);
+ analogtv_load_ximage(st->tv, input, image, 0, 0, 0, 0, 0);
+ if (image) XDestroyImage(image);
+ st->chansettings[this].image_loaded_p = True;
+#if 0
+ if (name) {
+ const char *s = strrchr (name, '/');
+ if (s) s++;
+ else s = name;
+ st->chansettings[this].filename = strdup (s);
+ }
+ fprintf(stderr, "%s: loaded channel %d, %s\n", progname, this,
+ st->chansettings[this].filename);
#endif
+ }
-
-enum {
- N_CHANNELS=12, /* Channels 2 through 13 on VHF */
- MAX_MULTICHAN=2
-};
-
-typedef struct chansetting_s {
-
- analogtv_reception recs[MAX_MULTICHAN];
- double noise_level;
-
- int dur;
-} chansetting;
-
-static struct timeval basetime;
-
-static int
-getticks(void)
-{
- struct timeval tv;
- gettimeofday(&tv,NULL);
- return ((tv.tv_sec - basetime.tv_sec)*1000 +
- (tv.tv_usec - basetime.tv_usec)/1000);
+ /* If there are still unloaded stations, fire off another loader. */
+ if (next != -1)
+ analogtv_load_random_image (st);
}
-int
-analogtv_load_random_image(analogtv *it, analogtv_input *input)
+
+/* Queues a single image for loading. Only load one at a time.
+ The image is done loading when st->img_loader is null and
+ it->loaded_image is a pixmap.
+ */
+static void
+analogtv_load_random_image(struct state *st)
{
- Pixmap pixmap;
- XImage *image=NULL;
int width=ANALOGTV_PIC_LEN;
int height=width*3/4;
- int rc;
-
- pixmap=XCreatePixmap(it->dpy, it->window, width, height, it->visdepth);
- XSync(it->dpy, False);
- load_random_image(it->screen, it->window, pixmap, NULL);
- image = XGetImage(it->dpy, pixmap, 0, 0, width, height, ~0L, ZPixmap);
- XFreePixmap(it->dpy, pixmap);
-
- /* Make sure the window's background is not set to None, and get the
- grabbed bits (if any) off it as soon as possible. */
- XSetWindowBackground (it->dpy, it->window,
- get_pixel_resource ("background", "Background",
- it->dpy, it->xgwa.colormap));
- XClearWindow (it->dpy, it->window);
-
- analogtv_setup_sync(input, 1, (random()%20)==0);
- rc=analogtv_load_ximage(it, input, image);
- if (image) XDestroyImage(image);
- XSync(it->dpy, False);
- return rc;
+ Pixmap p;
+
+ if (st->image_loading_p) /* a load is already in progress */
+ return;
+
+ st->image_loading_p = True;
+ p = XCreatePixmap(st->dpy, st->window, width, height, st->tv->visdepth);
+ hack_resources(st->dpy);
+ load_image_async (st->tv->xgwa.screen, st->window, p, image_loaded_cb, st);
}
-int
-analogtv_load_xpm(analogtv *it, analogtv_input *input, char **xpm)
+
+static void add_stations(struct state *st)
{
- Pixmap pixmap;
- XImage *image;
- int width,height;
- int rc;
-
- pixmap=xpm_data_to_pixmap (it->dpy, it->window, xpm,
- &width, &height, NULL);
- image = XGetImage(it->dpy, pixmap, 0, 0, width, height, ~0L, ZPixmap);
- XFreePixmap(it->dpy, pixmap);
- rc=analogtv_load_ximage(it, input, image);
- if (image) XDestroyImage(image);
- XSync(it->dpy, False);
- return rc;
+ while (st->n_stations < MAX_STATIONS) {
+ analogtv_input *input=analogtv_input_allocate();
+ st->stations[st->n_stations++]=input;
+ input->client_data = st;
+ }
}
-enum { MAX_STATIONS = 6 };
-static int n_stations;
-static analogtv_input *stations[MAX_STATIONS];
-
-void add_stations(void)
+static void load_station_images(struct state *st)
{
- while (n_stations < MAX_STATIONS) {
- analogtv_input *input=analogtv_input_allocate();
- stations[n_stations++]=input;
+ int i;
+ for (i = 0; i < MAX_STATIONS; i++) {
+ analogtv_input *input = st->stations[i];
- if (n_stations==1) {
+ st->chansettings[i].image_loaded_p = True;
+ if (i == 0 || /* station 0 is always colorbars */
+ st->colorbars_only_p) {
input->updater = update_smpte_colorbars;
input->do_teletext=1;
}
#ifdef USE_TEST_PATTERNS
else if (random()%5==0) {
- j=random()%countof(test_patterns);
- analogtv_setup_sync(input);
- analogtv_load_xpm(tv, input, test_patterns[j]);
+ int count = 0, j;
+ for (count = 0; st->test_patterns[count]; count++)
+ ;
+ j=random()%count;
+ analogtv_setup_sync(input, 1, 0);
+ analogtv_load_ximage(st->tv, input, st->test_patterns[j],
+ 0, 0, 0, 0, 0);
analogtv_setup_teletext(input);
}
#endif
else {
- analogtv_load_random_image(tv, input);
+ analogtv_load_random_image(st);
input->do_teletext=1;
+ st->chansettings[i].image_loaded_p = False;
}
}
}
-void
-screenhack (Display *dpy, Window window)
+
+static void *
+xanalogtv_init (Display *dpy, Window window)
{
+ struct state *st = (struct state *) calloc (1, sizeof(*st));
int i;
- int curinputi;
- int change_ticks;
- int using_mouse=0;
- int change_now;
- chansetting chansettings[N_CHANNELS];
- chansetting *cs;
int last_station=42;
- int delay = get_integer_resource("delay", "Integer");
+ int delay = get_integer_resource(dpy, "delay", "Integer");
+
if (delay < 1) delay = 1;
- analogtv_make_font(dpy, window, &ugly_font, 7, 10, "6x10");
+ analogtv_make_font(dpy, window, &st->ugly_font, 7, 10, "6x10");
- tv=analogtv_allocate(dpy, window);
- tv->event_handler = screenhack_handle_event;
+ st->dpy = dpy;
+ st->window = window;
+ st->tv=analogtv_allocate(dpy, window);
+
+ st->colorbars_only_p =
+ get_boolean_resource(dpy, "colorbarsOnly", "ColorbarsOnly");
+
+ /* if (!st->colorbars_only_p) */
+ {
+ int w, h;
+ Pixmap mask = 0;
+ Pixmap p = image_data_to_pixmap (dpy, window,
+ logo_180_png, sizeof(logo_180_png),
+ &w, &h, &mask);
+ st->logo = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap);
+ XFreePixmap (dpy, p);
+ if (mask)
+ {
+ st->logo_mask = XGetImage (dpy, mask, 0, 0, w, h, ~0L, ZPixmap);
+ XFreePixmap (dpy, mask);
+ }
+ }
- add_stations();
+# ifdef USE_TEST_PATTERNS
+ {
+ int i = 0;
+ int w, h;
+ Pixmap p;
+ p = image_data_to_pixmap (dpy, window,
+ testcard_rca_png, sizeof(testcard_rca_png),
+ &w, &h, 0);
+ st->test_patterns[i++] = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap);
+ XFreePixmap (dpy, p);
+
+ p = image_data_to_pixmap (dpy, window,
+ testcard_pm5544_png, sizeof(testcard_pm5544_png),
+ &w, &h, 0);
+ st->test_patterns[i++] = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap);
+ XFreePixmap (dpy, p);
+
+ p = image_data_to_pixmap (dpy, window,
+ testcard_bbcf_png, sizeof(testcard_bbcf_png),
+ &w, &h, 0);
+ st->test_patterns[i++] = XGetImage (dpy, p, 0, 0, w, h, ~0L, ZPixmap);
+ XFreePixmap (dpy, p);
+ }
+# endif /* USE_TEST_PATTERNS */
- analogtv_set_defaults(tv, "");
- tv->need_clear=1;
+
+ add_stations(st);
+
+ analogtv_set_defaults(st->tv, "");
+ st->tv->need_clear=1;
if (random()%4==0) {
- tv->tint_control += pow(frand(2.0)-1.0, 7) * 180.0;
+ st->tv->tint_control += pow(frand(2.0)-1.0, 7) * 180.0;
}
if (1) {
- tv->color_control += frand(0.3);
+ st->tv->color_control += frand(0.3);
}
for (i=0; i<N_CHANNELS; i++) {
- memset(&chansettings[i], 0, sizeof(chansetting));
+ memset(&st->chansettings[i], 0, sizeof(chansetting));
- chansettings[i].noise_level = 0.06;
- chansettings[i].dur = 1000*delay;
+ st->chansettings[i].noise_level = 0.06;
+ st->chansettings[i].dur = 1000*delay;
if (random()%6==0) {
- chansettings[i].dur=600;
+ st->chansettings[i].dur=600;
}
else {
int stati;
for (stati=0; stati<MAX_MULTICHAN; stati++) {
- analogtv_reception *rec=&chansettings[i].recs[stati];
+ analogtv_reception *rec=&st->chansettings[i].recs[stati];
int station;
while (1) {
- station=random()%n_stations;
+ station=random()%st->n_stations;
if (station!=last_station) break;
if ((random()%10)==0) break;
}
last_station=station;
- rec->input = stations[station];
+ rec->input = st->stations[station];
rec->level = pow(frand(1.0), 3.0) * 2.0 + 0.05;
rec->ofs=random()%ANALOGTV_SIGNAL_LEN;
if (random()%3) {
}
}
- gettimeofday(&basetime,NULL);
+ gettimeofday(&st->basetime,NULL);
- curinputi=0;
- cs=&chansettings[curinputi];
- change_ticks = cs->dur + 1500;
+ st->curinputi=0;
+ st->cs = &st->chansettings[st->curinputi];
+ st->change_ticks = st->cs->dur + 1500;
- tv->powerup=0.0;
- while (1) {
- int curticks=getticks();
- double curtime=curticks*0.001;
+ st->tv->powerup=0.0;
- change_now=0;
- if (analogtv_handle_events(tv)) {
- using_mouse=1;
- change_now=1;
- }
- if (change_now || (!using_mouse && curticks>=change_ticks
- && tv->powerup > 10.0)) {
- curinputi=(curinputi+1)%N_CHANNELS;
- cs=&chansettings[curinputi];
- change_ticks = curticks + cs->dur;
- /* Set channel change noise flag */
- tv->channel_change_cycles=200000;
- }
+ load_station_images(st);
+
+ return st;
+}
- for (i=0; i<MAX_MULTICHAN; i++) {
- analogtv_reception *rec=&cs->recs[i];
- analogtv_input *inp=rec->input;
- if (!inp) continue;
+static unsigned long
+xanalogtv_draw (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ int i;
- if (inp->updater) {
- inp->next_update_time = curtime;
- (inp->updater)(inp);
- }
- rec->ofs += rec->freqerr;
- }
+ int curticks=getticks(st);
+ double curtime=curticks*0.001;
- tv->powerup=curtime;
+ const analogtv_reception *recs[MAX_MULTICHAN];
+ unsigned rec_count = 0;
- analogtv_init_signal(tv, cs->noise_level);
- for (i=0; i<MAX_MULTICHAN; i++) {
- analogtv_reception *rec=&cs->recs[i];
- analogtv_input *inp=rec->input;
- if (!inp) continue;
+ int auto_change = curticks >= st->change_ticks && st->tv->powerup > 10.0 ? 1 : 0;
+ if (st->change_now || auto_change) {
+ st->curinputi=(st->curinputi+st->change_now+auto_change+N_CHANNELS)%N_CHANNELS;
+ st->change_now = 0;
+ st->cs = &st->chansettings[st->curinputi];
+#if 0
+ fprintf (stderr, "%s: channel %d, %s\n", progname, st->curinputi,
+ st->cs->filename);
+#endif
+ st->change_ticks = curticks + st->cs->dur;
+ /* Set channel change noise flag */
+ st->tv->channel_change_cycles=200000;
+ }
+
+ for (i=0; i<MAX_MULTICHAN; i++) {
+ analogtv_reception *rec = &st->cs->recs[i];
+ analogtv_input *inp=rec->input;
+ if (!inp) continue;
+
+ if (inp->updater) {
+ inp->next_update_time = curtime;
+ (inp->updater)(inp);
+ }
+ rec->ofs += rec->freqerr;
+ }
+
+ st->tv->powerup=curtime;
+
+ for (i=0; i<MAX_MULTICHAN; i++) {
+ analogtv_reception *rec = &st->cs->recs[i];
+ if (rec->input) {
analogtv_reception_update(rec);
- analogtv_add_signal(tv, rec);
+ recs[rec_count] = rec;
+ ++rec_count;
}
- analogtv_draw(tv);
}
+ analogtv_draw(st->tv, st->cs->noise_level, recs, rec_count);
- XSync(dpy, False);
- XClearWindow(dpy, window);
-
- if (tv) analogtv_release(tv);
+#ifdef HAVE_MOBILE
+ return 0;
+#else
+ return 5000;
+#endif
+}
+
+static void
+xanalogtv_reshape (Display *dpy, Window window, void *closure,
+ unsigned int w, unsigned int h)
+{
+ struct state *st = (struct state *) closure;
+ analogtv_reconfigure(st->tv);
+}
+
+static Bool
+xanalogtv_event (Display *dpy, Window window, void *closure, XEvent *event)
+{
+ struct state *st = (struct state *) closure;
+
+ if (event->type == ButtonPress)
+ {
+ unsigned button = event->xbutton.button;
+ st->change_now = button == 2 || button == 3 || button == 5 ? -1 : 1;
+ return True;
+ }
+ else if (event->type == KeyPress)
+ {
+ KeySym keysym;
+ char c = 0;
+ XLookupString (&event->xkey, &c, 1, &keysym, 0);
+ if (c == ' ' || c == '\t' || c == '\r' || c == '\n' ||
+ keysym == XK_Up || keysym == XK_Right || keysym == XK_Prior)
+ {
+ st->change_now = 1;
+ return True;
+ }
+ else if (c == '\b' ||
+ keysym == XK_Down || keysym == XK_Left || keysym == XK_Next)
+ {
+ st->change_now = -1;
+ return True;
+ }
+ else if (screenhack_event_helper (dpy, window, event))
+ goto DEF;
+ }
+ else if (screenhack_event_helper (dpy, window, event))
+ {
+ DEF:
+ st->change_now = ((random() & 1) ? 1 : -1);
+ return True;
+ }
+
+ return False;
}
+static void
+xanalogtv_free (Display *dpy, Window window, void *closure)
+{
+ struct state *st = (struct state *) closure;
+ analogtv_release(st->tv);
+ if (st->logo) XDestroyImage (st->logo);
+ if (st->logo_mask) XDestroyImage (st->logo_mask);
+# ifdef USE_TEST_PATTERNS
+ {
+ int i;
+ for (i = 0; i < countof(st->test_patterns); i++)
+ if (st->test_patterns[i]) XDestroyImage (st->test_patterns[i]);
+ }
+# endif
+ free (st);
+}
+
+
+static const char *xanalogtv_defaults [] = {
+ ".background: black",
+ ".foreground: white",
+ "*delay: 5",
+ "*grabDesktopImages: False", /* HAVE_JWXYZ */
+ "*chooseRandomImages: True", /* HAVE_JWXYZ */
+ "*colorbarsOnly: False",
+ ANALOGTV_DEFAULTS
+ 0,
+};
+
+static XrmOptionDescRec xanalogtv_options [] = {
+ { "-delay", ".delay", XrmoptionSepArg, 0 },
+ { "-colorbars-only", ".colorbarsOnly", XrmoptionNoArg, "True" },
+ ANALOGTV_OPTIONS
+ { 0, 0, 0, 0 }
+};
+
+
+XSCREENSAVER_MODULE ("XAnalogTV", xanalogtv)