/* 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. */ #include #include "screenhack.h" #include "alpha.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); } /* 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 speed; double x, y; /* ball position */ double dx, dy; /* ball direction */ int w, h; /* ball width, height */ GC gc; /* graphics context */ XWindowAttributes xgwa; XColor color; 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 */ }; /* initialize ball position */ static void init_ball_pos(struct state *st) { int sw, sh; sw = st->xgwa.width; /* window width */ sh = st->xgwa.height; /* window height */ /* set width and height */ st->w = st->h = ((sw > sh) ? sh : sw) / 16; /* set position */ st->x = (random() % (sw / 2)) + (sw / 4); st->y = (random() % (sh / 2)) + (sh / 4); /* set direction */ { double rad; rad = deg2rad(random() % 360); st->dx = st->speed * cos(rad); st->dy = st->speed * sin(rad); } } /* * init screensaver. * Return an object holding your global state. */ static void * helloxsaver_init(Display *display, Window window) { struct state *st = (struct state *)calloc(1, sizeof(*st)); st->display = display; st->window = window; /* get parameter */ st->delay = get_integer_resource(st->display, "delay", "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); /* define colors */ st->color.pixel = get_pixel_resource(st->display, st->xgwa.colormap, "foreground", "Foreground"); 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. use erase. */ { XGCValues gcv; gcv.foreground = get_pixel_resource(st->display, st->xgwa.colormap, "background", "Background"); st->erase_gc = XCreateGC(st->display, st->backbuf, GCForeground, &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); /* initialize ball position */ init_ball_pos(st); /* init graphics context */ { XGCValues gcv; unsigned long flags; flags = GCForeground; gcv.foreground = st->color.pixel; gcv.line_width = 2; gcv.cap_style = CapProjecting; gcv.join_style = JoinMiter; flags |= (GCLineWidth | GCCapStyle | GCJoinStyle); st->gc = XCreateGC(st->display, window, flags, &gcv); } return st; } /* Draw a single frame */ static unsigned long helloxsaver_draw(Display *display, Window window, void *closure) { struct state *st = (struct state *)closure; /* clear double buffer */ #ifdef HAVE_DOUBLE_BUFFER_EXTENSION if (!st->dbeclear_p || !st->backb) XFillRectangle(st->display, st->backbuf, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); #else XFillRectangle(st->display, st->backbuf, st->erase_gc, 0, 0, st->xgwa.width, st->xgwa.height); #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ /* ball move and draw */ { /* draw circle */ XFillArc(st->display, st->backbuf, st->gc, st->x, st->y, st->w, st->h, 0, 360 * 64); /* move */ st->x += st->dx; st->y += st->dy; /* change directon */ if (st->x <= 0 || (st->x + st->w) >= st->xgwa.width) st->dx *= -1; if (st->y <= 0 || (st->y + st->h) >= st->xgwa.height) st->dy *= -1; } /* 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->xgwa.width, st->xgwa.height, 0, 0); st->backbuf = (st->backbuf == st->ba ? st->bb : st->ba); } return st->delay; } /* Called when the window is resized. */ static void helloxsaver_reshape(Display *display, Window window, void *closure, unsigned int w, unsigned int h) { struct state *st = (struct state *)closure; if (!st->use_dbuf) { /* #### more complicated if we have a back buffer... */ XGetWindowAttributes(st->display, st->window, &st->xgwa); XClearWindow(display, window); init_ball_pos(st); } } /* Called when a keyboard or mouse event happens. */ static Bool helloxsaver_event(Display *display, Window window, void *closure, XEvent *event) { return False; } /* Free everything you've allocated. */ static void helloxsaver_free(Display *display, Window window, void *closure) { struct state *st = (struct state *)closure; XFreeGC(display, st->erase_gc); if (st->ba) XFreePixmap(display, st->ba); if (st->bb) XFreePixmap(display, st->bb); if (st->plane_masks) free(st->plane_masks); XFreeGC(display, st->gc); free(st); } /* Default values for the resources you use. */ static const char *helloxsaver_defaults[] = { ".background: black", ".foreground: white", "*delay: 10000", "*speed: 15", "*doubleBuffer: True", #ifdef HAVE_DOUBLE_BUFFER_EXTENSION "*useDBE: True", "*useDBEClear: True", #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ #ifdef HAVE_MOBILE "*ignoreRotation: True", #endif 0}; /* The command-line options you accept. */ static XrmOptionDescRec helloxsaver_options[] = { {"-delay", ".delay", XrmoptionSepArg, 0}, {"-speed", ".speed", XrmoptionSepArg, 0}, {"-db", ".doubleBuffer", XrmoptionNoArg, "True"}, {"-no-db", ".doubleBuffer", XrmoptionNoArg, "False"}, {0, 0, 0, 0}}; /* * The last line of the file should be * XSCREENSAVER_MODULE ("YourSaverName", yoursavername) */ XSCREENSAVER_MODULE("Helloxsaver", helloxsaver)