headers/bsd: Add sys/queue.h.
[haiku.git] / src / servers / app / EventDispatcher.cpp
blob9c8fb902f60ea8eedde7fbfdd3e023a2258bac23
1 /*
2 * Copyright 2005-2009, Haiku, Inc. All Rights Reserved.
3 * Distributed under the terms of the MIT License.
5 * Authors:
6 * Axel Dörfler, axeld@pinc-software.de
7 */
10 #include "EventDispatcher.h"
12 #include "BitmapManager.h"
13 #include "Desktop.h"
14 #include "EventStream.h"
15 #include "HWInterface.h"
16 #include "InputManager.h"
17 #include "ServerBitmap.h"
19 #include <MessagePrivate.h>
20 #include <MessengerPrivate.h>
21 #include <ServerProtocol.h>
22 #include <TokenSpace.h>
24 #include <Autolock.h>
25 #include <ToolTipManager.h>
26 #include <View.h>
28 #include <new>
29 #include <stdio.h>
30 #include <string.h>
33 //#define TRACE_EVENTS
34 #ifdef TRACE_EVENTS
35 # define ETRACE(x) printf x
36 #else
37 # define ETRACE(x) ;
38 #endif
41 /*!
42 The EventDispatcher is a per Desktop object that handles all input
43 events for that desktop.
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).
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.
64 struct event_listener {
65 int32 token;
66 uint32 event_mask;
67 uint32 options;
68 uint32 temporary_event_mask;
69 uint32 temporary_options;
71 uint32 EffectiveEventMask() const { return event_mask | temporary_event_mask; }
72 uint32 EffectiveOptions() const { return options | temporary_options; }
75 static const char* kTokenName = "_token";
77 static const uint32 kFakeMouseMoved = 'fake';
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;
85 EventTarget::EventTarget()
87 fListeners(2, true)
92 EventTarget::~EventTarget()
97 void
98 EventTarget::SetTo(const BMessenger& messenger)
100 fMessenger = messenger;
104 event_listener*
105 EventTarget::FindListener(int32 token, int32* _index)
107 for (int32 i = fListeners.CountItems(); i-- > 0;) {
108 event_listener* listener = fListeners.ItemAt(i);
110 if (listener->token == token) {
111 if (_index)
112 *_index = i;
113 return listener;
117 return NULL;
121 bool
122 EventTarget::_RemoveTemporaryListener(event_listener* listener, int32 index)
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));
129 fListeners.RemoveItemAt(index);
130 delete listener;
131 return true;
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));
140 listener->temporary_event_mask = 0;
141 listener->temporary_options = 0;
144 return false;
148 void
149 EventTarget::RemoveTemporaryListeners()
151 for (int32 index = CountListeners(); index-- > 0;) {
152 event_listener* listener = ListenerAt(index);
154 _RemoveTemporaryListener(listener, index);
159 bool
160 EventTarget::RemoveTemporaryListener(int32 token)
162 int32 index;
163 event_listener* listener = FindListener(token, &index);
164 if (listener == NULL)
165 return false;
167 return _RemoveTemporaryListener(listener, index);
171 bool
172 EventTarget::RemoveListener(int32 token)
174 int32 index;
175 event_listener* listener = FindListener(token, &index);
176 if (listener == NULL)
177 return false;
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;
186 fListeners.RemoveItemAt(index);
187 delete listener;
188 return true;
192 bool
193 EventTarget::AddListener(int32 token, uint32 eventMask,
194 uint32 options, bool temporary)
196 event_listener* listener = new (std::nothrow) event_listener;
197 if (listener == NULL)
198 return false;
200 listener->token = token;
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;
214 bool success = fListeners.AddItem(listener);
215 if (!success)
216 delete listener;
218 return success;
222 // #pragma mark -
225 void
226 EventFilter::RemoveTarget(EventTarget* target)
231 // #pragma mark -
234 EventDispatcher::EventDispatcher()
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 fDragBitmap(NULL),
251 fCursorLock("cursor loop lock"),
252 fHWInterface(NULL),
253 fDesktop(NULL)
258 EventDispatcher::~EventDispatcher()
260 _Unset();
264 status_t
265 EventDispatcher::SetTo(EventStream* stream)
267 ETRACE(("event dispatcher: stream = %p\n", stream));
269 _Unset();
271 if (stream == NULL)
272 return B_OK;
274 fStream = stream;
275 return _Run();
279 status_t
280 EventDispatcher::InitCheck()
282 if (fStream != NULL) {
283 if (fThread < B_OK)
284 return fThread;
286 return B_OK;
288 return B_NO_INIT;
292 void
293 EventDispatcher::_Unset()
295 if (fStream == NULL)
296 return;
298 fStream->SendQuit();
300 status_t status;
301 wait_for_thread(fThread, &status);
302 wait_for_thread(fCursorThread, &status);
304 fThread = fCursorThread = -1;
306 gInputManager->PutStream(fStream);
307 fStream = NULL;
311 status_t
312 EventDispatcher::_Run()
314 fThread = spawn_thread(_event_looper, "event loop",
315 B_REAL_TIME_DISPLAY_PRIORITY - 10, this);
316 if (fThread < B_OK)
317 return fThread;
319 if (fStream->SupportsCursorThread()) {
320 ETRACE(("event stream supports cursor thread!\n"));
322 fCursorThread = spawn_thread(_cursor_looper, "cursor loop",
323 B_REAL_TIME_DISPLAY_PRIORITY - 5, this);
324 if (resume_thread(fCursorThread) != B_OK) {
325 kill_thread(fCursorThread);
326 fCursorThread = -1;
330 return resume_thread(fThread);
335 \brief Removes any reference to the target, but doesn't delete it.
337 void
338 EventDispatcher::RemoveTarget(EventTarget& target)
340 BAutolock _(this);
342 if (fFocus == &target)
343 fFocus = NULL;
344 if (fPreviousMouseTarget == &target)
345 fPreviousMouseTarget = NULL;
347 if (fKeyboardFilter != NULL)
348 fKeyboardFilter->RemoveTarget(&target);
349 if (fMouseFilter != NULL)
350 fMouseFilter->RemoveTarget(&target);
352 fTargets.RemoveItem(&target);
357 \brief Adds the specified listener or updates its event mask and options
358 if already added.
360 It follows the BView semantics in that specifiying an event mask of zero
361 leaves the event mask untouched and just updates the options.
363 bool
364 EventDispatcher::_AddListener(EventTarget& target, int32 token,
365 uint32 eventMask, uint32 options, bool temporary)
367 BAutolock _(this);
369 if (temporary && fLastButtons == 0) {
370 // only allow to add temporary listeners in case a buttons is pressed
371 return false;
374 if (!fTargets.HasItem(&target))
375 fTargets.AddItem(&target);
377 event_listener* listener = target.FindListener(token);
378 if (listener != NULL) {
379 // we already have this target, update its event mask
380 if (temporary) {
381 if (eventMask != 0)
382 listener->temporary_event_mask = eventMask;
383 listener->temporary_options = options;
384 } else {
385 if (eventMask != 0)
386 listener->event_mask = eventMask;
387 listener->options = options;
390 return true;
393 if (eventMask == 0)
394 return false;
396 ETRACE(("events: add listener: token %ld, eventMask = %ld, options = %ld,"
397 "%s\n",
398 token, eventMask, options, temporary ? "temporary" : "permanent"));
400 // we need a new target
402 bool success = target.AddListener(token, eventMask, options, temporary);
403 if (!success) {
404 if (target.IsEmpty())
405 fTargets.RemoveItem(&target);
406 } else {
407 if (options & B_SUSPEND_VIEW_FOCUS)
408 fSuspendFocus = true;
411 return success;
415 void
416 EventDispatcher::_RemoveTemporaryListeners()
418 for (int32 i = fTargets.CountItems(); i-- > 0;) {
419 EventTarget* target = fTargets.ItemAt(i);
421 target->RemoveTemporaryListeners();
426 bool
427 EventDispatcher::AddListener(EventTarget& target, int32 token,
428 uint32 eventMask, uint32 options)
430 options &= B_NO_POINTER_HISTORY;
431 // that's currently the only allowed option
433 return _AddListener(target, token, eventMask, options, false);
437 bool
438 EventDispatcher::AddTemporaryListener(EventTarget& target,
439 int32 token, uint32 eventMask, uint32 options)
441 return _AddListener(target, token, eventMask, options, true);
445 void
446 EventDispatcher::RemoveListener(EventTarget& target, int32 token)
448 BAutolock _(this);
449 ETRACE(("events: remove listener token %ld\n", token));
451 if (target.RemoveListener(token) && target.IsEmpty())
452 fTargets.RemoveItem(&target);
456 void
457 EventDispatcher::RemoveTemporaryListener(EventTarget& target, int32 token)
459 BAutolock _(this);
460 ETRACE(("events: remove temporary listener token %ld\n", token));
462 if (target.RemoveTemporaryListener(token) && target.IsEmpty())
463 fTargets.RemoveItem(&target);
467 void
468 EventDispatcher::SetMouseFilter(EventFilter* filter)
470 BAutolock _(this);
472 if (fMouseFilter == filter)
473 return;
475 delete fMouseFilter;
476 fMouseFilter = filter;
480 void
481 EventDispatcher::SetKeyboardFilter(EventFilter* filter)
483 BAutolock _(this);
485 if (fKeyboardFilter == filter)
486 return;
488 delete fKeyboardFilter;
489 fKeyboardFilter = filter;
493 void
494 EventDispatcher::GetMouse(BPoint& where, int32& buttons)
496 BAutolock _(this);
498 where = fLastCursorPosition;
499 buttons = fLastButtons;
503 void
504 EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken)
506 if (fStream == NULL)
507 return;
509 BMessage* fakeMove = new BMessage(kFakeMouseMoved);
510 if (fakeMove == NULL)
511 return;
513 fakeMove->AddMessenger("target", target.Messenger());
514 fakeMove->AddInt32("view_token", viewToken);
516 fStream->InsertEvent(fakeMove);
520 void
521 EventDispatcher::_SendFakeMouseMoved(BMessage* message)
523 BMessenger target;
524 int32 viewToken;
525 if (message->FindInt32("view_token", &viewToken) != B_OK
526 || message->FindMessenger("target", &target) != B_OK)
527 return;
529 if (fDesktop == NULL)
530 return;
532 // Check if the target is still valid
533 ::EventTarget* eventTarget = NULL;
535 fDesktop->LockSingleWindow();
537 if (target.IsValid())
538 eventTarget = fDesktop->FindTarget(target);
540 fDesktop->UnlockSingleWindow();
542 if (eventTarget == NULL)
543 return;
545 BMessage moved(B_MOUSE_MOVED);
546 moved.AddPoint("screen_where", fLastCursorPosition);
547 moved.AddInt32("buttons", fLastButtons);
549 if (fDraggingMessage)
550 moved.AddMessage("be:drag_message", &fDragMessage);
552 if (fPreviousMouseTarget != NULL
553 && fPreviousMouseTarget->Messenger() != target) {
554 _AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS);
555 _SendMessage(fPreviousMouseTarget->Messenger(), &moved,
556 kMouseTransitImportance);
558 _RemoveTokens(&moved);
561 moved.AddInt32("_view_token", viewToken);
562 // this only belongs to the new target
564 moved.AddBool("be:transit_only", true);
565 // let the view know this what not user generated
567 _SendMessage(target, &moved, kMouseTransitImportance);
569 fPreviousMouseTarget = eventTarget;
573 bigtime_t
574 EventDispatcher::IdleTime()
576 BAutolock _(this);
577 return system_time() - fLastUpdate;
581 bool
582 EventDispatcher::HasCursorThread()
584 return fCursorThread >= B_OK;
589 \brief Sets the HWInterface to use when moving the mouse cursor.
590 \a interface is allowed to be NULL.
592 void
593 EventDispatcher::SetHWInterface(HWInterface* interface)
595 BAutolock _(fCursorLock);
597 fHWInterface = interface;
599 // adopt the cursor position of the new HW interface
600 if (interface != NULL)
601 fLastCursorPosition = interface->CursorPosition();
605 void
606 EventDispatcher::SetDragMessage(BMessage& message,
607 ServerBitmap* bitmap, const BPoint& offsetFromCursor)
609 ETRACE(("EventDispatcher::SetDragMessage()\n"));
611 BAutolock _(this);
613 if (fLastButtons == 0) {
614 // mouse buttons has already been released or was never pressed
615 if (bitmap != NULL)
616 bitmap->ReleaseReference();
617 return;
620 if (fDragBitmap != bitmap) {
621 if (fDragBitmap)
622 fDragBitmap->ReleaseReference();
624 fDragBitmap = bitmap;
626 if (fDragBitmap != NULL)
627 fDragBitmap->AcquireReference();
630 fHWInterface->SetDragBitmap(bitmap, offsetFromCursor);
632 fDragMessage = message;
633 fDraggingMessage = true;
634 fDragOffset = offsetFromCursor;
638 void
639 EventDispatcher::SetDesktop(Desktop* desktop)
641 fDesktop = desktop;
645 // #pragma mark - Message methods
649 \brief Sends \a message to the provided \a messenger.
651 TODO: the following feature is not yet implemented:
652 If the message could not be delivered immediately, it is included
653 in a waiting message queue with a fixed length - the least important
654 messages are removed first when that gets full.
656 Returns "false" if the target port does not exist anymore, "true"
657 if it doesn't.
659 bool
660 EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message,
661 float importance)
663 // TODO: add failed messages to a queue, and start dropping them by importance
664 // (and use the same mechanism in ServerWindow::SendMessageToClient())
666 status_t status = messenger.SendMessage(message, (BHandler*)NULL, 0);
667 if (status != B_OK) {
668 printf("EventDispatcher: failed to send message '%.4s' to target: %s\n",
669 (char*)&message->what, strerror(status));
672 if (status == B_BAD_PORT_ID) {
673 // the target port is gone
674 return false;
677 return true;
681 bool
682 EventDispatcher::_AddTokens(BMessage* message, EventTarget* target,
683 uint32 eventMask, BMessage* nextMouseMoved, int32* _viewToken)
685 _RemoveTokens(message);
687 int32 count = target->CountListeners();
688 int32 added = 0;
690 for (int32 i = 0; i < count; i++) {
691 event_listener* listener = target->ListenerAt(i);
692 if ((listener->EffectiveEventMask() & eventMask) == 0)
693 continue;
695 if (nextMouseMoved != NULL && message->what == B_MOUSE_MOVED
696 && (listener->EffectiveOptions() & B_NO_POINTER_HISTORY) != 0
697 && message != nextMouseMoved
698 && _viewToken != NULL) {
699 if (listener->token == *_viewToken) {
700 // focus view doesn't want to get pointer history
701 *_viewToken = B_NULL_TOKEN;
703 continue;
706 ETRACE((" add token %ld\n", listener->token));
708 if (message->AddInt32(kTokenName, listener->token) == B_OK)
709 added++;
712 return added != 0;
716 void
717 EventDispatcher::_RemoveTokens(BMessage* message)
719 message->RemoveName(kTokenName);
723 void
724 EventDispatcher::_SetFeedFocus(BMessage* message)
726 if (message->ReplaceBool("_feed_focus", true) != B_OK)
727 message->AddBool("_feed_focus", true);
731 void
732 EventDispatcher::_UnsetFeedFocus(BMessage* message)
734 message->RemoveName("_feed_focus");
738 void
739 EventDispatcher::_DeliverDragMessage()
741 ETRACE(("EventDispatcher::_DeliverDragMessage()\n"));
743 if (fDraggingMessage && fPreviousMouseTarget != NULL) {
744 BMessage::Private(fDragMessage).SetWasDropped(true);
745 fDragMessage.RemoveName("_original_what");
746 fDragMessage.AddInt32("_original_what", fDragMessage.what);
747 fDragMessage.AddPoint("_drop_point_", fLastCursorPosition);
748 fDragMessage.AddPoint("_drop_offset_", fDragOffset);
749 fDragMessage.what = _MESSAGE_DROPPED_;
751 _SendMessage(fPreviousMouseTarget->Messenger(),
752 &fDragMessage, 100.0);
755 fDragMessage.MakeEmpty();
756 fDragMessage.what = 0;
757 fDraggingMessage = false;
759 fHWInterface->SetDragBitmap(NULL, B_ORIGIN);
760 if (fDragBitmap != NULL) {
761 fDragBitmap->ReleaseReference();
762 fDragBitmap = NULL;
767 // #pragma mark - Event loops
770 void
771 EventDispatcher::_EventLoop()
773 BMessage* event;
774 while (fStream->GetNextEvent(&event)) {
775 BAutolock _(this);
776 fLastUpdate = system_time();
778 EventTarget* current = NULL;
779 EventTarget* previous = NULL;
780 bool pointerEvent = false;
781 bool keyboardEvent = false;
782 bool addedTokens = false;
784 switch (event->what) {
785 case kFakeMouseMoved:
786 _SendFakeMouseMoved(event);
787 break;
788 case B_MOUSE_MOVED:
790 BPoint where;
791 if (event->FindPoint("where", &where) == B_OK)
792 fLastCursorPosition = where;
794 if (fDraggingMessage)
795 event->AddMessage("be:drag_message", &fDragMessage);
797 if (!HasCursorThread()) {
798 // There is no cursor thread, we need to move the cursor
799 // ourselves
800 BAutolock _(fCursorLock);
802 if (fHWInterface != NULL) {
803 fHWInterface->MoveCursorTo(fLastCursorPosition.x,
804 fLastCursorPosition.y);
808 // This is for B_NO_POINTER_HISTORY - we always want the
809 // latest mouse moved event in the queue only
810 if (fNextLatestMouseMoved == NULL)
811 fNextLatestMouseMoved = fStream->PeekLatestMouseMoved();
812 else if (fNextLatestMouseMoved != event) {
813 // Drop older mouse moved messages if the server is lagging
814 // too much (if the message is older than 100 msecs)
815 bigtime_t eventTime;
816 if (event->FindInt64("when", &eventTime) == B_OK) {
817 if (system_time() - eventTime > 100000)
818 break;
822 // supposed to fall through
824 case B_MOUSE_DOWN:
825 case B_MOUSE_UP:
826 case B_MOUSE_IDLE:
828 #ifdef TRACE_EVENTS
829 if (event->what != B_MOUSE_MOVED)
830 printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget);
831 #endif
832 pointerEvent = true;
834 if (fMouseFilter == NULL)
835 break;
837 EventTarget* mouseTarget = fPreviousMouseTarget;
838 int32 viewToken = B_NULL_TOKEN;
839 if (fMouseFilter->Filter(event, &mouseTarget, &viewToken,
840 fNextLatestMouseMoved) == B_SKIP_MESSAGE) {
841 // this is a work-around if the wrong B_MOUSE_UP
842 // event is filtered out
843 if (event->what == B_MOUSE_UP
844 && event->FindInt32("buttons") == 0) {
845 fSuspendFocus = false;
846 _RemoveTemporaryListeners();
848 break;
851 int32 buttons;
852 if (event->FindInt32("buttons", &buttons) == B_OK)
853 fLastButtons = buttons;
854 else
855 fLastButtons = 0;
857 // The "where" field will be filled in by the receiver
858 // (it's supposed to be expressed in local window coordinates)
859 event->RemoveName("where");
860 event->AddPoint("screen_where", fLastCursorPosition);
862 if (event->what == B_MOUSE_MOVED
863 && fPreviousMouseTarget != NULL
864 && mouseTarget != fPreviousMouseTarget) {
865 // Target has changed, we need to notify the previous target
866 // that the mouse has exited its views
867 addedTokens = _AddTokens(event, fPreviousMouseTarget,
868 B_POINTER_EVENTS);
869 if (addedTokens)
870 _SetFeedFocus(event);
872 _SendMessage(fPreviousMouseTarget->Messenger(), event,
873 kMouseTransitImportance);
874 previous = fPreviousMouseTarget;
877 current = fPreviousMouseTarget = mouseTarget;
879 if (current != NULL) {
880 int32 focusView = viewToken;
881 addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS,
882 fNextLatestMouseMoved, &focusView);
884 bool noPointerHistoryFocus = focusView != viewToken;
886 if (viewToken != B_NULL_TOKEN)
887 event->AddInt32("_view_token", viewToken);
889 if (addedTokens && !noPointerHistoryFocus)
890 _SetFeedFocus(event);
891 else if (noPointerHistoryFocus) {
892 // No tokens were added or the focus shouldn't get a
893 // mouse moved
894 break;
897 _SendMessage(current->Messenger(), event,
898 event->what == B_MOUSE_MOVED
899 ? kMouseMovedImportance : kStandardImportance);
901 break;
904 case B_KEY_DOWN:
905 case B_KEY_UP:
906 case B_UNMAPPED_KEY_DOWN:
907 case B_UNMAPPED_KEY_UP:
908 case B_MODIFIERS_CHANGED:
909 case B_INPUT_METHOD_EVENT:
910 ETRACE(("key event, focus = %p\n", fFocus));
912 if (fKeyboardFilter != NULL
913 && fKeyboardFilter->Filter(event, &fFocus)
914 == B_SKIP_MESSAGE) {
915 break;
918 keyboardEvent = true;
920 if (fFocus != NULL && _AddTokens(event, fFocus,
921 B_KEYBOARD_EVENTS)) {
922 // if tokens were added, we need to explicetly suspend
923 // focus in the event - if not, the event is simply not
924 // forwarded to the target
925 addedTokens = true;
927 if (!fSuspendFocus)
928 _SetFeedFocus(event);
931 // supposed to fall through
933 default:
934 // TODO: the keyboard filter sets the focus - ie. no other
935 // focus messages that go through the event dispatcher can
936 // go through.
937 if (event->what == B_MOUSE_WHEEL_CHANGED)
938 current = fPreviousMouseTarget;
939 else
940 current = fFocus;
942 if (current != NULL && (!fSuspendFocus || addedTokens)) {
943 _SendMessage(current->Messenger(), event,
944 kStandardImportance);
946 break;
949 if (keyboardEvent || pointerEvent) {
950 // send the event to the additional listeners
952 if (addedTokens) {
953 _RemoveTokens(event);
954 _UnsetFeedFocus(event);
956 if (pointerEvent) {
957 // this is added in the Desktop mouse processing
958 // but it's only intended for the focus view
959 event->RemoveName("_view_token");
962 for (int32 i = fTargets.CountItems(); i-- > 0;) {
963 EventTarget* target = fTargets.ItemAt(i);
965 // We already sent the event to the all focus and last focus
966 // tokens
967 if (current == target || previous == target)
968 continue;
970 // Don't send the message if there are no tokens for this event
971 if (!_AddTokens(event, target,
972 keyboardEvent ? B_KEYBOARD_EVENTS : B_POINTER_EVENTS,
973 event->what == B_MOUSE_MOVED
974 ? fNextLatestMouseMoved : NULL))
975 continue;
977 if (!_SendMessage(target->Messenger(), event,
978 event->what == B_MOUSE_MOVED
979 ? kMouseMovedImportance : kListenerImportance)) {
980 // the target doesn't seem to exist anymore, let's remove it
981 fTargets.RemoveItemAt(i);
985 if (event->what == B_MOUSE_UP && fLastButtons == 0) {
986 // no buttons are pressed anymore
987 fSuspendFocus = false;
988 _RemoveTemporaryListeners();
989 if (fDraggingMessage)
990 _DeliverDragMessage();
994 if (fNextLatestMouseMoved == event)
995 fNextLatestMouseMoved = NULL;
996 delete event;
999 // The loop quit, therefore no more events are coming from the input
1000 // server, it must have died. Unset ourselves and notify the desktop.
1001 fThread = -1;
1002 // Needed to avoid problems with wait_for_thread in _Unset()
1003 _Unset();
1005 if (fDesktop)
1006 fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED);
1010 void
1011 EventDispatcher::_CursorLoop()
1013 BPoint where;
1014 const bigtime_t toolTipDelay = BToolTipManager::Manager()->ShowDelay();
1015 bool mouseIdleSent = true;
1016 status_t status = B_OK;
1018 while (status != B_ERROR) {
1019 const bigtime_t timeout = mouseIdleSent ?
1020 B_INFINITE_TIMEOUT : toolTipDelay;
1021 status = fStream->GetNextCursorPosition(where, timeout);
1023 if (status == B_OK) {
1024 mouseIdleSent = false;
1025 BAutolock _(fCursorLock);
1027 if (fHWInterface != NULL)
1028 fHWInterface->MoveCursorTo(where.x, where.y);
1029 } else if (status == B_TIMED_OUT) {
1030 mouseIdleSent = true;
1031 BMessage* mouseIdle = new BMessage(B_MOUSE_IDLE);
1032 mouseIdle->AddPoint("screen_where", fLastCursorPosition);
1033 fStream->InsertEvent(mouseIdle);
1037 fCursorThread = -1;
1041 /*static*/
1042 status_t
1043 EventDispatcher::_event_looper(void* _dispatcher)
1045 EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
1047 ETRACE(("Start event loop\n"));
1048 dispatcher->_EventLoop();
1049 return B_OK;
1053 /*static*/
1054 status_t
1055 EventDispatcher::_cursor_looper(void* _dispatcher)
1057 EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher;
1059 ETRACE(("Start cursor loop\n"));
1060 dispatcher->_CursorLoop();
1061 return B_OK;