diff options
Diffstat (limited to 'krdc/vnc/desktop.c')
-rw-r--r-- | krdc/vnc/desktop.c | 1613 |
1 files changed, 1613 insertions, 0 deletions
diff --git a/krdc/vnc/desktop.c b/krdc/vnc/desktop.c new file mode 100644 index 00000000..f5a60966 --- /dev/null +++ b/krdc/vnc/desktop.c @@ -0,0 +1,1613 @@ +/* + * Copyright (C) 1999 AT&T Laboratories Cambridge. All Rights Reserved. + * Copyright (C) 2002 Tim Jansen. All Rights Reserved. + * Copyright (C) 1999-2001 Anders Lindstr�m + * + * + * + * This is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This software is distributed in the hope that it will be useful, + * but WITHOUT ANY WARRANTY; without even the implied warranty of + * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the + * GNU General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this software; if not, write to the Free Software + * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, + * USA. + * + * [email protected]: - removed stuff for krdc + * - merged with shm.c and misc.c + * - added FillRectangle and Sync methods to draw only on + * the image + * - added Zoom functionality, based on rotation funcs from + * SGE by Anders Lindstr�m) + * - added support for softcursor encoding + * + */ + +/* + * desktop.c - functions to deal with "desktop" window. + */ + +#include <X11/Xlib.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/extensions/XShm.h> +#include <math.h> +#include <limits.h> +#include "vncviewer.h" + +static XShmSegmentInfo shminfo; +static Bool caughtShmError = False; +static Bool needShmCleanup = False; + +static XShmSegmentInfo zoomshminfo; +static Bool caughtZoomShmError = False; +static Bool needZoomShmCleanup = False; + +static Bool gcInited = False; +GC gc; +GC srcGC, dstGC; /* used for debugging copyrect */ +Dimension dpyWidth, dpyHeight; + +static XImage *image = NULL; +Bool useShm = True; + +static Bool zoomActive = False; +static int zoomWidth, zoomHeight; +static XImage *zoomImage = NULL; +static Bool useZoomShm = True; + +/* for softcursor */ +static char *savedArea = NULL; + +typedef enum { + SOFTCURSOR_UNDER, + SOFTCURSOR_PART_UNDER, + SOFTCURSOR_UNAFFECTED +} SoftCursorState; + +typedef int Sint32; +typedef short Sint16; +typedef char Sint8; +typedef unsigned int Uint32; +typedef unsigned short Uint16; +typedef unsigned char Uint8; + +typedef struct { + int w, h; + unsigned int pitch; + void *pixels; + int BytesPerPixel; +} Surface; + +typedef struct { + Sint16 x, y; + Uint16 w, h; +} Rect; + +static void bgr233cpy(CARD8 *dst, CARD8 *src, int len); +static void CopyDataToScreenRaw(char *buf, int x, int y, int width, int height); +static void CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width,int height); +static void FillRectangleBGR233(CARD8 buf, int x, int y, int width,int height); +static int CheckRectangle(int x, int y, int width, int height); +static SoftCursorState getSoftCursorState(int x, int y, int width, int height); +static void discardCursorSavedArea(void); +static void saveCursorSavedArea(void); + +static void ZoomInit(void); +static void transformZoomSrc(int six, int siy, int siw, int sih, + int *dix, int *diy, int *diw, int *dih, + int srcW, int dstW, int srcH, int dstH); +static void transformZoomDst(int *six, int *siy, int *siw, int *sih, + int dix, int diy, int diw, int dih, + int srcW, int dstW, int srcH, int dstH); +static void ZoomSurfaceSrcCoords(int x, int y, int w, int h, + int *dix, int *diy, int *diw, int *dih, + Surface * src, Surface * dst); +static void ZoomSurfaceCoords32(int sx, int sy, int sw, int sh, + int dx, int dy, Surface * src, Surface * dst); +static void sge_transform(Surface *src, Surface *dst, float xscale, float yscale, + Uint16 qx, Uint16 qy); + + +void +DesktopInit(Window win) +{ + XGCValues gcv; + + image = CreateShmImage(); + + if (!image) { + useShm = False; + image = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, + si.framebufferWidth, si.framebufferHeight, + BitmapPad(dpy), 0); + + image->data = calloc(image->bytes_per_line * image->height, 1); + if (!image->data) { + fprintf(stderr,"malloc failed\n"); + exit(1); + } + } + + gc = XCreateGC(dpy,win,0,NULL); + + gcv.function = GXxor; + gcv.foreground = 0x0f0f0f0f; + srcGC = XCreateGC(dpy,win,GCFunction|GCForeground,&gcv); + gcv.foreground = 0xf0f0f0f0; + dstGC = XCreateGC(dpy,win,GCFunction|GCForeground,&gcv); + gcInited = True; +} + +/* + * DrawScreenRegionX11Thread + * Never call from any other desktop.c function, only for X11 thread + */ + +void +DrawScreenRegionX11Thread(Window win, int x, int y, int width, int height) { + zoomActive = False; + zoomWidth = 0; + zoomHeight = 0; + + if (!image) + return; + + if (useShm) + XShmPutImage(dpy, win, gc, image, x, y, x, y, width, height, False); + else + XPutImage(dpy, win, gc, image, x, y, x, y, width, height); +} + +/* + * CheckRectangle + */ + +static int CheckRectangle(int x, int y, int width, int height) { + if ((x < 0) || (y < 0)) + return 0; + + if (((x+width) > si.framebufferWidth) || ((y+height) > si.framebufferHeight)) + return 0; + + return 1; +} + +static +void bgr233cpy(CARD8 *dst, CARD8 *src, int len) { + int i; + CARD16 *d16; + CARD32 *d32; + + switch (visbpp) { + case 8: + for (i = 0; i < len; i++) + *(dst++) = (CARD8) BGR233ToPixel[*(src++)]; + break; + case 16: + d16 = (CARD16*) dst; + for (i = 0; i < len; i++) + *(d16++) = (CARD16) BGR233ToPixel[*(src++)]; + break; + case 32: + d32 = (CARD32*) dst; + for (i = 0; i < len; i++) + *(d32++) = (CARD32) BGR233ToPixel[*(src++)]; + break; + default: + fprintf(stderr, "Unsupported softcursor depth %d\n", visbpp); + } +} + + +/* + * CopyDataToScreen. + */ + +void +CopyDataToScreen(char *buf, int x, int y, int width, int height) +{ + SoftCursorState s; + + if (!CheckRectangle(x, y, width, height)) + return; + + LockFramebuffer(); + s = getSoftCursorState(x, y, width, height); + if (s == SOFTCURSOR_PART_UNDER) + undrawCursor(); + + if (!appData.useBGR233) + CopyDataToScreenRaw(buf, x, y, width, height); + else + CopyBGR233ToScreen((CARD8 *)buf, x, y, width, height); + + if (s != SOFTCURSOR_UNAFFECTED) + drawCursor(); + + UnlockFramebuffer(); + SyncScreenRegion(x, y, width, height); +} + +/* + * CopyDataToScreenRaw. + */ + +static void +CopyDataToScreenRaw(char *buf, int x, int y, int width, int height) +{ + int h; + int widthInBytes = width * visbpp / 8; + int scrWidthInBytes = image->bytes_per_line; + char *scr = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + + for (h = 0; h < height; h++) { + memcpy(scr, buf, widthInBytes); + buf += widthInBytes; + scr += scrWidthInBytes; + } +} + +/* + * CopyBGR233ToScreen. + */ + +static void +CopyBGR233ToScreen(CARD8 *buf, int x, int y, int width, int height) +{ + int p, q; + int xoff = 7 - (x & 7); + int xcur; + int fbwb = si.framebufferWidth / 8; + CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8; + CARD8 *scrt; + CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x; + CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x; + CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x; + + switch (visbpp) { + + /* thanks to Chris Hooper for single bpp support */ + + case 1: + for (q = 0; q < height; q++) { + xcur = xoff; + scrt = scr1; + for (p = 0; p < width; p++) { + *scrt = ((*scrt & ~(1 << xcur)) + | (BGR233ToPixel[*(buf++)] << xcur)); + + if (xcur-- == 0) { + xcur = 7; + scrt++; + } + } + scr1 += fbwb; + } + break; + + case 8: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr8++) = BGR233ToPixel[*(buf++)]; + } + scr8 += si.framebufferWidth - width; + } + break; + + case 16: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr16++) = BGR233ToPixel[*(buf++)]; + } + scr16 += si.framebufferWidth - width; + } + break; + + case 32: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr32++) = BGR233ToPixel[*(buf++)]; + } + scr32 += si.framebufferWidth - width; + } + break; + } +} + +/* + * FillRectangle8. + */ + +void +FillRectangle8(CARD8 fg, int x, int y, int width, int height) +{ + SoftCursorState s; + + if (!CheckRectangle(x, y, width, height)) + return; + + s = getSoftCursorState(x, y, width, height); + if (s == SOFTCURSOR_PART_UNDER) + undrawCursor(); + + if (!appData.useBGR233) { + int h; + int widthInBytes = width * visbpp / 8; + int scrWidthInBytes = image->bytes_per_line; + + char *scr = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + + for (h = 0; h < height; h++) { + memset(scr, fg, widthInBytes); + scr += scrWidthInBytes; + } + } else { + FillRectangleBGR233(fg, x, y, width, height); + } + + if (s != SOFTCURSOR_UNAFFECTED) + drawCursor(); +} + +/* + * FillRectangleBGR233. + */ + +static void +FillRectangleBGR233(CARD8 fg, int x, int y, int width, int height) +{ + int p, q; + int xoff = 7 - (x & 7); + int xcur; + int fbwb = si.framebufferWidth / 8; + CARD8 *scr1 = ((CARD8 *)image->data) + y * fbwb + x / 8; + CARD8 *scrt; + CARD8 *scr8 = ((CARD8 *)image->data) + y * si.framebufferWidth + x; + CARD16 *scr16 = ((CARD16 *)image->data) + y * si.framebufferWidth + x; + CARD32 *scr32 = ((CARD32 *)image->data) + y * si.framebufferWidth + x; + + unsigned long fg233 = BGR233ToPixel[fg]; + + switch (visbpp) { + + /* thanks to Chris Hooper for single bpp support */ + + case 1: + for (q = 0; q < height; q++) { + xcur = xoff; + scrt = scr1; + for (p = 0; p < width; p++) { + *scrt = ((*scrt & ~(1 << xcur)) + | (fg233 << xcur)); + + if (xcur-- == 0) { + xcur = 7; + scrt++; + } + } + scr1 += fbwb; + } + break; + + case 8: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr8++) = fg233; + } + scr8 += si.framebufferWidth - width; + } + break; + + case 16: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr16++) = fg233; + } + scr16 += si.framebufferWidth - width; + } + break; + + case 32: + for (q = 0; q < height; q++) { + for (p = 0; p < width; p++) { + *(scr32++) = fg233; + } + scr32 += si.framebufferWidth - width; + } + break; + } +} + +/* + * FillRectangle16 + */ + +void +FillRectangle16(CARD16 fg, int x, int y, int width, int height) +{ + int i, h; + int scrWidthInBytes = image->bytes_per_line; + + char *scr = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + CARD16 *scr16; + SoftCursorState s; + + if (!CheckRectangle(x, y, width, height)) + return; + + s = getSoftCursorState(x, y, width, height); + if (s == SOFTCURSOR_PART_UNDER) + undrawCursor(); + + for (h = 0; h < height; h++) { + scr16 = (CARD16*) scr; + for (i = 0; i < width; i++) + scr16[i] = fg; + scr += scrWidthInBytes; + } + + if (s != SOFTCURSOR_UNAFFECTED) + drawCursor(); +} + +/* + * FillRectangle32 + */ + +void +FillRectangle32(CARD32 fg, int x, int y, int width, int height) +{ + int i, h; + int scrWidthInBytes = image->bytes_per_line; + SoftCursorState s; + + char *scr = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + CARD32 *scr32; + + if (!CheckRectangle(x, y, width, height)) + return; + + s = getSoftCursorState(x, y, width, height); + if (s == SOFTCURSOR_PART_UNDER) + undrawCursor(); + + for (h = 0; h < height; h++) { + scr32 = (CARD32*) scr; + for (i = 0; i < width; i++) + scr32[i] = fg; + scr += scrWidthInBytes; + } + + if (s != SOFTCURSOR_UNAFFECTED) + drawCursor(); +} + +/* + * CopyDataFromScreen. + */ + +void +CopyDataFromScreen(char *buf, int x, int y, int width, int height) +{ + int widthInBytes = width * visbpp / 8; + int scrWidthInBytes = image->bytes_per_line; + char *src = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + int h; + + if (!CheckRectangle(x, y, width, height)) + return; + + for (h = 0; h < height; h++) { + memcpy(buf, src, widthInBytes); + src += scrWidthInBytes; + buf += widthInBytes; + } +} + +/* + * CopyArea + */ + +void +CopyArea(int srcX, int srcY, int width, int height, int x, int y) +{ + int widthInBytes = width * visbpp / 8; + SoftCursorState sSrc, sDst; + + LockFramebuffer(); + sSrc = getSoftCursorState(srcX, srcY, width, height); + sDst = getSoftCursorState(x, y, width, height); + if ((sSrc != SOFTCURSOR_UNAFFECTED) || + (sDst == SOFTCURSOR_PART_UNDER)) + undrawCursor(); + + if ((srcY+height < y) || (y+height < srcY) || + (srcX+width < x) || (x+width < srcX)) { + + int scrWidthInBytes = image->bytes_per_line; + char *src = (image->data + srcY * scrWidthInBytes + + srcX * visbpp / 8); + char *dst = (image->data + y * scrWidthInBytes + + x * visbpp / 8); + int h; + + if (!CheckRectangle(srcX, srcY, width, height)) { + UnlockFramebuffer(); + return; + } + if (!CheckRectangle(x, y, width, height)) { + UnlockFramebuffer(); + return; + } + + for (h = 0; h < height; h++) { + memcpy(dst, src, widthInBytes); + src += scrWidthInBytes; + dst += scrWidthInBytes; + } + } + else { + char *buf = malloc(widthInBytes*height); + if (!buf) { + UnlockFramebuffer(); + fprintf(stderr, "Out of memory, CopyArea impossible\n"); + return; + } + CopyDataFromScreen(buf, srcX, srcY, width, height); + CopyDataToScreenRaw(buf, x, y, width, height); + free(buf); + } + if ((sSrc != SOFTCURSOR_UNAFFECTED) || + (sDst != SOFTCURSOR_UNAFFECTED)) + drawCursor(); + UnlockFramebuffer(); + SyncScreenRegion(x, y, width, height); +} + +void SyncScreenRegion(int x, int y, int width, int height) { + int dx, dy, dw, dh; + + if (zoomActive) { + Surface src, dest; + src.w = si.framebufferWidth; + src.h = si.framebufferHeight; + src.pitch = image->bytes_per_line; + src.pixels = image->data; + src.BytesPerPixel = visbpp / 8; + dest.w = zoomWidth; + dest.h = zoomHeight; + dest.pitch = zoomImage->bytes_per_line; + dest.pixels = zoomImage->data; + dest.BytesPerPixel = visbpp / 8; + ZoomSurfaceSrcCoords(x, y, width, height, &dx, &dy, &dw, &dh, &src, &dest); + } + else { + dx = x; dy = y; + dw = width; dh = height; + } + DrawScreenRegion(dx, dy, dw, dh); +} + +void SyncScreenRegionX11Thread(int x, int y, int width, int height) { + int dx, dy, dw, dh; + + if (zoomActive) { + Surface src, dest; + src.w = si.framebufferWidth; + src.h = si.framebufferHeight; + src.pitch = image->bytes_per_line; + src.pixels = image->data; + src.BytesPerPixel = visbpp / 8; + dest.w = zoomWidth; + dest.h = zoomHeight; + dest.pitch = zoomImage->bytes_per_line; + dest.pixels = zoomImage->data; + dest.BytesPerPixel = visbpp / 8; + ZoomSurfaceSrcCoords(x, y, width, height, &dx, &dy, &dw, &dh, &src, &dest); + } + else { + dx = x; dy = y; + dw = width; dh = height; + } + DrawAnyScreenRegionX11Thread(dx, dy, dw, dh); +} + +/* + * ToplevelInitBeforeRealization sets the title, geometry and other resources + * on the toplevel window. + */ + +void +ToplevelInit() +{ + dpyWidth = WidthOfScreen(DefaultScreenOfDisplay(dpy)); + dpyHeight = HeightOfScreen(DefaultScreenOfDisplay(dpy)); +} + +/* + * Cleanup - perform shm cleanup operations prior to exiting. + */ + +void +Cleanup() +{ + if (useShm || useZoomShm) + ShmCleanup(); +} + +void +ShmCleanup() +{ + fprintf(stderr,"ShmCleanup called\n"); + if (needShmCleanup) { + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + needShmCleanup = False; + } + if (needZoomShmCleanup) { + shmdt(zoomshminfo.shmaddr); + shmctl(zoomshminfo.shmid, IPC_RMID, 0); + needZoomShmCleanup = False; + } +} + +static int +ShmCreationXErrorHandler(Display *d, XErrorEvent *e) +{ + caughtShmError = True; + return 0; +} + +XImage * +CreateShmImage() +{ + XImage *_image; + XErrorHandler oldXErrorHandler; + + if (!XShmQueryExtension(dpy)) + return NULL; + + _image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &shminfo, + si.framebufferWidth, si.framebufferHeight); + if (!_image) return NULL; + + shminfo.shmid = shmget(IPC_PRIVATE, + _image->bytes_per_line * _image->height, + IPC_CREAT|0777); + + if (shminfo.shmid == -1) { + XDestroyImage(_image); + return NULL; + } + + shminfo.shmaddr = _image->data = shmat(shminfo.shmid, 0, 0); + + if (shminfo.shmaddr == (char *)-1) { + XDestroyImage(_image); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; + } + + shminfo.readOnly = True; + + oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); + XShmAttach(dpy, &shminfo); + XSync(dpy, False); + XSetErrorHandler(oldXErrorHandler); + + if (caughtShmError) { + XDestroyImage(_image); + shmdt(shminfo.shmaddr); + shmctl(shminfo.shmid, IPC_RMID, 0); + return NULL; + } + + needShmCleanup = True; + + fprintf(stderr,"Using shared memory PutImage\n"); + + return _image; +} + +void undrawCursor() { + int x, y, w, h; + + if ((imageIndex < 0) || !savedArea) + return; + + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &x, &y, &w, &h); + + if ((w < 1) || (h < 1)) + return; + + CopyDataToScreenRaw(savedArea, x, y, w, h); + discardCursorSavedArea(); +} + +static void drawCursorImage() { + int x, y, w, h, pw, pixelsLeft, processingMask; + int skipLeft, skipRight; + PointerImage *pi = &pointerImages[imageIndex]; + CARD8 *img = (CARD8*) pi->image; + CARD8 *imgEnd = &img[pi->len]; + CARD8 *fb; + + /* check whether the source image has ended (image broken) */ +#define CHECK_IMG(x) if (&img[x] > imgEnd) goto imgError + +/* check whether the end of the framebuffer has been reached (last line) */ +#define CHECK_END() if ((wl == 0) && (h == 1)) return + +/* skip x pixels in the source (x must be < pixelsLeft!) */ +#define SKIP_IMG(x) if ((x > 0) && !processingMask) { \ + CHECK_END(); \ + img += pw * x; \ + CHECK_IMG(0); \ + } + +/* skip x pixels in source and destination */ +#define SKIP_PIXELS(x) { int wl = x; \ + while (pixelsLeft <= wl) { \ + wl -= pixelsLeft; \ + SKIP_IMG(pixelsLeft); \ + CHECK_END(); \ + pixelsLeft = *(img++); \ + CHECK_IMG(0); \ + processingMask = processingMask ? 0 : 1; \ + } \ + pixelsLeft -= wl; \ + SKIP_IMG(wl); \ + } + + if (!img) + return; + + x = cursorX - pi->hotX; + y = cursorY - pi->hotY; + w = pi->w; + h = pi->h; + + if (!rectsIntersect(x, y, w, h, + 0, 0, si.framebufferWidth, si.framebufferHeight)) { + fprintf(stderr, "intersect abort\n"); + return; + } + + pw = myFormat.bitsPerPixel / 8; + processingMask = 1; + pixelsLeft = *(img++); + +/* at this point everything is initialized for the macros */ + + /* skip/clip bottom lines */ + if ((y+h) > si.framebufferHeight) + h = si.framebufferHeight - y; + + /* Skip invisible top lines */ + while (y < 0) { + SKIP_PIXELS(w); + y++; + h--; + } + + /* calculate left/right clipping */ + if (x < 0) { + skipLeft = -x; + w += x; + x = 0; + } + else + skipLeft = 0; + + if ((x+w) > si.framebufferWidth) { + skipRight = (x+w) - si.framebufferWidth; + w = si.framebufferWidth - x; + } + else + skipRight = 0; + + fb = (CARD8*) image->data + y * image->bytes_per_line + x * visbpp / 8; + + /* Paint the thing */ + while (h > 0) { + SKIP_PIXELS(skipLeft); + + { + CARD8 *fbx = fb; + int wl = w; + while (pixelsLeft <= wl) { + wl -= pixelsLeft; + if ((pixelsLeft > 0) && !processingMask) { + int pl = pw * pixelsLeft; + CHECK_IMG(pl); + if (!appData.useBGR233) + memcpy(fbx, img, pl); + else + bgr233cpy(fbx, img, pixelsLeft); + img += pl; + } + + CHECK_END(); + fbx += pixelsLeft * visbpp / 8; + pixelsLeft = *(img++); + + CHECK_IMG(0); + processingMask = processingMask ? 0 : 1; + } + pixelsLeft -= wl; + if ((wl > 0) && !processingMask) { + int pl = pw * wl; + CHECK_IMG(pl); + if (!appData.useBGR233) + memcpy(fbx, img, pl); + else + bgr233cpy(fbx, img, wl); + img += pl; + } + } + + SKIP_PIXELS(skipRight); + fb += image->bytes_per_line; + h--; + } + return; + +imgError: + fprintf(stderr, "Error in softcursor image %d\n", imageIndex); + pointerImages[imageIndex].set = 0; +} + +static void discardCursorSavedArea() { + if (savedArea) + free(savedArea); + savedArea = 0; +} + +static void saveCursorSavedArea() { + int x, y, w, h; + + if (imageIndex < 0) + return; + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &x, &y, &w, &h); + if ((w < 1) || (h < 1)) + return; + discardCursorSavedArea(); + savedArea = malloc(h*image->bytes_per_line); + if (!savedArea) { + fprintf(stderr,"malloc failed, saving cursor not possible\n"); + exit(1); + } + CopyDataFromScreen(savedArea, x, y, w, h); +} + +void drawCursor() { + saveCursorSavedArea(); + drawCursorImage(); +} + +void getBoundingRectCursor(int cx, int cy, int _imageIndex, + int *x, int *y, int *w, int *h) { + int nx, ny, nw, nh; + + if ((_imageIndex < 0) || !pointerImages[_imageIndex].set) { + *x = 0; + *y = 0; + *w = 0; + *h = 0; + return; + } + + nx = cx - pointerImages[_imageIndex].hotX; + ny = cy - pointerImages[_imageIndex].hotY; + nw = pointerImages[_imageIndex].w; + nh = pointerImages[_imageIndex].h; + if (nx < 0) { + nw += nx; + nx = 0; + } + if (ny < 0) { + nh += ny; + ny = 0; + } + if ((nx+nw) > si.framebufferWidth) + nw = si.framebufferWidth - nx; + if ((ny+nh) > si.framebufferHeight) + nh = si.framebufferHeight - ny; + if ((nw <= 0) || (nh <= 0)) { + *x = 0; + *y = 0; + *w = 0; + *h = 0; + return; + } + + *x = nx; + *y = ny; + *w = nw; + *h = nh; +} + +static SoftCursorState getSoftCursorState(int x, int y, int w, int h) { + int cx, cy, cw, ch; + + if (imageIndex < 0) + return SOFTCURSOR_UNAFFECTED; + + getBoundingRectCursor(cursorX, cursorY, imageIndex, + &cx, &cy, &cw, &ch); + + if ((cw == 0) || (ch == 0)) + return SOFTCURSOR_UNAFFECTED; + + if (!rectsIntersect(x, y, w, h, cx, cy, cw, ch)) + return SOFTCURSOR_UNAFFECTED; + if (rectContains(x, y, w, h, cx, cy, cw, ch)) + return SOFTCURSOR_UNDER; + else + return SOFTCURSOR_PART_UNDER; +} + +int rectsIntersect(int x, int y, int w, int h, + int x2, int y2, int w2, int h2) { + if (x2 >= (x+w)) + return 0; + if (y2 >= (y+h)) + return 0; + if ((x2+w2) <= x) + return 0; + if ((y2+h2) <= y) + return 0; + return 1; +} + +int rectContains(int outX, int outY, int outW, int outH, + int inX, int inY, int inW, int inH) { + if (inX < outX) + return 0; + if (inY < outY) + return 0; + if ((inX+inW) > (outX+outW)) + return 0; + if ((inY+inH) > (outY+outH)) + return 0; + return 1; +} + +void rectsJoin(int *nx1, int *ny1, int *nw1, int *nh1, + int x2, int y2, int w2, int h2) { + int ox, oy, ow, oh; + ox = *nx1; + oy = *ny1; + ow = *nw1; + oh = *nh1; + + if (x2 < ox) { + ow += ox - x2; + ox = x2; + } + if (y2 < oy) { + oh += oy - y2; + oy = y2; + } + if ((x2+w2) > (ox+ow)) + ow = (x2+w2) - ox; + if ((y2+h2) > (oy+oh)) + oh = (y2+h2) - oy; + + *nx1 = ox; + *ny1 = oy; + *nw1 = ow; + *nh1 = oh; +} + +XImage * +CreateShmZoomImage() +{ + XImage *_image; + XErrorHandler oldXErrorHandler; + + if (!XShmQueryExtension(dpy)) + return NULL; + + _image = XShmCreateImage(dpy, vis, visdepth, ZPixmap, NULL, &zoomshminfo, + si.framebufferWidth, si.framebufferHeight); + if (!_image) return NULL; + + zoomshminfo.shmid = shmget(IPC_PRIVATE, + _image->bytes_per_line * _image->height, + IPC_CREAT|0777); + + if (zoomshminfo.shmid == -1) { + XDestroyImage(_image); + return NULL; + } + + zoomshminfo.shmaddr = _image->data = shmat(zoomshminfo.shmid, 0, 0); + + if (zoomshminfo.shmaddr == (char *)-1) { + XDestroyImage(_image); + shmctl(zoomshminfo.shmid, IPC_RMID, 0); + return NULL; + } + + zoomshminfo.readOnly = True; + + oldXErrorHandler = XSetErrorHandler(ShmCreationXErrorHandler); + XShmAttach(dpy, &zoomshminfo); + XSync(dpy, False); + XSetErrorHandler(oldXErrorHandler); + + if (caughtZoomShmError) { + XDestroyImage(_image); + shmdt(zoomshminfo.shmaddr); + shmctl(zoomshminfo.shmid, IPC_RMID, 0); + return NULL; + } + + needZoomShmCleanup = True; + + fprintf(stderr,"Using shared memory PutImage\n"); + + return _image; +} + + +/* + * DrawZoomedScreenRegionX11Thread + * Never call from any other desktop.c function, only for X11 thread + */ + +void +DrawZoomedScreenRegionX11Thread(Window win, int zwidth, int zheight, + int x, int y, int width, int height) { + if (!image) + return; + + if (zwidth > si.framebufferWidth) + zwidth = si.framebufferWidth; + if (zheight > si.framebufferHeight) + zheight = si.framebufferHeight; + + if (!zoomActive) { + ZoomInit(); + zoomActive = True; + } + + if ((zoomWidth != zwidth) || (zoomHeight != zheight)) { + Surface src, dest; + + zoomWidth = zwidth; + zoomHeight = zheight; + + src.w = si.framebufferWidth; + src.h = si.framebufferHeight; + src.pitch = image->bytes_per_line; + src.pixels = image->data; + src.BytesPerPixel = visbpp / 8; + dest.w = zwidth; + dest.h = zheight; + dest.pitch = zoomImage->bytes_per_line; + dest.pixels = zoomImage->data; + dest.BytesPerPixel = visbpp / 8; + sge_transform(&src, &dest, + (float)dest.w/(float)src.w, (float)dest.h/(float)src.h, + 0, 0); + + if (useZoomShm) + XShmPutImage(dpy, win, gc, zoomImage, 0, 0, 0, 0, zwidth, zheight, False); + else + XPutImage(dpy, win, gc, zoomImage, 0, 0, 0, 0, zwidth, zheight); + return; + } + + if (useZoomShm) + XShmPutImage(dpy, win, gc, zoomImage, x, y, x, y, width, height, False); + else + XPutImage(dpy, win, gc, zoomImage, x, y, x, y, width, height); +} + + +static void +ZoomInit() +{ + if (zoomImage) + return; + + zoomImage = CreateShmZoomImage(); + + if (!zoomImage) { + useZoomShm = False; + zoomImage = XCreateImage(dpy, vis, visdepth, ZPixmap, 0, NULL, + si.framebufferWidth, si.framebufferHeight, + BitmapPad(dpy), 0); + + zoomImage->data = calloc(zoomImage->bytes_per_line * zoomImage->height, 1); + if (!zoomImage->data) { + fprintf(stderr,"malloc failed\n"); + exit(1); + } + } +} + +static void transformZoomSrc(int six, int siy, int siw, int sih, + int *dix, int *diy, int *diw, int *dih, + int srcW, int dstW, int srcH, int dstH) { + double sx, sy, sw, sh; + double dx, dy, dw, dh; + double wq, hq; + + sx = six; sy = siy; + sw = siw; sh = sih; + + wq = ((double)dstW) / (double) srcW; + hq = ((double)dstH) / (double) srcH; + + dx = sx * wq; + dy = sy * hq; + dw = sw * wq; + dh = sh * hq; + + *dix = dx; + *diy = dy; + *diw = dw+(dx-(int)dx)+0.5; + *dih = dh+(dy-(int)dy)+0.5; +} + +static void transformZoomDst(int *six, int *siy, int *siw, int *sih, + int dix, int diy, int diw, int dih, + int srcW, int dstW, int srcH, int dstH) { + double sx, sy, sw, sh; + double dx, dy, dw, dh; + double wq, hq; + + dx = dix; dy = diy; + dw = diw; dh = dih; + + wq = ((double)dstW) / (double) srcW; + hq = ((double)dstH) / (double) srcH; + + sx = dx / wq; + sy = dy / hq; + sw = dw / wq; + sh = dh / hq; + + *six = sx; + *siy = sy; + *siw = sw+(sx-(int)sx)+0.5; + *sih = sh+(sy-(int)sy)+0.5; +} + + +static void ZoomSurfaceSrcCoords(int six, int siy, int siw, int sih, + int *dix, int *diy, int *diw, int *dih, + Surface * src, Surface * dst) +{ + int dx, dy, dw, dh; + int sx, sy, sw, sh; + + transformZoomSrc(six, siy, siw, sih, + &dx, &dy, &dw, &dh, + src->w, dst->w, src->h, dst->h); + dx-=2; + dy-=2; + dw+=4; + dh+=4; + + if (dx < 0) + dx = 0; + if (dy < 0) + dy = 0; + if (dx+dw > dst->w) + dw = dst->w - dx; + if (dy+dh > dst->h) + dh = dst->h - dy; + + transformZoomDst(&sx, &sy, &sw, &sh, + dx, dy, dw, dh, + src->w, dst->w, src->h, dst->h); + + if (sx+sw > src->w) + sw = src->w - sx; + if (sy+sh > src->h) + sh = src->h - sy; + + ZoomSurfaceCoords32(sx, sy, sw, sh, dx, dy, src, dst); + + *dix = dx; + *diy = dy; + *diw = dw; + *dih = dh; +} + +static void ZoomSurfaceCoords32(int sx, int sy, int sw, int sh, + int dx, int dy, + Surface * src, Surface * dst) +{ + Surface s2; + + s2 = *src; + s2.pixels = ((char*)s2.pixels) + (sx * s2.BytesPerPixel) + (sy * src->pitch); + s2.w = sw; + s2.h = sh; + sge_transform(&s2, dst, + (float)dst->w/(float)src->w, (float)dst->h/(float)src->h, + dx, dy); +} + + +#define sge_clip_xmin(pnt) 0 +#define sge_clip_xmax(pnt) pnt->w +#define sge_clip_ymin(pnt) 0 +#define sge_clip_ymax(pnt) pnt->h + +/*================================================================================== +// Helper function to sge_transform() +// Returns the bounding box +//================================================================================== +*/ +static void _calcRect(Surface *src, Surface *dst, float xscale, float yscale, + Uint16 qx, Uint16 qy, + Sint16 *xmin, Sint16 *ymin, Sint16 *xmax, Sint16 *ymax) +{ + Sint16 x, y, rx, ry; + int i; + + /* Clip to src surface */ + Sint16 sxmin = sge_clip_xmin(src); + Sint16 sxmax = sge_clip_xmax(src); + Sint16 symin = sge_clip_ymin(src); + Sint16 symax = sge_clip_ymax(src); + Sint16 sx[5]; + Sint16 sy[4]; + + /* We don't really need fixed-point here + * but why not? */ + Sint32 ictx = (Sint32) (xscale * 8192.0); + Sint32 icty = (Sint32) (yscale * 8192.0); + + sx[0] = sxmin; + sx[1] = sxmax; + sx[2] = sxmin; + sx[3] = sxmax; + sy[0] = symin; + sy[1] = symax; + sy[2] = symax; + sy[3] = symin; + + /* Calculate the four corner points */ + for(i=0; i<4; i++){ + rx = sx[i]; + ry = sy[i]; + + x = (Sint16)(((ictx*rx) >> 13) + qx); + y = (Sint16)(((icty*ry) >> 13) + qy); + + + if(i==0){ + *xmax = *xmin = x; + *ymax = *ymin = y; + }else{ + if(x>*xmax) + *xmax=x; + else if(x<*xmin) + *xmin=x; + + if(y>*ymax) + *ymax=y; + else if(y<*ymin) + *ymin=y; + } + } + + /* Better safe than sorry...*/ + *xmin -= 1; + *ymin -= 1; + *xmax += 1; + *ymax += 1; + + /* Clip to dst surface */ + if( !dst ) + return; + if( *xmin < sge_clip_xmin(dst) ) + *xmin = sge_clip_xmin(dst); + if( *xmax > sge_clip_xmax(dst) ) + *xmax = sge_clip_xmax(dst); + if( *ymin < sge_clip_ymin(dst) ) + *ymin = sge_clip_ymin(dst); + if( *ymax > sge_clip_ymax(dst) ) + *ymax = sge_clip_ymax(dst); +} + + +/*================================================================================== +** Scale by scale and place at position (qx,qy). +** +** +** Developed with the help from Terry Hancock ([email protected]) +** +**==================================================================================*/ +/* First we need some macros to handle different bpp + * I'm sorry about this... + */ +#define TRANSFORM(UintXX, DIV) \ + Sint32 src_pitch=src->pitch/DIV; \ + Sint32 dst_pitch=dst->pitch/DIV; \ + UintXX *src_row = (UintXX *)src->pixels; \ + UintXX *dst_row; \ +\ + for (y=ymin; y<ymax; y++){ \ + dy = y - qy; \ +\ + sx = (Sint32)ctdx; /* Compute source anchor points */ \ + sy = (Sint32)(cty*dy); \ +\ + /* Calculate pointer to dst surface */ \ + dst_row = (UintXX *)dst->pixels + y*dst_pitch; \ +\ + for (x=xmin; x<xmax; x++){ \ + rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \ + ry=(Sint16)(sy >> 13); \ +\ + /* Make sure the source pixel is actually in the source image. */ \ + if( (rx>=sxmin) && (rx<sxmax) && (ry>=symin) && (ry<symax) ) \ + *(dst_row + x) = *(src_row + ry*src_pitch + rx); \ +\ + sx += ctx; /* Incremental transformations */ \ + } \ + } + + +/* Interpolated transform */ +#define TRANSFORM_AA(UintXX, DIV) \ + Sint32 src_pitch=src->pitch/DIV; \ + Sint32 dst_pitch=dst->pitch/DIV; \ + UintXX *src_row = (UintXX *)src->pixels; \ + UintXX *dst_row; \ + UintXX c1, c2, c3, c4;\ + Uint32 R, G, B, A=0; \ + UintXX Rmask = image->red_mask;\ + UintXX Gmask = image->green_mask;\ + UintXX Bmask = image->blue_mask;\ + UintXX Amask = 0;\ + Uint32 wx, wy;\ + Uint32 p1, p2, p3, p4;\ +\ + /* + * Interpolation: + * We calculate the distances from our point to the four nearest pixels, d1..d4. + * d(a,b) = sqrt(a�+b�) ~= 0.707(a+b) (Pythagoras (Taylor) expanded around (0.5;0.5)) + * + * 1 wx 2 + * *-|-* (+ = our point at (x,y)) + * | | | (* = the four nearest pixels) + * wy --+ | wx = float(x) - int(x) + * | | wy = float(y) - int(y) + * *---* + * 3 4 + * d1 = d(wx,wy) d2 = d(1-wx,wy) d3 = d(wx,1-wy) d4 = d(1-wx,1-wy) + * We now want to weight each pixels importance - it's vicinity to our point: + * w1=d4 w2=d3 w3=d2 w4=d1 (Yes it works... just think a bit about it) + * + * If the pixels have the colors c1..c4 then our point should have the color + * c = (w1*c1 + w2*c2 + w3*c3 + w4*c4)/(w1+w2+w3+w4) (the weighted average) + * but w1+w2+w3+w4 = 4*0.707 so we might as well write it as + * c = p1*c1 + p2*c2 + p3*c3 + p4*c4 where p1..p4 = (w1..w4)/(4*0.707) + * + * But p1..p4 are fixed point so we can just divide the fixed point constant! + * 8192/(4*0.71) = 2897 and we can skip 0.71 too (the division will cancel it everywhere) + * 8192/4 = 2048 + * + * 020102: I changed the fixed-point representation for the variables in the weighted average + * to 24.7 to avoid problems with 32bit colors. Everything else is still 18.13. This + * does however not solve the problem with 32bit RGBA colors... + */\ +\ + Sint32 one = 2048>>6; /* 1 in Fixed-point */ \ + Sint32 two = 2*2048>>6; /* 2 in Fixed-point */ \ +\ + for (y=ymin; y<ymax; y++){ \ + dy = y - qy; \ +\ + sx = (Sint32)(ctdx); /* Compute source anchor points */ \ + sy = (Sint32)(cty*dy); \ +\ + /* Calculate pointer to dst surface */ \ + dst_row = (UintXX *)dst->pixels + y*dst_pitch; \ +\ + for (x=xmin; x<xmax; x++){ \ + rx=(Sint16)(sx >> 13); /* Convert from fixed-point */ \ + ry=(Sint16)(sy >> 13); \ +\ + /* Make sure the source pixel is actually in the source image. */ \ + if( (rx>=sxmin) && (rx+1<sxmax) && (ry>=symin) && (ry+1<symax) ){ \ + wx = (sx & 0x00001FFF) >>8; /* (float(x) - int(x)) / 4 */ \ + wy = (sy & 0x00001FFF) >>8;\ +\ + p4 = wx+wy;\ + p3 = one-wx+wy;\ + p2 = wx+one-wy;\ + p1 = two-wx-wy;\ +\ + c1 = *(src_row + ry*src_pitch + rx);\ + c2 = *(src_row + ry*src_pitch + rx+1);\ + c3 = *(src_row + (ry+1)*src_pitch + rx);\ + c4 = *(src_row + (ry+1)*src_pitch + rx+1);\ +\ + /* Calculate the average */\ + R = ((p1*(c1 & Rmask) + p2*(c2 & Rmask) + p3*(c3 & Rmask) + p4*(c4 & Rmask))>>7) & Rmask;\ + G = ((p1*(c1 & Gmask) + p2*(c2 & Gmask) + p3*(c3 & Gmask) + p4*(c4 & Gmask))>>7) & Gmask;\ + B = ((p1*(c1 & Bmask) + p2*(c2 & Bmask) + p3*(c3 & Bmask) + p4*(c4 & Bmask))>>7) & Bmask;\ + if(Amask)\ + A = ((p1*(c1 & Amask) + p2*(c2 & Amask) + p3*(c3 & Amask) + p4*(c4 & Amask))>>7) & Amask;\ + \ + *(dst_row + x) = R | G | B | A;\ + } \ + sx += ctx; /* Incremental transformations */ \ + } \ + } + +void sge_transform(Surface *src, Surface *dst, float xscale, float yscale, Uint16 qx, Uint16 qy) +{ + Sint32 dy, sx, sy; + Sint16 x, y, rx, ry; + Rect r; + + Sint32 ctx, cty; + Sint16 xmin, xmax, ymin, ymax; + Sint16 sxmin, sxmax, symin, symax; + Sint32 dx, ctdx; + + + /* Here we use 18.13 fixed point integer math + // Sint32 should have 31 usable bits and one for sign + // 2^13 = 8192 + */ + + /* Check scales */ + Sint32 maxint = (Sint32)(pow(2, sizeof(Sint32)*8 - 1 - 13)); /* 2^(31-13) */ + + r.x = r.y = r.w = r.h = 0; + + if( xscale == 0 || yscale == 0) + return; + + if( 8192.0/xscale > maxint ) + xscale = (float)(8192.0/maxint); + else if( 8192.0/xscale < -maxint ) + xscale = (float)(-8192.0/maxint); + + if( 8192.0/yscale > maxint ) + yscale = (float)(8192.0/maxint); + else if( 8192.0/yscale < -maxint ) + yscale = (float)(-8192.0/maxint); + + + /* Fixed-point equivalents */ + ctx = (Sint32)(8192.0/xscale); + cty = (Sint32)(8192.0/yscale); + + /* Compute a bounding rectangle */ + xmin=0; xmax=dst->w; ymin=0; ymax=dst->h; + _calcRect(src, dst, xscale, yscale, + qx, qy, &xmin, &ymin, &xmax, &ymax); + + /* Clip to src surface */ + sxmin = sge_clip_xmin(src); + sxmax = sge_clip_xmax(src); + symin = sge_clip_ymin(src); + symax = sge_clip_ymax(src); + + /* Some terms in the transform are constant */ + dx = xmin - qx; + ctdx = ctx*dx; + + /* Use the correct bpp */ + if( src->BytesPerPixel == dst->BytesPerPixel){ + switch( src->BytesPerPixel ){ + case 1: { /* Assuming 8-bpp */ + TRANSFORM(Uint8, 1) + } + break; + case 2: { /* Probably 15-bpp or 16-bpp */ + TRANSFORM_AA(Uint16, 2) + } + break; + case 4: { /* Probably 32-bpp */ + TRANSFORM_AA(Uint32, 4) + } + break; + } + } +} + +void freeDesktopResources() { + Cleanup(); + if (image) { + XDestroyImage(image); + } + if (zoomImage) { + XDestroyImage(zoomImage); + } + if (savedArea) + free(savedArea); + + if (gcInited) { + XFreeGC(dpy, gc); + XFreeGC(dpy, srcGC); + XFreeGC(dpy, dstGC); + } + + caughtShmError = False; + needShmCleanup = False; + caughtZoomShmError = False; + needZoomShmCleanup = False; + gcInited = False; + image = NULL; + useShm = True; + zoomActive = False; + zoomImage = NULL; + useZoomShm = True; + savedArea = NULL; +} + + +/* + * ColorRectangle32 + * Only used for debugging / visualizing output + */ +/* +static void +ColorRectangle32(XImage *img, CARD32 fg, int x, int y, int width, int height) +{ + int i, h; + int scrWidthInBytes = img->bytes_per_line; + char *scr; + CARD32 *scr32; + + if ((!img) || (!img->data)) + return; + + scr = (img->data + y * scrWidthInBytes + x * 4); + + if (!CheckRectangle(x, y, width, height)) + return; + + for (h = 0; h < height; h++) { + scr32 = (CARD32*) scr; + for (i = 0; i < width; i++) { + CARD32 n = 0; + CARD32 p = scr32[i]; + if (0xff & fg) + n |= ((( 0xff & p)+( 0xff & fg)) >> 2) & 0xff; + else + n |= (0xff & p); + if (0xff00 & fg) + n |= ((( 0xff00 & p)+( 0xff00 & fg)) >> 2) & 0xff00; + else + n |= (0xff00 & p); + if (0xff0000 & fg) + n |= (((0xff0000 & p)+(0xff0000 & fg)) >> 2) & 0xff0000; + else + n |= (0xff0000 & p); + scr32[i] = n; + } + scr += scrWidthInBytes; + } +} +*/ + |