예제 #1
0
파일: screen.cpp 프로젝트: Tkachov/scummvm
void Screen::flushScaleImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp,
		int16 *width_, int16 *height_, int scaleVal) {
	Common::Point imgPos(pt.x + frame->sDrawXOffset(scaleVal), pt.y + frame->sDrawYOffset(scaleVal));
	Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->sDrawXSize(scaleVal),
		imgPos.y + frame->sDrawYSize(scaleVal));
	Common::Rect oldBounds(*xp, *yp, *xp + *width_, *yp + *height_);

	if (!_flushScreen) {
		// See if the areas of the old and new overlap, and if so combine the areas
		if (newBounds.intersects(oldBounds)) {
			Common::Rect mergedBounds = newBounds;
			mergedBounds.extend(oldBounds);
			mergedBounds.right += 1;
			mergedBounds.bottom += 1;

			slamRect(mergedBounds);
		} else {
			// The two areas are independent, so copy them both
			slamRect(newBounds);
			slamRect(oldBounds);
		}
	}

	*xp = newBounds.left;
	*yp = newBounds.top;
	*width_ = newBounds.width();
	*height_ = newBounds.height();
}
예제 #2
0
void RenderWidget::updateWidgetPosition()
{
    if (!m_widget)
        return;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = localToAbsolute();
    absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());

    int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight();
    int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom();

    IntRect newBounds(absPos.x(), absPos.y(), w, h);
    IntRect oldBounds(m_widget->frameRect());
    if (newBounds != oldBounds) {
        // The widget changed positions.  Update the frame geometry.
        if (checkForRepaintDuringLayout()) {
            RenderView* v = view();
            if (!v->printing()) {
                // FIXME: do container-relative repaint
                v->repaintRectangleInViewAndCompositedLayers(oldBounds);
                v->repaintRectangleInViewAndCompositedLayers(newBounds);
            }
        }

        RenderArena* arena = ref();
        element()->ref();
        m_widget->setFrameRect(newBounds);
        element()->deref();
        deref(arena);
    }
}
예제 #3
0
파일: screen.cpp 프로젝트: idkiller/scummvm
void Screen::flushImage(ImageFrame *frame, const Common::Point &pt, int16 *xp, int16 *yp, 
		int16 *width, int16 *height) {
	Common::Point imgPos = pt + frame->_offset;
	Common::Rect newBounds(imgPos.x, imgPos.y, imgPos.x + frame->_frame.w, imgPos.y + frame->_frame.h);
	Common::Rect oldBounds(*xp, *yp, *xp + *width, *yp + *height);

	if (!_flushScreen) {
		// See if the areas of the old and new overlap, and if so combine the areas
		if (newBounds.intersects(oldBounds)) {
			Common::Rect mergedBounds = newBounds;
			mergedBounds.extend(oldBounds);
			mergedBounds.right += 1;
			mergedBounds.bottom += 1;

			slamRect(mergedBounds);
		} else {
			// The two areas are independent, so copy them both
			slamRect(newBounds);
			slamRect(oldBounds);
		}
	}

	*xp = newBounds.left;
	*yp = newBounds.top;
	*width = newBounds.width();
	*height = newBounds.height();
}
예제 #4
0
void RenderWidget::updateWidgetPosition()
{
    if (!m_widget)
        return;

    // FIXME: This doesn't work correctly with transforms.
    FloatPoint absPos = localToAbsolute();
    absPos.move(borderLeft() + paddingLeft(), borderTop() + paddingTop());

    int w = width() - borderLeft() - borderRight() - paddingLeft() - paddingRight();
    int h = height() - borderTop() - borderBottom() - paddingTop() - paddingBottom();

    IntRect newBounds(absPos.x(), absPos.y(), w, h);
    IntRect oldBounds(m_widget->frameRect());
    bool boundsChanged = newBounds != oldBounds;
    if (boundsChanged) {
        RenderArena* arena = ref();
        node()->ref();
        m_widget->setFrameRect(newBounds);
        node()->deref();
        deref(arena);
    }
    
    // if the frame bounds got changed, or if view needs layout (possibly indicating
    // content size is wrong) we have to do a layout to set the right widget size
    if (m_widget->isFrameView()) {
        FrameView* frameView = static_cast<FrameView*>(m_widget.get());
        if (boundsChanged || frameView->needsLayout())
            frameView->layout();
    }
}
예제 #5
0
void RenderWidget::updateWidgetPosition()
{
    if (!m_widget)
        return;

    int x;
    int y;
    absolutePosition(x, y);
    x += borderLeft() + paddingLeft();
    y += borderTop() + paddingTop();

    int width = m_width - borderLeft() - borderRight() - paddingLeft() - paddingRight();
    int height = m_height - borderTop() - borderBottom() - paddingTop() - paddingBottom();

    IntRect newBounds(x, y, width, height);
    IntRect oldBounds(m_widget->frameGeometry());
    if (newBounds != oldBounds) {
        // The widget changed positions.  Update the frame geometry.
        if (checkForRepaintDuringLayout()) {
            RenderView* v = view();
            if (!v->printing()) {
                v->repaintViewRectangle(oldBounds);
                v->repaintViewRectangle(newBounds);
            }
        }

        RenderArena* arena = ref();
        element()->ref();
        m_widget->setFrameGeometry(newBounds);
        element()->deref();
        deref(arena);
    }
}
예제 #6
0
void TWindow::SetBounds(const TRect& bounds)
{
	if (fWindow)
		XMoveResizeWindow(sDisplay, fWindow, bounds.left, bounds.top, bounds.GetWidth(), bounds.GetHeight());
	
	// do the notification for child windows or unmapped windows.
	if ((!fWindow || fParent) && bounds != fBounds)
	{
		TRect oldBounds(fBounds);

		fBounds = bounds;
		NotifyBoundsChanged(oldBounds);
	}
} 
void SearchAgent::reset(const SteerLib::AgentInitialConditions & initialConditions, SteerLib::EngineInterface * engineInfo)
{
	// compute the "old" bounding box of the agent before it is reset.  its OK that it will be invalid if the agent was previously disabled
	// because the value is not used in that case.
	std::cout<<"Reset is called";
	Util::AxisAlignedBox oldBounds(__position.x-_radius, __position.x+_radius, 0.0f, 0.0f, __position.z-_radius, __position.z+_radius);

	// initialize the agent based on the initial conditions
	__position = initialConditions.position;
	_forward = initialConditions.direction;
	_radius = initialConditions.radius;
	_velocity = initialConditions.speed * Util::normalize(initialConditions.direction);

	// compute the "new" bounding box of the agent
	Util::AxisAlignedBox newBounds(__position.x-_radius, __position.x+_radius, 0.0f, 0.0f, __position.z-_radius, __position.z+_radius);

	if (!_enabled) {
		// if the agent was not enabled, then it does not already exist in the database, so add it.
		gSpatialDatabase->addObject( this, newBounds);
	}
	else {
		// if the agent was enabled, then the agent already existed in the database, so update it instead of adding it.
		gSpatialDatabase->updateObject( this, oldBounds, newBounds);
	}

	_enabled = true;

	if (initialConditions.goals.size() == 0) {
		throw Util::GenericException("No goals were specified!\n");
	}

	// iterate over the sequence of goals specified by the initial conditions.
	for (unsigned int i=0; i<initialConditions.goals.size(); i++) {
		if (initialConditions.goals[i].goalType == SteerLib::GOAL_TYPE_SEEK_STATIC_TARGET) {
			_goalQueue.push(initialConditions.goals[i]);
			if (initialConditions.goals[i].targetIsRandom) {
				// if the goal is random, we must randomly generate the goal.
				_goalQueue.back().targetLocation = gSpatialDatabase->randomPositionWithoutCollisions(1.0f, true);
			}
		}
		else {
			throw Util::GenericException("Unsupported goal type; SearchAgent only supports GOAL_TYPE_SEEK_STATIC_TARGET.");
		}
	}

	assert(_forward.length()!=0.0f);
	assert(_goalQueue.size() != 0);
	assert(_radius != 0.0f);
}
예제 #8
0
void CurveAgent::_doEulerStep(const Util::Vector & steeringDecisionForce, float dt)
{
	// compute acceleration, _velocity, and newPosition by a simple Euler step
	const Util::Vector clippedForce = Util::clamp(steeringDecisionForce, MAX_FORCE_MAGNITUDE);
	Util::Vector acceleration = (clippedForce / AGENT_MASS);
	_velocity = _velocity + (dt*acceleration);
	_velocity = clamp(_velocity, MAX_SPEED);  // clamp _velocity to the max speed
	const Util::Point newPosition = __position + (dt*_velocity);

	// For this simple agent, we just make the orientation point along the agent's current velocity.
	if (_velocity.lengthSquared() != 0.0f) {
		_forward = normalize(_velocity);
	}

	// update the database with the new agent's setup
	Util::AxisAlignedBox oldBounds(__position.x - _radius, __position.x + _radius, 0.0f, 0.0f, __position.z - _radius, __position.z + _radius);
	Util::AxisAlignedBox newBounds(newPosition.x - _radius, newPosition.x + _radius, 0.0f, 0.0f, newPosition.z - _radius, newPosition.z + _radius);
	gSpatialDatabase->updateObject( this, oldBounds, newBounds);

	__position = newPosition;
}
예제 #9
0
void CurveAgent::updateAI(float timeStamp, float dt, unsigned int frameNumber)
{
	//For this function, we assume that all goals are of type GOAL_TYPE_SEEK_STATIC_TARGET.
	//The error check for this was performed in reset().
	Util::AutomaticFunctionProfiler profileThisFunction( &CurveAIGlobals::gPhaseProfilers->aiProfiler );
	Util::Point newPosition;

	//Move one step on hermiteCurve
	if (!curve.calculatePoint(newPosition, timeStamp+dt))
	{
		disable();
		return;
	}

	//Update the database with the new agent's setup
	Util::AxisAlignedBox oldBounds(__position.x - _radius, __position.x + _radius, 0.0f, 0.0f, __position.z - _radius, __position.z + _radius);
	Util::AxisAlignedBox newBounds(newPosition.x - _radius, newPosition.x + _radius, 0.0f, 0.0f, newPosition.z - _radius, newPosition.z + _radius);
	gSpatialDatabase->updateObject(this, oldBounds, newBounds);

	//Update current position
	__position = newPosition;
}
예제 #10
0
void SearchAgent::updateAI(float timeStamp, float dt, unsigned int frameNumber)
{
	Util::AutomaticFunctionProfiler profileThisFunction( &SearchAIGlobals::gPhaseProfilers->aiProfiler );

	
	double steps = (DURATION/(double)__path.size());
	if(timeStamp*dt > last_waypoint*steps)
	{	
		if(!_goalQueue.empty())
		{
			Util::AxisAlignedBox oldBounds(__position.x - _radius, __position.x + _radius, 0.0f, 0.0f, __position.z - _radius, __position.z + _radius);

			__position = _goalQueue.front().targetLocation;
			std::cout << "Waypoint: " << __position;
			_goalQueue.pop();
			last_waypoint++;

			Util::AxisAlignedBox newBounds(__position.x - _radius, __position.x + _radius, 0.0f, 0.0f, __position.z - _radius, __position.z + _radius);
			gSpatialDatabase->updateObject(this, oldBounds, newBounds);
		}
	}
}
예제 #11
0
void CurveAgent::reset(const SteerLib::AgentInitialConditions & initialConditions, SteerLib::EngineInterface * engineInfo)
{
	// compute the "old" bounding box of the agent before it is reset.  its OK that it will be invalid if the agent was previously disabled
	// because the value is not used in that case.
	Util::AxisAlignedBox oldBounds(__position.x-_radius, __position.x+_radius, 0.0f, 0.0f, __position.z-_radius, __position.z+_radius);

	// initialize the agent based on the initial conditions
	__startPosition = initialConditions.position;
	__position = initialConditions.position;
	_forward = initialConditions.direction;
	_radius = initialConditions.radius;
	_velocity = initialConditions.speed * Util::normalize(initialConditions.direction);

	// Find random agent color
	if (initialConditions.colorSet)
		agentColor = initialConditions.color;
	else
	{
		std::random_device seed;
		std::default_random_engine generator(seed());
		std::uniform_real_distribution<float> distribution(0.0f, 0.8f);
		agentColor = Util::Color(distribution(generator), distribution(generator), distribution(generator));
	}

	// compute the "new" bounding box of the agent
	Util::AxisAlignedBox newBounds(__position.x-_radius, __position.x+_radius, 0.0f, 0.0f, __position.z-_radius, __position.z+_radius);

	if (!_enabled) {
		// if the agent was not enabled, then it does not already exist in the database, so add it.
		gSpatialDatabase->addObject( this, newBounds);
	}
	else {
		// if the agent was enabled, then the agent already existed in the database, so update it instead of adding it.
		gSpatialDatabase->updateObject( this, oldBounds, newBounds);
	}

	_enabled = true;

	if (initialConditions.goals.size() == 0) {
		throw Util::GenericException("No goals were specified!\n");
	}

	// iterate over the sequence of goals specified by the initial conditions.
	for (unsigned int i=0; i<initialConditions.goals.size(); i++) {
		if (initialConditions.goals[i].goalType == SteerLib::GOAL_TYPE_SEEK_STATIC_TARGET) {
			_goalQueue.push_back(initialConditions.goals[i]);
			if (initialConditions.goals[i].targetIsRandom) {
				// if the goal is random, we must randomly generate the goal.
				_goalQueue.back().targetLocation = gSpatialDatabase->randomPositionWithoutCollisions(1.0f, true);
			}
		}
		else {
			throw Util::GenericException("Unsupported goal type; CurveAgent only supports GOAL_TYPE_SEEK_STATIC_TARGET.");
		}
	}

	// Add control points to curve
	std::vector<Util::CurvePoint> controlPoints;
	Util::Vector startTangent(0.f, 0.f, 0.f);
	controlPoints.push_back(Util::CurvePoint(__position, startTangent, 0.f));
	for (int i = 0; i < _goalQueue.size(); i++)
	{
		controlPoints.push_back(Util::CurvePoint(_goalQueue[i].targetLocation, _goalQueue[i].targetTangent, _goalQueue[i].targetTime));
	}
	curve.addControlPoints(controlPoints);

	assert(_forward.length()!=0.0f);
	assert(_goalQueue.size() != 0);
	assert(_radius != 0.0f);
}
예제 #12
0
void TattooMap::showCloseUp(int closeUpNum) {
	Events &events = *_vm->_events;
	Screen &screen = *_vm->_screen;

	// Reset scroll position
	screen._currentScroll = Common::Point(0, 0);

	// Get the closeup images
	Common::String fname = Common::String::format("res%02d.vgs", closeUpNum + 1);
	ImageFile pic(fname);

	Point32 closeUp(_data[closeUpNum].x * 100, _data[closeUpNum].y * 100);
	Point32 delta((SHERLOCK_SCREEN_WIDTH / 2 - closeUp.x / 100) * 100 / CLOSEUP_STEPS,
		(SHERLOCK_SCREEN_HEIGHT / 2 - closeUp.y / 100) * 100 / CLOSEUP_STEPS);
	Common::Rect oldBounds(closeUp.x / 100, closeUp.y / 100, closeUp.x / 100 + 1, closeUp.y / 100 + 1);
	int size = 64;
	int n = 256;
	int deltaVal = 512;
	bool minimize = false;
	int scaleVal, newSize;

	do {
		scaleVal = n;
		newSize = pic[0].sDrawXSize(n);

		if (newSize > size) {
			if (minimize)
				deltaVal /= 2;
			n += deltaVal;
		} else {
			minimize = true;
			deltaVal /= 2;
			n -= deltaVal;
			if (n < 1)
				n = 1;
		}
	} while (deltaVal && size != newSize);

	int deltaScale = (SCALE_THRESHOLD - scaleVal) / CLOSEUP_STEPS;

	for (int step = 0; step < CLOSEUP_STEPS; ++step) {
		Common::Point picSize(pic[0].sDrawXSize(scaleVal), pic[0].sDrawYSize(scaleVal));
		Common::Point pt(closeUp.x / 100 - picSize.x / 2, closeUp.y / 100 - picSize.y / 2);

		restoreArea(oldBounds);
		screen._backBuffer1.transBlitFrom(pic[0], pt, false, 0, scaleVal);

		screen.slamRect(oldBounds);
		screen.slamArea(pt.x, pt.y, picSize.x, picSize.y);

		oldBounds = Common::Rect(pt.x, pt.y, pt.x + picSize.x + 1, pt.y + picSize.y + 1);
		closeUp += delta;
		scaleVal += deltaScale;

		events.wait(1);
	}

	// Handle final drawing of closeup
	// TODO: Handle scrolling
	Common::Rect r(SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2, SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2,
		SHERLOCK_SCREEN_WIDTH / 2 - pic[0]._width / 2 + pic[0]._width,
		SHERLOCK_SCREEN_HEIGHT / 2 - pic[0]._height / 2 + pic[0]._height);

	restoreArea(oldBounds);
	screen._backBuffer1.transBlitFrom(pic[0], Common::Point(r.left, r.top));
	screen.slamRect(oldBounds);
	screen.slamRect(r);
	events.wait(2);
}
예제 #13
0
void TWindow::HandleEvent(XEvent& event)
{
	TPoint	mouse;
	const TPoint& scroll = GetScroll();
	
	switch (event.type)
	{
		case Expose:
		{
			TRect	r(event.xexpose.x, event.xexpose.y, event.xexpose.x + event.xexpose.width, event.xexpose.y + event.xexpose.height);

			if (fUpdateRegion)
				fUpdateRegion->Union(r);
			else
			{
				fUpdateRegion = new TRegion(r);
				fNextUpdate = sFirstUpdate;
				sFirstUpdate = this;
			}
				
//			if (event.xexpose.count == 0)
//				Update();
		
			break;
		}

		case KeyPress:
		case KeyRelease:
		{			
			TTopLevelWindow* topLevel = GetTopLevelWindow();
			if (topLevel)
				topLevel->DispatchKeyEvent(event);
			break;
		}		
		
		case ButtonPress:
			if (event.xbutton.button >= 1 && event.xbutton.button <= 3)
			{
				fCurrentEventTime = event.xbutton.time;
				mouse.Set(event.xbutton.x + scroll.h, event.xbutton.y + scroll.v);

				// check for multiple clicks
				TTime now = gApplication->GetCurrentTime();
				if (now - fLastClickTime < kDoubleClickTime && 
					abs(fLastClick.h - mouse.h) <= kDoubleClickDelta &&
					abs(fLastClick.v - mouse.v) <= kDoubleClickDelta)
					++fClickCount;
				else
					fClickCount = 1;

				fLastClick = mouse;
				fLastClickTime = now;

				if (IsTargetable() && event.xbutton.button != 2)
					RequestTarget();
				
				HandleMouseDown(mouse, (TMouseButton)event.xbutton.button, event.xbutton.state);
			}
			else if (event.xbutton.button == 4 || event.xbutton.button == 5)
			{
				HandleScrollWheel(event.xbutton.button == 5);
			}
			break;

		case ButtonRelease:
			if (event.xbutton.button >= 1 && event.xbutton.button <= 3)
			{
				fCurrentEventTime = event.xbutton.time;
				mouse.Set(event.xbutton.x + scroll.h, event.xbutton.y + scroll.v);
				HandleMouseUp(mouse, (TMouseButton)event.xbutton.button, event.xbutton.state);
			}
			break;

		case EnterNotify:
			fCurrentEventTime = event.xcrossing.time;
			mouse.Set(event.xcrossing.x + scroll.h, event.xcrossing.y + scroll.v);
			HandleMouseEnter(mouse, event.xcrossing.state);
			break;

		case LeaveNotify:
			fCurrentEventTime = event.xcrossing.time;
			mouse.Set(event.xcrossing.x + scroll.h, event.xcrossing.y + scroll.v);
			HandleMouseLeave(mouse, event.xcrossing.state);
			break;

		case MotionNotify:
		{
			// avoid getting too many MotionNotify events by ignoring them if we have more in the queue
			XEvent testEvent;
			if (XPending(sDisplay) > 0 && XCheckTypedWindowEvent(sDisplay, event.xany.window, MotionNotify, &testEvent))
				break;

			fLastMouseMovedLocation.Set(event.xmotion.x, event.xmotion.y);
			fLastMouseMovedModifiers = event.xmotion.state;
			fCurrentEventTime = event.xmotion.time;
			mouse.Set(event.xmotion.x + scroll.h, event.xmotion.y + scroll.v);
			HandleMouseMoved(mouse, event.xmotion.state);
			break;
		}

		case FocusIn:
		{
			if (event.xfocus.detail == NotifyAncestor ||  
				event.xfocus.detail == NotifyInferior ||
				event.xfocus.detail == NotifyNonlinear ||
				event.xfocus.detail == NotifyNonlinearVirtual)
			{
				if (event.xfocus.mode != NotifyGrab &&
					event.xfocus.mode != NotifyUngrab)	// these events confuse XIM, according to gdk comment
				{
					TTopLevelWindow* topLevel = GetTopLevelWindow();
					if (topLevel)
						topLevel->GotFocus(this);
					break;
				}
			}
		}
			
		case FocusOut:
		{
			if (event.xfocus.detail == NotifyAncestor ||  
				event.xfocus.detail == NotifyInferior ||
				event.xfocus.detail == NotifyNonlinear ||
				event.xfocus.detail == NotifyNonlinearVirtual)
			{
				if (event.xfocus.mode != NotifyGrab &&
					event.xfocus.mode != NotifyUngrab)	// these events confuse XIM, according to gdk comment
				{
					TTopLevelWindow* topLevel = GetTopLevelWindow();
					if (topLevel)
						topLevel->LostFocus(this);
					break;
				}
			}
		}	
				
		case KeymapNotify:
//			printf("KeymapNotify\n");
			break;
			
		case GraphicsExpose:
//			printf("GraphicsExpose\n");
			break;
			
		case NoExpose:
//mgl why are we getting these when drawing scrollbars?
//			printf("NoExpose\n");
			break;
			
		case VisibilityNotify:
			fObscured = (event.xvisibility.state != VisibilityUnobscured);
			break;
			
		case CreateNotify:
			printf("CreateNotify\n");
			break;
			
		case DestroyNotify:
			printf("DestroyNotify\n");
			break;
			
		case MapNotify:
			DoMapped(true);
			break;

		case UnmapNotify:
			DoMapped(false);
			break;
			
		case MapRequest:
			printf("MapRequest\n");
			break;
			
		case ReparentNotify:
//			printf("ReparentNotify\n");
			break;
			
		case ConfigureNotify:
		{
			// we manage child window notification ourselves
			if (fParent == NULL)
			{
				TRect oldBounds(fBounds);
				fBounds.Set(event.xconfigure.x, event.xconfigure.y, 
							event.xconfigure.x + event.xconfigure.width,
							event.xconfigure.y + event.xconfigure.height);
	
				NotifyBoundsChanged(oldBounds);
			}
			break;
		}
			
		case ConfigureRequest:
			printf("ConfigureRequest\n");
			break;
			
		case GravityNotify:
			printf("GravityNotify\n");
			break;
			
		case ResizeRequest:
			printf("ResizeRequest\n");
			break;
			
		case CirculateNotify:
			printf("CirculateNotify\n");
			break;
			
		case CirculateRequest:
			printf("CirculateRequest\n");
			break;
			
		case PropertyNotify:
			printf("PropertyNotify\n");
			break;
			
		case SelectionClear:
		{
			if (fIsSelectionOwner)
			{
				LostSelectionOwnership();
				fIsSelectionOwner = false;
			}
			break;
		}
			
		case SelectionRequest:
		{
			XSelectionEvent response;

			response.type = SelectionNotify;
			response.display = event.xselectionrequest.display;
			response.requestor = event.xselectionrequest.requestor;
			response.selection = event.xselectionrequest.selection;
			response.target = event.xselectionrequest.target;
			response.property = event.xselectionrequest.property;
			response.time = event.xselectionrequest.time;
			
			Atom	targetAtom = XInternAtom(event.xselectionrequest.display, "TARGETS", false);
			
			if (event.xselectionrequest.target == targetAtom)
			{
				Atom				targets[] = { XA_STRING };
				int					result;
				
				result = XChangeProperty(event.xselectionrequest.display,
										 event.xselectionrequest.requestor,
										 event.xselectionrequest.property,
										 event.xselectionrequest.target,
										 8,
										 PropModeReplace,
										 (const unsigned char*)targets,
										 sizeof(targets));
							   
				if (result == BadAlloc || result == BadAtom || result == BadMatch || result == BadValue || result == BadWindow)
					printf ("SelectionRequest - XChangeProperty failed: %d\n", result);
				
				response.send_event = true;
			}
			else
			{
				unsigned char* data;
				uint32 length;
				Atom type = event.xselectionrequest.target;
				if (response.selection == XA_PRIMARY && RequestSelectionData(type, data, length))
				{
					response.target = type;
					XChangeProperty(response.display, response.requestor, event.xselectionrequest.property, type, 
									8, PropModeReplace, data, length);
					free(data);
				}
				else
					response.property = None;
			}

			XSendEvent(sDisplay, response.requestor, false, NoEventMask, (XEvent *)&response);	
			break;
		}
			
		case SelectionNotify:
		{
			if (event.xselection.property != None)
			{
				Atom type;
				unsigned long items, length, remaining;
				int actualFormat;
				unsigned char*	data;

				// first compute the length
				XGetWindowProperty(sDisplay, fWindow, event.xselection.property, 0, 0, false, AnyPropertyType,
								&type, &actualFormat, &items, &length, &data);
				if (data)
					XFree(data);

				// now get the data
				XGetWindowProperty(sDisplay, fWindow, event.xselection.property, 0, length, true, AnyPropertyType,
								&type, &actualFormat, &items, &remaining, &data);
				ASSERT(remaining == 0);

				ReceiveSelectionData(type, data, length);
				XFree(data);
			}			
			
			break;
		}
			
		case ColormapNotify:
			printf("ColormapNotify\n");
			break;
			
		case ClientMessage:
			if ((Atom)event.xclient.data.l[0] == sDeleteWindowAtom)
			{
				Close();
			}
			else if ((Atom)event.xclient.data.l[0] == sTakeFocusAtom)
			{
/*				TTopLevelWindow* topLevel = GetTopLevelWindow();
				ASSERT(topLevel == this);
				topLevel->TakeFocus();
*/				
			}
			else
				printf("unknown ClientMessage\n");
			break;
			
		case MappingNotify:
			printf("MappingNotify\n");
			break;
			
		default:
			break;
	}
}
void ResizeGesture::doResize(bool scaleContent)
{
	PageItem* currItem = m_doc->m_Selection->itemAt(0);
	QString targetName = Um::SelectionGroup;
	QPixmap* targetIcon = Um::IGroup;
	if (!m_doc->m_Selection->isMultipleSelection())
	{
		targetName = currItem->getUName();
		targetIcon = currItem->getUPixmap();
	}
	if (!m_transactionStarted)
	{
		m_transactionStarted = new UndoTransaction(Um::instance()->beginTransaction(targetName, targetIcon,
																					Um::Resize, "", Um::IResize));
//		qDebug() << "ResizeGesture::doResize: begin transaction" << m_transactionStarted;
	}
	QRectF newBounds = m_bounds.normalized();
	double dw = (newBounds.width() - m_extraWidth) - currItem->width();
	double dh = (newBounds.height() - m_extraHeight) - currItem->height();
	double dsch = 1.0;
	double dscw = 1.0;
	if (currItem->isArc())
	{
		PageItem_Arc* item = currItem->asArc();
		if (currItem->height() != 0.0)
			dsch = item->arcHeight / currItem->height();
		if (currItem->width() != 0.0)
			dscw = item->arcWidth / currItem->width();
	}
	if (m_doc->m_Selection->isMultipleSelection())
	{
		int RotModeBack = m_doc->RotMode();
		m_doc->RotMode ( 0 );
		double gx, gy, gh, gw;
		m_doc->m_Selection->getGroupRect(&gx, &gy, &gw, &gh);
		QRectF oldBounds(gx, gy, gw, gh);
		double scx = oldBounds.width() == 0? 1.0 : (newBounds.width() - m_extraWidth) / oldBounds.width();
		double scy = oldBounds.height() == 0? 1.0 : (newBounds.height() - m_extraHeight) / oldBounds.height();
		//CB #3012 only scale text in a group if alt is pressed
		if ((currItem->itemType() == PageItem::TextFrame) && scaleContent)
			m_doc->scaleGroup(scx, scy, true);
		else
			m_doc->scaleGroup(scx, scy, false);
		double dx = newBounds.x() - oldBounds.x();
		double dy = newBounds.y() - oldBounds.y();
		if (dx != 0 || dy != 0)
			m_doc->moveGroup(dx + m_extraX, dy + m_extraY);
		m_doc->RotMode ( RotModeBack );
	}
	else
	{
		if (currItem->itemType() == PageItem::ImageFrame && scaleContent)
		{
			double divX = (currItem->width() != 0) ? currItem->width() : 1.0;
			double divY = (currItem->height() != 0) ? currItem->height() : 1.0;
			double imgScX = (newBounds.width() - m_extraWidth) / divX * currItem->imageXScale();
			double imgScY = (newBounds.height() - m_extraHeight) / divY * currItem->imageYScale();
			// The aspect ratio has been fixed, so make the modification in the direction of the larger movement.
			if (currItem->keepAspectRatio() && currItem->fitImageToFrame()) 
			{
				if (qAbs((newBounds.width() - m_extraWidth) - currItem->width()) > qAbs((newBounds.height() - m_extraHeight) - currItem->height()))
					imgScY = imgScX;
				else
					imgScX = imgScY;
			}
			currItem->setImageXYScale(imgScX, imgScY);
		}
		else if (currItem->itemType() == PageItem::ImageFrame && currItem->PictureIsAvailable)
		{
			double dx = ((newBounds.x() + m_extraX) - currItem->xPos());
			double dy = ((newBounds.y() + m_extraY) - currItem->yPos());
			double cosa = cos(currItem->rotation() * M_PI / 180.0);
			double sina = sin(currItem->rotation() * M_PI / 180.0);
			double xoff = -(cosa*dx + sina*dy);
			if (currItem->imageFlippedH())
				xoff += (currItem->width() - (newBounds.width() - m_extraWidth));
			double yoff = -(cosa*dy - sina*dx);
			if (currItem->imageFlippedV())
				yoff += (currItem->height() - (newBounds.height() - m_extraHeight));
			if (xoff != 0.0 || yoff != 0.0)
			{
				currItem->moveImageInFrame(xoff / currItem->imageXScale(), yoff / currItem->imageYScale());
			}
		}
		// We do not want to scale the text of a linked frame
		// as it would alter text in other frames of the string
		else if((currItem->itemType() == PageItem::TextFrame) 
				       && (currItem->nextInChain() == 0) 
				       && (currItem->prevInChain() == 0) 
				       && scaleContent)
		{
			double divX = (currItem->width() != 0) ? currItem->width() : 1.0;
			double divY = (currItem->height() != 0) ? currItem->height() : 1.0;
			double txtScX = (newBounds.width() - m_extraWidth) / divX;
			double txtScY = (newBounds.height() - m_extraHeight) / divY;
			if (currItem->itemText.length() != 0)
			{
				for (int aa = 0; aa < currItem->itemText.length(); ++aa)
				{
#if 0 // hard to decide if it’s batter to scale or to change font size
					currItem->itemText.item(aa)->setScaleV(
							qMax(qMin(qRound(currItem->itemText.item(aa)->scaleV()*txtScY), 4000), 100));
					currItem->itemText.item(aa)->setScaleH(
							qMax(qMin(qRound(currItem->itemText.item(aa)->scaleH() * txtScX), 4000), 100));
#else
					currItem->itemText.item(aa)->setFontSize(
							qMax(qMin(currItem->itemText.item(aa)->fontSize() * txtScY, 4000.0), 1.0));
					currItem->itemText.item(aa)->setScaleH(
							qMax(qMin(qRound(currItem->itemText.item(aa)->scaleH() * txtScX / txtScY), 4000), 100));
#endif

					// We need to scale the linespacing _only once_ per paragraph.
					if((aa == 0) 
						|| ( SpecialChars::isBreak(currItem->itemText.itemText(aa - 1).at(0))))
					{
						ParagraphStyle ps(currItem->itemText.paragraphStyle(aa));
						double oldLS(currItem->itemText.paragraphStyle(aa).lineSpacing());
						ps.setLineSpacing(qMax(qRound(oldLS * txtScY), 1));
						currItem->itemText.setStyle(aa,ps);
					}
				}
			}
		}
		currItem->setXYPos(newBounds.x() + m_extraX, newBounds.y() + m_extraY);
		currItem->setWidth(newBounds.width() - m_extraWidth);
		currItem->setHeight(newBounds.height() - m_extraHeight);
		currItem->updateClip();
		if (currItem->isArc())
		{
			PageItem_Arc* item = currItem->asArc();
			item->arcWidth += dw * dscw;
			item->arcHeight += dh * dsch;
			item->recalcPath();
			FPoint tp2(getMinClipF(&currItem->PoLine));
			currItem->PoLine.translate(-tp2.x(), -tp2.y());
			m_doc->AdjustItemSize(currItem);
		}
		if (currItem->isSpiral())
		{
			PageItem_Spiral* item = currItem->asSpiral();
			item->recalcPath();
		}
		// rotation does not change
	}
	m_origBounds = m_bounds;
}