void
EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
{
	if (fStream == NULL)
		return;

	BMessage* fakeMove = new BMessage(kFakeMouseMoved);
	if (fakeMove == NULL)
		return;

	fakeMove->AddMessenger("target", target.Messenger());
	fakeMove->AddInt32("view_token", viewToken);

	fStream->InsertEvent(fakeMove);
}
void
EventDispatcher::_EventLoop()
{
	BMessage* event;
	while (fStream->GetNextEvent(&event)) {
		BAutolock _(this);
		fLastUpdate = system_time();

		EventTarget* current = NULL;
		EventTarget* previous = NULL;
		bool pointerEvent = false;
		bool keyboardEvent = false;
		bool addedTokens = false;

		switch (event->what) {
			case kFakeMouseMoved:
				_SendFakeMouseMoved(event);
				break;
			case B_MOUSE_MOVED:
			{
				BPoint where;
				if (event->FindPoint("where", &where) == B_OK)
					fLastCursorPosition = where;

				if (fDraggingMessage)
					event->AddMessage("be:drag_message", &fDragMessage);

				if (!HasCursorThread()) {
					// There is no cursor thread, we need to move the cursor
					// ourselves
					BAutolock _(fCursorLock);

					if (fHWInterface != NULL) {
						fHWInterface->MoveCursorTo(fLastCursorPosition.x,
							fLastCursorPosition.y);
					}
				}

				// This is for B_NO_POINTER_HISTORY - we always want the
				// latest mouse moved event in the queue only
				if (fNextLatestMouseMoved == NULL)
					fNextLatestMouseMoved = fStream->PeekLatestMouseMoved();
				else if (fNextLatestMouseMoved != event) {
					// Drop older mouse moved messages if the server is lagging
					// too much (if the message is older than 100 msecs)
					bigtime_t eventTime;
					if (event->FindInt64("when", &eventTime) == B_OK) {
						if (system_time() - eventTime > 100000)
							break;
					}
				}

				// supposed to fall through
			}
			case B_MOUSE_DOWN:
			case B_MOUSE_UP:
			{
#ifdef TRACE_EVENTS
				if (event->what != B_MOUSE_MOVED)
					printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget);
#endif
				pointerEvent = true;

				if (fMouseFilter == NULL)
					break;

				EventTarget* mouseTarget = fPreviousMouseTarget;
				int32 viewToken = B_NULL_TOKEN;
				if (fMouseFilter->Filter(event, &mouseTarget, &viewToken,
						fNextLatestMouseMoved) == B_SKIP_MESSAGE) {
					// this is a work-around if the wrong B_MOUSE_UP
					// event is filtered out
					if (event->what == B_MOUSE_UP
						&& event->FindInt32("buttons") == 0) {
						fSuspendFocus = false;
						_RemoveTemporaryListeners();
					}
					break;
				}

				int32 buttons;
				if (event->FindInt32("buttons", &buttons) == B_OK)
					fLastButtons = buttons;
				else
					fLastButtons = 0;

				// The "where" field will be filled in by the receiver
				// (it's supposed to be expressed in local window coordinates)
				event->RemoveName("where");
				event->AddPoint("screen_where", fLastCursorPosition);

				if (event->what == B_MOUSE_MOVED
					&& fPreviousMouseTarget != NULL
					&& mouseTarget != fPreviousMouseTarget) {
					// Target has changed, we need to notify the previous target
					// that the mouse has exited its views
					addedTokens = _AddTokens(event, fPreviousMouseTarget,
						B_POINTER_EVENTS);
					if (addedTokens)
						_SetFeedFocus(event);

					_SendMessage(fPreviousMouseTarget->Messenger(), event,
						kMouseTransitImportance);
					previous = fPreviousMouseTarget;
				}

				current = fPreviousMouseTarget = mouseTarget;

				if (current != NULL) {
					int32 focusView = viewToken;
					addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS,
						fNextLatestMouseMoved, &focusView);

					bool noPointerHistoryFocus = focusView != viewToken;

					if (viewToken != B_NULL_TOKEN)
						event->AddInt32("_view_token", viewToken);

					if (addedTokens && !noPointerHistoryFocus)
						_SetFeedFocus(event);
					else if (noPointerHistoryFocus) {
						// No tokens were added or the focus shouldn't get a
						// mouse moved
						break;
					}

					_SendMessage(current->Messenger(), event,
						event->what == B_MOUSE_MOVED
							? kMouseMovedImportance : kStandardImportance);
				}
				break;
			}

			case B_KEY_DOWN:
			case B_KEY_UP:
			case B_UNMAPPED_KEY_DOWN:
			case B_UNMAPPED_KEY_UP:
			case B_MODIFIERS_CHANGED:
			case B_INPUT_METHOD_EVENT:
				ETRACE(("key event, focus = %p\n", fFocus));

				if (fKeyboardFilter != NULL
					&& fKeyboardFilter->Filter(event, &fFocus) == B_SKIP_MESSAGE)
					break;

				keyboardEvent = true;

				if (fFocus != NULL && _AddTokens(event, fFocus,
						B_KEYBOARD_EVENTS)) {
					// if tokens were added, we need to explicetly suspend
					// focus in the event - if not, the event is simply not
					// forwarded to the target
					addedTokens = true;

					if (!fSuspendFocus)
						_SetFeedFocus(event);
				}

				// supposed to fall through

			default:
				// TODO: the keyboard filter sets the focus - ie. no other
				//	focus messages that go through the event dispatcher can
				//	go through.
				if (event->what == B_MOUSE_WHEEL_CHANGED)
					current = fPreviousMouseTarget;
				else
					current = fFocus;

				if (current != NULL && (!fSuspendFocus || addedTokens)) {
					_SendMessage(current->Messenger(), event,
						kStandardImportance);
				}
				break;
		}

		if (keyboardEvent || pointerEvent) {
			// send the event to the additional listeners

			if (addedTokens) {
				_RemoveTokens(event);
				_UnsetFeedFocus(event);
			}
			if (pointerEvent) {
				// this is added in the Desktop mouse processing
				// but it's only intended for the focus view
				event->RemoveName("_view_token");
			}

			for (int32 i = fTargets.CountItems(); i-- > 0;) {
				EventTarget* target = fTargets.ItemAt(i);

				// We already sent the event to the all focus and last focus
				// tokens
				if (current == target || previous == target)
					continue;

				// Don't send the message if there are no tokens for this event
				if (!_AddTokens(event, target,
						keyboardEvent ? B_KEYBOARD_EVENTS : B_POINTER_EVENTS,
						event->what == B_MOUSE_MOVED
							? fNextLatestMouseMoved : NULL))
					continue;

				if (!_SendMessage(target->Messenger(), event,
						event->what == B_MOUSE_MOVED
							? kMouseMovedImportance : kListenerImportance)) {
					// the target doesn't seem to exist anymore, let's remove it
					fTargets.RemoveItemAt(i);
				}
			}

			if (event->what == B_MOUSE_UP && fLastButtons == 0) {
				// no buttons are pressed anymore
				fSuspendFocus = false;
				_RemoveTemporaryListeners();
				if (fDraggingMessage)
					_DeliverDragMessage();
			}
		}

		if (fNextLatestMouseMoved == event)
			fNextLatestMouseMoved = NULL;
		delete event;
	}

	// The loop quit, therefore no more events are coming from the input
	// server, it must have died. Unset ourselves and notify the desktop.
	fThread = -1;
		// Needed to avoid problems with wait_for_thread in _Unset()
	_Unset();

	if (fDesktop)
		fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED);
}