/* xscreensaver, Copyright (c) 2022 YOURNAME * * Permission to use, copy, modify, distribute, and sell this software and its * documentation for any purpose is hereby granted without fee, provided that * the above copyright notice appear in all copies and that both that * copyright notice and this permission notice appear in supporting * documentation. No representations are made about the suitability of this * software for any purpose. It is provided "as is" without express or * implied warranty. */ /* fork noseguy.c */ #include #include #include "screenhack.h" #include "ximage-loader.h" /* include png image binary */ #define IMG_MAX 1 #include "images/gen/ufoimage256c_png.h" #ifdef HAVE_DOUBLE_BUFFER_EXTENSION #include "xdbe.h" #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ #define PI 3.141592 /* degree to radian */ static double deg2rad(double angle) { return (angle * PI / 180.0); } /* ufo object work */ struct obj { double x, y; /* position */ double dx, dy; /* direction */ int w, h; /* width, height */ int scrw, scrh; /* screen width, height */ GC gc; }; typedef struct { Pixmap p, m; } PIXMAPS; /* screensaver state */ struct state { Display *display; Window window; int nplanes; unsigned long base_pixel; unsigned long *plane_masks; Bool monochrome; Bool use_dbuf; int delay; int count; int speed; struct obj **objs; Bool running; XWindowAttributes xgwa; int scrw, scrh; GC gc; /* GC fg_gc, bg_gc; */ PIXMAPS image0; int pix_w, pix_h; XColor fgcolor, bgcolor; unsigned long fg, bg; GC erase_gc; /* double-buffer to reduce flicker */ Pixmap backbuf; Pixmap ba; Pixmap bb; #ifdef HAVE_DOUBLE_BUFFER_EXTENSION Bool dbeclear_p; XdbeBackBuffer backb; #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ }; /* init images */ static void init_images(struct state *st) { PIXMAPS *images[IMG_MAX]; struct { const unsigned char *png; unsigned long size; } bits[IMG_MAX]; images[0] = &st->image0; bits[0].png = ufoimage256c_png; bits[0].size = sizeof(ufoimage256c_png); { int i; for (i = 0; i < IMG_MAX; i++) { Pixmap mask = 0; Pixmap pixmap = image_data_to_pixmap(st->display, st->window, bits[i].png, bits[i].size, &st->pix_w, &st->pix_h, &mask); if (!pixmap) { fprintf(stderr, "%s: Can't load nose images\n", progname); exit(1); } images[i]->p = pixmap; images[i]->m = mask; } } } static void init_obj(struct state *st, struct obj *o, int ang) { o->scrw = st->scrw; o->scrh = st->scrh; o->x = o->scrw / 2; o->y = o->scrh / 2; o->w = st->pix_w; o->h = st->pix_h; /* set direction */ { double rad; int spd = st->speed; rad = deg2rad(ang); o->dx = spd * cos(rad); o->dy = spd * sin(rad); } } static struct obj * create_obj(struct state *st, int ang) { struct obj *o = (struct obj *)malloc(sizeof(*o)); init_obj(st, o, ang); { XGCValues gcv; unsigned long flags; flags = GCForeground; gcv.foreground = st->fgcolor.pixel; o->gc = XCreateGC(st->display, st->backbuf, flags, &gcv); } return o; } static void free_obj(struct state *st, struct obj *o) { XFreeGC(st->display, o->gc); free(o); } static void update_obj(struct state *st, struct obj *o) { o->x += o->dx; o->y += o->dy; { int wh = o->w / 2; int hh = o->h / 2; if (o->x - wh <= 0 || o->x + wh >= o->scrw) o->dx *= -1; if (o->y - hh <= 0 || o->y + hh >= o->scrh) o->dy *= -1; } } static void init_objs(struct state *st, int count) { st->objs = (struct obj **)calloc(count, sizeof(struct obj *)); { int i; for (i = 0; i < count; i++) { int ang = 360 * i / count; st->objs[i] = create_obj(st, ang); } } } static void update_objs(struct state *st) { int i; for (i = 0; i < st->count; i++) { update_obj(st, st->objs[i]); } } static void draw_image(Display *display, Pixmap window, GC gc, PIXMAPS *img, int x, int y, int w, int h) { /* XFillRectangle(display, window, gc, X2, Y2, w, h); */ XSetClipMask(display, gc, img->m); XSetClipOrigin(display, gc, x, y); XCopyArea(display, img->p, window, gc, 0, 0, w, h, x, y); XSetClipMask(display, gc, None); } static void draw_objs(struct state *st) { int i; for (i = 0; i < st->count; i++) { int x, y, w, h; struct obj *o = st->objs[i]; w = o->w; h = o->h; x = o->x - (o->w / 2); y = o->y - (o->h / 2); draw_image(st->display, st->backbuf, o->gc, &st->image0, x, y, w, h); } } /* init screensaver. Return an object holding your global state. */ static void * helloimgdraw_init(Display *display, Window window) { struct state *st = (struct state *)calloc(1, sizeof(*st)); /* char *s; */ st->running = true; st->display = display; st->window = window; /* get parameter */ st->delay = get_integer_resource(st->display, "delay", "Integer"); st->count = get_integer_resource(st->display, "count", "Integer"); st->speed = get_integer_resource(st->display, "speed", "Speed"); st->use_dbuf = get_boolean_resource(st->display, "doubleBuffer", "Boolean"); st->monochrome = get_boolean_resource(st->display, "mono", "Boolean"); #ifdef HAVE_DOUBLE_BUFFER_EXTENSION st->dbeclear_p = get_boolean_resource(st->display, "useDBEClear", "Boolean"); #endif #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ st->use_dbuf = False; #endif /* get window attributes */ XGetWindowAttributes(st->display, st->window, &st->xgwa); st->scrw = st->xgwa.width; st->scrh = st->xgwa.height; { Colormap cmap; char *cname; cmap = st->xgwa.colormap; cname = get_string_resource(st->display, "textForeground", "Foreground"); if (!cname) cname = strdup("black"); st->fg = get_pixel_resource(st->display, cmap, "foreground", "Foreground"); st->bg = get_pixel_resource(st->display, cmap, "background", "Background"); st->fgcolor.pixel = get_pixel_resource(st->display, cmap, "foreground", "Foreground"); st->bgcolor.pixel = get_pixel_resource(st->display, cmap, "background", "Background"); } if (st->use_dbuf) { /* init double buffer */ #ifdef HAVE_DOUBLE_BUFFER_EXTENSION if (st->dbeclear_p) st->backbuf = xdbe_get_backbuffer(st->display, st->window, XdbeBackground); else st->backbuf = xdbe_get_backbuffer(st->display, st->window, XdbeUndefined); st->backb = st->backbuf; #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ if (!st->backbuf) { /* create buffer A, B */ st->ba = XCreatePixmap(st->display, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth); st->bb = XCreatePixmap(st->display, st->window, st->xgwa.width, st->xgwa.height, st->xgwa.depth); st->backbuf = st->ba; } } else { st->backbuf = st->window; } /* init graphics context */ { /* XGCValues gcv; unsigned long flags; flags = GCForeground | GCBackground; gcv.foreground = st->fg; gcv.background = st->bg; st->fg_gc = XCreateGC(st->display, st->window, flags, &gcv); gcv.foreground = st->bg; gcv.background = st->fg; st->bg_gc = XCreateGC(st->display, st->window, flags, &gcv); */ } /* init graphics context */ { XGCValues gcv; unsigned long flags; /* flags = GCForeground | GCBackground; gcv.foreground = st->fg; gcv.background = st->bg; st->gc = XCreateGC(st->display, st->backbuf, flags, &gcv); flags = GCForeground; gcv.foreground = st->bg; gcv.background = st->fg; st->erase_gc = XCreateGC(st->display, st->backbuf, flags, &gcv); */ flags = GCForeground; gcv.foreground = st->fgcolor.pixel; st->gc = XCreateGC(st->display, st->backbuf, flags, &gcv); flags = GCForeground; gcv.foreground = st->bgcolor.pixel; st->erase_gc = XCreateGC(st->display, st->backbuf, flags, &gcv); } /* clear buffer A, B */ if (st->ba) XFillRectangle(st->display, st->ba, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); if (st->bb) XFillRectangle(st->display, st->bb, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); init_images(st); init_objs(st, st->count); st->running = false; return st; } /* clear double buffer */ static void clear_doublebuffer(struct state *st) { #ifdef HAVE_DOUBLE_BUFFER_EXTENSION if (!st->dbeclear_p || !st->backb) XFillRectangle(st->display, st->backbuf, st->erase_gc, 0, 0, st->scrw, st->scrh); #else XFillRectangle(st->display, st->backbuf, st->erase_gc, 0, 0, st->scrw, st->scrh); #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ } /* draw double buffer */ static void draw_doublebuffer(struct state *st) { /* draw double buffer */ #ifdef HAVE_DOUBLE_BUFFER_EXTENSION if (st->backb) { XdbeSwapInfo info[1]; info[0].swap_window = st->window; info[0].swap_action = (st->dbeclear_p ? XdbeBackground : XdbeUndefined); XdbeSwapBuffers(st->display, info, 1); } else #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ if (st->use_dbuf) { XCopyArea(st->display, st->backbuf, st->window, st->erase_gc, 0, 0, st->scrw, st->scrh, 0, 0); st->backbuf = (st->backbuf == st->ba ? st->bb : st->ba); } } /* draw single frame. */ static unsigned long helloimgdraw_draw(Display *display, Window window, void *closure) { struct state *st = (struct state *)closure; if (st->running) return st->delay; st->running = true; clear_doublebuffer(st); update_objs(st); draw_objs(st); draw_doublebuffer(st); st->running = false; return st->delay; } /* Called when the window is resized. */ static void helloimgdraw_reshape(Display *display, Window window, void *closure, unsigned int w, unsigned int h) { struct state *st = (struct state *)closure; XGetWindowAttributes(st->display, st->window, &st->xgwa); st->scrw = st->xgwa.width; st->scrh = st->xgwa.height; /* reset obj work */ { int i; for (i = 0; i < st->count; i++) { int ang = 360 * i / st->count; init_obj(st, st->objs[i], ang); } } if (!st->use_dbuf) { /* #### more complicated if we have a back buffer... */ XClearWindow(display, window); } } /* Called when a keyboard or mouse event happens. */ static Bool helloimgdraw_event(Display *display, Window window, void *closure, XEvent *event) { return False; } /* Free everything you've allocated. */ static void helloimgdraw_free(Display *display, Window window, void *closure) { struct state *st = (struct state *)closure; XFreeGC(display, st->erase_gc); XFreeGC(display, st->gc); /* XFreeGC(display, st->fg_gc); XFreeGC(display, st->bg_gc); */ if (st->ba) XFreePixmap(display, st->ba); if (st->bb) XFreePixmap(display, st->bb); if (st->plane_masks) free(st->plane_masks); if (st->image0.p) XFreePixmap(display, st->image0.p); if (st->image0.m) XFreePixmap(display, st->image0.m); /* free obj work */ { int i; for (i = 0; i < st->count; i++) { free_obj(st, st->objs[i]); } } free(st); } /* Default values for the resources you use. */ static const char *helloimgdraw_defaults[] = { ".background: black", ".foreground: white", "*delay: 20000", "*count: 80", "*speed: 8", "*fpsSolid: true", "*program: xscreensaver-text", "*usePty: False", 0}; /* The command-line options you accept. */ static XrmOptionDescRec helloimgdraw_options[] = { {"-delay", ".delay", XrmoptionSepArg, 0}, {"-count", ".count", XrmoptionSepArg, 0}, {"-speed", ".speed", XrmoptionSepArg, 0}, {"-program", ".program", XrmoptionSepArg, 0}, {0, 0, 0, 0}}; XSCREENSAVER_MODULE("Helloimgdraw", helloimgdraw)