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