/*-
* 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;
}
syntax highlighted by Code2HTML, v. 0.9.1