/*- * Copyright (c) 2001 Jordan DeLong * All rights reserved. * * Redistribution and use in source and binary forms, with or without * modification, are permitted provided that the following conditions * are met: * 1. Redistributions of source code must retain the above copyright * notice, this list of conditions and the following disclaimer. * 2. Redistributions in binary form must reproduce the above copyright * notice, this list of conditions and the following disclaimer in the * documentation and/or other materials provided with the distribution. * 3. Neither the name of the author nor the names of contributors may be * used to endorse or promote products derived from this software * without specific prior written permission. * * THIS SOFTWARE IS PROVIDED BY THE AUTHOR AND CONTRIBUTORS ``AS IS'' AND * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE * ARE DISCLAIMED. IN NO EVENT SHALL THE AUTHOR OR CONTRIBUTORS BE LIABLE * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF * SUCH DAMAGE. */ #include "plugutil.h" /* steps for animations */ #define NUMSTEPS 15 #define TRIMHEIGHT 20 /* per-screen structure */ static struct slidescr { Window top; /* top window */ Window bottom; /* bottom window */ Window toptrim; /* top trim window */ Window bottomtrim; /* bottom trim window */ Pixmap bgpixmap; /* background pixmap */ Pixmap logopixmap; /* the logo pixmap */ Pixmap trimpixmap; /* the trim stuff */ int height; /* dimensions of screen */ int width; } *slidescr; /* number of screens to deal with */ static int cnt = 0; /* * make our windows and stuff. We don't use the golem internal client stuff because, * a) at init() we aren't allowed to try to make golem clients (screen_init() hasn't * been called yet), and b) we are making override_redirect windows. */ int init() { XSetWindowAttributes attr; XEvent event; Window dumwin; int dumint, screen; int pmwidth = -1, pmheight; char *bgfn, *logofn, *trimfn; /* get the pixmaps */ REQUIRED_PARAM(&plugin_this->params, "pixmap", string, bgfn); REQUIRED_PARAMTO(&plugin_this->params, "logo", string, logofn, free1); REQUIRED_PARAMTO(&plugin_this->params, "trim", string, trimfn, free2); /* get num of screens, and malloc our window array */ cnt = ScreenCount(display); slidescr = calloc(cnt, sizeof(struct slidescr)); if (!slidescr) goto free3; /* create and map the windows */ for (screen = 0; screen < cnt; screen++) { /* we need to know the screen dimensions */ XGetGeometry(display, RootWindow(display, screen), &dumwin, &dumint, &dumint, &slidescr[screen].width, &slidescr[screen].height, &dumint, &dumint); /* get our pixmaps */ XpmReadFileToPixmap(display, RootWindow(display, screen), bgfn, &slidescr[screen].bgpixmap, NULL, NULL); XpmReadFileToPixmap(display, RootWindow(display, screen), logofn, &slidescr[screen].logopixmap, NULL, NULL); XpmReadFileToPixmap(display, RootWindow(display, screen), trimfn, &slidescr[screen].trimpixmap, NULL, NULL); /* create the windows */ attr.override_redirect = 1; attr.background_pixmap = slidescr[screen].bgpixmap; attr.save_under = 1; slidescr[screen].top = XCreateWindow(display, RootWindow(display, screen), 0, 0, slidescr[screen].width, slidescr[screen].height / 2, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWSaveUnder | CWOverrideRedirect | CWBackPixmap, &attr); slidescr[screen].bottom = XCreateWindow(display, RootWindow(display, screen), 0, slidescr[screen].height / 2, slidescr[screen].width, slidescr[screen].height / 2, 0, CopyFromParent, CopyFromParent, CopyFromParent, CWSaveUnder | CWOverrideRedirect | CWBackPixmap, &attr); XSelectInput(display, slidescr[screen].top, StructureNotifyMask); /* the trim windows */ slidescr[screen].toptrim = XCreateSimpleWindow(display, slidescr[screen].top, 0, (slidescr[screen].height / 2) - TRIMHEIGHT, slidescr[screen].width, TRIMHEIGHT, 0, BlackPixel(display, screen), BlackPixel(display, screen)); slidescr[screen].bottomtrim = XCreateSimpleWindow(display, slidescr[screen].bottom, 0, 0, slidescr[screen].width, TRIMHEIGHT, 0, BlackPixel(display, screen), BlackPixel(display, screen)); XSetWindowBackgroundPixmap(display, slidescr[screen].toptrim, slidescr[screen].trimpixmap); XSetWindowBackgroundPixmap(display, slidescr[screen].bottomtrim, slidescr[screen].trimpixmap); } /* this is in a seperate loop so that it appears that all screens come up at once */ for (screen = 0; screen < cnt; screen++) { /* map the windows */ XMapRaised(display, slidescr[screen].top); XMapRaised(display, slidescr[screen].bottom); XMapWindow(display, slidescr[screen].toptrim); XMapWindow(display, slidescr[screen].bottomtrim); /* no longer need events here */ XSelectInput(display, slidescr[screen].top, NoEventMask); /* draw the logo */ if (pmwidth == -1) XGetGeometry(display, slidescr[screen].logopixmap, &dumwin, &dumint, &dumint, &pmwidth, &pmheight, &dumint, &dumint); /* wait for it to be mapped */ while (1) { /* * it's safe to throw away other events because we're in init(), and thus nothing is * happening except plugin init()'s (which should use their events they need within * their own callbacks), and the rcfile parsing. Doing something like this is * unnacceptable (and unneccesary) anywhere other than like this. */ XNextEvent(display, &event); if (event.type == MapNotify && event.xmap.window == slidescr[screen].top) break; } XCopyArea(display, slidescr[screen].logopixmap, slidescr[screen].top, DefaultGC(display, screen), 0, 0, pmwidth, pmheight, 0, 0); } /* filenames need to be freed */ free(trimfn); free(logofn); free(bgfn); return PLUGIN_OK; free3: free(trimfn); free2: free(logofn); free1: free(bgfn); return PLUGIN_UNLOAD; } /* * when start() returns PLUGIN_UNLOAD the main golem code will call this function * before dlclosing us: we free any of our allocated memory. */ void shutdown() { int screen; /* we also destroy the windows */ if (slidescr) { for (screen = 0; screen < cnt; screen++) { XDestroyWindow(display, slidescr[screen].top); XDestroyWindow(display, slidescr[screen].bottom); XDestroyWindow(display, slidescr[screen].toptrim); XDestroyWindow(display, slidescr[screen].bottomtrim); XFreePixmap(display, slidescr[screen].bgpixmap); XFreePixmap(display, slidescr[screen].logopixmap); XFreePixmap(display, slidescr[screen].trimpixmap); } free(slidescr); } } /* * this is called right after rcfile parsing and screen intialization, so when golem * is ready for interactive use by the user. We make a little animatory thing, and * then unload. */ int start() { int screen; int yt[cnt], yb[cnt], mod[cnt]; int i; XSync(display, 0); /* first we go through and figure out yt and yb and mod */ for (screen = 0; screen < cnt; screen++) { yt[screen] = 0; yb[screen] = slidescr[screen].height / 2; mod[screen] = (slidescr[screen].height / 2) / NUMSTEPS; } /* wait a few frames before scrolling it */ usleep(options.anim_delay * 3); /* slide our two windows up and down */ for (i = 0; i < NUMSTEPS; i++) { for (screen = 0; screen < cnt; screen++) { yt[screen] -= mod[screen]; yb[screen] += mod[screen]; XMoveWindow(display, slidescr[screen].top, 0, yt[screen]); XMoveWindow(display, slidescr[screen].bottom, 0, yb[screen]); } XSync(display, 0); usleep(20); } return PLUGIN_UNLOAD; }