legacy-imlib2/ximage.c

288 lines
7.7 KiB
C

#include <X11/Xlib.h>
#include <X11/extensions/XShm.h>
#include <X11/Xutil.h>
#include <sys/ipc.h>
#include <sys/shm.h>
#include "common.h"
#include "ximage.h"
/* static private variables */
static char x_does_shm = -1;
static int list_num = 0;
static XImage **list_xim = NULL;
static XShmSegmentInfo **list_si = NULL;
static Display **list_d = NULL;
static char *list_used = NULL;
static int list_mem_use = 0;
static int list_max_mem = 1024 * 1024 * 1024;
static int list_max_count = 0;
/* temporary X error catcher we use later */
static char _x_err = 0;
/* the fucntion we use for catching the error */
static void
TmpXError(Display * d, XErrorEvent * ev)
{
_x_err = 1;
return;
d = NULL;
ev = NULL;
}
void
__imlib_SetMaxXImageCount(Display *d, int num)
{
list_max_count = num;
__imlib_FlushXImage(d);
}
int
__imlib_GetMaxXImageCount(Display *d)
{
return list_max_count;
d = NULL;
}
void
__imlib_SetMaxXImageTotalSize(Display *d, int num)
{
list_max_mem = num;
__imlib_FlushXImage(d);
}
int
__imlib_GetMaxXImageTotalSize(Display *d)
{
return list_max_mem;
d = NULL;
}
void
__imlib_FlushXImage(Display *d)
{
int i;
XImage *xim;
char did_free = 1;
while (((list_mem_use > list_max_mem) || (list_num > list_max_count)) &&
(did_free))
{
did_free = 0;
for (i = 0; i < list_num; i++)
{
if (list_used[i] == 0)
{
int j;
xim = list_xim[i];
list_mem_use -= xim->bytes_per_line * xim->height;
if (list_si[i])
XShmDetach(d, list_si[i]);
XDestroyImage(xim);
if (list_si[i])
{
shmdt(list_si[i]->shmaddr);
shmctl(list_si[i]->shmid, IPC_RMID, 0);
free(list_si[i]);
}
list_num--;
for (j = i; j < list_num; j++)
{
list_xim[j] = list_xim[j + 1];
list_si[j] = list_si[j + 1];
list_used[j] = list_used[j + 1];
list_d[j] = list_d[j + 1];
}
list_xim = realloc(list_xim, sizeof(XImage *) * list_num);
list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num);
list_used = realloc(list_used, sizeof(char) * list_num);
list_d = realloc(list_d, sizeof(Display *) * list_num);
did_free = 1;
}
}
}
}
/* free (consume == opposite of produce) the XImage (mark as unused) */
void
__imlib_ConsumeXImage(Display *d, XImage *xim)
{
int i;
/* march through the XImage list */
for (i = 0; i < list_num; i++)
{
/* find a match */
if (list_xim[i] == xim)
{
/* we have a match = mark as unused */
list_used[i] = 0;
/* flush the XImage list to get rud of stuff we dont want */
__imlib_FlushXImage(d);
/* return */
return;
}
}
}
/* create a new XImage or find it on our list of currently available ones so */
/* we dont need to create a new one */
XImage *
__imlib_ProduceXImage(Display *d, Visual *v, int depth, int w, int h, char *shared)
{
XImage *xim;
int i;
/* if we havent check the shm extension before - see if its there */
if (x_does_shm < 0)
{
/* if its there set dose_xhm flag */
if (XShmQueryExtension(d))
x_does_shm = 1;
/* clear the flag - no shm at all */
else
x_does_shm = 0;
}
/* find a cached XImage (to avoid server to & fro) that is big enough */
/* for our needs and the right depth */
*shared = 0;
/* go thru the current image list */
for (i = 0; i < list_num; i++)
{
/* if the image has the same depth, width and height - recycle it */
/* as long as its not used */
if ((list_xim[i]->bits_per_pixel == depth) &&
(list_xim[i]->width >= w) &&
(list_xim[i]->height >= h) &&
/* (list_d[i] == d) &&*/
(!list_used[i]))
{
/* mark it as used */
list_used[i] = 1;
/* if its shared set shared flag */
if (list_si[i])
*shared = 1;
/* return it */
return list_xim[i];
}
}
/* can't find a usable XImage on the cache - create one */
/* add the new XImage to the XImage cache */
list_num++;
list_xim = realloc(list_xim, sizeof(XImage *) * list_num);
list_si = realloc(list_si, sizeof(XShmSegmentInfo *) * list_num);
list_used = realloc(list_used, sizeof(char) * list_num);
list_d = realloc(list_d, sizeof(Display *) * list_num);
list_si[list_num - 1] = malloc(sizeof(XShmSegmentInfo));
/* work on making a shared image */
xim = NULL;
/* if the server does shm */
if (x_does_shm)
{
/* try create an shm image */
xim = XShmCreateImage(d, v, depth, ZPixmap, NULL,
list_si[list_num - 1], w, h);
/* if it succeeds */
if (xim)
{
/* add to list */
list_xim[list_num - 1] = xim;
/* get an shm id of this image */
list_si[list_num - 1]->shmid =
shmget(IPC_PRIVATE, xim->bytes_per_line * xim->height,
IPC_CREAT | 0777);
/* if the get succeeds */
if (list_si[list_num - 1]->shmid != -1)
{
/* set the params for the shm segment */
list_si[list_num - 1]->readOnly = False;
list_si[list_num - 1]->shmaddr = xim->data =
shmat(list_si[list_num - 1]->shmid, 0, 0);
/* get the shm addr for this data chunk */
if (xim->data != (char *)-1)
{
XErrorHandler ph;
/* setup a temporary error handler */
_x_err = 0;
ph = XSetErrorHandler((XErrorHandler) TmpXError);
/* ask X to attach to the shared mem segment */
XShmAttach(d, list_si[list_num - 1]);
/* wait for X to reply and do this */
XSync(d, False);
/* reset the error handler */
XSetErrorHandler((XErrorHandler) ph);
/* if we attached without an error we're set */
if (!_x_err)
{
/* mark the image as used */
list_used[list_num - 1] = 1;
/* incrument our memory count */
list_mem_use += xim->bytes_per_line * xim->height;
/* set shared flag */
*shared = 1;
}
/* attach by X failed... must be remote client */
else
{
/* flag shm foevere to not work - remote */
x_does_shm = 0;
/* destroy our previous image */
XDestroyImage(xim);
/* detach */
shmdt(list_si[list_num - 1]->shmaddr);
/* remove the shm id */
shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0);
/* flag out xim as NULL */
xim = NULL;
}
}
/* get failed - out of shm id's or shm segment too big ? */
else
{
/* destroy previous image */
XDestroyImage(xim);
/* remove the shm id we created */
shmctl(list_si[list_num - 1]->shmid, IPC_RMID, 0);
/* flag xim as NULL */
xim = NULL;
}
}
/* couldnt create SHM image ? */
else
{
/* destroy previous image */
XDestroyImage(xim);
/* flag xim as NULL */
xim = NULL;
}
}
}
/* ok if xim == NULL it all failed - fall back to XImages */
if (!xim)
{
/* get rid of out shm info struct */
free(list_si[list_num - 1]);
/* flag it as NULL ot indicate a normal XImage */
list_si[list_num - 1] = NULL;
/* create a normal ximage */
xim = XCreateImage(d, v, depth, ZPixmap, 0, NULL, w, h, 32, 0);
/* allocate data for it */
xim->data = malloc(xim->bytes_per_line * xim->height);
/* add xim to our list */
list_xim[list_num - 1] = xim;
/* incriment our memory count */
list_mem_use += xim->bytes_per_line * xim->height;
/* mark image as used */
list_used[list_num - 1] = 1;
/* remember what display that XImage was for */
list_d[list_num - 1] = d;
}
/* flush unused images from the image list */
__imlib_FlushXImage(d);
/* return out image */
return xim;
}