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