xref: /haiku/src/servers/app/EventDispatcher.cpp (revision 779ab335dd81d47f9aa7ef06822de37c8fec1c6e)
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 
64 struct event_listener {
65 	int32		token;
66 	uint32		event_mask;
67 	uint32		options;
68 	uint32		temporary_event_mask;
69 	uint32		temporary_options;
70 
EffectiveEventMaskevent_listener71 	uint32		EffectiveEventMask() const { return event_mask | temporary_event_mask; }
EffectiveOptionsevent_listener72 	uint32		EffectiveOptions() const { return options | temporary_options; }
73 };
74 
75 static const char* kTokenName = "_token";
76 
77 static const uint32 kFakeMouseMoved = 'fake';
78 
79 static const float kMouseMovedImportance = 0.1f;
80 static const float kMouseTransitImportance = 1.0f;
81 static const float kStandardImportance = 0.9f;
82 static const float kListenerImportance = 0.8f;
83 
84 
EventTarget()85 EventTarget::EventTarget()
86 	:
87 	fListeners(2, true)
88 {
89 }
90 
91 
~EventTarget()92 EventTarget::~EventTarget()
93 {
94 }
95 
96 
97 void
SetTo(const BMessenger & messenger)98 EventTarget::SetTo(const BMessenger& messenger)
99 {
100 	fMessenger = messenger;
101 }
102 
103 
104 event_listener*
FindListener(int32 token,int32 * _index)105 EventTarget::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 
121 bool
_RemoveTemporaryListener(event_listener * listener,int32 index)122 EventTarget::_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 
148 void
RemoveTemporaryListeners()149 EventTarget::RemoveTemporaryListeners()
150 {
151 	for (int32 index = CountListeners(); index-- > 0;) {
152 		event_listener* listener = ListenerAt(index);
153 
154 		_RemoveTemporaryListener(listener, index);
155 	}
156 }
157 
158 
159 bool
RemoveTemporaryListener(int32 token)160 EventTarget::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 
171 bool
RemoveListener(int32 token)172 EventTarget::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 
192 bool
AddListener(int32 token,uint32 eventMask,uint32 options,bool temporary)193 EventTarget::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 
225 void
RemoveTarget(EventTarget * target)226 EventFilter::RemoveTarget(EventTarget* target)
227 {
228 }
229 
230 
231 //	#pragma mark -
232 
233 
EventDispatcher()234 EventDispatcher::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 
~EventDispatcher()257 EventDispatcher::~EventDispatcher()
258 {
259 	_Unset();
260 }
261 
262 
263 status_t
SetTo(EventStream * stream)264 EventDispatcher::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 
278 status_t
InitCheck()279 EventDispatcher::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 
291 void
_Unset()292 EventDispatcher::_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 
310 status_t
_Run()311 EventDispatcher::_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 */
336 void
RemoveTarget(EventTarget & target)337 EventDispatcher::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 */
362 bool
_AddListener(EventTarget & target,int32 token,uint32 eventMask,uint32 options,bool temporary)363 EventDispatcher::_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 
414 void
_RemoveTemporaryListeners()415 EventDispatcher::_RemoveTemporaryListeners()
416 {
417 	for (int32 i = fTargets.CountItems(); i-- > 0;) {
418 		EventTarget* target = fTargets.ItemAt(i);
419 
420 		target->RemoveTemporaryListeners();
421 	}
422 }
423 
424 
425 bool
AddListener(EventTarget & target,int32 token,uint32 eventMask,uint32 options)426 EventDispatcher::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 
436 bool
AddTemporaryListener(EventTarget & target,int32 token,uint32 eventMask,uint32 options)437 EventDispatcher::AddTemporaryListener(EventTarget& target,
438 	int32 token, uint32 eventMask, uint32 options)
439 {
440 	return _AddListener(target, token, eventMask, options, true);
441 }
442 
443 
444 void
RemoveListener(EventTarget & target,int32 token)445 EventDispatcher::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 
455 void
RemoveTemporaryListener(EventTarget & target,int32 token)456 EventDispatcher::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 
466 void
SetMouseFilter(EventFilter * filter)467 EventDispatcher::SetMouseFilter(EventFilter* filter)
468 {
469 	BAutolock _(this);
470 
471 	if (fMouseFilter.Get() == filter)
472 		return;
473 
474 	fMouseFilter.SetTo(filter);
475 }
476 
477 
478 void
SetKeyboardFilter(EventFilter * filter)479 EventDispatcher::SetKeyboardFilter(EventFilter* filter)
480 {
481 	BAutolock _(this);
482 
483 	if (fKeyboardFilter.Get() == filter)
484 		return;
485 
486 	fKeyboardFilter.SetTo(filter);
487 }
488 
489 
490 void
GetMouse(BPoint & where,int32 & buttons)491 EventDispatcher::GetMouse(BPoint& where, int32& buttons)
492 {
493 	BAutolock _(this);
494 
495 	where = fLastCursorPosition;
496 	buttons = fLastButtons;
497 }
498 
499 
500 void
SendFakeMouseMoved(EventTarget & target,int32 viewToken)501 EventDispatcher::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 
517 void
_SendFakeMouseMoved(BMessage * message)518 EventDispatcher::_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 
570 bigtime_t
IdleTime()571 EventDispatcher::IdleTime()
572 {
573 	BAutolock _(this);
574 	return system_time() - fLastUpdate;
575 }
576 
577 
578 bool
HasCursorThread()579 EventDispatcher::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 */
589 void
SetHWInterface(HWInterface * interface)590 EventDispatcher::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 
602 void
SetDragMessage(BMessage & message,ServerBitmap * bitmap,const BPoint & offsetFromCursor)603 EventDispatcher::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 
623 void
SetDesktop(Desktop * desktop)624 EventDispatcher::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 */
644 bool
_SendMessage(BMessenger & messenger,BMessage * message,float importance)645 EventDispatcher::_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 
666 bool
_AddTokens(BMessage * message,EventTarget * target,uint32 eventMask,BMessage * nextMouseMoved,int32 * _viewToken)667 EventDispatcher::_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 
701 void
_RemoveTokens(BMessage * message)702 EventDispatcher::_RemoveTokens(BMessage* message)
703 {
704 	message->RemoveName(kTokenName);
705 }
706 
707 
708 void
_SetFeedFocus(BMessage * message)709 EventDispatcher::_SetFeedFocus(BMessage* message)
710 {
711 	if (message->ReplaceBool("_feed_focus", true) != B_OK)
712 		message->AddBool("_feed_focus", true);
713 }
714 
715 
716 void
_UnsetFeedFocus(BMessage * message)717 EventDispatcher::_UnsetFeedFocus(BMessage* message)
718 {
719 	message->RemoveName("_feed_focus");
720 }
721 
722 
723 void
_DeliverDragMessage()724 EventDispatcher::_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 
751 void
_EventLoop()752 EventDispatcher::_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 
991 void
_CursorLoop()992 EventDispatcher::_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*/
1023 status_t
_event_looper(void * _dispatcher)1024 EventDispatcher::_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*/
1035 status_t
_cursor_looper(void * _dispatcher)1036 EventDispatcher::_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