xref: /haiku/src/servers/app/EventDispatcher.cpp (revision 1acbe440b8dd798953bec31d18ee589aa3f71b73)
1 /*
2  * Copyright 2005-2006, Haiku, Inc. All Rights Reserved.
3  * Distributed under the terms of the MIT License.
4  *
5  * Authors:
6  *		Axel Dörfler, axeld@pinc-software.de
7  */
8 
9 
10 #include "EventDispatcher.h"
11 
12 #include "BitmapManager.h"
13 #include "Desktop.h"
14 #include "EventStream.h"
15 #include "HWInterface.h"
16 #include "InputManager.h"
17 #include "ServerBitmap.h"
18 
19 #include <MessagePrivate.h>
20 #include <ServerProtocol.h>
21 #include <TokenSpace.h>
22 
23 #include <Autolock.h>
24 #include <View.h>
25 
26 #include <new>
27 #include <stdio.h>
28 #include <string.h>
29 
30 
31 //#define TRACE_EVENTS
32 #ifdef TRACE_EVENTS
33 #	define ETRACE(x) printf x
34 #else
35 #	define ETRACE(x) ;
36 #endif
37 
38 
39 /*!
40 	The EventDispatcher is a per Desktop object that handles all input
41 	events for that desktop.
42 
43 	The events are processed as needed in the Desktop class (via EventFilters),
44 	and then forwarded to the actual target of the event, a client window
45 	(or more correctly, to its EventTarget).
46 	You cannot set the target of an event directly - the event filters need
47 	to specify the targets.
48 	The event loop will make sure that every target and interested listener
49 	will get the event - it also delivers mouse moved events to the previous
50 	target once so that this target can then spread the B_EXITED_VIEW transit
51 	to the local target handler (usually a BView).
52 
53 	If you look at the event_listener structure below, the differentiation
54 	between target and token may look odd, but it really has a reason as
55 	well:
56 	All events are sent to the preferred window handler only - the window
57 	may then use the token or token list to identify the specific target
58 	view(s). This makes it possible to send every event only once, no
59 	matter how many local target handlers there are.
60 */
61 
62 struct event_listener {
63 	int32		token;
64 	uint32		event_mask;
65 	uint32		options;
66 	uint32		temporary_event_mask;
67 	uint32		temporary_options;
68 
69 	uint32		EffectiveEventMask() const { return event_mask | temporary_event_mask; }
70 	uint32		EffectiveOptions() const { return options | temporary_options; }
71 };
72 
73 static const char* kTokenName = "_token";
74 
75 static const float kMouseMovedImportance = 0.1f;
76 static const float kMouseTransitImportance = 1.0f;
77 static const float kStandardImportance = 0.9f;
78 static const float kListenerImportance = 0.8f;
79 
80 
81 EventTarget::EventTarget()
82 	:
83 	fListeners(2, true)
84 {
85 }
86 
87 
88 EventTarget::~EventTarget()
89 {
90 }
91 
92 
93 void
94 EventTarget::SetTo(const BMessenger& messenger)
95 {
96 	fMessenger = messenger;
97 }
98 
99 
100 event_listener*
101 EventTarget::FindListener(int32 token, int32* _index)
102 {
103 	for (int32 i = fListeners.CountItems(); i-- > 0;) {
104 		event_listener* listener = fListeners.ItemAt(i);
105 
106 		if (listener->token == token) {
107 			if (_index)
108 				*_index = i;
109 			return listener;
110 		}
111 	}
112 
113 	return NULL;
114 }
115 
116 
117 bool
118 EventTarget::_RemoveTemporaryListener(event_listener* listener, int32 index)
119 {
120 	if (listener->event_mask == 0) {
121 		// this is only a temporary target
122 		ETRACE(("events: remove temp. listener: token %ld, eventMask = %ld, options = %ld\n",
123 			listener->token, listener->temporary_event_mask, listener->temporary_options));
124 
125 		fListeners.RemoveItemAt(index);
126 		delete listener;
127 		return true;
128 	}
129 
130 	if (listener->temporary_event_mask != 0) {
131 		ETRACE(("events: clear temp. listener: token %ld, eventMask = %ld, options = %ld\n",
132 			listener->token, listener->temporary_event_mask, listener->temporary_options));
133 
134 		listener->temporary_event_mask = 0;
135 		listener->temporary_options = 0;
136 	}
137 
138 	return false;
139 }
140 
141 
142 void
143 EventTarget::RemoveTemporaryListeners()
144 {
145 	for (int32 index = CountListeners(); index-- > 0;) {
146 		event_listener* listener = ListenerAt(index);
147 
148 		_RemoveTemporaryListener(listener, index);
149 	}
150 }
151 
152 
153 bool
154 EventTarget::RemoveTemporaryListener(int32 token)
155 {
156 	int32 index;
157 	event_listener* listener = FindListener(token, &index);
158 	if (listener == NULL)
159 		return false;
160 
161 	return _RemoveTemporaryListener(listener, index);
162 }
163 
164 
165 bool
166 EventTarget::RemoveListener(int32 token)
167 {
168 	int32 index;
169 	event_listener* listener = FindListener(token, &index);
170 	if (listener == NULL)
171 		return false;
172 
173 	if (listener->temporary_event_mask != 0) {
174 		// we still need this event
175 		listener->event_mask = 0;
176 		listener->options = 0;
177 		return false;
178 	}
179 
180 	fListeners.RemoveItemAt(index);
181 	delete listener;
182 	return true;
183 }
184 
185 
186 bool
187 EventTarget::AddListener(int32 token, uint32 eventMask,
188 	uint32 options, bool temporary)
189 {
190 	event_listener* listener = new (std::nothrow) event_listener;
191 	if (listener == NULL)
192 		return false;
193 
194 	listener->token = token;
195 
196 	if (temporary) {
197 		listener->event_mask = 0;
198 		listener->options = 0;
199 		listener->temporary_event_mask = eventMask;
200 		listener->temporary_options = options;
201 	} else {
202 		listener->event_mask = eventMask;
203 		listener->options = options;
204 		listener->temporary_event_mask = 0;
205 		listener->temporary_options = 0;
206 	}
207 
208 	bool success = fListeners.AddItem(listener);
209 	if (!success)
210 		delete listener;
211 
212 	return success;
213 }
214 
215 
216 //	#pragma mark -
217 
218 
219 void
220 EventFilter::RemoveTarget(EventTarget* target)
221 {
222 }
223 
224 
225 //	#pragma mark -
226 
227 
228 EventDispatcher::EventDispatcher()
229 	: BLocker("event dispatcher"),
230 	fStream(NULL),
231 	fThread(-1),
232 	fCursorThread(-1),
233 	fPreviousMouseTarget(NULL),
234 	fFocus(NULL),
235 	fSuspendFocus(false),
236 	fMouseFilter(NULL),
237 	fKeyboardFilter(NULL),
238 	fTargets(10),
239 	fNextLatestMouseMoved(NULL),
240 	fCursorLock("cursor loop lock"),
241 	fHWInterface(NULL),
242 	fDesktop(NULL)
243 {
244 }
245 
246 
247 EventDispatcher::~EventDispatcher()
248 {
249 	_Unset();
250 }
251 
252 
253 status_t
254 EventDispatcher::SetTo(EventStream* stream)
255 {
256 	ETRACE(("event dispatcher: stream = %p\n", stream));
257 
258 	_Unset();
259 
260 	if (stream == NULL)
261 		return B_OK;
262 
263 	fStream = stream;
264 	return _Run();
265 }
266 
267 
268 status_t
269 EventDispatcher::InitCheck()
270 {
271 	if (fStream != NULL) {
272 		if (fThread < B_OK)
273 			return fThread;
274 
275 		return B_OK;
276 	}
277 	return B_NO_INIT;
278 }
279 
280 
281 void
282 EventDispatcher::_Unset()
283 {
284 	if (fStream == NULL)
285 		return;
286 
287 	fStream->SendQuit();
288 
289 	status_t status;
290 	wait_for_thread(fThread, &status);
291 	wait_for_thread(fCursorThread, &status);
292 
293 	fThread = fCursorThread = -1;
294 
295 	gInputManager->PutStream(fStream);
296 	fStream = NULL;
297 }
298 
299 
300 status_t
301 EventDispatcher::_Run()
302 {
303 	fThread = spawn_thread(_event_looper, "event loop",
304 		B_REAL_TIME_DISPLAY_PRIORITY - 10, this);
305 	if (fThread < B_OK)
306 		return fThread;
307 
308 	if (fStream->SupportsCursorThread()) {
309 		ETRACE(("event stream supports cursor thread!\n"));
310 
311 		fCursorThread = spawn_thread(_cursor_looper, "cursor loop",
312 			B_REAL_TIME_DISPLAY_PRIORITY - 5, this);
313 		if (resume_thread(fCursorThread) != B_OK) {
314 			kill_thread(fCursorThread);
315 			fCursorThread = -1;
316 		}
317 	}
318 
319 	return resume_thread(fThread);
320 }
321 
322 
323 /*!
324 	\brief Removes any reference to the target, but doesn't delete it.
325 */
326 void
327 EventDispatcher::RemoveTarget(EventTarget& target)
328 {
329 	BAutolock _(this);
330 
331 	if (fFocus == &target)
332 		fFocus = NULL;
333 	if (fPreviousMouseTarget == &target)
334 		fPreviousMouseTarget = NULL;
335 
336 	if (fKeyboardFilter != NULL)
337 		fKeyboardFilter->RemoveTarget(&target);
338 	if (fMouseFilter != NULL)
339 		fMouseFilter->RemoveTarget(&target);
340 
341 	fTargets.RemoveItem(&target);
342 }
343 
344 
345 /*!
346 	\brief Adds the specified listener or updates its event mask and options
347 		if already added.
348 
349 	It follows the BView semantics in that specifiying an event mask of zero
350 	leaves the event mask untouched and just updates the options.
351 */
352 bool
353 EventDispatcher::_AddListener(EventTarget& target, int32 token,
354 	uint32 eventMask, uint32 options, bool temporary)
355 {
356 	BAutolock _(this);
357 
358 	if (temporary && fLastButtons == 0) {
359 		// only allow to add temporary listeners in case a buttons is pressed
360 		return false;
361 	}
362 
363 	if (!fTargets.HasItem(&target))
364 		fTargets.AddItem(&target);
365 
366 	event_listener* listener = target.FindListener(token);
367 	if (listener != NULL) {
368 		// we already have this target, update its event mask
369 		if (temporary) {
370 			if (eventMask != 0)
371 				listener->temporary_event_mask = eventMask;
372 			listener->temporary_options = options;
373 		} else {
374 			if (eventMask != 0)
375 				listener->event_mask = eventMask;
376 			listener->options = options;
377 		}
378 
379 		return true;
380 	}
381 
382 	if (eventMask == 0)
383 		return false;
384 
385 	ETRACE(("events: add listener: token %ld, eventMask = %ld, options = %ld, %s\n",
386 		token, eventMask, options, temporary ? "temporary" : "permanent"));
387 
388 	// we need a new target
389 
390 	bool success = target.AddListener(token, eventMask, options, temporary);
391 	if (!success) {
392 		if (target.IsEmpty())
393 			fTargets.RemoveItem(&target);
394 	} else {
395 		if (options & B_SUSPEND_VIEW_FOCUS)
396 			fSuspendFocus = true;
397 	}
398 
399 	return success;
400 }
401 
402 
403 void
404 EventDispatcher::_RemoveTemporaryListeners()
405 {
406 	for (int32 i = fTargets.CountItems(); i-- > 0;) {
407 		EventTarget* target = fTargets.ItemAt(i);
408 
409 		target->RemoveTemporaryListeners();
410 	}
411 }
412 
413 
414 bool
415 EventDispatcher::AddListener(EventTarget& target, int32 token,
416 	uint32 eventMask, uint32 options)
417 {
418 	options &= B_NO_POINTER_HISTORY;
419 		// that's currently the only allowed option
420 
421 	return _AddListener(target, token, eventMask, options, false);
422 }
423 
424 
425 bool
426 EventDispatcher::AddTemporaryListener(EventTarget& target,
427 	int32 token, uint32 eventMask, uint32 options)
428 {
429 	return _AddListener(target, token, eventMask, options, true);
430 }
431 
432 
433 void
434 EventDispatcher::RemoveListener(EventTarget& target, int32 token)
435 {
436 	BAutolock _(this);
437 	ETRACE(("events: remove listener token %ld\n", token));
438 
439 	if (target.RemoveListener(token) && target.IsEmpty())
440 		fTargets.RemoveItem(&target);
441 }
442 
443 
444 void
445 EventDispatcher::RemoveTemporaryListener(EventTarget& target, int32 token)
446 {
447 	BAutolock _(this);
448 	ETRACE(("events: remove temporary listener token %ld\n", token));
449 
450 	if (target.RemoveTemporaryListener(token) && target.IsEmpty())
451 		fTargets.RemoveItem(&target);
452 }
453 
454 
455 void
456 EventDispatcher::SetMouseFilter(EventFilter* filter)
457 {
458 	BAutolock _(this);
459 
460 	if (fMouseFilter == filter)
461 		return;
462 
463 	delete fMouseFilter;
464 	fMouseFilter = filter;
465 }
466 
467 
468 void
469 EventDispatcher::SetKeyboardFilter(EventFilter* filter)
470 {
471 	BAutolock _(this);
472 
473 	if (fKeyboardFilter == filter)
474 		return;
475 
476 	delete fKeyboardFilter;
477 	fKeyboardFilter = filter;
478 }
479 
480 
481 void
482 EventDispatcher::GetMouse(BPoint& where, int32& buttons)
483 {
484 	BAutolock _(this);
485 
486 	where = fLastCursorPosition;
487 	buttons = fLastButtons;
488 }
489 
490 
491 void
492 EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
493 {
494 	BAutolock _(this);
495 
496 	BMessage moved(B_MOUSE_MOVED);
497 	moved.AddPoint("screen_where", fLastCursorPosition);
498 	moved.AddInt32("buttons", fLastButtons);
499 
500 	if (fDraggingMessage) {
501 /*		moved.AddInt32("_msg_data", );
502 		moved.AddInt32("_msg_base_", );
503 		moved.AddInt32("_msg_what_", fDragMessage->what);*/
504 		moved.AddMessage("be:drag_message", &fDragMessage);
505 	}
506 
507 	if (fPreviousMouseTarget != NULL
508 		&& fPreviousMouseTarget != &target) {
509 		_AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
510 		_SendMessage(fPreviousMouseTarget->Messenger(), &moved,
511 			kMouseTransitImportance);
512 
513 		_RemoveTokens(&moved);
514 	}
515 
516 	moved.AddInt32("_view_token", viewToken);
517 		// this only belongs to the new target
518 
519 	_SendMessage(target.Messenger(), &moved, kMouseTransitImportance);
520 	fPreviousMouseTarget = &target;
521 }
522 
523 
524 bool
525 EventDispatcher::HasCursorThread()
526 {
527 	return fCursorThread >= B_OK;
528 }
529 
530 
531 /*!
532 	\brief Sets the HWInterface to use when moving the mouse cursor.
533 		\a interface is allowed to be NULL.
534 */
535 void
536 EventDispatcher::SetHWInterface(HWInterface* interface)
537 {
538 	BAutolock _(fCursorLock);
539 
540 	fHWInterface = interface;
541 
542 	// adopt the cursor position of the new HW interface
543 	if (interface != NULL)
544 		fLastCursorPosition = interface->CursorPosition();
545 }
546 
547 
548 void
549 EventDispatcher::SetDragMessage(BMessage& message,
550 	ServerBitmap* bitmap, const BPoint& offsetFromCursor)
551 {
552 	ETRACE(("EventDispatcher::SetDragMessage()\n"));
553 
554 	if (fDragBitmap != bitmap) {
555 		if (fDragBitmap)
556 			gBitmapManager->DeleteBitmap(fDragBitmap);
557 
558 		fDragBitmap = bitmap;
559 
560 		if (fDragBitmap)
561 			fDragBitmap->Acquire();
562 	}
563 
564 	fHWInterface->SetDragBitmap(bitmap, offsetFromCursor);
565 
566 	fDragMessage = message;
567 	fDraggingMessage = true;
568 	fDragOffset = offsetFromCursor;
569 }
570 
571 
572 void
573 EventDispatcher::SetDesktop(Desktop* desktop)
574 {
575 	fDesktop = desktop;
576 }
577 
578 
579 //	#pragma mark - Message methods
580 
581 
582 /*!
583 	\brief Sends \a message to the provided \a messenger.
584 
585 	TODO: the following feature is not yet implemented:
586 	If the message could not be delivered immediately, it is included
587 	in a waiting message queue with a fixed length - the least important
588 	messages are removed first when that gets full.
589 
590 	Returns "false" if the target port does not exist anymore, "true"
591 	if it doesn't.
592 */
593 bool
594 EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
595 	float importance)
596 {
597 	// TODO: add failed messages to a queue, and start dropping them by importance
598 	//	(and use the same mechanism in ServerWindow::SendMessageToClient())
599 
600 	status_t status = messenger.SendMessage(message, (BHandler*)NULL, 0);
601 	if (status != B_OK) {
602 		printf("EventDispatcher: failed to send message '%.4s' to target: %s\n",
603 			(char*)&message->what, strerror(status));
604 	}
605 
606 	if (status == B_BAD_PORT_ID) {
607 		// the target port is gone
608 		return false;
609 	}
610 
611 	return true;
612 }
613 
614 
615 bool
616 EventDispatcher::_AddTokens(BMessage* message, EventTarget* target,
617 	uint32 eventMask, BMessage* nextMouseMoved, int32* _viewToken)
618 {
619 	_RemoveTokens(message);
620 
621 	int32 count = target->CountListeners();
622 	int32 added = 0;
623 
624 	for (int32 i = 0; i < count; i++) {
625 		event_listener* listener = target->ListenerAt(i);
626 		if ((listener->EffectiveEventMask() & eventMask) == 0)
627 			continue;
628 
629 		if (nextMouseMoved != NULL && message->what == B_MOUSE_MOVED
630 			&& (listener->EffectiveOptions() & B_NO_POINTER_HISTORY) != 0
631 			&& message != nextMouseMoved
632 			&& _viewToken != NULL) {
633 			if (listener->token == *_viewToken) {
634 				// focus view doesn't want to get pointer history
635 				*_viewToken = B_NULL_TOKEN;
636 			}
637 			continue;
638 		}
639 
640 		ETRACE(("  add token %ld\n", listener->token));
641 
642 		if (message->AddInt32(kTokenName, listener->token) == B_OK)
643 			added++;
644 	}
645 
646 	return added != 0;
647 }
648 
649 
650 void
651 EventDispatcher::_RemoveTokens(BMessage* message)
652 {
653 	message->RemoveName(kTokenName);
654 }
655 
656 
657 void
658 EventDispatcher::_SetFeedFocus(BMessage* message)
659 {
660 	if (message->ReplaceBool("_feed_focus", true) != B_OK)
661 		message->AddBool("_feed_focus", true);
662 }
663 
664 
665 void
666 EventDispatcher::_UnsetFeedFocus(BMessage* message)
667 {
668 	message->RemoveName("_feed_focus");
669 }
670 
671 
672 void
673 EventDispatcher::_DeliverDragMessage()
674 {
675 	ETRACE(("EventDispatcher::_DeliverDragMessage()\n"));
676 
677 	if (fDraggingMessage && fPreviousMouseTarget != NULL) {
678 		BMessage::Private(fDragMessage).SetWasDropped(true);
679 		fDragMessage.RemoveName("_original_what");
680 		fDragMessage.AddInt32("_original_what", fDragMessage.what);
681 		fDragMessage.AddPoint("_drop_point_", fLastCursorPosition);
682 		fDragMessage.AddPoint("_drop_offset_", fDragOffset);
683 		fDragMessage.what = _MESSAGE_DROPPED_;
684 
685 		_SendMessage(fPreviousMouseTarget->Messenger(),
686 			&fDragMessage, 100.0);
687 	}
688 
689 	fDragMessage.MakeEmpty();
690 	fDragMessage.what = 0;
691 	fDraggingMessage = false;
692 
693 	fHWInterface->SetDragBitmap(NULL, B_ORIGIN);
694 	if (fDragBitmap)
695 		gBitmapManager->DeleteBitmap(fDragBitmap);
696 	fDragBitmap = NULL;
697 }
698 
699 
700 //	#pragma mark - Event loops
701 
702 
703 void
704 EventDispatcher::_EventLoop()
705 {
706 	BMessage* event;
707 	while (fStream->GetNextEvent(&event)) {
708 		if (event == NULL) {
709 			// may happen in out of memory situations or junk at the port
710 			// we can't do anything about those yet
711 			continue;
712 		}
713 
714 		BAutolock _(this);
715 
716 		EventTarget* current = NULL;
717 		EventTarget* previous = NULL;
718 		bool pointerEvent = false;
719 		bool keyboardEvent = false;
720 		bool addedTokens = false;
721 
722 		switch (event->what) {
723 			case B_MOUSE_MOVED:
724 			{
725 				BPoint where;
726 				if (event->FindPoint("where", &where) == B_OK)
727 					fLastCursorPosition = where;
728 
729 				if (fDraggingMessage) {
730 /*					event->AddInt32("_msg_data", );
731 					event->AddInt32("_msg_base_", );
732 					event->AddInt32("_msg_what_", fDragMessage->what);*/
733 					event->AddMessage("be:drag_message", &fDragMessage);
734 				}
735 
736 				if (!HasCursorThread()) {
737 					// there is no cursor thread, we need to move the cursor ourselves
738 					BAutolock _(fCursorLock);
739 
740 					if (fHWInterface != NULL) {
741 						fHWInterface->MoveCursorTo(fLastCursorPosition.x,
742 							fLastCursorPosition.y);
743 					}
744 				}
745 
746 				// This is for B_NO_POINTER_HISTORY - we always want the
747 				// latest mouse moved event in the queue only
748 				if (fNextLatestMouseMoved == NULL)
749 					fNextLatestMouseMoved = fStream->PeekLatestMouseMoved();
750 				else if (fNextLatestMouseMoved != event) {
751 					// Drop older mouse moved messages if the server is lagging too
752 					// much (if the message is older than 100 msecs)
753 					bigtime_t eventTime;
754 					if (event->FindInt64("when", &eventTime) == B_OK) {
755 						if (system_time() - eventTime > 100000)
756 							break;
757 					}
758 				}
759 
760 				// supposed to fall through
761 			}
762 			case B_MOUSE_DOWN:
763 			case B_MOUSE_UP:
764 			{
765 #ifdef TRACE_EVENTS
766 				if (event->what != B_MOUSE_MOVED)
767 					printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget);
768 #endif
769 				pointerEvent = true;
770 
771 				if (fMouseFilter == NULL)
772 					break;
773 
774 				EventTarget* mouseTarget = fPreviousMouseTarget;
775 				int32 viewToken = B_NULL_TOKEN;
776 				if (fMouseFilter->Filter(event, &mouseTarget, &viewToken,
777 						fNextLatestMouseMoved) == B_SKIP_MESSAGE) {
778 					// this is a work-around if the wrong B_MOUSE_UP
779 					// event is filtered out
780 					if (event->what == B_MOUSE_UP && event->FindInt32("buttons") == 0) {
781 						fSuspendFocus = false;
782 						_RemoveTemporaryListeners();
783 					}
784 					break;
785 				}
786 
787 				int32 buttons;
788 				if (event->FindInt32("buttons", &buttons) == B_OK)
789 					fLastButtons = buttons;
790 				else
791 					fLastButtons = 0;
792 
793 				// the "where" field will be filled in by the receiver
794 				// (it's supposed to be expressed in local window coordinates)
795 				event->RemoveName("where");
796 				event->AddPoint("screen_where", fLastCursorPosition);
797 
798 				if (event->what == B_MOUSE_MOVED
799 					&& fPreviousMouseTarget != NULL
800 					&& mouseTarget != fPreviousMouseTarget) {
801 					// target has changed, we need to notify the previous target
802 					// that the mouse has exited its views
803 					addedTokens = _AddTokens(event, fPreviousMouseTarget,
804 						B_POINTER_EVENTS);
805 
806 					_SendMessage(fPreviousMouseTarget->Messenger(), event,
807 						kMouseTransitImportance);
808 					previous = fPreviousMouseTarget;
809 				}
810 
811 				current = fPreviousMouseTarget = mouseTarget;
812 
813 				if (current != NULL) {
814 					int32 focusView = viewToken;
815 					addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS,
816 						fNextLatestMouseMoved, &focusView);
817 
818 					bool noPointerHistoryFocus = focusView != viewToken;
819 
820 					if (viewToken != B_NULL_TOKEN)
821 						event->AddInt32("_view_token", viewToken);
822 
823 					if (addedTokens && !noPointerHistoryFocus)
824 						_SetFeedFocus(event);
825 					else if (noPointerHistoryFocus) {
826 						// no tokens were added or the focus shouldn't get a mouse moved
827 						break;
828 					}
829 
830 					_SendMessage(current->Messenger(), event, event->what == B_MOUSE_MOVED
831 						? kMouseMovedImportance : kStandardImportance);
832 				}
833 				break;
834 			}
835 
836 			case B_KEY_DOWN:
837 			case B_KEY_UP:
838 			case B_UNMAPPED_KEY_DOWN:
839 			case B_UNMAPPED_KEY_UP:
840 			case B_MODIFIERS_CHANGED:
841 			case B_INPUT_METHOD_EVENT:
842 				ETRACE(("key event, focus = %p\n", fFocus));
843 
844 				if (fKeyboardFilter != NULL
845 					&& fKeyboardFilter->Filter(event, &fFocus) == B_SKIP_MESSAGE)
846 					break;
847 
848 				keyboardEvent = true;
849 
850 				if (fFocus != NULL && _AddTokens(event, fFocus, B_KEYBOARD_EVENTS)) {
851 					// if tokens were added, we need to explicetly suspend
852 					// focus in the event - if not, the event is simply not
853 					// forwarded to the target
854 					addedTokens = true;
855 
856 					if (!fSuspendFocus)
857 						_SetFeedFocus(event);
858 				}
859 
860 				// supposed to fall through
861 
862 			default:
863 				// TODO: the keyboard filter sets the focus - ie. no other
864 				//	focus messages that go through the event dispatcher can
865 				//	go through.
866 				if (event->what == B_MOUSE_WHEEL_CHANGED)
867 					current = fPreviousMouseTarget;
868 				else
869 					current = fFocus;
870 
871 				if (current != NULL && (!fSuspendFocus || addedTokens))
872 					_SendMessage(current->Messenger(), event, kStandardImportance);
873 				break;
874 		}
875 
876 		if (keyboardEvent || pointerEvent) {
877 			// send the event to the additional listeners
878 
879 			if (addedTokens) {
880 				_RemoveTokens(event);
881 				_UnsetFeedFocus(event);
882 			}
883 			if (pointerEvent) {
884 				// this is added in the Desktop mouse processing
885 				// but it's only intended for the focus view
886 				event->RemoveName("_view_token");
887 			}
888 
889 			for (int32 i = fTargets.CountItems(); i-- > 0;) {
890 				EventTarget* target = fTargets.ItemAt(i);
891 
892 				// we already sent the event to the all focus and last focus tokens
893 				if (current == target || previous == target)
894 					continue;
895 
896 				// don't send the message if there are no tokens for this event
897 				if (!_AddTokens(event, target,
898 						keyboardEvent ? B_KEYBOARD_EVENTS : B_POINTER_EVENTS,
899 						event->what == B_MOUSE_MOVED ? fNextLatestMouseMoved : NULL))
900 					continue;
901 
902 				if (!_SendMessage(target->Messenger(), event, event->what == B_MOUSE_MOVED
903 						? kMouseMovedImportance : kListenerImportance)) {
904 					// the target doesn't seem to exist anymore, let's remove it
905 					fTargets.RemoveItemAt(i);
906 				}
907 			}
908 
909 			if (event->what == B_MOUSE_UP && fLastButtons == 0) {
910 				// no buttons are pressed anymore
911 				fSuspendFocus = false;
912 				_RemoveTemporaryListeners();
913 				if (fDraggingMessage)
914 					_DeliverDragMessage();
915 			}
916 		}
917 
918 		if (fNextLatestMouseMoved == event)
919 			fNextLatestMouseMoved = NULL;
920 		delete event;
921 	}
922 
923 	// The loop quit, therefore no more events are coming from the input
924 	// server, it must have died. Unset ourselves and notify the desktop.
925 	fThread = -1;
926 		// Needed to avoid problems with wait_for_thread in _Unset()
927 	_Unset();
928 
929 	if (fDesktop)
930 		fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED);
931 }
932 
933 
934 void
935 EventDispatcher::_CursorLoop()
936 {
937 	BPoint where;
938 	while (fStream->GetNextCursorPosition(where)) {
939 		BAutolock _(fCursorLock);
940 
941 		if (fHWInterface != NULL)
942 			fHWInterface->MoveCursorTo(where.x, where.y);
943 	}
944 
945 	fCursorThread = -1;
946 }
947 
948 
949 /*static*/
950 status_t
951 EventDispatcher::_event_looper(void* _dispatcher)
952 {
953 	EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
954 
955 	ETRACE(("Start event loop\n"));
956 	dispatcher->_EventLoop();
957 	return B_OK;
958 }
959 
960 
961 /*static*/
962 status_t
963 EventDispatcher::_cursor_looper(void* _dispatcher)
964 {
965 	EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
966 
967 	ETRACE(("Start cursor loop\n"));
968 	dispatcher->_CursorLoop();
969 	return B_OK;
970 }
971