1
0
mirror of https://github.com/gryf/wmaker.git synced 2025-12-19 20:38:08 +01:00
Files
wmaker/util/wmagnify.c
Christophe CURIS 90d24a1648 Unified usage of the 'inline' attribute for functions
Autoconf provides the necessary stuff to detect if inline keyword
is supported, and to detect special syntaxes, so let's use this
and remove the multiple local definitions, this makes code simpler.
2013-05-11 00:17:27 +01:00

486 lines
11 KiB
C

/*
* magnify - a X utility for magnifying screen image
*
* 2000/5/21 Alfredo K. Kojima
*
* This program is in the Public Domain.
*/
#include <config.h>
#include <X11/Xproto.h>
#include <WINGs/WINGs.h>
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
/*
* TODO:
* - lens that shows where it's magnifying
*
*
*/
int refreshrate = 200;
typedef struct {
Drawable d;
XRectangle *rects;
int rectP;
unsigned long lastpixel;
unsigned long *buffer;
int width, height;
int rwidth, rheight; /* size of window in real pixels */
int magfactor;
int refreshrate;
WMWindow *win;
WMLabel *label;
WMPixmap *pixmap;
WMWindow *dlg;
WMSlider *speed;
WMSlider *magnify;
WMButton *okB;
WMButton *cancelB;
WMButton *newB;
int x, y;
Bool frozen;
Bool firstDraw;
Bool markPointerHotspot;
WMHandlerID tid;
} BufferData;
static BufferData *newWindow(int magfactor);
int windowCount = 0;
int rectBufferSize = 32;
Display *dpy, *vdpy;
WMScreen *scr;
unsigned int black;
WMColor *cursorColor1;
WMColor *cursorColor2;
static BufferData *makeBufferData(WMWindow * win, WMLabel * label, int width, int height, int magfactor)
{
BufferData *data;
data = wmalloc(sizeof(BufferData));
data->rwidth = width;
data->rheight = height;
data->refreshrate = refreshrate;
data->firstDraw = True;
data->magfactor = magfactor;
data->rects = wmalloc(sizeof(XRectangle) * rectBufferSize);
data->rectP = 0;
data->win = win;
data->label = label;
data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
WMSetLabelImage(data->label, data->pixmap);
data->d = WMGetPixmapXID(data->pixmap);
data->frozen = False;
width /= magfactor;
height /= magfactor;
data->buffer = wmalloc(sizeof(unsigned long) * width * height);
data->width = width;
data->height = height;
return data;
}
static void resizeBufferData(BufferData * data, int width, int height, int magfactor)
{
int w = width / magfactor;
int h = height / magfactor;
data->rwidth = width;
data->rheight = height;
data->firstDraw = True;
data->magfactor = magfactor;
data->buffer = wrealloc(data->buffer, sizeof(unsigned long) * w * h);
data->width = w;
data->height = h;
memset(data->buffer, 0, w * h * sizeof(unsigned long));
WMResizeWidget(data->label, width, height);
WMReleasePixmap(data->pixmap);
data->pixmap = WMCreatePixmap(scr, width, height, WMScreenDepth(scr), False);
WMSetLabelImage(data->label, data->pixmap);
data->d = WMGetPixmapXID(data->pixmap);
}
static int drawpoint(BufferData * data, unsigned long pixel, int x, int y)
{
static GC gc = NULL;
Bool flush = (x < 0);
if (!flush) {
if (data->buffer[x + data->width * y] == pixel && !data->firstDraw)
return 0;
data->buffer[x + data->width * y] = pixel;
}
if (gc == NULL) {
gc = XCreateGC(dpy, DefaultRootWindow(dpy), 0, NULL);
}
if (!flush && data->lastpixel == pixel && data->rectP < rectBufferSize) {
data->rects[data->rectP].x = x * data->magfactor;
data->rects[data->rectP].y = y * data->magfactor;
data->rects[data->rectP].width = data->magfactor;
data->rects[data->rectP].height = data->magfactor;
data->rectP++;
return 0;
}
XSetForeground(dpy, gc, data->lastpixel);
XFillRectangles(dpy, data->d, gc, data->rects, data->rectP);
data->rectP = 0;
data->rects[data->rectP].x = x * data->magfactor;
data->rects[data->rectP].y = y * data->magfactor;
data->rects[data->rectP].width = data->magfactor;
data->rects[data->rectP].height = data->magfactor;
data->rectP++;
data->lastpixel = pixel;
return 1;
}
static inline unsigned long getpix(XImage * image, int x, int y, int xoffs, int yoffs)
{
if (x < xoffs || y < yoffs || x >= xoffs + image->width || y >= yoffs + image->height) {
return black;
}
return XGetPixel(image, x - xoffs, y - yoffs);
}
static void updateImage(BufferData * data, int rx, int ry)
{
int gx, gy, gw, gh;
int x, y;
int xoffs, yoffs;
int changedPixels = 0;
XImage *image;
gw = data->width;
gh = data->height;
gx = rx - gw / 2;
gy = ry - gh / 2;
xoffs = yoffs = 0;
if (gx < 0) {
xoffs = abs(gx);
gw += gx;
gx = 0;
}
if (gx + gw >= WidthOfScreen(DefaultScreenOfDisplay(vdpy))) {
gw = WidthOfScreen(DefaultScreenOfDisplay(vdpy)) - gx;
}
if (gy < 0) {
yoffs = abs(gy);
gh += gy;
gy = 0;
}
if (gy + gh >= HeightOfScreen(DefaultScreenOfDisplay(vdpy))) {
gh = HeightOfScreen(DefaultScreenOfDisplay(vdpy)) - gy;
}
image = XGetImage(vdpy, DefaultRootWindow(vdpy), gx, gy, gw, gh, AllPlanes, ZPixmap);
for (y = 0; y < data->height; y++) {
for (x = 0; x < data->width; x++) {
unsigned long pixel;
pixel = getpix(image, x, y, xoffs, yoffs);
if (drawpoint(data, pixel, x, y))
changedPixels++;
}
}
/* flush the point cache */
drawpoint(data, 0, -1, -1);
XDestroyImage(image);
if (data->markPointerHotspot && !data->frozen) {
XRectangle rects[4];
rects[0].x = (data->width / 2 - 3) * data->magfactor;
rects[0].y = (data->height / 2) * data->magfactor;
rects[0].width = 2 * data->magfactor;
rects[0].height = data->magfactor;
rects[1].x = (data->width / 2 + 2) * data->magfactor;
rects[1].y = (data->height / 2) * data->magfactor;
rects[1].width = 2 * data->magfactor;
rects[1].height = data->magfactor;
XFillRectangles(dpy, data->d, WMColorGC(cursorColor1), rects, 2);
rects[2].y = (data->height / 2 - 3) * data->magfactor;
rects[2].x = (data->width / 2) * data->magfactor;
rects[2].height = 2 * data->magfactor;
rects[2].width = data->magfactor;
rects[3].y = (data->height / 2 + 2) * data->magfactor;
rects[3].x = (data->width / 2) * data->magfactor;
rects[3].height = 2 * data->magfactor;
rects[3].width = data->magfactor;
XFillRectangles(dpy, data->d, WMColorGC(cursorColor2), rects + 2, 2);
}
if (changedPixels > 0) {
WMRedisplayWidget(data->label);
}
data->firstDraw = False;
}
static void update(void *d)
{
BufferData *data = (BufferData *) d;
Window win;
int rx, ry;
int bla;
unsigned ubla;
if (data->frozen) {
rx = data->x;
ry = data->y;
} else {
XQueryPointer(dpy, DefaultRootWindow(dpy), &win, &win, &rx, &ry, &bla, &bla, &ubla);
}
updateImage(data, rx, ry);
data->tid = WMAddTimerHandler(data->refreshrate, update, data);
}
void resizedWindow(void *d, WMNotification * notif)
{
BufferData *data = (BufferData *) d;
WMView *view = (WMView *) WMGetNotificationObject(notif);
WMSize size;
size = WMGetViewSize(view);
resizeBufferData(data, size.width, size.height, data->magfactor);
}
void closeWindow(WMWidget * w, void *d)
{
BufferData *data = (BufferData *) d;
windowCount--;
if (windowCount == 0) {
exit(0);
} else {
WMDeleteTimerHandler(data->tid);
WMDestroyWidget(w);
wfree(data->buffer);
wfree(data->rects);
WMReleasePixmap(data->pixmap);
wfree(data);
}
}
static void keyHandler(XEvent * event, void *d)
{
BufferData *data = (BufferData *) d;
char buf[32];
KeySym ks;
WMView *view = WMWidgetView(data->win);
WMSize size;
size = WMGetViewSize(view);
if (XLookupString(&event->xkey, buf, 31, &ks, NULL) > 0) {
switch (buf[0]) {
case 'n':
newWindow(data->magfactor);
break;
case 'm':
data->markPointerHotspot = !data->markPointerHotspot;
break;
case 'f':
case ' ':
data->frozen = !data->frozen;
if (data->frozen) {
data->x = event->xkey.x_root;
data->y = event->xkey.y_root;
sprintf(buf, "[Magnify %ix]", data->magfactor);
} else {
sprintf(buf, "Magnify %ix", data->magfactor);
}
WMSetWindowTitle(data->win, buf);
break;
case '1':
case '2':
case '3':
case '4':
case '5':
case '6':
case '7':
case '8':
case '9':
resizeBufferData(data, size.width, size.height, buf[0] - '0');
if (data->frozen) {
sprintf(buf, "[Magnify %ix]", data->magfactor);
} else {
sprintf(buf, "Magnify %ix", data->magfactor);
}
WMSetWindowTitle(data->win, buf);
break;
}
}
}
static BufferData *newWindow(int magfactor)
{
WMWindow *win;
WMLabel *label;
BufferData *data;
char buf[32];
windowCount++;
win = WMCreateWindow(scr, "magnify");
WMResizeWidget(win, 300, 200);
sprintf(buf, "Magnify %ix", magfactor);
WMSetWindowTitle(win, buf);
WMSetViewNotifySizeChanges(WMWidgetView(win), True);
label = WMCreateLabel(win);
WMResizeWidget(label, 300, 200);
WMMoveWidget(label, 0, 0);
WMSetLabelRelief(label, WRSunken);
WMSetLabelImagePosition(label, WIPImageOnly);
data = makeBufferData(win, label, 300, 200, magfactor);
WMCreateEventHandler(WMWidgetView(win), KeyReleaseMask, keyHandler, data);
WMAddNotificationObserver(resizedWindow, data, WMViewSizeDidChangeNotification, WMWidgetView(win));
WMRealizeWidget(win);
WMMapSubwidgets(win);
WMMapWidget(win);
WMSetWindowCloseAction(win, closeWindow, data);
data->tid = WMAddTimerHandler(refreshrate, update, data);
return data;
}
int main(int argc, char **argv)
{
int i;
char *display = "";
char *vdisplay = NULL;
int magfactor = 2;
WMInitializeApplication("Magnify", &argc, argv);
for (i = 1; i < argc; i++) {
if (strcmp(argv[i], "-display") == 0) {
i++;
if (i >= argc)
goto help;
display = argv[i];
} else if (strcmp(argv[i], "-vdisplay") == 0) {
i++;
if (i >= argc)
goto help;
vdisplay = argv[i];
} else if (strcmp(argv[i], "-m") == 0) {
i++;
if (i >= argc)
goto help;
magfactor = atoi(argv[i]);
if (magfactor < 1 || magfactor > 32) {
printf("%s:invalid magnification factor ``%s''\n", argv[0], argv[i]);
exit(1);
}
} else if (strcmp(argv[i], "-r") == 0) {
i++;
if (i >= argc)
goto help;
refreshrate = atoi(argv[i]);
if (refreshrate < 1) {
printf("%s:invalid refresh rate ``%s''\n", argv[0], argv[i]);
exit(1);
}
} else if (strcmp(argv[i], "-h") == 0 || strcmp(argv[i], "--help") == 0) {
help:
printf("Usage: %s [options]\n", argv[0]);
puts("Options:");
puts(" -display <display> display that should be used");
puts(" -m <number> change magnification factor (default 2)");
puts(" -r <number> change refresh delay, in milliseconds (default 200)");
puts("Keys:");
puts(" 1,2,3,4,5,6,7,8,9 change the magnification factor");
puts(" <space>, f freeze the 'camera', making it magnify only the current\n"
" position");
puts(" n create a new window");
puts(" m show/hide the pointer hotspot mark");
exit(0);
}
}
dpy = XOpenDisplay(display);
if (!dpy) {
puts("could not open display");
exit(1);
}
if (vdisplay) {
vdpy = XOpenDisplay(vdisplay);
if (!vdpy) {
puts("could not open display to be viewed");
exit(1);
}
} else {
vdpy = dpy;
}
/* calculate how many rectangles we can send in a trip to the server */
rectBufferSize = XMaxRequestSize(dpy) - 128;
rectBufferSize /= sizeof(XRectangle);
if (rectBufferSize < 1)
rectBufferSize = 1;
black = BlackPixel(dpy, DefaultScreen(dpy));
scr = WMCreateScreen(dpy, 0);
cursorColor1 = WMCreateNamedColor(scr, "#ff0000", False);
cursorColor2 = WMCreateNamedColor(scr, "#00ff00", False);
newWindow(magfactor);
WMScreenMainLoop(scr);
return 0;
}