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