#ifdef HAVE_CONFIG_H # include #endif #ifdef STDC_HEADERS # include # include #else # ifdef HAVE_STDLIB_H # include # endif #endif #ifdef HAVE_ALLOCA_H # include #elif !defined alloca # ifdef __GNUC__ # define alloca __builtin_alloca # elif defined _AIX # define alloca __alloca # elif defined _MSC_VER # include # define alloca _alloca # elif !defined HAVE_ALLOCA # ifdef __cplusplus extern "C" # endif void *alloca (size_t); # endif #endif #include #include #include #include #include "ecore_x_private.h" #include "Ecore_X.h" #include #include static int _ecore_x_image_shm_can = -1; static int _ecore_x_image_err = 0; static int _ecore_x_image_error_handler(Display *d __UNUSED__, XErrorEvent *ev __UNUSED__) { _ecore_x_image_err = 1; return 0; } static void _ecore_x_image_shm_check(void) { XErrorHandler ph; XShmSegmentInfo shminfo; XImage *xim; if (_ecore_x_image_shm_can != -1) return; XSync(_ecore_x_disp, False); _ecore_x_image_err = 0; xim = XShmCreateImage(_ecore_x_disp, DefaultVisual(_ecore_x_disp, DefaultScreen(_ecore_x_disp)), DefaultDepth(_ecore_x_disp, DefaultScreen(_ecore_x_disp)), ZPixmap, NULL, &shminfo, 1, 1); if (!xim) { _ecore_x_image_shm_can = 0; return; } shminfo.shmid = shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height, IPC_CREAT | 0666); if (shminfo.shmid == -1) { XDestroyImage(xim); _ecore_x_image_shm_can = 0; return; } shminfo.readOnly = False; shminfo.shmaddr = shmat(shminfo.shmid, 0, 0); xim->data = shminfo.shmaddr; if (xim->data == (char *)-1) { XDestroyImage(xim); _ecore_x_image_shm_can = 0; return; } ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler); XShmAttach(_ecore_x_disp, &shminfo); XShmGetImage(_ecore_x_disp, DefaultRootWindow(_ecore_x_disp), xim, 0, 0, 0xffffffff); XSync(_ecore_x_disp, False); XSetErrorHandler((XErrorHandler)ph); if (_ecore_x_image_err) { XShmDetach(_ecore_x_disp, &shminfo); XDestroyImage(xim); shmdt(shminfo.shmaddr); shmctl(shminfo.shmid, IPC_RMID, 0); _ecore_x_image_shm_can = 0; return; } XShmDetach(_ecore_x_disp, &shminfo); XDestroyImage(xim); shmdt(shminfo.shmaddr); shmctl(shminfo.shmid, IPC_RMID, 0); _ecore_x_image_shm_can = 1; } struct _Ecore_X_Image { XShmSegmentInfo shminfo; Ecore_X_Visual vis; XImage *xim; int depth; int w, h; int bpl, bpp, rows; unsigned char *data; Eina_Bool shm : 1; }; EAPI Ecore_X_Image * ecore_x_image_new(int w, int h, Ecore_X_Visual vis, int depth) { Ecore_X_Image *im; im = calloc(1, sizeof(Ecore_X_Image)); if (!im) return NULL; LOGFN(__FILE__, __LINE__, __FUNCTION__); im->w = w; im->h = h; im->vis = vis; im->depth = depth; _ecore_x_image_shm_check(); im->shm = _ecore_x_image_shm_can; return im; } EAPI void ecore_x_image_free(Ecore_X_Image *im) { LOGFN(__FILE__, __LINE__, __FUNCTION__); if (im->shm) { if (im->xim) { XShmDetach(_ecore_x_disp, &(im->shminfo)); XDestroyImage(im->xim); shmdt(im->shminfo.shmaddr); shmctl(im->shminfo.shmid, IPC_RMID, 0); } } else if (im->xim) { free(im->xim->data); im->xim->data = NULL; XDestroyImage(im->xim); } free(im); } static void _ecore_x_image_shm_create(Ecore_X_Image *im) { im->xim = XShmCreateImage(_ecore_x_disp, im->vis, im->depth, ZPixmap, NULL, &(im->shminfo), im->w, im->h); if (!im->xim) return; im->shminfo.shmid = shmget(IPC_PRIVATE, im->xim->bytes_per_line * im->xim->height, IPC_CREAT | 0666); if (im->shminfo.shmid == -1) { XDestroyImage(im->xim); return; } im->shminfo.readOnly = False; im->shminfo.shmaddr = shmat(im->shminfo.shmid, 0, 0); im->xim->data = im->shminfo.shmaddr; if ((im->xim->data == (char *)-1) || (!im->xim->data)) { shmdt(im->shminfo.shmaddr); shmctl(im->shminfo.shmid, IPC_RMID, 0); XDestroyImage(im->xim); return; } XShmAttach(_ecore_x_disp, &im->shminfo); im->data = (unsigned char *)im->xim->data; im->bpl = im->xim->bytes_per_line; im->rows = im->xim->height; if (im->xim->bits_per_pixel <= 8) im->bpp = 1; else if (im->xim->bits_per_pixel <= 16) im->bpp = 2; else im->bpp = 4; } EAPI Eina_Bool ecore_x_image_get(Ecore_X_Image *im, Ecore_X_Drawable draw, int x, int y, int sx, int sy, int w, int h) { Eina_Bool ret = EINA_TRUE; XErrorHandler ph; LOGFN(__FILE__, __LINE__, __FUNCTION__); if (im->shm) { if (!im->xim) _ecore_x_image_shm_create(im); if (!im->xim) return 0; _ecore_x_image_err = 0; // optimised path ph = XSetErrorHandler((XErrorHandler)_ecore_x_image_error_handler); if ((sx == 0) && (w == im->w)) { im->xim->data = (char *) im->data + (im->xim->bytes_per_line * sy) + (sx * im->bpp); im->xim->width = w; im->xim->height = h; XGrabServer(_ecore_x_disp); if (!XShmGetImage(_ecore_x_disp, draw, im->xim, x, y, 0xffffffff)) ret = EINA_FALSE; XUngrabServer(_ecore_x_disp); ecore_x_sync(); } // unavoidable thanks to mit-shm get api - tmp shm buf + copy into it else { Ecore_X_Image *tim; unsigned char *spixels, *sp, *pixels, *p; int bpp, bpl, rows, sbpp, sbpl, srows; int r; tim = ecore_x_image_new(w, h, im->vis, im->depth); if (tim) { ret = ecore_x_image_get(tim, draw, x, y, 0, 0, w, h); if (ret) { spixels = ecore_x_image_data_get(tim, &sbpl, &srows, &sbpp); pixels = ecore_x_image_data_get(im, &bpl, &rows, &bpp); if ((pixels) && (spixels)) { p = pixels + (sy * bpl) + (sx * bpp); sp = spixels; for (r = srows; r > 0; r--) { memcpy(p, sp, sbpl); p += bpl; sp += sbpl; } } } ecore_x_image_free(tim); } } XSetErrorHandler((XErrorHandler)ph); if (_ecore_x_image_err) ret = EINA_FALSE; } else { printf("currently unimplemented ecore_x_image_get without shm\n"); ret = EINA_FALSE; } return ret; } EAPI void ecore_x_image_put(Ecore_X_Image *im, Ecore_X_Drawable draw, Ecore_X_GC gc, int x, int y, int sx, int sy, int w, int h) { Ecore_X_GC tgc = 0; LOGFN(__FILE__, __LINE__, __FUNCTION__); if (!gc) { XGCValues gcv; memset(&gcv, 0, sizeof(gcv)); gcv.subwindow_mode = IncludeInferiors; tgc = XCreateGC(_ecore_x_disp, draw, GCSubwindowMode, &gcv); gc = tgc; } if (!im->xim) _ecore_x_image_shm_create(im); if (im->xim) XShmPutImage(_ecore_x_disp, draw, gc, im->xim, sx, sy, x, y, w, h, False); if (tgc) ecore_x_gc_free(tgc); } EAPI void * ecore_x_image_data_get(Ecore_X_Image *im, int *bpl, int *rows, int *bpp) { LOGFN(__FILE__, __LINE__, __FUNCTION__); if (!im->xim) _ecore_x_image_shm_create(im); if (!im->xim) return NULL; if (bpl) *bpl = im->bpl; if (rows) *rows = im->rows; if (bpp) *bpp = im->bpp; return im->data; } EAPI Eina_Bool ecore_x_image_is_argb32_get(Ecore_X_Image *im) { Visual *vis = im->vis; if (!im->xim) _ecore_x_image_shm_create(im); if (((vis->class == TrueColor) || (vis->class == DirectColor)) && (im->depth >= 24) && (vis->red_mask == 0xff0000) && (vis->green_mask == 0x00ff00) && (vis->blue_mask == 0x0000ff)) { #ifdef WORDS_BIGENDIAN if (im->xim->bitmap_bit_order == MSBFirst) return EINA_TRUE; #else if (im->xim->bitmap_bit_order == LSBFirst) return EINA_TRUE; #endif } return EINA_FALSE; } EAPI Eina_Bool ecore_x_image_to_argb_convert(void *src, int sbpp, int sbpl, Ecore_X_Colormap c, Ecore_X_Visual v, int x, int y, int w, int h, unsigned int *dst, int dbpl, int dx, int dy) { Visual *vis = v; XColor *cols = NULL; int n = 0, nret = 0, i, row; unsigned int pal[256], r, g, b; enum { rgbnone = 0, rgb565, bgr565, rgbx555, argbx888, abgrx888, rgba888x, bgra888x, argbx666 }; int mode = 0; sbpp *= 8; n = vis->map_entries; if ((n <= 256) && ((vis->class == PseudoColor) || (vis->class == StaticColor) || (vis->class == GrayScale) || (vis->class == StaticGray))) { if (!c) c = DefaultColormap(_ecore_x_disp, DefaultScreen(_ecore_x_disp)); cols = alloca(n * sizeof(XColor)); for (i = 0; i < n; i++) { cols[i].pixel = i; cols[i].flags = DoRed | DoGreen | DoBlue; cols[i].red = 0; cols[i].green = 0; cols[i].blue = 0; } XQueryColors(_ecore_x_disp, c, cols, n); for (i = 0; i < n; i++) { pal[i] = 0xff000000 | ((cols[i].red >> 8) << 16) | ((cols[i].green >> 8) << 8) | ((cols[i].blue >> 8)); } nret = n; } else if ((vis->class == TrueColor) || (vis->class == DirectColor)) { if ((vis->red_mask == 0x00ff0000) && (vis->green_mask == 0x0000ff00) && (vis->blue_mask == 0x000000ff)) mode = argbx888; else if ((vis->red_mask == 0x000000ff) && (vis->green_mask == 0x0000ff00) && (vis->blue_mask == 0x00ff0000)) mode = abgrx888; else if ((vis->red_mask == 0xff000000) && (vis->green_mask == 0x00ff0000) && (vis->blue_mask == 0x0000ff00)) mode = rgba888x; else if ((vis->red_mask == 0x0000ff00) && (vis->green_mask == 0x00ff0000) && (vis->blue_mask == 0xff000000)) mode = bgra888x; else if ((vis->red_mask == 0x0003f000) && (vis->green_mask == 0x00000fc0) && (vis->blue_mask == 0x0000003f)) mode = argbx666; else if ((vis->red_mask == 0x0000f800) && (vis->green_mask == 0x000007e0) && (vis->blue_mask == 0x0000001f)) mode = rgb565; else if ((vis->red_mask == 0x0000001f) && (vis->green_mask == 0x000007e0) && (vis->blue_mask == 0x0000f800)) mode = bgr565; else if ((vis->red_mask == 0x00007c00) && (vis->green_mask == 0x000003e0) && (vis->blue_mask == 0x0000001f)) mode = rgbx555; else return EINA_FALSE; } for (row = 0; row < h; row++) { unsigned char *s8; unsigned short *s16; unsigned int *s32; unsigned int *dp, *de; dp = ((unsigned int *)(((unsigned char *)dst) + ((dy + row) * dbpl))) + dx; de = dp + w; switch (sbpp) { case 8: s8 = ((unsigned char *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; if (nret > 0) { while (dp < de) { *dp = pal[*s8]; s8++; dp++; } } else return EINA_FALSE; break; case 16: s16 = ((unsigned short *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; switch (mode) { case rgb565: while (dp < de) { r = (*s16 & 0xf800) << 8; g = (*s16 & 0x07e0) << 5; b = (*s16 & 0x001f) << 3; r |= (r >> 5) & 0xff0000; g |= (g >> 6) & 0x00ff00; b |= (b >> 5); *dp = 0xff000000 | r | g | b; s16++; dp++; } break; case bgr565: while (dp < de) { r = (*s16 & 0x001f) << 19; g = (*s16 & 0x07e0) << 5; b = (*s16 & 0xf800) >> 8; r |= (r >> 5) & 0xff0000; g |= (g >> 6) & 0x00ff00; b |= (b >> 5); *dp = 0xff000000 | r | g | b; s16++; dp++; } break; case rgbx555: while (dp < de) { r = (*s16 & 0x7c00) << 9; g = (*s16 & 0x03e0) << 6; b = (*s16 & 0x001f) << 3; r |= (r >> 5) & 0xff0000; g |= (g >> 5) & 0x00ff00; b |= (b >> 5); *dp = 0xff000000 | r | g | b; s16++; dp++; } break; default: return EINA_FALSE; break; } break; case 24: case 32: s32 = ((unsigned int *)(((unsigned char *)src) + ((y + row) * sbpl))) + x; switch (mode) { case argbx888: while (dp < de) { *dp = 0xff000000 | *s32; s32++; dp++; } break; case abgrx888: while (dp < de) { r = *s32 & 0x000000ff; g = *s32 & 0x0000ff00; b = *s32 & 0x00ff0000; *dp = 0xff000000 | (r << 16) | (g) | (b >> 16); s32++; dp++; } break; case rgba888x: while (dp < de) { *dp = 0xff000000 | (*s32 >> 8); s32++; dp++; } break; case bgra888x: while (dp < de) { r = *s32 & 0x0000ff00; g = *s32 & 0x00ff0000; b = *s32 & 0xff000000; *dp = 0xff000000 | (r << 8) | (g >> 8) | (b >> 24); s32++; dp++; } break; case argbx666: while (dp < de) { r = (*s32 & 0x3f000) << 6; g = (*s32 & 0x00fc0) << 4; b = (*s32 & 0x0003f) << 2; r |= (r >> 6) & 0xff0000; g |= (g >> 6) & 0x00ff00; b |= (b >> 6); *dp = 0xff000000 | r | g | b; s32++; dp++; } break; default: return EINA_FALSE; break; } break; break; default: return EINA_FALSE; break; } } return EINA_TRUE; }