/***********************************************************/
/*                                                         */
/*  System dependent widget management (unix, x11)         */
/*                                                         */
/***********************************************************/

#include "unix/guts.h"
#include "Window.h"
#include "Application.h"

#define SORT(a,b)       { int swp; if ((a) > (b)) { swp=(a); (a)=(b); (b)=swp; }}
#define REVERT(a)	( XX-> size. y - (a) - 1)

Bool
apc_widget_map_points( Handle self, Bool toScreen, int n, Point *p)
{
	Point d = {0,0};
	
	while ( self && (self != application)) {
		DEFXX;
		Point origin;
		if ( XX-> parentHandle) {
			XWindow dummy;
			XTranslateCoordinates( DISP, XX-> client, guts. root, 0, XX-> size.y-1, &origin.x, &origin.y, &dummy);
			origin. y = guts. displaySize. y - origin. y;
			self = application;
		} else {
			origin = XX-> origin;
			self = XX-> flags. clip_owner ? PWidget(self)-> owner : application;
		}
		d. x += origin. x;
		d. y += origin. y;
	}
	
	if ( !toScreen) {
		d. x = -d. x;
		d. y = -d. y;
	}
	
	while (n--) {
		p[n]. x += d. x;
		p[n]. y += d. y;
	}
	return true;
}

ApiHandle
apc_widget_get_parent_handle( Handle self)
{
	return X(self)-> parentHandle;
}

Handle
apc_widget_get_z_order( Handle self, int zOrderId)
{
	DEFXX;
	XWindow root, parent, *children;
	unsigned int count;
	int i, inc;
	Handle ret = nilHandle;

	if ( !( PComponent(self)-> owner))
		return self;

	switch ( zOrderId) {
	case zoFirst:
		i = 1;
		inc = -1;
		break;
	case zoLast:
		i  = 1;
		inc = 1;
		break;
	case zoNext:
		i = 0;
		inc = -1;
		break;
	case zoPrev:
		i = 0;
		inc = 1;
		break;
	default:
		return nilHandle;
	}

	if ( XQueryTree( DISP, X(PComponent(self)-> owner)-> client, 
		&root, &parent, &children, &count) == 0)
			return nilHandle;

	if ( count == 0) goto EXIT;

	if ( i == 0) {
		int found = -1;
		for ( i = 0; i < count; i++) {
			if ( children[ i] == XX-> client) {
				found = i;
				break;
			}   
		}   
		if ( found < 0) { /* if !clipOwner */
			ret = self;
			goto EXIT; 
		}   
		i = found + inc;
		if ( i < 0 || i >= count) goto EXIT; /* last in line */
	} else
		i = ( zOrderId == zoFirst) ? count - 1 : 0;
	
	while ( 1) {
		Handle who = ( Handle) hash_fetch( guts. windows, (void*)&(children[i]), sizeof(X_WINDOW));
		if ( who) {
			ret = who;
			break;
		}   
		i += inc;
		if ( i < 0 || i >= count) break;
	}   

EXIT:   
	if ( children) XFree( children);
	return ret;
}   

void
process_transparents( Handle self)
{
	int i;
	Point sz = X(self)-> size;
	for ( i = 0; i < PWidget(self)-> widgets. count; i++) {
		Handle x = PWidget(self)-> widgets. items[ i];
		if ( X(x)-> flags. transparent && 
			X(x)-> flags. want_visible &&
			!X(x)-> flags. falsely_hidden) {
			Point pos = X(x)-> origin;
			if ( pos. x >= sz.x || pos.y >= sz.y ||
				pos. x + X(x)-> size.x <= 0 ||
				pos. y + X(x)-> size.y <= 0) continue;
			apc_widget_invalidate_rect( x, nil);
		}
	}
}

int
prima_flush_events( Display * disp, XEvent * ev, Handle self)
{
	XWindow win;
	/* leave only configuration unrelated commands on the queue */
	switch ( ev-> type) {
	case SelectionRequest:
	case SelectionClear:
	case MappingNotify:
	case SelectionNotify:
	case ClientMessage:
	case MapNotify:
	case UnmapNotify:
	case KeymapNotify:
	case KeyPress:
	case KeyRelease:
	case PropertyNotify:
	case ColormapNotify:
	case DestroyNotify:
		return false;
	}

	switch ( ev-> type) {
	case ConfigureNotify:
	case -ConfigureNotify:
		win = ev-> xconfigure. window;
		break;
	case ReparentNotify:
		win = ev-> xreparent. window;
		break;
	default:
		win = ev-> xany. window;
	}

	return win == X(self)-> client || win == X_WINDOW;
}

void
prima_get_view_ex( Handle self, PViewProfile p)
{
DEFXX;
if ( !p) return;
if ( XX-> type. window) {
	p-> pos       = apc_window_get_client_pos( self);
	p-> size      = apc_window_get_client_size( self);
	XFetchName( DISP, X_WINDOW, &p-> title);
} else {
	p-> pos       = apc_widget_get_pos( self);
	p-> size      = apc_widget_get_size( self);
	p-> title     = NULL;
}
p-> capture   = apc_widget_is_captured( self);
p-> focused   = apc_widget_is_focused( self);
p-> visible   = apc_widget_is_visible( self);

#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
p-> shape_count = 0;
if ( XX-> shape_extent. x != 0 && XX-> shape_extent. y != 0)
	p-> shape_rects = XShapeGetRectangles( DISP, X_WINDOW, ShapeBounding, &p-> shape_count, &p->shape_ordering);
#endif
}

void
prima_set_view_ex( Handle self, PViewProfile p)
{
	DEFXX;
	
	if ( p-> visible ) XMapWindow( DISP, X_WINDOW);
	XX-> origin. x--; /* force it */
	if ( XX-> type. window ) {
		apc_window_set_client_rect( self, p-> pos.x, p-> pos.y, p-> size.x, p->size.y);
		apc_window_set_caption( self, p->title, XX->flags. title_utf8);
		XFree(p->title);
	} else {
		apc_widget_set_rect( self, p-> pos.x, p-> pos.y, p-> size.x, p->size.y);
	}

	if ( p-> focused) apc_widget_set_focused( self);
	if ( p-> capture) apc_widget_set_capture( self, 1, nilHandle);

#ifdef HAVE_X11_EXTENSIONS_SHAPE_H
	if ( p-> shape_count > 0 ) {
		XShapeCombineRectangles( DISP, X_WINDOW, ShapeBounding, 0, 0, p-> shape_rects, p->shape_count, ShapeSet, p->shape_ordering);
		if ( X_WINDOW != XX-> client)
			XShapeCombineRectangles( DISP, XX->client, ShapeBounding, 0, 0, p-> shape_rects, p->shape_count, ShapeSet, p->shape_ordering);
		XFree( p-> shape_rects );
	}
#endif
}

