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