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