Bool
apc_widget_create( Handle self, Handle owner, Bool sync_paint,
						Bool clip_owner, Bool transparent, ApiHandle parentHandle, Bool layered)
{
	DEFXX;
	ViewProfile vprf;
	Bool reparent, recreate, layered_requested;
	Handle real_owner, old_parent;
	XWindow parent, old = X_WINDOW;
	XSetWindowAttributes attrs;
	unsigned long valuemask;

	if ( !guts. argb_visual. visual || guts. argb_visual. visualid == guts. visual. visualid)
		layered = false;

	layered_requested = layered;
	layered = ( clip_owner && owner != application ) ? X(owner)->flags. layered : layered_requested;

	XX-> visual   = layered ? &guts. argb_visual : &guts. visual;
	XX-> colormap = layered ? guts. argbColormap : guts. defaultColormap;

	reparent = ( old != nilHandle) && ( 
		( clip_owner != XX-> flags. clip_owner) ||
		( parentHandle != XX-> parent)
	);
	recreate = ( old != nilHandle) && (
		( layered != XX-> flags. layered )
	);
	if ( recreate ) {
		int i, count;
		Handle * list;
		XEvent dummy_ev;

		list  = PWidget(self)-> widgets. items;
		count = PWidget(self)-> widgets. count;
		CWidget(self)-> end_paint_info( self);
		CWidget(self)-> end_paint( self);
		prima_release_gc( XX);
		for( i = 0; i < count; i++)
			prima_get_view_ex( list[ i], ( ViewProfile*)( X( list[ i])-> recreateData = malloc( sizeof( ViewProfile))));
		
		reparent = false;
		if ( XX-> recreateData) {
			memcpy( &vprf, XX-> recreateData, sizeof( vprf));
			free( XX-> recreateData);
			XX-> recreateData = nil;
		} else
			prima_get_view_ex( self, &vprf);
		if ( guts. currentMenu && PComponent( guts. currentMenu)-> owner == self) prima_end_menu();
		CWidget( self)-> end_paint_info( self);
		CWidget( self)-> end_paint( self);
		if ( XX-> flags. paint_pending) {
			TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
			XX-> flags. paint_pending = false;
		}
		/* flush configure events */
		XSync( DISP, false);
		while ( XCheckIfEvent( DISP, &dummy_ev, (XIfEventProcType)prima_flush_events, (XPointer)self));
		hash_delete( guts.windows, (void*)&old, sizeof(old), false);
		XCHECKPOINT;
	}

	old_parent = ( old != nilHandle ) ? XX->parent : nilHandle;

	XX-> flags. transparent = !!transparent;
	XX-> type.drawable = true;
	XX-> type.widget = true;
	if ( !clip_owner || ( owner == application)) {
		parent = guts. root;
		real_owner = application;
	} else {
		parent = X( owner)-> client;
		real_owner = owner;
	}
	
	if ( parentHandle)
		parent = parentHandle;
	XX-> parentHandle = parentHandle;
	XX-> real_parent = XX-> parent = parent;
	XX-> above = nilHandle;
	XX-> owner = real_owner;

	XX-> flags. clip_owner = !!clip_owner;
	XX-> flags. sync_paint = !!sync_paint;
	XX-> flags. layered    = !!layered;
	XX-> flags. layered_requested = !!layered_requested;

	attrs. event_mask = KeyPressMask | KeyReleaseMask | ButtonPressMask
		| ButtonReleaseMask | EnterWindowMask | LeaveWindowMask | PointerMotionMask
		| ButtonMotionMask | KeymapStateMask | ExposureMask | VisibilityChangeMask
		| StructureNotifyMask | FocusChangeMask | PropertyChangeMask | ColormapChangeMask
		| OwnerGrabButtonMask;
	attrs. override_redirect = true;
	attrs. do_not_propagate_mask = attrs. event_mask;
	attrs. win_gravity = ( clip_owner && ( owner != application)) 
		? SouthWestGravity : NorthWestGravity;
	attrs. colormap = XX->colormap;

	if ( reparent) {
		Point pos = PWidget(self)-> pos;
		XEvent dummy_ev;

		if ( old_parent == parent ) return true;

		if ( guts. currentMenu && PComponent( guts. currentMenu)-> owner == self) prima_end_menu();
		CWidget( self)-> end_paint_info( self);
		CWidget( self)-> end_paint( self);
		if ( XX-> flags. paint_pending) {
			TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
			XX-> flags. paint_pending = false;
		}
		/* flush configure events */
		XSync( DISP, false);
		while ( XCheckIfEvent( DISP, &dummy_ev, (XIfEventProcType)prima_flush_events, (XPointer)self));
		
		XChangeWindowAttributes( DISP, X_WINDOW, CWWinGravity, &attrs);
		XReparentWindow( DISP, X_WINDOW, parent, pos. x, 
			X(real_owner)-> size.y - pos. y - X(self)-> size. y);

		XX-> ackOrigin = pos;
		XX-> ackSize   = XX-> size;
		XX-> flags. mapped = XX-> flags. want_visible;
		process_transparents( self);
		return true;
	}   

	valuemask = 
		0
		/* | CWBackPixmap */
		/* | CWBackPixel */
		/* | CWBorderPixmap */
		/* | CWBorderPixel */
		/* | CWBitGravity */
		| CWWinGravity
		/* | CWBackingStore */
		/* | CWBackingPlanes */
		/* | CWBackingPixel */
		| CWOverrideRedirect
		/* | CWSaveUnder */
		| CWEventMask
		/* | CWDontPropagate */
		| CWColormap 
		/* | CWCursor */
	;

	if ( layered ) {
		valuemask |= CWBackPixel | CWBorderPixel;
		attrs. background_pixel = 0;
		attrs. border_pixel = 0;
	}

	XX-> client = X_WINDOW = XCreateWindow( DISP, parent,
									0, 0, 1, 1, 0, XX-> visual-> depth,
									InputOutput, XX-> visual-> visual,
									valuemask, &attrs);
	XCHECKPOINT;
	if (!X_WINDOW) {
		warn("error creating window");
		return false;
	}

	if (recreate) {
		int i, count;
		Handle * list;
		Point pos = PWidget(self)-> pos;
		list  = PWidget(self)-> widgets. items;
		count = PWidget(self)-> widgets. count;
		prima_set_view_ex( self, &vprf);
		XX-> gdrawable = XX-> udrawable = X_WINDOW;
		XX-> ackOrigin = pos;
		XX-> ackSize   = XX-> size;
		XX-> flags. mapped = XX-> flags. want_visible;
		hash_store( guts.windows, &X_WINDOW, sizeof(X_WINDOW), (void*)self);
		for ( i = 0; i < count; i++) ((( PComponent) list[ i])-> self)-> recreate( list[ i]);
		XDestroyWindow( DISP, old);
		return true;
	}

	XX-> size. x = XX-> size. y = 
	XX-> ackOrigin. x = XX-> ackOrigin. y = 
	XX-> ackSize. x = XX-> ackOrigin. y = 0;

	hash_store( guts.windows, &X_WINDOW, sizeof(X_WINDOW), (void*)self);

	XX-> gdrawable = XX-> udrawable = X_WINDOW;

	XX-> flags. position_determined = 1;
	
	apc_component_fullname_changed_notify( self);
	
	prima_send_create_event( X_WINDOW);

	return true;
}

