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