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