Bool
apc_widget_begin_paint( Handle self, Bool inside_on_paint)
{
	DEFXX;
	Bool useRPDraw = false;

	if ( guts. appLock > 0) return false;

	if ( XX-> size.x <= 0 || XX-> size.y <= 0) return false;
	
	if ( XX-> flags. transparent && inside_on_paint) {
		if ( XX-> flags. want_visible && !XX-> flags. falsely_hidden) {
			if ( XX-> parent == guts. root) {
				XEvent ev;
				if ( XX-> flags. transparent_busy) return false;
				XX-> flags. transparent_busy = 1;
				XUnmapWindow( DISP, X_WINDOW); 
				XSync( DISP, false);
				while ( XCheckMaskEvent( DISP, ExposureMask, &ev))
					prima_handle_event( &ev, nil);
				XMapWindow( DISP, X_WINDOW); 
				XSync( DISP, false);
				while ( XCheckMaskEvent( DISP, ExposureMask, &ev))
					prima_handle_event( &ev, nil);
				if ( XX-> flags. paint_pending) {
					TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
					XX-> flags. paint_pending = false;
				}
				XX-> flags. transparent_busy = 0;
			} else
				useRPDraw = true;
		}
	}
	XCHECKPOINT;    
	if ( guts. dynamicColors && inside_on_paint) prima_palette_free( self, false);
	prima_no_cursor( self);
	prima_prepare_drawable_for_painting( self, inside_on_paint);
#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
	if ( XF_LAYERED(XX) )
		XX->argb_picture = XRenderCreatePicture( DISP, XX->gdrawable, guts. argb_pic_format, 0, NULL);
#endif
	if ( useRPDraw) {
		Handle owner = PWidget(self)->owner;
		Point po = apc_widget_get_pos( self);
		Point sz = apc_widget_get_size( self);
		Point so = CWidget(owner)-> get_size( owner);
		XDrawable dc;
		Region region;
		XRectangle xr = {0,0,0,0};
		xr. width = sz.x;
		xr. height = sz.y;

		CWidget(owner)-> begin_paint( owner);
		dc = X(owner)-> gdrawable;
		X(owner)-> gdrawable = XX-> gdrawable;
		X(owner)-> btransform. x = -po. x;
		X(owner)-> btransform. y = so. y - sz. y - po. y;
		if ( X(owner)-> paint_region) {
			XDestroyRegion( X(owner)-> paint_region);
			X(owner)-> paint_region = nil;
		}
		region = XCreateRegion();
		XUnionRectWithRegion( &xr, region, region);
		if ( XX-> paint_region) 
			XIntersectRegion( XX-> paint_region, region, region);
		X(owner)-> paint_region = XCreateRegion();
		XUnionRegion( X(owner)-> paint_region, region, X(owner)-> paint_region);
		XOffsetRegion( X(owner)-> paint_region, -X(owner)-> btransform.x, X(owner)-> btransform.y); 
		XSetRegion( DISP, X(owner)-> gc, region);
		X(owner)-> current_region = region;
		X(owner)-> flags. kill_current_region = 1;
		CWidget( owner)-> notify( owner, "sH", "Paint", owner);
		X(owner)-> gdrawable = dc;
		CWidget( owner)-> end_paint( owner);
	}

	XX-> flags. force_flush = !inside_on_paint;

	return true;
}

Bool
apc_widget_begin_paint_info( Handle self)
{
	prima_no_cursor( self);
	prima_prepare_drawable_for_painting( self, false);
	return true;
}

Bool
apc_widget_destroy( Handle self)
{
	DEFXX;
	ConfigureEventPair *n1, *n2;
	
	if ( XX-> recreateData) free( XX-> recreateData);

	n1 = TAILQ_FIRST( &XX-> configure_pairs);
	while (n1 != nil) {
		n2 = TAILQ_NEXT(n1, link);
		free(n1);
		n1 = n2;
	}

	if ( XX-> user_pointer != None) {
		XFreeCursor( DISP, XX-> user_pointer);
		XX-> user_pointer = None;
	}
	if ( XX-> user_p_source != None) {
		XFreePixmap( DISP, XX-> user_p_source);
		XX-> user_p_source = None;
	}
	if ( XX-> user_p_mask != None) {
		XFreePixmap( DISP, XX-> user_p_mask);
		XX-> user_p_mask = None;
	}
	if ( guts. currentMenu && PComponent( guts. currentMenu)-> owner == self)
		prima_end_menu();
	if ( guts. focused == self)
		guts. focused = nilHandle;
	XX-> flags.modal = false;
	if ( XX-> flags. paint_pending) {
		TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
		XX-> flags. paint_pending = false;
	}
	if ( XX-> invalid_region) {
		XDestroyRegion( XX-> invalid_region);
		XX-> invalid_region = nil;
	}
	if ( X_WINDOW) {
		if ( guts. grab_redirect == XX-> client || guts. grab_redirect == X_WINDOW) 
			guts. grab_redirect = nilHandle;
		if ( guts. grab_widget == self || XX-> flags. grab) {
			XUngrabPointer( DISP, CurrentTime);
			guts. grab_widget = nilHandle;
		}
		XCHECKPOINT;
		if ( XX-> client != X_WINDOW) {
			XDestroyWindow( DISP, XX-> client);
			hash_delete( guts.windows, (void*)&XX-> client, sizeof(X_WINDOW), false);
		}
		XX-> client = nilHandle;
		XDestroyWindow( DISP, X_WINDOW);
		XCHECKPOINT;
		hash_delete( guts.windows, (void*)&X_WINDOW, sizeof(X_WINDOW), false);
		X_WINDOW = nilHandle;
	}
	return true;
}

