diff options
Diffstat (limited to 'display/xshm.c')
-rw-r--r-- | display/xshm.c | 1202 |
1 files changed, 1202 insertions, 0 deletions
diff --git a/display/xshm.c b/display/xshm.c new file mode 100644 index 0000000..31ea861 --- /dev/null +++ b/display/xshm.c @@ -0,0 +1,1202 @@ +#include <Python.h> +#include <sys/ipc.h> +#include <sys/shm.h> +#include <X11/X.h> +#include <X11/Xlib.h> +#include <X11/Xutil.h> +#include <X11/extensions/XShm.h> + +typedef struct { + XImage* m_shm_image; + XShmSegmentInfo m_shminfo; + int m_width, m_height; +} XImage_Shm; + +typedef struct { + PyObject_HEAD + Display* dpy; + int default_scr; + Window root, win; + int width, height; + XVisualInfo visual_info; + GC gc, gc_and, gc_or; + XImage_Shm plane; + Pixmap backpixmap; + int shmmode; + int selectinput; + PyObject* keyevents; + PyObject* mouseevents; + PyObject* motionevent; +} DisplayObject; + +typedef struct { + PyObject_HEAD + DisplayObject* dpy; + int width, height; + Pixmap mask; + Pixmap handle; +} XPixmapObject; + + +#define DisplayObject_Check(v) ((v)->ob_type == &Display_Type) +staticforward PyTypeObject Display_Type; +staticforward PyTypeObject XPixmap_Type; + + +static void pixmap_dealloc(XPixmapObject* pm) +{ + if (pm->dpy->dpy) + { + if (pm->mask != (Pixmap) -1) + XFreePixmap(pm->dpy->dpy, pm->mask); + XFreePixmap(pm->dpy->dpy, pm->handle); + } + Py_DECREF(pm->dpy); + PyObject_Del(pm); +} + +static XPixmapObject* new_pixmap(DisplayObject* self, int w, int h, int withmask) +{ + XPixmapObject* pm = PyObject_New(XPixmapObject, &XPixmap_Type); + if (pm != NULL) + { + Py_INCREF(self); + pm->dpy = self; + pm->width = w; + pm->height = h; + pm->handle = XCreatePixmap(self->dpy, self->win, w, h, + self->visual_info.depth); + if (withmask) + pm->mask = XCreatePixmap(self->dpy, self->win, w, h, + self->visual_info.depth); + else + pm->mask = (Pixmap) -1; + } + return pm; +} + + +static void flush(DisplayObject* self) +{ + XSync(self->dpy, False); +} + +static int create_shm_image(DisplayObject* self, XImage_Shm* img, + int width, int height) +{ + int image_size = 4*width*height; + + if (XShmQueryExtension(self->dpy) == False) + /* does we have the extension at all? */ + return 0; + + img->m_shm_image = XShmCreateImage( + self->dpy, + self->visual_info.visual, + self->visual_info.depth, + ZPixmap, + NULL, + &img->m_shminfo, + width, + height); + if (img->m_shm_image == NULL) + return 0; + img->m_width = width; + img->m_height = height; + + /* Create shared memory segment: */ + img->m_shminfo.shmid = shmget(IPC_PRIVATE, image_size, IPC_CREAT|0777); + if (img->m_shminfo.shmid < 0) + return 0; + + /* Get memory address to segment: */ + img->m_shminfo.shmaddr = (char *) shmat(img->m_shminfo.shmid, 0, 0); + + /* Mark the segment as destroyable (it will be destroyed when this + process terminates) */ + shmctl(img->m_shminfo.shmid, IPC_RMID, NULL); + + /* Tell XServer that it may only read from it and attach to display: */ + img->m_shminfo.readOnly = True; + XShmAttach (self->dpy, &img->m_shminfo); + + /* Fill the XImage struct: */ + img->m_shm_image->data = img->m_shminfo.shmaddr; + return 1; +} + +static PyObject* new_display(PyObject* dummy, PyObject* args) +{ + DisplayObject* self; + XSetWindowAttributes attr; + int width, height, use_shm=1; + if (!PyArg_ParseTuple(args, "ii|i", &width, &height, &use_shm)) + return NULL; + + self = PyObject_New(DisplayObject, &Display_Type); + if (self == NULL) + return NULL; + + self->dpy = XOpenDisplay(NULL); + if (self->dpy == NULL) goto err; + self->default_scr = DefaultScreen(self->dpy); + self->root = RootWindow(self->dpy, self->default_scr); + self->width = width; + self->height = height; + + if (!XMatchVisualInfo(self->dpy, self->default_scr, + DefaultDepth(self->dpy,self->default_scr), TrueColor, + &self->visual_info)) goto err2; + + /* set window attributes */ + memset(&attr, 0, sizeof(attr)); + attr.override_redirect = False; + attr.background_pixel = BlackPixel(self->dpy, self->default_scr); + attr.backing_store = NotUseful; + + /* Create the window */ + self->win = XCreateWindow( + self->dpy, + self->root, + 0, + 0, + width, + height, + 0, + CopyFromParent, + CopyFromParent, + self->visual_info.visual, + CWOverrideRedirect | CWBackPixel | CWBackingStore, + &attr); + if (self->win == (Window) -1) goto err2; + + XMapRaised(self->dpy, self->win); + + self->shmmode = use_shm && + create_shm_image(self, &self->plane, width, height); + + self->gc = XCreateGC(self->dpy, self->win, 0, 0); + if (!self->shmmode) + { + self->backpixmap = XCreatePixmap(self->dpy, self->root, + width, height, self->visual_info.depth); + if (self->backpixmap == (Pixmap) -1) goto err2; + + self->gc_and = XCreateGC(self->dpy, self->win, 0, 0); + self->gc_or = XCreateGC(self->dpy, self->win, 0, 0); + XSetForeground(self->dpy, self->gc, attr.background_pixel); + XSetFunction(self->dpy, self->gc_and, GXand); + XSetFunction(self->dpy, self->gc_or, GXor); + } + + self->selectinput = 0; + self->keyevents = NULL; + self->mouseevents = NULL; + self->motionevent = NULL; + + flush(self); + return (PyObject*) self; + + err2: + XCloseDisplay(self->dpy); + err: + Py_DECREF(self); + PyErr_SetString(PyExc_IOError, "cannot open X11 display"); + return NULL; +} + +static void display_close(DisplayObject* self) +{ + if (self->dpy) + { + XCloseDisplay(self->dpy); + self->dpy = NULL; + } +} + +static void display_dealloc(DisplayObject* self) +{ + display_close(self); + Py_XDECREF(self->keyevents); + Py_XDECREF(self->mouseevents); + Py_XDECREF(self->motionevent); + PyObject_Del(self); +} + +static PyObject* display_close1(DisplayObject* self, PyObject* args) +{ + display_close(self); + Py_INCREF(Py_None); + return Py_None; +} + +static int checkopen(DisplayObject* self) +{ + if (self->dpy) + return 1; + PyErr_SetString(PyExc_IOError, "X11 connexion already closed"); + return 0; +} + +static unsigned char* get_dpy_data(DisplayObject* self) +{ + unsigned char* result; + if (!checkopen(self)) + return NULL; + result = (unsigned char*)(self->plane.m_shminfo.shmaddr); + if (!result) + PyErr_SetString(PyExc_IOError, "X11 SHM failed"); + return result; +} + +static PyObject* display_clear1(DisplayObject* self, PyObject* args) +{ + if (self->shmmode) + { + unsigned char* data = get_dpy_data(self); + if (data == NULL) + return NULL; + memset(data, 0, + ( self->plane.m_shm_image->bits_per_pixel/8 + *self->width*self->height ) ); + } + else + { + if (!checkopen(self)) + return NULL; + XFillRectangle(self->dpy, self->backpixmap, self->gc, + 0, 0, self->width, self->height); + } + Py_INCREF(Py_None); + return Py_None; +} + +inline void pack_pixel(unsigned char *data, int r, int g, int b, + int depth, int bytes_per_pixel) +{ + unsigned short pixel = 0; + switch( depth ) + { + /* No True color below 15 bits per pixel */ + case 15: + pixel = ((r<<7) & 0x7c00) | ((g<<2) & 0x03e0) | ((b>>3) & 0x001f); + data[0] = (pixel) & 0xff; + data[1] = (pixel>>8) & 0xff; + break; + case 16: + /* assumes 5,6,5 model. */ + pixel = ((r<<8) & 0xf800) | ((g<<3) & 0x07e0) | ((b>>3) & 0x001f); + data[0] = (pixel) & 0xff; + data[1] = (pixel>>8) & 0xff; + break; + case 24: + if( bytes_per_pixel == 3 ) + { + data[0] = b; + data[1] = g; + data[2] = r; + break; + } + /* else it's on 32 bits. Drop into depth of 32. */ + case 32: + *((long *)data) = (r<<16) | (g<<8) | b; + break; + } +} + +static PyObject* display_pixmap1(DisplayObject* self, PyObject* args) +{ + int w,h; + unsigned char* input = NULL; + int length; + long keycol = -1; + + if (!checkopen(self)) + return NULL; + if (!PyArg_ParseTuple(args, "ii|s#l", &w, &h, &input, &length, &keycol)) + return NULL; + + if (self->shmmode) + { + int x, y; + int bytes_per_pixel = self->plane.m_shm_image->bits_per_pixel/8; + int countblocks, countpixels; + PyObject* result; + PyObject* strblocks; + PyObject* strpixels; + unsigned int* pblocks; + unsigned char* ppixels; + unsigned char* input1; + + if (input == NULL) + { + Py_INCREF(Py_None); + return Py_None; + } + if (3*w*h != length) + { + PyErr_SetString(PyExc_ValueError, "bad string length"); + return NULL; + } + + /* Convert the image to our internal format. + See display_putppm1() for a description of the format. + */ + + countblocks = 0; + countpixels = 0; + input1 = input; + for (y=0; y<h; y++) + { + int opaque = 0; + for (x=0; x<w; x++) + { + unsigned int r = input1[0]; + unsigned int g = input1[1]; + unsigned int b = input1[2]; + input1 += 3; + if (((r<<16)|(g<<8)|b) == keycol) + opaque = 0; + else + { + if (!opaque) + { + countblocks++; /* start a new block */ + opaque = 1; + } + countpixels++; + } + } + countblocks++; /* end-of-line marker block */ + } + + /* allocate memory */ + strblocks = PyString_FromStringAndSize(NULL, + countblocks*sizeof(int)); + if (strblocks == NULL) + return NULL; + strpixels = PyString_FromStringAndSize(NULL, + countpixels*bytes_per_pixel); + if (strpixels == NULL) + { + Py_DECREF(strblocks); + return NULL; + } + + /* write data */ + pblocks = (unsigned int*) PyString_AS_STRING(strblocks); + ppixels = (unsigned char*) PyString_AS_STRING(strpixels); + for (y=0; y<h; y++) + { + int opaque = 0; + for (x=0; x<w; x++) + { + unsigned int r = input[0]; + unsigned int g = input[1]; + unsigned int b = input[2]; + input += 3; + if (((r<<16)|(g<<8)|b) == keycol) + opaque = 0; + else + { + if (!opaque) + { + *pblocks++ = x*bytes_per_pixel; /* start a new block */ + opaque = 1; + } + pblocks[-1] += bytes_per_pixel<<16; /* add pixel to block */ + pack_pixel(ppixels, r, g, b, + self->visual_info.depth, bytes_per_pixel); + ppixels += bytes_per_pixel; + } + } + *pblocks++ = 0; /* end-of-line marker block */ + } + + result = Py_BuildValue("iiOO", w, h, strblocks, strpixels); + Py_DECREF(strblocks); + Py_DECREF(strpixels); + return result; + } + else + { + XImage* image; + long extent; + unsigned char* data = NULL; + unsigned char* maskdata = NULL; + int scanline, bitmap_pad; + XPixmapObject* pm; + + pm = new_pixmap(self, w, h, keycol>=0); + if (pm == NULL) + return NULL; + + if (input == NULL) + return (PyObject*) pm; /* uninitialized pixmap */ + + extent = w*h; + if (3*extent != length) + { + PyErr_SetString(PyExc_ValueError, "bad string length"); + goto err; + } + + bitmap_pad = self->visual_info.depth >= 24 ? 32 : 16; + scanline = ((w+bitmap_pad-1) & ~(bitmap_pad-1)) / 8; + /*while (scanline&3) scanline++;*/ + data = malloc(self->visual_info.depth*scanline*h); + if (data == NULL) + { + PyErr_NoMemory(); + goto err; + } + memset(data, 0, self->visual_info.depth*scanline*h); + maskdata = malloc(self->visual_info.depth*scanline*h); + if (maskdata == NULL) + { + PyErr_NoMemory(); + goto err; + } + memset(maskdata, 0, self->visual_info.depth*scanline*h); + + { + int key_r = keycol>>16; + unsigned char key_g = keycol>>8; + unsigned char key_b = keycol>>0; + unsigned char* target = data; + unsigned char* masktarget = maskdata; + int plane, color; + + unsigned int p_size[3]; + switch( self->visual_info.depth ) + { + case 15: + p_size[0] = p_size[1] = p_size[2] = 5; + break; + case 16: + p_size[0] = p_size[2] = 5; + p_size[1] = 6; + break; + case 24: + case 32: + p_size[0] = p_size[1] = p_size[2] = 8; + break; + } + + for (color=0; color<3; color++) + for (plane=128; plane>=(1<<(8-p_size[color])); plane/=2) + { + unsigned char* src = input; + int x, y; + for (y=0; y<h; y++, target+=scanline, masktarget+=scanline) + for (x=0; x<w; x++, src+=3) + { + if (src[0] == key_r && src[1] == key_g && src[2] == key_b) + { + /* transparent */ + masktarget[x/8] |= (1<<(x&7)); + } + else + if (src[color] & plane) + target[x/8] |= (1<<(x&7)); + } + } + } + + if (keycol < 0) + free(maskdata); + else + { + image = XCreateImage(self->dpy, self->visual_info.visual, + self->visual_info.depth, XYPixmap, 0, + maskdata, w, h, + bitmap_pad, scanline); + if (image == NULL || image == (XImage*) -1) + { + PyErr_SetString(PyExc_IOError, "XCreateImage failed (2)"); + goto err; + } + image->byte_order = LSBFirst; + image->bitmap_bit_order = LSBFirst; + maskdata = NULL; + XPutImage(self->dpy, pm->mask, self->gc, image, 0, 0, 0, 0, w, h); + XDestroyImage(image); + } + + image = XCreateImage(self->dpy, self->visual_info.visual, + self->visual_info.depth, XYPixmap, 0, + data, w, h, + bitmap_pad, scanline); + if (image == NULL || image == (XImage*) -1) + { + PyErr_SetString(PyExc_IOError, "XCreateImage failed"); + goto err; + } + image->byte_order = LSBFirst; + image->bitmap_bit_order = LSBFirst; + data = NULL; + XPutImage(self->dpy, pm->handle, self->gc, image, 0, 0, 0, 0, w, h); + XDestroyImage(image); + + return (PyObject*) pm; + + err: + free(maskdata); + free(data); + Py_DECREF(pm); + return NULL; + } +} + +static PyObject* display_get(DisplayObject* self, int x, int y, int w, int h) +{ + if (self->shmmode) + { + int clipx=0, clipy=0, clipw=self->width, cliph=self->height; + int original_w, original_h; + int firstline=0, firstcol=0; + unsigned int bytes_per_pixel = self->plane.m_shm_image->bits_per_pixel/8; + unsigned char* data = get_dpy_data(self); + if (!data) + return NULL; + + original_w = w; + original_h = h; + if (x<clipx) { firstcol=clipx-x; w+=x-clipx; x=clipx; } + if (y<clipy) { firstline=clipy-y; h+=y-clipy; y=clipy; } + if (x+w > clipw) w = clipw-x; + if (y+h > cliph) h = cliph-y; + + { + int countblocks = original_h + ((w>0 && h>0) ? h : 0); + /* end blocks + real blocks */ + int countpixels = (w>0 && h>0) ? w * h : 0; + PyObject* result; + PyObject* strblocks; + PyObject* strpixels; + unsigned int* pblocks; + unsigned char* ppixels; + int wbytes = w * bytes_per_pixel; + int block = (firstcol * bytes_per_pixel) | (wbytes << 16); + int data_scanline = bytes_per_pixel*self->width; + + /* allocate memory */ + strblocks = PyString_FromStringAndSize(NULL, + countblocks*sizeof(int)); + if (strblocks == NULL) + return NULL; + strpixels = PyString_FromStringAndSize(NULL, + countpixels*bytes_per_pixel); + if (strpixels == NULL) + { + Py_DECREF(strblocks); + return NULL; + } + + /* write data */ + pblocks = (unsigned int*) PyString_AS_STRING(strblocks); + ppixels = (unsigned char*) PyString_AS_STRING(strpixels); + data += bytes_per_pixel*(x+y*self->width); + for (y=0; y<original_h; y++) + { + if (y >= firstline && y < firstline+h && w > 0) + { + *pblocks++ = block; + memcpy(ppixels, data, wbytes); + ppixels += wbytes; + data += data_scanline; + } + *pblocks++ = 0; + } + + result = Py_BuildValue("iiOO", original_w, original_h, + strblocks, strpixels); + Py_DECREF(strblocks); + Py_DECREF(strpixels); + return result; + } + } + else + { + XPixmapObject* pm = new_pixmap(self, w, h, 0); + if (pm != NULL) + XCopyArea(self->dpy, self->backpixmap, pm->handle, self->gc, + x, y, w, h, 0, 0); + return (PyObject*) pm; + } +} + +static PyObject* save_background(DisplayObject* self, int x, int y, + int w, int h, int save_bkgnd) +{ + if (save_bkgnd) + { + PyObject* pm = display_get(self, x, y, w, h); + PyObject* result; + if (pm == NULL) + return NULL; + result = Py_BuildValue("iiO", x, y, pm); + Py_DECREF(pm); + return result; + } + else + { + Py_INCREF(Py_None); + return Py_None; + } +} + +#define ALPHAFACTOR 2 +#define ALPHABLEND(maximum, x, y) ((maximum-y)*x/(maximum*ALPHAFACTOR) + y) + +static void memcpy_alpha_32(unsigned int* dst, unsigned int* src, int count) +{ + int i; + for (i=0; i<count/4; i++) + { + int x = dst[i]; + int y = src[i]; + + int xr = x >> 16; + int xg = x & 0xff00; + int xb = x & 0xff; + + int yr = y >> 16; + int yg = y & 0xff00; + int yb = y & 0xff; + + int zr = ALPHABLEND(0xff, xr, yr); + int zg = ALPHABLEND(0xff00, xg, yg); + int zb = ALPHABLEND(0xff, xb, yb); + + dst[i] = (zr << 16) | (zg & 0xff00) | zb; + } +} + +static void memcpy_alpha_24(unsigned char* dst, unsigned char* src, int count) +{ + int i; + for (i=0; i<count; i++) + { + int x = dst[i]; + int y = src[i]; + dst[i] = ALPHABLEND(255, x, y); + } +} + +static void memcpy_alpha_15(unsigned short* dst, unsigned short* src, int count) +{ + int i; + for (i=0; i<count/2; i++) + { + unsigned short x = dst[i]; + unsigned short y = src[i]; + + int xr = x >> 10; + int xg = x & 0x03e0; + int xb = x & 0x001f; + + int yr = y >> 10; + int yg = y & 0x03e0; + int yb = y & 0x001f; + + int zr = ALPHABLEND(31, xr, yr); + int zg = ALPHABLEND(0x3e0, xg, yg); + int zb = ALPHABLEND(31, xb, yb); + + dst[i] = (zr << 10) | (zg & 0x03e0) | zb; + } +} + +static void memcpy_alpha_16(unsigned short* dst, unsigned short* src, int count) +{ + int i; + for (i=0; i<count/2; i++) + { + unsigned short x = dst[i]; + unsigned short y = src[i]; + + int xr = x >> 11; + int xg = x & 0x07e0; + int xb = x & 0x001f; + + int yr = y >> 11; + int yg = y & 0x07e0; + int yb = y & 0x001f; + + int zr = ALPHABLEND(31, xr, yr); + int zg = ALPHABLEND(0x7e0, xg, yg); + int zb = ALPHABLEND(31, xb, yb); + + dst[i] = (zr << 11) | (zg & 0x07e0) | zb; + } +} + +typedef void (*memcpy_alpha_fn) (unsigned char*, unsigned char*, int); + +static PyObject* display_overlay(DisplayObject* self, PyObject* args, + int save_bkgnd) +{ + PyObject* result; + + if (self->shmmode) + { + int x,y,w,h, original_x, original_y, original_w, original_h; + int data_scanline; + int clipx=0, clipy=0, clipw=65536, cliph=65536, alpha=255; + unsigned int* src; + unsigned char* srcdata; + unsigned char* original_srcdata; + int length1, length2, firstline=0, firstcol=0; + unsigned int bytes_per_pixel = self->plane.m_shm_image->bits_per_pixel/8; + memcpy_alpha_fn memcpy_alpha; + unsigned char* data = get_dpy_data(self); + if (!PyArg_ParseTuple(args, "ii(iis#s#)|(iiii)i", + &x, &y, &w, &h, &src, &length1, &srcdata, &length2, + &clipx, &clipy, &clipw, &cliph, &alpha) || !data) + return NULL; + + original_x = x; + original_y = y; + original_w = w; + original_h = h; + original_srcdata = srcdata; + x -= clipx; + y -= clipy; + clipx += x; + clipy += y; + clipw += clipx; + cliph += clipy; + if (clipx<0) clipx=0; + if (clipy<0) clipy=0; + if (clipw>self->width) clipw=self->width; + if (cliph>self->height) cliph=self->height; + if (x<clipx) { firstcol = clipx-x; w+=x-clipx; x=clipx; } + if (y<clipy) { firstline = clipy-y; h+=y-clipy; y=clipy; } + if (x+w > clipw) w = clipw-x; + if (y+h > cliph) h = cliph-y; + if (w > 0 && h > 0) + { + int dstoffset, blocksize; + unsigned int block; + data += bytes_per_pixel*(x+y*self->width); + data_scanline = bytes_per_pixel*self->width; + + memcpy_alpha = (memcpy_alpha_fn) memcpy; + if (alpha < 255) + switch (self->visual_info.depth) { + case 15: memcpy_alpha = (memcpy_alpha_fn) memcpy_alpha_15; break; + case 16: memcpy_alpha = (memcpy_alpha_fn) memcpy_alpha_16; break; + case 24: memcpy_alpha = (memcpy_alpha_fn) memcpy_alpha_24; break; + case 32: memcpy_alpha = (memcpy_alpha_fn) memcpy_alpha_32; break; + } + + /* 'structure' points to a sequence of int-sized blocks with the + following meaning: + + n & 0xFFFF -- byte offset within the line + n >> 16 -- number of opaque bytes to copy there + + n == 0 means end of line. + */ + + /* read and ignore 'firstline' complete lines */ + while (firstline--) + { + while ((block = *src++) != 0) + { + blocksize = block >> 16; + srcdata += blocksize; + } + } + + if (w == original_w) + { + if (!save_bkgnd) + { + /* common fast case: copy the whole width of the image */ + do + { + while ((block = *src++) != 0) + { + dstoffset = block & 0xFFFF; + blocksize = block >> 16; + memcpy(data + dstoffset, srcdata, blocksize); + srcdata += blocksize; + } + data += data_scanline; + } + while (--h); + result = Py_None; + Py_INCREF(result); + } + else + { + /* copy and save the background */ + PyObject* cliprect; + PyObject* strblocks; + PyObject* strpixels; + unsigned char* ppixels; + + strpixels = PyString_FromStringAndSize(NULL, length2); + if (strpixels == NULL) + return NULL; + ppixels = (unsigned char*) PyString_AS_STRING(strpixels); + ppixels += srcdata - original_srcdata; + + do + { + while ((block = *src++) != 0) + { + dstoffset = block & 0xFFFF; + blocksize = block >> 16; + memcpy(ppixels, data + dstoffset, blocksize); + ppixels += blocksize; + memcpy_alpha(data + dstoffset, srcdata, blocksize); + srcdata += blocksize; + } + data += data_scanline; + } + while (--h); + + strblocks = PyTuple_GET_ITEM(PyTuple_GET_ITEM(args, 2), 2); + if (PyTuple_GET_SIZE(args) > 3) + { + cliprect = PyTuple_GET_ITEM(args, 3); + result = Py_BuildValue("ii(iiOO)O", + original_x, + original_y, + original_w, + original_h, + strblocks, + strpixels, + cliprect); + } + else + { + result = Py_BuildValue("ii(iiOO)", + original_x, + original_y, + original_w, + original_h, + strblocks, + strpixels); + } + Py_DECREF(strpixels); + } + } + else + { + /* byte offsets within a line */ + unsigned char* blocksrc; + int skip, lastcol; + + result = save_background(self, x, y, w, h, save_bkgnd); + + lastcol = (firstcol + w) * bytes_per_pixel; + firstcol *= bytes_per_pixel; + + /* slow case: only copy a portion of the width of the image */ + data -= firstcol; + do + { + while ((block = *src++) != 0) + { + dstoffset = block & 0xFFFF; + blocksize = block >> 16; + blocksrc = srcdata; + srcdata += blocksize; + skip = firstcol - dstoffset; + if (skip < 0) + skip = 0; + if (blocksize > lastcol - dstoffset) + blocksize = lastcol - dstoffset; + if (blocksize > skip) + memcpy_alpha(data + dstoffset + skip, blocksrc + skip, + blocksize - skip); + } + data += data_scanline; + } + while (--h); + } + } + else + { + result = args; + Py_INCREF(result); + } + } + else + { + int x,y, x1=0,y1=0,w1=-1,h1=-1,alpha; + XPixmapObject* pm; + + if (!checkopen(self)) + return NULL; + if (!PyArg_ParseTuple(args, "iiO!|(iiii)i", &x, &y, &XPixmap_Type, &pm, + &x1, &y1, &w1, &h1, &alpha)) + return NULL; + + if (w1 < 0) + w1 = pm->width; + if (h1 < 0) + h1 = pm->height; + + result = save_background(self, x, y, w1, h1, save_bkgnd); + + if (pm->mask == (Pixmap) -1) + { + XCopyArea(self->dpy, pm->handle, self->backpixmap, self->gc, + x1, y1, w1, h1, x, y); + } + else + { + XCopyArea(self->dpy, pm->mask, self->backpixmap, self->gc_and, + x1, y1, w1, h1, x, y); + XCopyArea(self->dpy, pm->handle, self->backpixmap, self->gc_or, + x1, y1, w1, h1, x, y); + } + } + return result; +} + +static PyObject* display_putppm1(DisplayObject* self, PyObject* args) +{ + return display_overlay(self, args, 0); +} + +static PyObject* display_overlayppm1(DisplayObject* self, PyObject* args) +{ + return display_overlay(self, args, 1); +} + +static PyObject* display_getppm1(DisplayObject* self, PyObject* args) +{ + int x, y, w, h; + if (!checkopen(self)) + return NULL; + if (!PyArg_ParseTuple(args, "(iiii)", &x, &y, &w, &h)) + return NULL; + return display_get(self, x, y, w, h); +} + +static int readXevents(DisplayObject* self) +{ + while (XEventsQueued(self->dpy, QueuedAfterReading) > 0) + { + XEvent e; + XNextEvent(self->dpy, &e); + switch (e.type) { + case KeyPress: + case KeyRelease: + { + KeySym sym; + PyObject* v; + int err; + if (self->keyevents == NULL) + { + self->keyevents = PyList_New(0); + if (self->keyevents == NULL) + return 0; + } + sym = XLookupKeysym(&e.xkey,0); + v = Py_BuildValue("ii", sym, e.type); + if (v == NULL) + return 0; + err = PyList_Append(self->keyevents, v); + Py_DECREF(v); + if (err) + return 0; + break; + } + case ButtonPress: + { + PyObject* v; + int err; + if (self->mouseevents == NULL) + { + self->mouseevents = PyList_New(0); + if (self->mouseevents == NULL) + return 0; + } + v = Py_BuildValue("ii", e.xbutton.x, e.xbutton.y); + if (v == NULL) + return 0; + err = PyList_Append(self->mouseevents, v); + Py_DECREF(v); + if (err) + return 0; + break; + } + case MotionNotify: + { + Py_XDECREF(self->motionevent); + self->motionevent = Py_BuildValue("ii", e.xmotion.x, e.xmotion.y); + if (self->motionevent == NULL) + return 0; + break; + } + } + } + return 1; +} + +#define ENABLE_EVENTS(mask) do { \ + if (!(self->selectinput & (mask))) \ + { \ + self->selectinput |= (mask); \ + XSelectInput(self->dpy, self->win, self->selectinput); \ + } \ +} while (0) + +static PyObject* display_keyevents1(DisplayObject* self, PyObject* args) +{ + PyObject* result; + ENABLE_EVENTS(KeyPressMask|KeyReleaseMask); + if (!readXevents(self)) + return NULL; + result = self->keyevents; + if (result == NULL) + result = PyList_New(0); + else + self->keyevents = NULL; + return result; +} + +static PyObject* display_mouseevents1(DisplayObject* self, PyObject* args) +{ + PyObject* result; + ENABLE_EVENTS(ButtonPressMask); + result = self->mouseevents; + if (result == NULL) + result = PyList_New(0); + else + self->mouseevents = NULL; + return result; +} + +static PyObject* display_pointermotion1(DisplayObject* self, PyObject* args) +{ + PyObject* result; + ENABLE_EVENTS(PointerMotionMask); + result = self->motionevent; + if (result == NULL) + { + Py_INCREF(Py_None); + result = Py_None; + } + else + self->motionevent = NULL; + return result; +} + +static PyObject* display_flip1(DisplayObject* self, PyObject* args) +{ + if (!checkopen(self)) + return NULL; + + if (self->shmmode) + { + XShmPutImage(self->dpy, self->win, self->gc, + self->plane.m_shm_image, + 0, 0, 0, 0, + self->plane.m_width, + self->plane.m_height, + False); + } + else + { + XCopyArea(self->dpy, self->backpixmap, self->win, self->gc, + 0, 0, self->width, self->height, 0, 0); + } + flush(self); + if (!readXevents(self)) + return NULL; + Py_INCREF(Py_None); + return Py_None; +} + +static PyObject* display_fd1(DisplayObject* self, PyObject *args) +{ + return PyInt_FromLong(ConnectionNumber(self->dpy)); +} + +static PyObject* display_shmmode(DisplayObject* self, PyObject *args) +{ + return PyInt_FromLong(self->shmmode); +} + +static PyMethodDef display_methods[] = { + {"close", (PyCFunction)display_close1, METH_VARARGS, NULL}, + {"flip", (PyCFunction)display_flip1, METH_VARARGS, NULL}, + {"clear", (PyCFunction)display_clear1, METH_VARARGS, NULL}, + {"pixmap", (PyCFunction)display_pixmap1, METH_VARARGS, NULL}, + {"putppm", (PyCFunction)display_putppm1, METH_VARARGS, NULL}, + {"getppm", (PyCFunction)display_getppm1, METH_VARARGS, NULL}, + {"overlayppm",(PyCFunction)display_overlayppm1, METH_VARARGS, NULL}, + {"keyevents",(PyCFunction)display_keyevents1,METH_VARARGS, NULL}, + {"mouseevents",(PyCFunction)display_mouseevents1,METH_VARARGS,NULL}, + {"pointermotion",(PyCFunction)display_pointermotion1,METH_VARARGS,NULL}, + {"fd", (PyCFunction)display_fd1, METH_VARARGS, NULL}, + {"shmmode", (PyCFunction)display_shmmode, METH_VARARGS, NULL}, + {NULL, NULL} /* sentinel */ +}; + +static PyObject* display_getattr(DisplayObject* self, char* name) +{ + return Py_FindMethod(display_methods, (PyObject*)self, name); +} + + +statichere PyTypeObject Display_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "Display", /*tp_name*/ + sizeof(DisplayObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)display_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + (getattrfunc)display_getattr, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ +}; + +statichere PyTypeObject XPixmap_Type = { + PyObject_HEAD_INIT(NULL) + 0, /*ob_size*/ + "Pixmap", /*tp_name*/ + sizeof(XPixmapObject), /*tp_basicsize*/ + 0, /*tp_itemsize*/ + /* methods */ + (destructor)pixmap_dealloc, /*tp_dealloc*/ + 0, /*tp_print*/ + 0, /*tp_getattr*/ + 0, /*tp_setattr*/ + 0, /*tp_compare*/ + 0, /*tp_repr*/ + 0, /*tp_as_number*/ + 0, /*tp_as_sequence*/ + 0, /*tp_as_mapping*/ + 0, /*tp_hash*/ + 0, /*tp_call*/ +}; + + +static PyMethodDef ShmMethods[] = { + {"Display", new_display, METH_VARARGS}, + {NULL, NULL} /* Sentinel */ + }; + +void initxshm(void) +{ + Display_Type.ob_type = &PyType_Type; + XPixmap_Type.ob_type = &PyType_Type; + Py_InitModule("xshm", ShmMethods); +} |