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:
Alexander Malmberg 2002-08-21 18:27:57 +00:00
parent bb6b4826aa
commit e61e02233f
5 changed files with 740 additions and 651 deletions

View file

@ -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,

View file

@ -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];
}

View 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

View 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

View file

@ -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