PFont
apc_widget_default_font( PFont f)
{
	memcpy( f, &guts. default_widget_font, sizeof( Font));
	return f;
}

Bool
apc_widget_end_paint( Handle self)
{
	DEFXX;
	XX-> flags. force_flush = 0;

	/* make the unintended layered window opaque */
	if ( !XX-> flags. layered_requested && XF_LAYERED(XX) && XX-> gc) {
		XGCValues gcv;
		Point sz;
		gcv. foreground = 0xFFFFFFFF;
		gcv. function   = GXcopy;
		gcv. fill_style = FillSolid;
		gcv. plane_mask = guts. argb_bits. alpha_mask;
		XChangeGC( DISP, XX->gc, GCPlaneMask|GCForeground|GCFunction|GCFillStyle, &gcv);
		sz = apc_widget_get_size( self);
		XFillRectangle( DISP, XX-> gdrawable, XX-> gc, 0, 0, sz.x, sz.y);
		gcv. plane_mask = 0xFFFFFFFF;
		XChangeGC( DISP, XX->gc, GCPlaneMask, &gcv);
	}

#ifdef HAVE_X11_EXTENSIONS_XRENDER_H
	if ( XF_LAYERED(XX) && XX->argb_picture ) {
		XRenderFreePicture( DISP, XX->argb_picture);
		XX->argb_picture = 0;
	}
#endif
	prima_cleanup_drawable_after_painting( self);
	prima_update_cursor( self);
	return true;
}

Bool
apc_widget_end_paint_info( Handle self)
{
	prima_cleanup_drawable_after_painting( self);
	prima_update_cursor( self);
	return true;
}

Bool
apc_widget_get_clip_owner( Handle self)
{
	return X(self)-> flags. clip_owner;
}

Color
apc_widget_get_color( Handle self, int index)
{
	return X(self)-> colors[ index];
}

Bool
apc_widget_get_first_click( Handle self)
{
	return X(self)-> flags. first_click ? true : false;
}

Handle
apc_widget_get_focused( void)
{
	return guts. focused;
}

ApiHandle
apc_widget_get_handle( Handle self)
{
	return X_WINDOW;
}

Rect
apc_widget_get_invalid_rect( Handle self)
{
	DEFXX;
	Rect ret;
	XRectangle r;
	if ( !XX-> invalid_region) {
		Rect r = {0,0,0,0}; 
		return r;
	}
	XClipBox( XX-> invalid_region, &r);
	ret. left = r.x;
	ret. bottom = XX-> size.y - r.height - r.y; 
	ret. right = r.x + r.width;
	ret. top =  XX-> size.y - r.y;
	return ret;
}

Bool
apc_widget_get_layered_request( Handle self)
{
	return X(self)-> flags. layered_requested;
}

Bool
apc_widget_surface_is_layered( Handle self)
{
	return X(self)-> flags. layered;
}

Point
apc_widget_get_pos( Handle self)
{
	DEFXX;
	XWindow r;
	Point ret;
	int x, y;
	unsigned int w, h, d, b;

	if ( XX-> type. window) {
		Rect rc;
		Point p = apc_window_get_client_pos( self);
		prima_get_frame_info( self, &rc);
		p. x -= rc. left;
		p. y -= rc. bottom;
		return p;
	}   
		
	if ( XX-> parentHandle == nilHandle)
		return XX-> origin;
	
	XGetGeometry( DISP, X_WINDOW, &r, &x, &y, &w, &h, &b, &d);
	XTranslateCoordinates( DISP, XX-> parentHandle, guts. root, x, y, &x, &y, &r);
	ret. x = x;
	ret. y = DisplayHeight( DISP, SCREEN) - y - w; 
	return ret;
}

Bool
apc_widget_get_shape( Handle self, Handle mask)
{
#ifndef HAVE_X11_EXTENSIONS_SHAPE_H
	return false;
#else
	DEFXX;
	XRectangle *r, *rc;
	int i, count, ordering;

	if ( !guts. shape_extension) return false;

	if ( !mask) 
		return XX-> shape_extent. x != 0 && XX-> shape_extent. y != 0;
		
	if ( XX-> shape_extent. x == 0 || XX-> shape_extent. y == 0)
		return false;

	r = rc = XShapeGetRectangles( DISP, X_WINDOW, ShapeBounding, &count, &ordering);

	CImage(mask)-> create_empty( mask, XX-> shape_extent. x, XX-> shape_extent. y, imBW);
	CImage(mask)-> begin_paint( mask); 
	XSetForeground( DISP, X(mask)-> gc, 0);
	XFillRectangle( DISP, X(mask)->gdrawable, X(mask)->gc, 0, 0, XX->shape_extent.x, XX->shape_extent.y);
	XSetForeground( DISP, X(mask)-> gc, 1);
	for ( i = 0; i < count; i++, r++) 
		XFillRectangle( DISP, X(mask)-> gdrawable, X(mask)-> gc, 
			r-> x - XX-> shape_offset. x, r-> y - XX-> shape_offset. y,
			r-> width, r-> height);
	XFree( rc);
	CImage(mask)-> end_paint( mask);  
	return true;
#endif   
}

Point
apc_widget_get_size( Handle self)
{
	DEFXX;
	if ( XX-> type. window) {
		Rect rc;
		Point p = apc_window_get_client_size( self);
		prima_get_frame_info( self, &rc);
		p. x += rc. left + rc. right;
		p. y += rc. bottom + rc. top;
		return p;
	}   
	
	return XX-> size;
}

Bool
apc_widget_get_sync_paint( Handle self)
{
	return X(self)-> flags. sync_paint;
}

Bool
apc_widget_get_transparent( Handle self)
{
	return X(self)-> flags. transparent;
}

Bool
apc_widget_is_captured( Handle self)
{
	return X(self)-> flags. grab ? true : false;
}

Bool
apc_widget_is_enabled( Handle self)
{
	return XF_ENABLED(X(self)) ? true : false;
}

Bool
apc_widget_is_exposed( Handle self)
{
	return X(self)-> flags. exposed ? true : false;
}

