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