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