Bool
apc_widget_is_focused( Handle self)
{
	return guts. focused == self;
}

Bool
apc_widget_is_responsive( Handle self)
{
	Bool ena = true;
	while ( ena && self != application) {
		ena  = XF_ENABLED(X(self)) ? true : false;
		self = PWidget(self)-> owner;
	}
	return ena;
}

Bool
apc_widget_is_showing( Handle self)
{
	XWindowAttributes attrs;
	DEFXX;

	if ( XX  
		&& XGetWindowAttributes( DISP, XX->udrawable, &attrs)
		&& attrs. map_state == IsViewable)
		return true;
	else
		return false;
}

Bool
apc_widget_is_visible( Handle self)
{
	return X(self)-> flags. want_visible ? true : false;
}

Bool
apc_widget_invalidate_rect( Handle self, Rect *rect)
{
	XRectangle r;
	DEFXX;

	if ( rect) {
		SORT( rect-> left,   rect-> right);
		SORT( rect-> bottom, rect-> top);
		r. x = rect-> left;
		r. width = rect-> right - rect-> left;
		r. y = XX-> size. y - rect-> top;
		r. height = rect-> top - rect-> bottom;
	} else {
		r. x = 0;
		r. width = XX-> size. x;
		r. y = 0;
		r. height = XX-> size. y;
	}

	if ( !XX-> invalid_region) {
		XX-> invalid_region = XCreateRegion();
		if ( !XX-> flags. paint_pending) {
			TAILQ_INSERT_TAIL( &guts.paintq, XX, paintq_link);
			XX-> flags. paint_pending = true;
		}
	}

	XUnionRectWithRegion( &r, XX-> invalid_region, XX-> invalid_region);
	if ( XX-> flags. sync_paint) {
		apc_widget_update( self);
	}
	process_transparents( self);
	return true;
}

static Bool 
scroll( Handle owner, Handle self, Point * delta)
{
	DEFXX;
	if ( XX-> flags. clip_owner)
		apc_widget_set_pos( self, XX-> origin. x + delta-> x, XX-> origin. y + delta-> y);
	return 0;
}

int
apc_widget_scroll( Handle self, int horiz, int vert,
						Rect *confine, Rect *clip, Bool withChildren)
{
	DEFXX;
	int src_x, src_y, w, h, dst_x, dst_y, iw, ih;
	XRectangle r;
	Region invalid, reg;

	prima_no_cursor( self);
	prima_get_gc( XX);
	XX-> gcv. clip_mask = None;
	XChangeGC( DISP, XX-> gc, VIRGIN_GC_MASK, &XX-> gcv);
	XCHECKPOINT;
	
	if ( confine) {
		SORT( confine-> left,   confine-> right);
		SORT( confine-> bottom, confine-> top);
		src_x = confine-> left;
		src_y = XX-> size. y - confine-> top;
		w = confine-> right - src_x;
		h = confine-> top - confine-> bottom;
	} else {
		src_x = 0;
		src_y = 0;
		w = XX-> size. x;
		h = XX-> size. y;
	}

	dst_x = src_x + horiz;
	dst_y = src_y - vert;
	iw = w;
	ih = h;

	if (clip) {
		XRectangle cpa;

		SORT( clip-> left,   clip-> right);
		SORT( clip-> bottom, clip-> top);

		r. x = clip-> left;
		r. y = REVERT( clip-> top) + 1;
		r. width = clip-> right - clip-> left;
		r. height = clip-> top - clip-> bottom;
		reg = XCreateRegion();
		XUnionRectWithRegion( &r, reg, reg);
		XSetRegion( DISP, XX-> gc, reg);
		XCHECKPOINT;
		XDestroyRegion( reg);
		cpa. x = src_x;
		cpa. y = src_y;
		cpa. width = w;
		cpa. height = h;
		prima_rect_intersect( &cpa, &r);
		dst_x += -src_x + cpa. x;
		dst_y += -src_y + cpa. y;
		src_x = cpa. x;
		src_y = cpa. y;
		w = cpa. width;
		h = cpa. height;
	}

	if ( src_x < XX-> size. x && src_x + w >= 0 && dst_x < XX-> size. x && dst_x + w >= 0 && 
		src_y < XX-> size. y && src_x + h >= 0 && dst_y < XX-> size. y && dst_y + h >= 0) {
		XGCValues gcv;
		gcv. graphics_exposures = true;
		XChangeGC( DISP, XX-> gc, GCGraphicsExposures, &gcv);
		XCopyArea( DISP, XX-> udrawable, XX-> udrawable, XX-> gc,
		      src_x, src_y, w, h, dst_x, dst_y);
		gcv. graphics_exposures = false;
		XChangeGC( DISP, XX-> gc, GCGraphicsExposures, &gcv);
	}
	prima_release_gc( XX);
	XCHECKPOINT;
	XFlush( DISP);

	r. x = src_x;
	r. y = src_y;
	r. width = w;
	r. height = h;
	invalid = XCreateRegion();
	if ( src_x < XX-> size. x && src_x + w >= 0 &&
		src_y < XX-> size. y && src_y + h >= 0) 
		XUnionRectWithRegion( &r, invalid, invalid);
	if ( clip &&
		dst_x < XX-> size. x && dst_x + iw >= 0 &&
		dst_y < XX-> size. y && dst_y + ih >= 0) {
		XRectangle cpa;
		cpa. x = dst_x;
		cpa. y = dst_y;
		cpa. width = iw;
		cpa. height = ih;
		XUnionRectWithRegion( &cpa, invalid, invalid);
	}

	if ( XX-> invalid_region) {
		reg = XCreateRegion();
		XUnionRegion( XX-> invalid_region, reg, reg);
		XIntersectRegion( reg, invalid, reg);
		XSubtractRegion( XX-> invalid_region, reg, XX-> invalid_region);
		XOffsetRegion( reg, horiz, -vert);
		XUnionRegion( XX-> invalid_region, reg, XX-> invalid_region);
		XDestroyRegion( reg);
	} else 
		XX-> invalid_region = XCreateRegion();

	if ( dst_x < XX-> size. x && dst_x + w >= 0 &&
		dst_y < XX-> size. y && dst_y + h >= 0) {
		r. x = dst_x;
		r. y = dst_y;
		reg = XCreateRegion();
		XUnionRectWithRegion( &r, reg, reg);
		XSubtractRegion( invalid, reg, invalid);
		XDestroyRegion( reg);
	}
	XUnionRegion( XX-> invalid_region, invalid, XX-> invalid_region);
	XDestroyRegion( invalid);
	if ( !XX-> flags. paint_pending) {
		TAILQ_INSERT_TAIL( &guts.paintq, XX, paintq_link);
		XX-> flags. paint_pending = true;
	}

	if ( withChildren) {
		Point delta;
		delta. x = horiz;
		delta. y = vert;
		CWidget(self)-> first_that( self, (void*)scroll, &delta);
	}
	
	return scrExpose;
}

