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