mirror of
https://github.com/gnustep/libs-back.git
synced 2025-04-22 15:31:14 +00:00
Rename and move WinImage class to ARTWindowBuffer.
git-svn-id: svn+ssh://svn.gna.org/svn/gnustep/libs/back/trunk@14314 72102866-910b-0410-8b05-ffd578937521
This commit is contained in:
parent
ba626c7954
commit
b6289c1347
5 changed files with 740 additions and 651 deletions
|
@ -1,3 +1,9 @@
|
|||
2002-08-21 20:27 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/ARTContext.m, Source/art/ARTWindowBuffer.h,
|
||||
Source/art/ARTWindowBuffer.m, Source/art/GNUmakefile: Renamed the
|
||||
WinImage class to ARTWindowBuffer and moved it to its own file.
|
||||
|
||||
2002-08-21 14:52 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
* Source/art/blit.h, Source/art/blit.m, Source/art/ftfont.h,
|
||||
|
|
|
@ -43,22 +43,13 @@ copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
|||
#include <libart_lgpl/libart.h>
|
||||
#include <libart_lgpl/art_svp_intersect.h>
|
||||
|
||||
#ifndef RDS
|
||||
#include <X11/extensions/XShm.h>
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
|
||||
#ifndef PI
|
||||
#define PI 3.14159265358979323846264338327950288
|
||||
#endif
|
||||
|
||||
|
||||
#ifndef RDS
|
||||
static int use_shape_hack=0; /* this is an ugly hack :) */
|
||||
#endif
|
||||
#include "ARTWindowBuffer.h"
|
||||
|
||||
|
||||
/*
|
||||
|
@ -121,629 +112,6 @@ Context:
|
|||
static draw_info_t DI;
|
||||
|
||||
|
||||
/*
|
||||
WinImage maintains an XImage for a window. Each ARTGState that renders
|
||||
to that window uses the same WinImage (and thus the same buffer, etc.).
|
||||
*/
|
||||
|
||||
@interface WinImage : NSObject
|
||||
{
|
||||
@public
|
||||
#ifdef RDS
|
||||
int window;
|
||||
RDSClient *remote;
|
||||
|
||||
struct
|
||||
{
|
||||
int shmid;
|
||||
char *shmaddr;
|
||||
} shminfo;
|
||||
#else
|
||||
gswindow_device_t *window;
|
||||
GC gc;
|
||||
Drawable drawable;
|
||||
XImage *ximage;
|
||||
Display *display;
|
||||
|
||||
int use_shm;
|
||||
XShmSegmentInfo shminfo;
|
||||
#endif
|
||||
|
||||
|
||||
/* While a XShmPutImage is in progress we don't try to call it
|
||||
again. The pending updates are stored here, and when we get the
|
||||
ShmCompletion event, we handle them. */
|
||||
int pending_put; /* There are pending updates */
|
||||
NSRect pending_rect; /* in this rectangle. */
|
||||
|
||||
int pending_event; /* We're waiting for the ShmCompletion event. */
|
||||
|
||||
|
||||
unsigned char *data;
|
||||
int sx,sy;
|
||||
int bytes_per_line,bits_per_pixel,bytes_per_pixel;
|
||||
|
||||
/* If has_alpha is 1 and alpha is NULL, the alpha is stored in data
|
||||
somehow. The drawing mechanism code should know how to deal with
|
||||
it. */
|
||||
unsigned char *alpha;
|
||||
int has_alpha;
|
||||
|
||||
|
||||
unsigned char *old_shape;
|
||||
int old_shape_size;
|
||||
}
|
||||
|
||||
#ifdef RDS
|
||||
+ winImageForWindow: (int)awindow remote: (RDSClient *)remote;
|
||||
#else
|
||||
+ winImageForWindow: (gswindow_device_t *)awindow;
|
||||
#endif
|
||||
|
||||
-(void) needsAlpha;
|
||||
|
||||
-(void) _gotShmCompletion;
|
||||
-(void) _exposeRect: (NSRect)r;
|
||||
@end
|
||||
|
||||
|
||||
@interface ARTContext (shm_stuff)
|
||||
+(void) _gotShmCompletion: (Drawable)d;
|
||||
@end
|
||||
|
||||
|
||||
/* Many states might render to the same window, so we need to make sure
|
||||
that there's only one WinImage for each window. */
|
||||
static WinImage **wimages;
|
||||
static int num_wimages;
|
||||
|
||||
|
||||
#ifndef RDS
|
||||
|
||||
@implementation WinImage
|
||||
|
||||
+ winImageForWindow: (gswindow_device_t *)awindow
|
||||
{
|
||||
int i;
|
||||
WinImage *wi;
|
||||
|
||||
for (i=0;i<num_wimages;i++)
|
||||
{
|
||||
if (wimages[i]->window==awindow)
|
||||
break;
|
||||
}
|
||||
if (i==num_wimages)
|
||||
{
|
||||
wi=[[WinImage alloc] init];
|
||||
wi->window=awindow;
|
||||
wimages=realloc(wimages,sizeof(WinImage *)*(num_wimages+1));
|
||||
if (!wimages)
|
||||
{
|
||||
NSLog(@"Out of memory (failed to allocate %i bytes)",
|
||||
sizeof(WinImage *)*(num_wimages+1));
|
||||
exit(1);
|
||||
}
|
||||
wimages[num_wimages++]=wi;
|
||||
}
|
||||
else
|
||||
{
|
||||
wi=wimages[i];
|
||||
wi=RETAIN(wi);
|
||||
}
|
||||
|
||||
wi->gc=awindow->gc;
|
||||
wi->drawable=awindow->ident;
|
||||
wi->display=awindow->display;
|
||||
|
||||
wi->window->gdriverProtocol=GDriverHandlesExpose|GDriverHandlesBacking;
|
||||
wi->window->gdriver=wi;
|
||||
|
||||
/* TODO: resolve properly.
|
||||
-x11 is creating buffers before I have a chance to tell it not to, so
|
||||
I'm freeing them here to reduce memory consumption (and prevent
|
||||
leaks, though that should be fixed now) */
|
||||
if (awindow->buffer)
|
||||
{
|
||||
XFreePixmap (awindow->display, awindow->buffer);
|
||||
awindow->buffer=0;
|
||||
}
|
||||
if (awindow->alpha_buffer)
|
||||
{
|
||||
XFreePixmap (awindow->display, awindow->alpha_buffer);
|
||||
awindow->alpha_buffer=0;
|
||||
}
|
||||
|
||||
/* create the image if necessary */
|
||||
if (!wi->ximage ||
|
||||
wi->sx!=awindow->xframe.size.width ||
|
||||
wi->sy!=awindow->xframe.size.height)
|
||||
{
|
||||
wi->sx=wi->window->xframe.size.width;
|
||||
/* printf("%@ updating image for %p (%gx%g)\n",wi,wi->window,
|
||||
wi->window->xframe.size.width,wi->window->xframe.size.height);*/
|
||||
if (wi->ximage)
|
||||
{
|
||||
if (wi->use_shm)
|
||||
{
|
||||
XShmDetach(wi->display,&wi->shminfo);
|
||||
XDestroyImage(wi->ximage);
|
||||
shmdt(wi->shminfo.shmaddr);
|
||||
}
|
||||
else
|
||||
XDestroyImage(wi->ximage);
|
||||
}
|
||||
wi->has_alpha=0;
|
||||
if (wi->alpha)
|
||||
{
|
||||
free(wi->alpha);
|
||||
wi->alpha=NULL;
|
||||
}
|
||||
|
||||
wi->pending_put=wi->pending_event=0;
|
||||
|
||||
wi->ximage=NULL;
|
||||
|
||||
/* Use XShm if possible, else fall back to normal XImage:s */
|
||||
if (XShmQueryExtension(wi->display))
|
||||
{
|
||||
wi->use_shm=1;
|
||||
wi->ximage=XShmCreateImage(wi->display,
|
||||
DefaultVisual(wi->display,DefaultScreen(wi->display)),
|
||||
DI.drawing_depth,ZPixmap,NULL,&wi->shminfo,
|
||||
wi->window->xframe.size.width,
|
||||
wi->window->xframe.size.height);
|
||||
}
|
||||
if (wi->ximage)
|
||||
{
|
||||
/* TODO: only use shared memory for 'real' on-screen
|
||||
windows. how can we tell? */
|
||||
wi->shminfo.shmid=shmget(IPC_PRIVATE,
|
||||
wi->ximage->bytes_per_line*wi->ximage->height,
|
||||
IPC_CREAT|0700);
|
||||
|
||||
if (!wi->shminfo.shmid==-1)
|
||||
NSLog(@"shmget() failed"); /* TODO */
|
||||
/* printf("shminfo.shmid=%08x %i bytes (%ix%i)\n",
|
||||
wi->shminfo.shmid,wi->ximage->bytes_per_line*wi->ximage->height,
|
||||
wi->ximage->width,wi->ximage->height);*/
|
||||
wi->shminfo.shmaddr=wi->ximage->data=shmat(wi->shminfo.shmid,0,0);
|
||||
|
||||
/* Mark the segment as destroyed now. Since we're
|
||||
attached, it won't actually be destroyed, but if we
|
||||
crashed before doing this, it wouldn't be destroyed
|
||||
despite nobody being attached anymore. */
|
||||
shmctl(wi->shminfo.shmid,IPC_RMID,0);
|
||||
|
||||
// printf("addr=%p\n",wi->shminfo.shmaddr);
|
||||
wi->shminfo.readOnly=1;
|
||||
if (!XShmAttach(wi->display,&wi->shminfo))
|
||||
NSLog(@"XShmAttach() failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"failed to create shared memory image, using normal XImage:s");
|
||||
wi->use_shm=0;
|
||||
wi->ximage=XCreateImage(wi->display,DefaultVisual(wi->display,DefaultScreen(wi->display)),
|
||||
DI.drawing_depth,ZPixmap,0,NULL,
|
||||
wi->window->xframe.size.width,wi->window->xframe.size.height,8,0);
|
||||
wi->ximage->data=malloc(wi->ximage->height*wi->ximage->bytes_per_line);
|
||||
if (!wi->ximage->data)
|
||||
{
|
||||
XDestroyImage(wi->ximage);
|
||||
wi->ximage=NULL;
|
||||
}
|
||||
/*TODO? wi->ximage=XGetImage(wi->display,wi->drawable,
|
||||
0,0,wi->window->xframe.size.width,wi->window->xframe.size.height,
|
||||
-1,ZPixmap);*/
|
||||
}
|
||||
}
|
||||
|
||||
if (wi->ximage)
|
||||
{
|
||||
wi->sx=wi->ximage->width;
|
||||
wi->sy=wi->ximage->height;
|
||||
wi->data=wi->ximage->data;
|
||||
wi->bytes_per_line=wi->ximage->bytes_per_line;
|
||||
wi->bits_per_pixel=wi->ximage->bits_per_pixel;
|
||||
wi->bytes_per_pixel=wi->bits_per_pixel/8;
|
||||
// NSLog(@"%@ ximage=%p data=%p\n",wi->ximage,wi->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Warning: failed to create image for window");
|
||||
wi->data=NULL;
|
||||
}
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
|
||||
extern int XShmGetEventBase(Display *d);
|
||||
|
||||
-(void) _gotShmCompletion
|
||||
{
|
||||
if (!use_shm)
|
||||
return;
|
||||
|
||||
pending_event=0;
|
||||
if (pending_put)
|
||||
{
|
||||
NSRect r=pending_rect;
|
||||
pending_put=0;
|
||||
if (r.origin.x+r.size.width>window->xframe.size.width)
|
||||
{
|
||||
r.size.width=window->xframe.size.width-r.origin.x;
|
||||
if (r.size.width<=0)
|
||||
return;
|
||||
}
|
||||
if (r.origin.y+r.size.height>window->xframe.size.height)
|
||||
{
|
||||
r.size.height=window->xframe.size.height-r.origin.y;
|
||||
if (r.size.height<=0)
|
||||
return;
|
||||
}
|
||||
if (!XShmPutImage(display,drawable,gc,ximage,
|
||||
r.origin.x,r.origin.y,
|
||||
r.origin.x,r.origin.y,
|
||||
r.size.width,r.size.height,
|
||||
1))
|
||||
{
|
||||
NSLog(@"XShmPutImage failed?");
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_event=1;
|
||||
}
|
||||
}
|
||||
// XFlush(window->display);
|
||||
}
|
||||
|
||||
-(void) _exposeRect: (NSRect)r
|
||||
{
|
||||
/* TODO: Somehow, we can get negative coordinates in the rectangle. So far
|
||||
I've tracked them back to [NSWindow flushWindow]. Should probably figure
|
||||
out where they're coming from originally, and see if they really should be
|
||||
negative. (Seems to happen when a window is created or resized, so possibly
|
||||
something is refreshing while coordinates are still invalid.
|
||||
|
||||
Also, just about every resize of a window causes a few calls here with
|
||||
rects in the new size before we are updated.
|
||||
|
||||
For now, we just intersect with our known size to avoid problems with X.
|
||||
*/
|
||||
|
||||
r=NSIntersectionRect(r,NSMakeRect(0,0,
|
||||
window->xframe.size.width,window->xframe.size.height));
|
||||
if (NSIsEmptyRect(r))
|
||||
return;
|
||||
|
||||
if (use_shm)
|
||||
{
|
||||
|
||||
/* HACK: lets try to use shaped windows to get some use out of destination
|
||||
alpha */
|
||||
if (has_alpha && use_shape_hack)
|
||||
{
|
||||
static int warn=0;
|
||||
Pixmap p;
|
||||
int dsize=((sx+7)/8)*sy;
|
||||
unsigned char *buf=malloc(dsize);
|
||||
unsigned char *dst;
|
||||
int bofs;
|
||||
unsigned char *a;
|
||||
int as;
|
||||
int i,x;
|
||||
|
||||
if (!warn)
|
||||
NSLog(@"Warning: activating shaped windows");
|
||||
warn=1;
|
||||
|
||||
memset(buf,0xff,dsize);
|
||||
|
||||
#define CUTOFF 128
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
a=data+DI.inline_alpha_ofs;
|
||||
as=4;
|
||||
}
|
||||
else
|
||||
{
|
||||
a=alpha;
|
||||
as=1;
|
||||
}
|
||||
|
||||
for (bofs=0,i=sx*sy,x=sx,dst=buf;i;i--,a+=as)
|
||||
{
|
||||
if (*a<CUTOFF)
|
||||
{
|
||||
*dst=*dst&~(1<<bofs);
|
||||
}
|
||||
bofs++;
|
||||
if (bofs==8)
|
||||
{
|
||||
dst++;
|
||||
bofs=0;
|
||||
}
|
||||
x--;
|
||||
if (!x)
|
||||
{
|
||||
if (bofs)
|
||||
{
|
||||
bofs=0;
|
||||
dst++;
|
||||
}
|
||||
x=sx;
|
||||
}
|
||||
}
|
||||
#undef CUTOFF
|
||||
//NSLog(@"check shape");
|
||||
if (old_shape_size==dsize && !memcmp(old_shape,buf,dsize))
|
||||
{
|
||||
free(buf);
|
||||
// NSLog(@" same shape");
|
||||
}
|
||||
else
|
||||
{
|
||||
// NSLog(@" updating");
|
||||
p=XCreatePixmapFromBitmapData(display,window->ident,buf,sx,sy,1,0,1);
|
||||
free(old_shape);
|
||||
old_shape=buf;
|
||||
old_shape_size=dsize;
|
||||
XShapeCombineMask(display,window->ident,
|
||||
ShapeBounding,0,0,p,ShapeSet);
|
||||
XFreePixmap(display,p);
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_event)
|
||||
{
|
||||
if (!pending_put)
|
||||
{
|
||||
pending_put=1;
|
||||
pending_rect=r;
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_rect=NSUnionRect(pending_rect,r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_put=0;
|
||||
if (!XShmPutImage(display,drawable,gc,ximage,
|
||||
r.origin.x,r.origin.y,
|
||||
r.origin.x,r.origin.y,
|
||||
r.size.width,r.size.height,
|
||||
1))
|
||||
{
|
||||
NSLog(@"XShmPutImage failed?");
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_event=1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance hack. Check right away for ShmCompletion
|
||||
events. */
|
||||
{
|
||||
XEvent e;
|
||||
while (XCheckTypedEvent(window->display,
|
||||
XShmGetEventBase(window->display)+ShmCompletion,
|
||||
&e))
|
||||
{
|
||||
[ARTContext _gotShmCompletion:
|
||||
((XShmCompletionEvent *)&e)->drawable];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ximage)
|
||||
XPutImage(display,drawable,gc,ximage,
|
||||
r.origin.x,r.origin.y,
|
||||
r.origin.x,r.origin.y,
|
||||
r.size.width,r.size.height);
|
||||
}
|
||||
|
||||
-(void) needsAlpha
|
||||
{
|
||||
if (has_alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"needs alpha for %p: %ix%i",self,sx,sy);
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s;
|
||||
alpha=NULL;
|
||||
has_alpha=1;
|
||||
/* fill the alpha channel */
|
||||
/* TODO: is +=4 correct? yes, but only because the only modes
|
||||
with inline alpha are 32 bit */
|
||||
for (i=0,s=data+DI.inline_alpha_ofs;i<sx*sy;i++,s+=4)
|
||||
*s=0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
alpha=malloc(sx*sy);
|
||||
if (!alpha)
|
||||
{
|
||||
NSLog(@"Warning! Failed to allocate alpha buffer for window!");
|
||||
return;
|
||||
}
|
||||
|
||||
// NSLog(@"got buffer at %p",alpha);
|
||||
|
||||
has_alpha=1;
|
||||
memset(alpha,0xff,sx*sy);
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i=0;i<num_wimages;i++)
|
||||
if (wimages[i]==self) break;
|
||||
if (i<num_wimages)
|
||||
{
|
||||
num_wimages--;
|
||||
for (;i<num_wimages;i++)
|
||||
wimages[i]=wimages[i+1];
|
||||
}
|
||||
|
||||
if (ximage)
|
||||
{
|
||||
if (use_shm)
|
||||
{
|
||||
XShmDetach(display,&shminfo);
|
||||
XDestroyImage(ximage);
|
||||
shmdt(shminfo.shmaddr);
|
||||
}
|
||||
else
|
||||
XDestroyImage(ximage);
|
||||
}
|
||||
if (alpha)
|
||||
free(alpha);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
@implementation WinImage
|
||||
|
||||
static WinImage **wimages;
|
||||
static int num_wimages;
|
||||
|
||||
+ winImageForWindow: (int)awindow remote: (RDSClient *)aremote;
|
||||
{
|
||||
int i;
|
||||
WinImage *wi;
|
||||
|
||||
int x,y;
|
||||
|
||||
for (i=0;i<num_wimages;i++)
|
||||
{
|
||||
if (wimages[i]->window==awindow)
|
||||
break;
|
||||
}
|
||||
if (i==num_wimages)
|
||||
{
|
||||
wi=[[WinImage alloc] init];
|
||||
wi->window=awindow;
|
||||
wi->remote=aremote;
|
||||
wimages=realloc(wimages,sizeof(WinImage *)*(num_wimages+1));
|
||||
if (!wimages)
|
||||
{
|
||||
NSLog(@"Out of memory (failed to allocate %i bytes)",
|
||||
sizeof(WinImage *)*(num_wimages+1));
|
||||
exit(1);
|
||||
}
|
||||
wimages[num_wimages++]=wi;
|
||||
}
|
||||
else
|
||||
{
|
||||
wi=wimages[i];
|
||||
wi=RETAIN(wi);
|
||||
}
|
||||
|
||||
[aremote setupGetWindowSize: awindow : &x : &y];
|
||||
if (x==wi->sx && y==wi->sy && wi->data)
|
||||
return wi;
|
||||
|
||||
{
|
||||
if (wi->alpha)
|
||||
{
|
||||
free(wi->alpha);
|
||||
wi->alpha=NULL;
|
||||
wi->has_alpha=0;
|
||||
}
|
||||
if (wi->data)
|
||||
{
|
||||
shmdt(wi->shminfo.shmaddr);
|
||||
wi->data=NULL;
|
||||
}
|
||||
|
||||
// wi->pending_put=wi->pending_event=0;
|
||||
|
||||
/* TODO: only use shared memory for 'real' on-screen windows */
|
||||
wi->shminfo.shmid=shmget(IPC_PRIVATE,DI.bytes_per_pixel*x*y,IPC_CREAT|0700);
|
||||
if (!wi->shminfo.shmid==-1)
|
||||
NSLog(@"shmget() failed");
|
||||
/* printf("shminfo.shmid=%08x %i bytes (%ix%i)\n",
|
||||
wi->shminfo.shmid,wi->ximage->bytes_per_line*wi->ximage->height,
|
||||
wi->ximage->width,wi->ximage->height);*/
|
||||
wi->shminfo.shmaddr=wi->data=shmat(wi->shminfo.shmid,0,0);
|
||||
shmctl(wi->shminfo.shmid,IPC_RMID,0);
|
||||
// printf("addr=%p\n",wi->shminfo.shmaddr);
|
||||
}
|
||||
|
||||
if (wi->data)
|
||||
{
|
||||
wi->sx=x;
|
||||
wi->sy=y;
|
||||
wi->bytes_per_line=DI.bytes_per_pixel*x;
|
||||
// wi->bits_per_pixel=DI.bits_per_pixel;
|
||||
wi->bytes_per_pixel=DI.bytes_per_pixel;
|
||||
// NSLog(@"%@ ximage=%p data=%p\n",wi->ximage,wi->data);
|
||||
|
||||
[wi needsAlpha];
|
||||
[aremote setupWindow: wi->window : wi->shminfo.shmid : wi->sx : wi->sy : wi->bytes_per_line];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Warning: failed to create shm buffer for window");
|
||||
wi->data=NULL;
|
||||
}
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
-(void) needsAlpha
|
||||
{
|
||||
if (has_alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"needs alpha for %p: %ix%i",self,sx,sy);
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s;
|
||||
alpha=NULL;
|
||||
has_alpha=1;
|
||||
/* fill the alpha channel */
|
||||
/* TODO: is +=4 correct? but only because the only modes
|
||||
with inline alpha are 32 bit */
|
||||
for (i=0,s=data+DI.inline_alpha_ofs;i<sx*sy;i++,s+=4)
|
||||
*s=0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
alpha=malloc(sx*sy);
|
||||
if (!alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"got buffer at %p",alpha);
|
||||
|
||||
has_alpha=1;
|
||||
memset(alpha,0xff,sx*sy);
|
||||
}
|
||||
|
||||
-(void) _gotShmCompletion
|
||||
{
|
||||
}
|
||||
|
||||
-(void) _exposeRect: (NSRect)r
|
||||
{
|
||||
}
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
||||
|
||||
/** ARTGState does all the work **/
|
||||
|
||||
@interface ARTGState : GSGState
|
||||
|
@ -758,7 +126,7 @@ static int num_wimages;
|
|||
int do_dash;
|
||||
|
||||
|
||||
WinImage *wi;
|
||||
ARTWindowBuffer *wi;
|
||||
|
||||
int clip_x0,clip_y0,clip_x1,clip_y1;
|
||||
BOOL all_clipped;
|
||||
|
@ -2681,14 +2049,14 @@ and that covers most (all?) actual uses of it */
|
|||
{
|
||||
NSLog(@"_setup_stuff: %i : %p",window,remote);
|
||||
DESTROY(wi);
|
||||
wi=[WinImage winImageForWindow: window remote: remote];
|
||||
wi=[ARTWindowBuffer artWindowBufferForWindow: window remote: remote];
|
||||
}
|
||||
#else
|
||||
-(void) _setup_stuff: (gswindow_device_t *)window : (int)x : (int)y
|
||||
{
|
||||
[self setOffset: NSMakePoint(x, y)];
|
||||
DESTROY(wi);
|
||||
wi=[WinImage winImageForWindow: window];
|
||||
wi=[ARTWindowBuffer artWindowBufferForWindow: window];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2740,9 +2108,8 @@ and that covers most (all?) actual uses of it */
|
|||
|
||||
artcontext_setup_draw_info(&DI,v->red_mask,v->green_mask,v->blue_mask,bpp);
|
||||
}
|
||||
|
||||
use_shape_hack=[[NSUserDefaults standardUserDefaults] boolForKey: @"back-art-shape-hack"];
|
||||
#endif
|
||||
[ARTWindowBuffer initializeBackendWithDrawInfo: &DI];
|
||||
|
||||
return self;
|
||||
}
|
||||
|
@ -2763,21 +2130,12 @@ and that covers most (all?) actual uses of it */
|
|||
#ifndef RDS
|
||||
+(void) _gotShmCompletion: (Drawable)d
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<num_wimages;i++)
|
||||
{
|
||||
if (wimages[i]->drawable==d)
|
||||
{
|
||||
[wimages[i] _gotShmCompletion];
|
||||
return;
|
||||
}
|
||||
}
|
||||
NSLog(@"Warning: gotShmCompletion: couldn't find WinImage for drawable");
|
||||
[ARTWindowBuffer _gotShmCompletion: d];
|
||||
}
|
||||
|
||||
-(void) gotShmCompletion: (Drawable)d
|
||||
{
|
||||
[[self class] _gotShmCompletion: d];
|
||||
[ARTWindowBuffer _gotShmCompletion: d];
|
||||
}
|
||||
#endif
|
||||
|
||||
|
@ -2802,7 +2160,7 @@ and that covers most (all?) actual uses of it */
|
|||
/* Private backend methods */
|
||||
+(void) handleExposeRect: (NSRect)rect forDriver: (void *)driver
|
||||
{
|
||||
[(WinImage *)driver _exposeRect: rect];
|
||||
[(ARTWindowBuffer *)driver _exposeRect: rect];
|
||||
}
|
||||
|
||||
|
||||
|
|
102
Source/art/ARTWindowBuffer.h
Normal file
102
Source/art/ARTWindowBuffer.h
Normal file
|
@ -0,0 +1,102 @@
|
|||
/*
|
||||
copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
This file is part of GNUstep.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#ifndef ARTWindowBuffer_h
|
||||
#define ARTWindowBuffer_h
|
||||
|
||||
#include <X11/extensions/XShm.h>
|
||||
|
||||
/*
|
||||
ARTWindowBuffer maintains an XImage for a window. Each ARTGState that
|
||||
renders to that window uses the same WinImage (and thus the same buffer,
|
||||
etc.).
|
||||
|
||||
Many states might render to the same window, so we need to make sure
|
||||
that there's only one WinImage for each window. */
|
||||
@interface ARTWindowBuffer : NSObject
|
||||
{
|
||||
@public
|
||||
#ifdef RDS
|
||||
int window;
|
||||
RDSClient *remote;
|
||||
|
||||
struct
|
||||
{
|
||||
int shmid;
|
||||
char *shmaddr;
|
||||
} shminfo;
|
||||
#else
|
||||
gswindow_device_t *window;
|
||||
GC gc;
|
||||
Drawable drawable;
|
||||
XImage *ximage;
|
||||
Display *display;
|
||||
|
||||
int use_shm;
|
||||
XShmSegmentInfo shminfo;
|
||||
#endif
|
||||
|
||||
|
||||
/* While a XShmPutImage is in progress we don't try to call it
|
||||
again. The pending updates are stored here, and when we get the
|
||||
ShmCompletion event, we handle them. */
|
||||
int pending_put; /* There are pending updates */
|
||||
NSRect pending_rect; /* in this rectangle. */
|
||||
|
||||
int pending_event; /* We're waiting for the ShmCompletion event. */
|
||||
|
||||
|
||||
unsigned char *data;
|
||||
int sx, sy;
|
||||
int bytes_per_line, bits_per_pixel, bytes_per_pixel;
|
||||
|
||||
/* If has_alpha is 1 and alpha is NULL, the alpha is stored in data
|
||||
somehow. The drawing mechanism code should know how to deal with
|
||||
it. */
|
||||
unsigned char *alpha;
|
||||
int has_alpha;
|
||||
|
||||
|
||||
unsigned char *old_shape;
|
||||
int old_shape_size;
|
||||
}
|
||||
|
||||
#ifdef RDS
|
||||
+ artWindowBufferForWindow: (int)awindow remote: (RDSClient *)remote;
|
||||
#else
|
||||
+ artWindowBufferForWindow: (gswindow_device_t *)awindow;
|
||||
#endif
|
||||
|
||||
-(void) needsAlpha;
|
||||
|
||||
-(void) _gotShmCompletion;
|
||||
-(void) _exposeRect: (NSRect)r;
|
||||
|
||||
+(void) initializeBackendWithDrawInfo: (draw_info_t *)d;
|
||||
|
||||
#ifndef RDS
|
||||
+(void) _gotShmCompletion: (Drawable)d;
|
||||
#endif
|
||||
|
||||
@end
|
||||
|
||||
|
||||
#endif
|
||||
|
622
Source/art/ARTWindowBuffer.m
Normal file
622
Source/art/ARTWindowBuffer.m
Normal file
|
@ -0,0 +1,622 @@
|
|||
/*
|
||||
copyright 2002 Alexander Malmberg <alexander@malmberg.org>
|
||||
|
||||
This file is part of GNUstep.
|
||||
|
||||
This library is free software; you can redistribute it and/or
|
||||
modify it under the terms of the GNU Library General Public
|
||||
License as published by the Free Software Foundation; either
|
||||
version 2 of the License, or (at your option) any later version.
|
||||
|
||||
This library 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
|
||||
Library General Public License for more details.
|
||||
|
||||
You should have received a copy of the GNU Library General Public
|
||||
License along with this library; if not, write to the Free
|
||||
Software Foundation, Inc., 675 Mass Ave, Cambridge, MA 02139, USA.
|
||||
*/
|
||||
|
||||
#include <Foundation/NSUserDefaults.h>
|
||||
|
||||
#include "x11/XGServer.h"
|
||||
#include "x11/XGServerWindow.h"
|
||||
|
||||
#include "gsc/GSContext.h"
|
||||
#include "art/ARTContext.h"
|
||||
#include "blit.h"
|
||||
|
||||
#include "ARTWindowBuffer.h"
|
||||
|
||||
#include <sys/ipc.h>
|
||||
#include <sys/shm.h>
|
||||
|
||||
|
||||
#ifndef RDS
|
||||
#include <X11/extensions/shape.h>
|
||||
#endif
|
||||
|
||||
|
||||
static ARTWindowBuffer **art_window_buffers;
|
||||
static int num_art_window_buffers;
|
||||
|
||||
|
||||
static draw_info_t DI;
|
||||
|
||||
|
||||
#ifndef RDS
|
||||
|
||||
static int use_shape_hack = 0; /* this is an ugly hack :) */
|
||||
|
||||
|
||||
|
||||
@implementation ARTWindowBuffer
|
||||
|
||||
+ artWindowBufferForWindow: (gswindow_device_t *)awindow
|
||||
{
|
||||
int i;
|
||||
ARTWindowBuffer *wi;
|
||||
|
||||
for (i = 0; i<num_art_window_buffers; i++)
|
||||
{
|
||||
if (art_window_buffers[i]->window == awindow)
|
||||
break;
|
||||
}
|
||||
if (i == num_art_window_buffers)
|
||||
{
|
||||
wi = [[ARTWindowBuffer alloc] init];
|
||||
wi->window = awindow;
|
||||
art_window_buffers = realloc(art_window_buffers,
|
||||
sizeof(ARTWindowBuffer *) * (num_art_window_buffers + 1));
|
||||
if (!art_window_buffers)
|
||||
{
|
||||
NSLog(@"Out of memory (failed to allocate %i bytes)",
|
||||
sizeof(ARTWindowBuffer *) * (num_art_window_buffers + 1));
|
||||
exit(1);
|
||||
}
|
||||
art_window_buffers[num_art_window_buffers++] = wi;
|
||||
}
|
||||
else
|
||||
{
|
||||
wi = art_window_buffers[i];
|
||||
wi = RETAIN(wi);
|
||||
}
|
||||
|
||||
wi->gc = awindow->gc;
|
||||
wi->drawable = awindow->ident;
|
||||
wi->display = awindow->display;
|
||||
|
||||
wi->window->gdriverProtocol = GDriverHandlesExpose | GDriverHandlesBacking;
|
||||
wi->window->gdriver = wi;
|
||||
|
||||
/* TODO: resolve properly.
|
||||
-x11 is creating buffers before I have a chance to tell it not to, so
|
||||
I'm freeing them here to reduce memory consumption (and prevent
|
||||
leaks, though that should be fixed now) */
|
||||
if (awindow->buffer)
|
||||
{
|
||||
XFreePixmap (awindow->display, awindow->buffer);
|
||||
awindow->buffer = 0;
|
||||
}
|
||||
if (awindow->alpha_buffer)
|
||||
{
|
||||
XFreePixmap (awindow->display, awindow->alpha_buffer);
|
||||
awindow->alpha_buffer = 0;
|
||||
}
|
||||
|
||||
/* create the image if necessary */
|
||||
if (!wi->ximage ||
|
||||
wi->sx != awindow->xframe.size.width ||
|
||||
wi->sy != awindow->xframe.size.height)
|
||||
{
|
||||
wi->sx = wi->window->xframe.size.width;
|
||||
/* printf("%@ updating image for %p (%gx%g)\n", wi, wi->window,
|
||||
wi->window->xframe.size.width, wi->window->xframe.size.height);*/
|
||||
if (wi->ximage)
|
||||
{
|
||||
if (wi->use_shm)
|
||||
{
|
||||
XShmDetach(wi->display, &wi->shminfo);
|
||||
XDestroyImage(wi->ximage);
|
||||
shmdt(wi->shminfo.shmaddr);
|
||||
}
|
||||
else
|
||||
XDestroyImage(wi->ximage);
|
||||
}
|
||||
wi->has_alpha = 0;
|
||||
if (wi->alpha)
|
||||
{
|
||||
free(wi->alpha);
|
||||
wi->alpha = NULL;
|
||||
}
|
||||
|
||||
wi->pending_put = wi->pending_event = 0;
|
||||
|
||||
wi->ximage = NULL;
|
||||
|
||||
/* Use XShm if possible, else fall back to normal XImage:s */
|
||||
if (XShmQueryExtension(wi->display))
|
||||
{
|
||||
wi->use_shm = 1;
|
||||
wi->ximage = XShmCreateImage(wi->display,
|
||||
DefaultVisual(wi->display, DefaultScreen(wi->display)),
|
||||
DI.drawing_depth, ZPixmap, NULL, &wi->shminfo,
|
||||
wi->window->xframe.size.width,
|
||||
wi->window->xframe.size.height);
|
||||
}
|
||||
if (wi->ximage)
|
||||
{
|
||||
/* TODO: only use shared memory for 'real' on-screen
|
||||
windows. how can we tell? */
|
||||
wi->shminfo.shmid = shmget(IPC_PRIVATE,
|
||||
wi->ximage->bytes_per_line * wi->ximage->height,
|
||||
IPC_CREAT | 0700);
|
||||
|
||||
if (!wi->shminfo.shmid == -1)
|
||||
NSLog(@"shmget() failed"); /* TODO */
|
||||
/* printf("shminfo.shmid=%08x %i bytes (%ix%i)\n",
|
||||
wi->shminfo.shmid, wi->ximage->bytes_per_line * wi->ximage->height,
|
||||
wi->ximage->width, wi->ximage->height);*/
|
||||
wi->shminfo.shmaddr = wi->ximage->data = shmat(wi->shminfo.shmid, 0, 0);
|
||||
|
||||
/* Mark the segment as destroyed now. Since we're
|
||||
attached, it won't actually be destroyed, but if we
|
||||
crashed before doing this, it wouldn't be destroyed
|
||||
despite nobody being attached anymore. */
|
||||
shmctl(wi->shminfo.shmid, IPC_RMID, 0);
|
||||
|
||||
// printf("addr=%p\n", wi->shminfo.shmaddr);
|
||||
wi->shminfo.readOnly = 1;
|
||||
if (!XShmAttach(wi->display, &wi->shminfo))
|
||||
NSLog(@"XShmAttach() failed");
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"failed to create shared memory image, using normal XImage:s");
|
||||
wi->use_shm = 0;
|
||||
wi->ximage = XCreateImage(wi->display, DefaultVisual(wi->display,
|
||||
DefaultScreen(wi->display)), DI.drawing_depth, ZPixmap, 0, NULL,
|
||||
wi->window->xframe.size.width, wi->window->xframe.size.height,
|
||||
8, 0);
|
||||
|
||||
wi->ximage->data = malloc(wi->ximage->height * wi->ximage->bytes_per_line);
|
||||
if (!wi->ximage->data)
|
||||
{
|
||||
XDestroyImage(wi->ximage);
|
||||
wi->ximage = NULL;
|
||||
}
|
||||
/*TODO? wi->ximage=XGetImage(wi->display, wi->drawable,
|
||||
0, 0, wi->window->xframe.size.width, wi->window->xframe.size.height,
|
||||
-1, ZPixmap);*/
|
||||
}
|
||||
}
|
||||
|
||||
if (wi->ximage)
|
||||
{
|
||||
wi->sx = wi->ximage->width;
|
||||
wi->sy = wi->ximage->height;
|
||||
wi->data = wi->ximage->data;
|
||||
wi->bytes_per_line = wi->ximage->bytes_per_line;
|
||||
wi->bits_per_pixel = wi->ximage->bits_per_pixel;
|
||||
wi->bytes_per_pixel = wi->bits_per_pixel / 8;
|
||||
// NSLog(@"%@ ximage=%p data=%p\n", wi->ximage, wi->data);
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Warning: failed to create image for window");
|
||||
wi->data = NULL;
|
||||
}
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
|
||||
extern int XShmGetEventBase(Display *d);
|
||||
|
||||
-(void) _gotShmCompletion
|
||||
{
|
||||
if (!use_shm)
|
||||
return;
|
||||
|
||||
pending_event = 0;
|
||||
if (pending_put)
|
||||
{
|
||||
NSRect r = pending_rect;
|
||||
pending_put = 0;
|
||||
if (r.origin.x + r.size.width>window->xframe.size.width)
|
||||
{
|
||||
r.size.width = window->xframe.size.width - r.origin.x;
|
||||
if (r.size.width <= 0)
|
||||
return;
|
||||
}
|
||||
if (r.origin.y + r.size.height>window->xframe.size.height)
|
||||
{
|
||||
r.size.height = window->xframe.size.height - r.origin.y;
|
||||
if (r.size.height <= 0)
|
||||
return;
|
||||
}
|
||||
if (!XShmPutImage(display, drawable, gc, ximage,
|
||||
r.origin.x, r.origin.y,
|
||||
r.origin.x, r.origin.y,
|
||||
r.size.width, r.size.height,
|
||||
1))
|
||||
{
|
||||
NSLog(@"XShmPutImage failed?");
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_event = 1;
|
||||
}
|
||||
}
|
||||
// XFlush(window->display);
|
||||
}
|
||||
|
||||
-(void) _exposeRect: (NSRect)r
|
||||
{
|
||||
/* TODO: Somehow, we can get negative coordinates in the rectangle. So far
|
||||
I've tracked them back to [NSWindow flushWindow]. Should probably figure
|
||||
out where they're coming from originally, and see if they really should be
|
||||
negative. (Seems to happen when a window is created or resized, so possibly
|
||||
something is refreshing while coordinates are still invalid.
|
||||
|
||||
Also, just about every resize of a window causes a few calls here with
|
||||
rects in the new size before we are updated.
|
||||
|
||||
For now, we just intersect with our known size to avoid problems with X.
|
||||
*/
|
||||
|
||||
r = NSIntersectionRect(r, NSMakeRect(0, 0,
|
||||
window->xframe.size.width, window->xframe.size.height));
|
||||
if (NSIsEmptyRect(r))
|
||||
return;
|
||||
|
||||
if (use_shm)
|
||||
{
|
||||
|
||||
/* HACK: lets try to use shaped windows to get some use out of
|
||||
destination alpha */
|
||||
if (has_alpha && use_shape_hack)
|
||||
{
|
||||
static int warn = 0;
|
||||
Pixmap p;
|
||||
int dsize = ((sx + 7) / 8) * sy;
|
||||
unsigned char *buf = malloc(dsize);
|
||||
unsigned char *dst;
|
||||
int bofs;
|
||||
unsigned char *a;
|
||||
int as;
|
||||
int i, x;
|
||||
|
||||
if (!warn)
|
||||
NSLog(@"Warning: activating shaped windows");
|
||||
warn = 1;
|
||||
|
||||
memset(buf, 0xff, dsize);
|
||||
|
||||
#define CUTOFF 128
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
a = data + DI.inline_alpha_ofs;
|
||||
as = 4;
|
||||
}
|
||||
else
|
||||
{
|
||||
a = alpha;
|
||||
as = 1;
|
||||
}
|
||||
|
||||
for (bofs = 0, i = sx * sy, x = sx, dst = buf; i; i--, a += as)
|
||||
{
|
||||
if (*a<CUTOFF)
|
||||
{
|
||||
*dst = *dst & ~(1<<bofs);
|
||||
}
|
||||
bofs++;
|
||||
if (bofs == 8)
|
||||
{
|
||||
dst++;
|
||||
bofs = 0;
|
||||
}
|
||||
x--;
|
||||
if (!x)
|
||||
{
|
||||
if (bofs)
|
||||
{
|
||||
bofs = 0;
|
||||
dst++;
|
||||
}
|
||||
x = sx;
|
||||
}
|
||||
}
|
||||
#undef CUTOFF
|
||||
//NSLog(@"check shape");
|
||||
if (old_shape_size == dsize && !memcmp(old_shape, buf, dsize))
|
||||
{
|
||||
free(buf);
|
||||
// NSLog(@" same shape");
|
||||
}
|
||||
else
|
||||
{
|
||||
// NSLog(@" updating");
|
||||
p = XCreatePixmapFromBitmapData(display, window->ident, buf, sx, sy, 1, 0, 1);
|
||||
free(old_shape);
|
||||
old_shape = buf;
|
||||
old_shape_size = dsize;
|
||||
XShapeCombineMask(display, window->ident,
|
||||
ShapeBounding, 0, 0, p, ShapeSet);
|
||||
XFreePixmap(display, p);
|
||||
}
|
||||
}
|
||||
|
||||
if (pending_event)
|
||||
{
|
||||
if (!pending_put)
|
||||
{
|
||||
pending_put = 1;
|
||||
pending_rect = r;
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_rect = NSUnionRect(pending_rect, r);
|
||||
}
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_put = 0;
|
||||
if (!XShmPutImage(display, drawable, gc, ximage,
|
||||
r.origin.x, r.origin.y,
|
||||
r.origin.x, r.origin.y,
|
||||
r.size.width, r.size.height,
|
||||
1))
|
||||
{
|
||||
NSLog(@"XShmPutImage failed?");
|
||||
}
|
||||
else
|
||||
{
|
||||
pending_event = 1;
|
||||
}
|
||||
}
|
||||
|
||||
/* Performance hack. Check right away for ShmCompletion
|
||||
events. */
|
||||
{
|
||||
XEvent e;
|
||||
while (XCheckTypedEvent(window->display,
|
||||
XShmGetEventBase(window->display) + ShmCompletion,
|
||||
&e))
|
||||
{
|
||||
[isa _gotShmCompletion: ((XShmCompletionEvent *)&e)->drawable];
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (ximage)
|
||||
XPutImage(display, drawable, gc, ximage,
|
||||
r.origin.x, r.origin.y,
|
||||
r.origin.x, r.origin.y,
|
||||
r.size.width, r.size.height);
|
||||
}
|
||||
|
||||
-(void) needsAlpha
|
||||
{
|
||||
if (has_alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"needs alpha for %p: %ix%i", self, sx, sy);
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s;
|
||||
alpha = NULL;
|
||||
has_alpha = 1;
|
||||
/* fill the alpha channel */
|
||||
/* TODO: is +=4 correct? yes, but only because the only modes
|
||||
with inline alpha are 32 bit */
|
||||
for (i = 0, s = data + DI.inline_alpha_ofs; i<sx * sy; i++, s += 4)
|
||||
*s = 0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
alpha = malloc(sx * sy);
|
||||
if (!alpha)
|
||||
{
|
||||
NSLog(@"Warning! Failed to allocate alpha buffer for window!");
|
||||
return;
|
||||
}
|
||||
|
||||
// NSLog(@"got buffer at %p", alpha);
|
||||
|
||||
has_alpha = 1;
|
||||
memset(alpha, 0xff, sx * sy);
|
||||
}
|
||||
|
||||
-(void) dealloc
|
||||
{
|
||||
int i;
|
||||
|
||||
for (i = 0; i<num_art_window_buffers; i++)
|
||||
if (art_window_buffers[i] == self) break;
|
||||
if (i<num_art_window_buffers)
|
||||
{
|
||||
num_art_window_buffers--;
|
||||
for (; i<num_art_window_buffers; i++)
|
||||
art_window_buffers[i] = art_window_buffers[i + 1];
|
||||
}
|
||||
|
||||
if (ximage)
|
||||
{
|
||||
if (use_shm)
|
||||
{
|
||||
XShmDetach(display, &shminfo);
|
||||
XDestroyImage(ximage);
|
||||
shmdt(shminfo.shmaddr);
|
||||
}
|
||||
else
|
||||
XDestroyImage(ximage);
|
||||
}
|
||||
if (alpha)
|
||||
free(alpha);
|
||||
[super dealloc];
|
||||
}
|
||||
|
||||
|
||||
+(void) initializeBackendWithDrawInfo: (draw_info_t *)d
|
||||
{
|
||||
use_shape_hack = [[NSUserDefaults standardUserDefaults]
|
||||
boolForKey: @"back-art-shape-hack"];
|
||||
DI = *d;
|
||||
}
|
||||
|
||||
|
||||
+(void) _gotShmCompletion: (Drawable)d
|
||||
{
|
||||
int i;
|
||||
for (i=0;i<num_art_window_buffers;i++)
|
||||
{
|
||||
if (art_window_buffers[i]->drawable==d)
|
||||
{
|
||||
[art_window_buffers[i] _gotShmCompletion];
|
||||
return;
|
||||
}
|
||||
}
|
||||
NSLog(@"Warning: gotShmCompletion: couldn't find ARTWindowBuffer for drawable");
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#else
|
||||
|
||||
@implementation ARTWindowBuffer
|
||||
|
||||
+ artWindowBufferForWindow: (int)awindow remote: (RDSClient *)aremote;
|
||||
{
|
||||
int i;
|
||||
ARTWindowBuffer *wi;
|
||||
|
||||
int x, y;
|
||||
|
||||
for (i = 0; i<num_art_window_buffers; i++)
|
||||
{
|
||||
if (art_window_buffers[i]->window == awindow)
|
||||
break;
|
||||
}
|
||||
if (i == num_art_window_buffers)
|
||||
{
|
||||
wi = [[ARTWindowBuffer alloc] init];
|
||||
wi->window = awindow;
|
||||
wi->remote = aremote;
|
||||
art_window_buffers = realloc(art_window_buffers,
|
||||
sizeof(ARTWindowBuffer *) * (num_art_window_buffers + 1));
|
||||
if (!art_window_buffers)
|
||||
{
|
||||
NSLog(@"Out of memory (failed to allocate %i bytes)",
|
||||
sizeof(ARTWindowBuffer *) * (num_art_window_buffers + 1));
|
||||
exit(1);
|
||||
}
|
||||
art_window_buffers[num_art_window_buffers++] = wi;
|
||||
}
|
||||
else
|
||||
{
|
||||
wi = art_window_buffers[i];
|
||||
wi = RETAIN(wi);
|
||||
}
|
||||
|
||||
[aremote setupGetWindowSize: awindow : &x : &y];
|
||||
if (x == wi->sx && y == wi->sy && wi->data)
|
||||
return wi;
|
||||
|
||||
{
|
||||
if (wi->alpha)
|
||||
{
|
||||
free(wi->alpha);
|
||||
wi->alpha = NULL;
|
||||
wi->has_alpha = 0;
|
||||
}
|
||||
if (wi->data)
|
||||
{
|
||||
shmdt(wi->shminfo.shmaddr);
|
||||
wi->data = NULL;
|
||||
}
|
||||
|
||||
// wi->pending_put = wi->pending_event = 0;
|
||||
|
||||
/* TODO: only use shared memory for 'real' on-screen windows */
|
||||
wi->shminfo.shmid = shmget(IPC_PRIVATE, DI.bytes_per_pixel * x * y,
|
||||
IPC_CREAT | 0700);
|
||||
if (!wi->shminfo.shmid == -1)
|
||||
NSLog(@"shmget() failed");
|
||||
/* printf("shminfo.shmid=%08x %i bytes (%ix%i)\n",
|
||||
wi->shminfo.shmid, wi->ximage->bytes_per_line * wi->ximage->height,
|
||||
wi->ximage->width, wi->ximage->height);*/
|
||||
wi->shminfo.shmaddr = wi->data = shmat(wi->shminfo.shmid, 0, 0);
|
||||
shmctl(wi->shminfo.shmid, IPC_RMID, 0);
|
||||
// printf("addr=%p\n", wi->shminfo.shmaddr);
|
||||
}
|
||||
|
||||
if (wi->data)
|
||||
{
|
||||
wi->sx = x;
|
||||
wi->sy = y;
|
||||
wi->bytes_per_line = DI.bytes_per_pixel * x;
|
||||
// wi->bits_per_pixel = DI.bits_per_pixel;
|
||||
wi->bytes_per_pixel = DI.bytes_per_pixel;
|
||||
// NSLog(@"%@ ximage=%p data=%p\n", wi->ximage, wi->data);
|
||||
|
||||
[wi needsAlpha];
|
||||
[aremote setupWindow: wi->window : wi->shminfo.shmid
|
||||
: wi->sx : wi->sy : wi->bytes_per_line];
|
||||
}
|
||||
else
|
||||
{
|
||||
NSLog(@"Warning: failed to create shm buffer for window");
|
||||
wi->data = NULL;
|
||||
}
|
||||
|
||||
return wi;
|
||||
}
|
||||
|
||||
-(void) needsAlpha
|
||||
{
|
||||
if (has_alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"needs alpha for %p: %ix%i", self, sx, sy);
|
||||
|
||||
if (DI.inline_alpha)
|
||||
{
|
||||
int i;
|
||||
unsigned char *s;
|
||||
alpha = NULL;
|
||||
has_alpha = 1;
|
||||
/* fill the alpha channel */
|
||||
/* TODO: is +=4 correct? but only because the only modes
|
||||
with inline alpha are 32 bit */
|
||||
for (i = 0, s = data + DI.inline_alpha_ofs; i<sx * sy; i++, s += 4)
|
||||
*s = 0xff;
|
||||
return;
|
||||
}
|
||||
|
||||
alpha = malloc(sx * sy);
|
||||
if (!alpha)
|
||||
return;
|
||||
|
||||
// NSLog(@"got buffer at %p", alpha);
|
||||
|
||||
has_alpha = 1;
|
||||
memset(alpha, 0xff, sx * sy);
|
||||
}
|
||||
|
||||
-(void) _gotShmCompletion
|
||||
{
|
||||
}
|
||||
|
||||
-(void) _exposeRect: (NSRect)r
|
||||
{
|
||||
}
|
||||
|
||||
@end
|
||||
|
||||
#endif
|
||||
|
|
@ -39,7 +39,8 @@ SUBPROJECT_NAME=art
|
|||
|
||||
# The Objective-C source files to be compiled
|
||||
art_OBJC_FILES = \
|
||||
ARTContext.m blit.m ftfont.m
|
||||
ARTContext.m blit.m ftfont.m \
|
||||
ARTWindowBuffer.m
|
||||
|
||||
art_HEADER_FILES_DIR = ../../Headers/art
|
||||
art_HEADER_FILES_INSTALL_DIR = gnustep/art
|
||||
|
|
Loading…
Reference in a new issue