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