Bool
apc_widget_set_capture( Handle self, Bool capture, Handle confineTo)
{
	int r;
	XWindow confine_to = None;
	DEFXX;

	if ( capture) {
		XWindow z = XX-> client;
		Time t = guts. last_time;
		Cursor cursor = XX-> flags. pointer_obscured ? prima_null_pointer() : 
				(( XX-> pointer_id == crUser) ?  XX-> user_pointer : XX-> actual_pointer);
		if ( confineTo && PWidget(confineTo)-> handle)
			confine_to = PWidget(confineTo)-> handle;
AGAIN:      
		r = XGrabPointer( DISP, z, false, 0
								| ButtonPressMask
								| ButtonReleaseMask
								| PointerMotionMask
								| ButtonMotionMask, GrabModeAsync, GrabModeAsync,
								confine_to, cursor, t);
		XCHECKPOINT;
		if ( r != GrabSuccess) {
			XWindow root = guts. root, rx;
			if (( r == GrabNotViewable) && ( root != z)) {
				XTranslateCoordinates( DISP, z, guts. root, 0, 0, 
					&guts. grab_translate_mouse.x, &guts. grab_translate_mouse.y, &rx);
				guts. grab_redirect = z;
				guts. grab_widget = self;
				z = root;
				goto AGAIN;
			} 
			if ( r == GrabInvalidTime) {
				t = CurrentTime;
				goto AGAIN;
			}  
			guts. grab_redirect = nilHandle;
			return false;
		} else {
			XX-> flags. grab   = true;
			guts. grab_widget  = self;
			guts. grab_confine = confineTo;
		}
	} else if ( XX-> flags. grab) {
		guts. grab_redirect = nilHandle;
		XUngrabPointer( DISP, CurrentTime);
		XCHECKPOINT;
		XX-> flags. grab = false;
		guts. grab_widget = nilHandle;
	}
	XFlush( DISP);
	return true;
}

Bool
apc_widget_set_color( Handle self, Color color, int i)
{
	Event e = {cmColorChanged};

	X(self)-> colors[ i] = color;
	if ( i == ciFore)
		apc_gp_set_color( self, color);
	else if ( i == ciBack)
		apc_gp_set_back_color( self, color);

	bzero( &e, sizeof(e));
	e. gen. source = self;
	e. gen. i      = i;
	apc_message( self, &e, false);

	return true;
}

Bool
apc_widget_set_enabled( Handle self, Bool enable)
{
	DEFXX;

	if ( enable == XF_ENABLED(XX)) return true;
	XF_ENABLED(XX) = enable;
	prima_simple_message(self, enable ? cmEnable : cmDisable, false);
	return true;
}

Bool
apc_widget_set_first_click( Handle self, Bool firstClick)
{
	X(self)-> flags. first_click = firstClick ? 1 : 0;
	return true;
}

static int
flush_refocus( Display * disp, XEvent * ev, void * dummy)
{
	return ev-> type == ClientMessage && 
			ev-> xclient. message_type == WM_PROTOCOLS &&
		(Atom) ev-> xclient. data. l[0] == WM_TAKE_FOCUS;
}

Bool
apc_widget_set_focused( Handle self)
{
	int rev;
	XWindow focus = None, xfoc;
	XEvent ev;
	if ( guts. message_boxes) return false;
	if ( self && ( self != CApplication( application)-> map_focus( application, self)))
		return false;
	if ( self) {
		if (XT_IS_WINDOW(X(self))) return true; /* already done in activate() */
		focus = X_WINDOW;
	}
	XGetInputFocus( DISP, &xfoc, &rev);
	if ( xfoc == focus) return true;

	{ /* code for no-wm environment */
		Handle who = ( Handle) hash_fetch( guts.windows, (void*)&xfoc, sizeof(xfoc)), x = self;
		while ( who && XT_IS_WINDOW(X(who))) who = PComponent( who)-> owner;
		while ( x && !XT_IS_WINDOW(X(x)) && X(x)->flags.clip_owner) x = PComponent( x)-> owner;
		if ( x && x != application && x != who && XT_IS_WINDOW(X(x)))
			XSetInputFocus( DISP, PComponent(x)-> handle, RevertToNone, guts. currentFocusTime);
	}

	XSetInputFocus( DISP, focus, RevertToParent, guts. currentFocusTime);
	XCHECKPOINT;
	
	XSync( DISP, false);
	while ( XCheckMaskEvent( DISP, FocusChangeMask|ExposureMask, &ev))
		prima_handle_event( &ev, nil);
	while ( XCheckIfEvent( DISP, &ev, (XIfEventProcType)flush_refocus, (XPointer)0));
	return true;
}

Bool
apc_widget_set_font( Handle self, PFont font)
{
	apc_gp_set_font( self, font);
	prima_simple_message( self, cmFontChanged, false);
	return true;
}

Bool
apc_widget_set_palette( Handle self)
{
	return prima_palette_replace( self, false);
}

Bool
apc_widget_set_pos( Handle self, int x, int y)
{
	DEFXX;
	Event e;
	if ( XX-> type. window) {
		Rect rc;
		prima_get_frame_info( self, &rc);
		return apc_window_set_client_pos( self, x + rc. left, y + rc. bottom);
	}   
	
	if ( XX-> parentHandle == nilHandle && x == XX-> origin.x && y == XX-> origin. y)
		return true;
	if ( XX-> client == guts. grab_redirect) {
		XWindow rx;
		XTranslateCoordinates( DISP, XX-> client, guts. root, 0, 0, 
			&guts. grab_translate_mouse.x, &guts. grab_translate_mouse.y, &rx);
	}
	bzero( &e, sizeof( e));
	e. cmd = cmMove;
	e. gen. source = self;
	XX-> origin. x = e. gen. P. x = x;
	XX-> origin. y = e. gen. P. y = y;
	y = X(XX-> owner)-> size. y - XX-> size.y - y;
	if ( XX-> parentHandle) {
		XWindow cld;
		XTranslateCoordinates( DISP, PWidget(XX-> owner)-> handle, XX-> parentHandle, x, y, &x, &y, &cld);
	} 
	XMoveWindow( DISP, X_WINDOW, x, y);
	XCHECKPOINT;
	apc_message( self, &e, false);
	if ( PObject( self)-> stage == csDead) return false; 
	if ( XX-> flags. transparent)
		apc_widget_invalidate_rect( self, nil);
	return true;
}

