/* 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, deluxe.c */ #include #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; Pixmap backbuf, ba, bb; /* double-buffer to reduce flicker */ Bool use_dbuf; Bool monochrome; #ifdef HAVE_DOUBLE_BUFFER_EXTENSION Bool dbeclear_p; XdbeBackBuffer backb; #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ XWindowAttributes xgwa; int scrw, scrh; XGCValues gcv; Colormap cmap; int delay; int count; int speed; struct obj **objs; PIXMAPS image0; int pix_w, pix_h; XColor fgcolor, bgcolor; unsigned long fg, bg; GC gc; GC erase_gc; /* GC fg_gc, bg_gc; */ }; /* 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_pos(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_pos(st, o, ang); { XGCValues gcv; gcv.foreground = st->fgcolor.pixel; o->gc = XCreateGC(st->display, st->window, GCForeground, &gcv); XSetGraphicsExposures(st->display, o->gc, False); } return o; } static void free_obj(struct state *st, struct obj *o) { XFreeGC(st->display, o->gc); free(o); } static void free_objs(struct state *st) { int i; for (i = 0; i < st->count; i++) free_obj(st, st->objs[i]); } 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]); } } /* debug. display double buffer status. */ static void display_dbuf_status(struct state *st) { XColor whitex, whites; char *mes0, *mes1; int x, y; x = st->scrw / 2; y = 24; mes0 = "Double buffer enable"; mes1 = "Double buffer disable"; XAllocNamedColor(st->display, DefaultColormapOfScreen(DefaultScreenOfDisplay(st->display)), "white", &whites, &whitex); XSetForeground(st->display, st->gc, whites.pixel); if (st->use_dbuf) XDrawString(st->display, st->backbuf, st->gc, x, y, mes0, strlen(mes0)); else XDrawString(st->display, st->backbuf, st->gc, x, y, mes1, strlen(mes1)); } /* draw transparent image */ static void draw_image(Display *display, Drawable wdw, GC gc, PIXMAPS *img, int x, int y, int w, int h) { XSetClipMask(display, gc, img->m); /* set mask */ XSetClipOrigin(display, gc, x, y); /* set mask position */ XCopyArea(display, img->p, wdw, gc, 0, 0, w, h, x, y); XSetClipMask(display, gc, None); /* reset mask */ } 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); } /* debug */ if (false) display_dbuf_status(st); } /* get parameter */ static void get_parameter(struct state *st) { 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->monochrome = get_boolean_resource(st->display, "mono", "Boolean"); /* st->use_dbuf = get_boolean_resource(st->display, "doubleBuffer", "Boolean"); */ } static void init_doublebuffer(struct state *st) { st->use_dbuf = True; #ifdef HAVE_JWXYZ /* Don't second-guess Quartz's double-buffering */ st->use_dbuf = False; #endif #ifdef HAVE_DOUBLE_BUFFER_EXTENSION st->dbeclear_p = get_boolean_resource(st->display, "useDBEClear", "Boolean"); #endif st->backbuf = st->ba = st->bb = 0; /* double-buffer to reduce flicker */ #ifdef HAVE_DOUBLE_BUFFER_EXTENSION st->backbuf = st->backb = xdbe_get_backbuffer(st->display, st->window, XdbeUndefined); #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ if (st->use_dbuf) { /* use double buffer. init */ #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->scrw, st->scrh, st->xgwa.depth); st->bb = XCreatePixmap(st->display, st->window, st->scrw, st->scrh, st->xgwa.depth); st->backbuf = st->ba; } } else { /* not use double buffer */ st->backbuf = st->window; } } static void init_color(struct state *st) { char *cname; cname = get_string_resource(st->display, "textForeground", "Foreground"); if (!cname) cname = strdup("black"); st->fg = get_pixel_resource(st->display, st->cmap, "foreground", "Foreground"); st->bg = get_pixel_resource(st->display, st->cmap, "background", "Background"); st->fgcolor.pixel = get_pixel_resource(st->display, st->cmap, "foreground", "Foreground"); st->bgcolor.pixel = get_pixel_resource(st->display, st->cmap, "background", "Background"); } /* init graphics context */ static void init_graphics_context(struct state *st) { st->gcv.foreground = get_pixel_resource(st->display, st->cmap, "foreground", "Foreground"); st->gc = XCreateGC(st->display, st->window, 0, &st->gcv); st->gcv.foreground = get_pixel_resource(st->display, st->cmap, "background", "Background"); st->erase_gc = XCreateGC(st->display, st->window, GCForeground, &st->gcv); } static void init_clear_double_buffer(struct state *st) { if (st->ba) XFillRectangle(st->display, st->ba, st->erase_gc, 0, 0, st->scrw, st->scrh); if (st->bb) XFillRectangle(st->display, st->bb, st->erase_gc, 0, 0, st->scrw, st->scrh); } /* 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)); st->display = display; st->window = window; get_parameter(st); /* get window attributes */ XGetWindowAttributes(st->display, st->window, &st->xgwa); st->scrw = st->xgwa.width; /* screen width */ st->scrh = st->xgwa.height; /* screen height */ st->cmap = st->xgwa.colormap; /* colormap */ init_color(st); init_doublebuffer(st); init_graphics_context(st); init_clear_double_buffer(st); init_images(st); init_objs(st, st->count); return st; } /* clear double buffer */ static void clear_fill_backbuffer(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->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; clear_fill_backbuffer(st); update_objs(st); draw_objs(st); draw_doublebuffer(st); 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_pos(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); /* free double buffer */ if (st->ba) XFreePixmap(display, st->ba); if (st->bb) XFreePixmap(display, st->bb); /* free images */ if (st->image0.p) XFreePixmap(display, st->image0.p); if (st->image0.m) XFreePixmap(display, st->image0.m); /* free obj work */ free_objs(st); 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", #ifdef HAVE_DOUBLE_BUFFER_EXTENSION "*useDBE: True", #endif /* HAVE_DOUBLE_BUFFER_EXTENSION */ 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)