Bool
apc_widget_set_shape( Handle self, Handle mask)
{
#ifndef HAVE_X11_EXTENSIONS_SHAPE_H
	return false;
#else
	DEFXX;
	PImage img;
	Pixmap px;
	GC gc;
	XGCValues gcv;
	ImageCache * cache;
	int i;
	XRectangle xr;

	if ( !guts. shape_extension) return false; 
	
	if ( !mask) {
		if ( XX-> shape_extent. x == 0 || XX-> shape_extent. y == 0) return true;
		XShapeCombineMask( DISP, X_WINDOW, ShapeBounding, 0, 0, None, ShapeSet);
		if ( X_WINDOW != XX-> client)
			XShapeCombineMask( DISP, XX-> client, ShapeBounding, 0, 0, None, ShapeSet);
		XX-> shape_extent. x = XX-> shape_extent. y = 0;
		return true;
	}
	
	img = PImage(mask);
	cache = prima_create_image_cache(img, nilHandle, CACHE_BITMAP);
	if ( !cache) return false;
	px = XCreatePixmap(DISP, guts. root, img->w, img->h, 1);
	gcv. graphics_exposures = false;
	gc = XCreateGC(DISP, px, GCGraphicsExposures, &gcv);
	XSetForeground( DISP, gc, 0);
	prima_put_ximage(px, gc, cache->image, 0, 0, 0, 0, img->w, img->h);
	XFreeGC( DISP, gc);
	/*
		XXX This static shape approach doesn't work when menuHeight is dynamically changed.
			Need to implement something more elaborated.
	*/
	xr. x = 0;
	xr. y = 0;
	XShapeCombineMask( DISP, X_WINDOW, ShapeBounding, 0, XX->size.y - img->h + XX->menuHeight, px, ShapeSet);
	xr. width  = XX->size.x;
	xr. height = XX->size.y + XX->menuHeight;
	XShapeCombineRectangles( DISP, X_WINDOW, ShapeBounding, 0, 0, &xr, 1, ShapeInvert, 0);
	XFreePixmap( DISP, px);
	apc_image_update_change( mask);
	XX-> shape_extent. x = img-> w; 
	XX-> shape_extent. y = img-> h; 
	XX-> shape_offset. x = 0;
	XX-> shape_offset. y = XX-> menuHeight;
	return true;
#endif   
}

/* Used instead of XUnmapWindow sometimes because when a focused
	widget gets hidden, the X server's revert_to is sometimes
	weirdly set to RevertToPointerRoot ( mwm is the guilty one ) */
static void
apc_XUnmapWindow( Handle self)
{
	Handle z = guts. focused;
	while ( z) {
		if ( z == self) {
			if (PComponent(self)-> owner) {
				z = PComponent(self)-> owner;
				while ( z && !X(z)-> type. window) z = PComponent(z)-> owner;
				if ( z && z != application)
					XSetInputFocus( DISP, PComponent(z)-> handle, RevertToNone, guts. currentFocusTime);
			}
			break;
		}
		z = PComponent(z)-> owner;
	}
	XUnmapWindow( DISP, X_WINDOW);
}

void
prima_send_cmSize( Handle self, Point oldSize)
{
	DEFXX;
	Event e;

	bzero( &e, sizeof(e));
	e. gen. source = self;
	e. cmd = cmSize;
	e. gen. R. left = oldSize. x;
	e. gen. R. bottom = oldSize. y;
	e. gen. P. x = e. gen. R. right = XX-> size. x;
	e. gen. P. y = e. gen. R. top = XX-> size. y;
	{
		int i, y = XX-> size. y, count = PWidget( self)-> widgets. count;
		for ( i = 0; i < count; i++) {
			PWidget child = PWidget( PWidget( self)-> widgets. items[i]);
			if ((( PWidget(child)-> growMode & gmDontCare) == 0) &&
				( !X(child)-> flags. clip_owner || ( child-> owner == application))) {
				XMoveWindow( DISP, child-> handle, X(child)-> origin.x, y - X(child)-> size.y - X(child)-> origin. y);
			}
		}
	}
	apc_message( self, &e, false);
}   

Bool
apc_widget_set_size( Handle self, int width, int height)
{
	DEFXX;
	Point sz = XX-> size;
	PWidget widg = PWidget( self);
	int x, y;

	if ( XX-> type. window) {
		Rect rc;
		prima_get_frame_info( self, &rc);
		return apc_window_set_client_size( self, width - rc. left - rc. right, height - rc. bottom - rc. top);
	}   
	
	widg-> virtualSize. x = width;
	widg-> virtualSize. y = height;

	width = ( width >= widg-> sizeMin. x)
			? (( width <= widg-> sizeMax. x)
				? width
				: widg-> sizeMax. x)
			: widg-> sizeMin. x;

	height = ( height >= widg-> sizeMin. y)
			? (( height <= widg-> sizeMax. y)
				? height
				: widg-> sizeMax. y)
			: widg-> sizeMin. y;
	
	if ( XX-> parentHandle == nilHandle && XX-> size. x == width && XX-> size. y == height)
		return true;

	XX-> size. x = width;
	XX-> size. y = height;

	x = XX-> origin. x;
	y = X(XX-> owner)-> size. y - XX-> size.y - XX-> origin. y;
	if ( XX-> parentHandle) {
		XWindow cld;
		XTranslateCoordinates( DISP, PWidget(XX-> owner)-> handle, XX-> parentHandle, x, y, &x, &y, &cld);
	} 
	if ( width != 0 && height != 0) {
		if ( XX-> client != X_WINDOW)
			XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, width, height);
		XMoveResizeWindow( DISP, X_WINDOW, x, y, width, height);
		if ( XX-> flags. falsely_hidden) {
			if ( XX-> flags. want_visible) XMapWindow( DISP, X_WINDOW);
			XX-> flags. falsely_hidden = 0;
		}   
	} else {
		if ( XX-> flags. want_visible) apc_XUnmapWindow( self);  
		if ( XX-> client != X_WINDOW)
			XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, ( width == 0) ? 1 : width, ( height == 0) ? 1 : height);
		XMoveResizeWindow( DISP, X_WINDOW, x, y, ( width == 0) ? 1 : width, ( height == 0) ? 1 : height);
		XX-> flags. falsely_hidden = 1;
	}   
	prima_send_cmSize( self, sz);
	if ( PObject( self)-> stage == csDead) return false; 
	return true;
}

Bool
apc_widget_set_rect( Handle self, int x, int y, int width, int height)
{
	DEFXX;
	Point sz = XX-> size;
	PWidget widg = PWidget( self);
	Event e;

	if ( XX-> type. window) {
		Rect rc;
		prima_get_frame_info( self, &rc);
		return apc_window_set_client_rect( self, x + rc. left, y + rc. bottom, 
			width - rc. left - rc. right, height - rc. bottom - rc. top);
	}   
	
	widg-> virtualSize. x = width;
	widg-> virtualSize. y = height;

	width = ( width >= widg-> sizeMin. x)
			? (( width <= widg-> sizeMax. x)
				? width
				: widg-> sizeMax. x)
			: widg-> sizeMin. x;

	height = ( height >= widg-> sizeMin. y)
			? (( height <= widg-> sizeMax. y)
				? height
				: widg-> sizeMax. y)
			: widg-> sizeMin. y;
	
	if ( XX-> parentHandle == nilHandle && 
		XX-> size. x == width && XX-> size. y == height &&
		x == XX-> origin.x && y == XX-> origin. y)
		return true;

	if ( XX-> client == guts. grab_redirect) {
		XWindow rx;
		XTranslateCoordinates( DISP, XX-> client, guts. root, 0, 0, 
			&guts. grab_translate_mouse.x, &guts. grab_translate_mouse.y, &rx);
	}

	XX-> size. x = width;
	XX-> size. y = height;

	bzero( &e, sizeof( e));
	e. cmd = cmMove;
	e. gen. source = self;
	XX-> origin. x = e. gen. P. x = x;
	XX-> origin. y = e. gen. P. y = y;
	y = X(XX-> owner)-> size. y - height - XX-> origin. y;
	if ( XX-> parentHandle) {
		XWindow cld;
		XTranslateCoordinates( DISP, PWidget(XX-> owner)-> handle, XX-> parentHandle, x, y, &x, &y, &cld);
	} 
	if ( width != 0 && height != 0) {
		if ( XX-> client != X_WINDOW)
			XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, width, height);
		XMoveResizeWindow( DISP, X_WINDOW, x, y, width, height);
		if ( XX-> flags. falsely_hidden) {
			if ( XX-> flags. want_visible) XMapWindow( DISP, X_WINDOW);
			XX-> flags. falsely_hidden = 0;
		}   
	} else {
		if ( XX-> flags. want_visible) apc_XUnmapWindow( self);
		if ( XX-> client != X_WINDOW)
			XMoveResizeWindow( DISP, XX-> client, 0, XX-> menuHeight, ( width == 0) ? 1 : width, ( height == 0) ? 1 : height);
		XMoveResizeWindow( DISP, X_WINDOW, x, y, ( width == 0) ? 1 : width, ( height == 0) ? 1 : height);
		XX-> flags. falsely_hidden = 1;
	}   
	apc_message( self, &e, false);
	if ( PObject( self)-> stage == csDead) return false; 
	prima_send_cmSize( self, sz);
	if ( PObject( self)-> stage == csDead) return false; 
	if ( XX-> flags. transparent)
		apc_widget_invalidate_rect( self, nil);
	return true;
}

Bool
apc_widget_set_size_bounds( Handle self, Point min, Point max)
{
	DEFXX;
	if ( XX-> type. window) { 
		XSizeHints hints;
		bzero( &hints, sizeof( hints));
		apc_SetWMNormalHints( self, &hints);
	}
	return true;
}   

Bool
apc_widget_set_visible( Handle self, Bool show)
{
	DEFXX;
	int oldShow;
	if ( XX-> type. window)
		return apc_window_set_visible( self, show);
	
	oldShow = XX-> flags. want_visible ? 1 : 0;
	XX-> flags. want_visible = show;
	if ( !XX-> flags. falsely_hidden) {
		if ( show) 
			XMapWindow( DISP, X_WINDOW);
		else 
			apc_XUnmapWindow( self);
		XCHECKPOINT;
	}
	if ( oldShow != ( show ? 1 : 0))
		prima_simple_message(self, show ? cmShow : cmHide, false);
	return true;
}

Bool
apc_widget_set_z_order( Handle self, Handle behind, Bool top)
{
	XWindow windoze[2];

	/* top does not matter if behind is non-nil */
	if (behind) {
		windoze[0] = PComponent(behind)->handle;
		windoze[1] = X_WINDOW;
		XRestackWindows( DISP, windoze, 2);
		XCHECKPOINT;
	} else if (top) {
		XRaiseWindow( DISP, X_WINDOW);
		XCHECKPOINT;
	} else {
		XLowerWindow( DISP, X_WINDOW);
		XCHECKPOINT;
	}

	if ( X(self)-> type. window)
		prima_wm_sync( self, ConfigureNotify);
	else 
		prima_simple_message( self, cmZOrderChanged, false);
	return true;
}

Bool
apc_widget_update( Handle self)
{
	DEFXX;

	if ( XX-> invalid_region) {
		if ( XX-> flags. paint_pending) {
			TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
			XX-> flags. paint_pending = false;
		}
		prima_simple_message( self, cmPaint, false);
	}
	return true;
}

Bool
apc_widget_validate_rect( Handle self, Rect rect)
{
	XRectangle r;
	DEFXX;
	Region rgn;

	SORT( rect. left,   rect. right);
	SORT( rect. bottom, rect. top);


	r. x = rect. left;
	r. width = rect. right - rect. left;
	r. y = XX-> size. y - rect. top;
	r. height = rect. top - rect. bottom;

	if ( !XX-> invalid_region) 
		return true;
	
	if ( !( rgn = XCreateRegion())) 
		return false;
	
	XUnionRectWithRegion( &r, rgn, rgn);
	XSubtractRegion( XX-> invalid_region, rgn, XX-> invalid_region);
	XDestroyRegion( rgn);

	if ( XEmptyRegion( XX-> invalid_region)) {
		if ( XX-> flags. paint_pending) {
			TAILQ_REMOVE( &guts.paintq, XX, paintq_link);
			XX-> flags. paint_pending = false;
		}
		XDestroyRegion( XX-> invalid_region);
		XX-> invalid_region = nil;
	}   
	return true;
}

