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 71 uint32 EffectiveEventMask() const { return event_mask | temporary_event_mask; } 72 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 85 EventTarget::EventTarget() 86 : 87 fListeners(2, true) 88 { 89 } 90 91 92 EventTarget::~EventTarget() 93 { 94 } 95 96 97 void 98 EventTarget::SetTo(const BMessenger& messenger) 99 { 100 fMessenger = messenger; 101 } 102 103 104 event_listener* 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 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 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 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 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 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 226 EventFilter::RemoveTarget(EventTarget* target) 227 { 228 } 229 230 231 // #pragma mark - 232 233 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 fDragBitmap(NULL), 251 fCursorLock("cursor loop lock"), 252 fHWInterface(NULL), 253 fDesktop(NULL) 254 { 255 } 256 257 258 EventDispatcher::~EventDispatcher() 259 { 260 _Unset(); 261 } 262 263 264 status_t 265 EventDispatcher::SetTo(EventStream* stream) 266 { 267 ETRACE(("event dispatcher: stream = %p\n", stream)); 268 269 _Unset(); 270 271 if (stream == NULL) 272 return B_OK; 273 274 fStream = stream; 275 return _Run(); 276 } 277 278 279 status_t 280 EventDispatcher::InitCheck() 281 { 282 if (fStream != NULL) { 283 if (fThread < B_OK) 284 return fThread; 285 286 return B_OK; 287 } 288 return B_NO_INIT; 289 } 290 291 292 void 293 EventDispatcher::_Unset() 294 { 295 if (fStream == NULL) 296 return; 297 298 fStream->SendQuit(); 299 300 status_t status; 301 wait_for_thread(fThread, &status); 302 wait_for_thread(fCursorThread, &status); 303 304 fThread = fCursorThread = -1; 305 306 gInputManager->PutStream(fStream); 307 fStream = NULL; 308 } 309 310 311 status_t 312 EventDispatcher::_Run() 313 { 314 fThread = spawn_thread(_event_looper, "event loop", 315 B_REAL_TIME_DISPLAY_PRIORITY - 10, this); 316 if (fThread < B_OK) 317 return fThread; 318 319 if (fStream->SupportsCursorThread()) { 320 ETRACE(("event stream supports cursor thread!\n")); 321 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; 327 } 328 } 329 330 return resume_thread(fThread); 331 } 332 333 334 /*! 335 \brief Removes any reference to the target, but doesn't delete it. 336 */ 337 void 338 EventDispatcher::RemoveTarget(EventTarget& target) 339 { 340 BAutolock _(this); 341 342 if (fFocus == &target) 343 fFocus = NULL; 344 if (fPreviousMouseTarget == &target) 345 fPreviousMouseTarget = NULL; 346 347 if (fKeyboardFilter != NULL) 348 fKeyboardFilter->RemoveTarget(&target); 349 if (fMouseFilter != NULL) 350 fMouseFilter->RemoveTarget(&target); 351 352 fTargets.RemoveItem(&target); 353 } 354 355 356 /*! 357 \brief Adds the specified listener or updates its event mask and options 358 if already added. 359 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. 362 */ 363 bool 364 EventDispatcher::_AddListener(EventTarget& target, int32 token, 365 uint32 eventMask, uint32 options, bool temporary) 366 { 367 BAutolock _(this); 368 369 if (temporary && fLastButtons == 0) { 370 // only allow to add temporary listeners in case a buttons is pressed 371 return false; 372 } 373 374 if (!fTargets.HasItem(&target)) 375 fTargets.AddItem(&target); 376 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; 388 } 389 390 return true; 391 } 392 393 if (eventMask == 0) 394 return false; 395 396 ETRACE(("events: add listener: token %ld, eventMask = %ld, options = %ld," 397 "%s\n", 398 token, eventMask, options, temporary ? "temporary" : "permanent")); 399 400 // we need a new target 401 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; 409 } 410 411 return success; 412 } 413 414 415 void 416 EventDispatcher::_RemoveTemporaryListeners() 417 { 418 for (int32 i = fTargets.CountItems(); i-- > 0;) { 419 EventTarget* target = fTargets.ItemAt(i); 420 421 target->RemoveTemporaryListeners(); 422 } 423 } 424 425 426 bool 427 EventDispatcher::AddListener(EventTarget& target, int32 token, 428 uint32 eventMask, uint32 options) 429 { 430 options &= B_NO_POINTER_HISTORY; 431 // that's currently the only allowed option 432 433 return _AddListener(target, token, eventMask, options, false); 434 } 435 436 437 bool 438 EventDispatcher::AddTemporaryListener(EventTarget& target, 439 int32 token, uint32 eventMask, uint32 options) 440 { 441 return _AddListener(target, token, eventMask, options, true); 442 } 443 444 445 void 446 EventDispatcher::RemoveListener(EventTarget& target, int32 token) 447 { 448 BAutolock _(this); 449 ETRACE(("events: remove listener token %ld\n", token)); 450 451 if (target.RemoveListener(token) && target.IsEmpty()) 452 fTargets.RemoveItem(&target); 453 } 454 455 456 void 457 EventDispatcher::RemoveTemporaryListener(EventTarget& target, int32 token) 458 { 459 BAutolock _(this); 460 ETRACE(("events: remove temporary listener token %ld\n", token)); 461 462 if (target.RemoveTemporaryListener(token) && target.IsEmpty()) 463 fTargets.RemoveItem(&target); 464 } 465 466 467 void 468 EventDispatcher::SetMouseFilter(EventFilter* filter) 469 { 470 BAutolock _(this); 471 472 if (fMouseFilter == filter) 473 return; 474 475 delete fMouseFilter; 476 fMouseFilter = filter; 477 } 478 479 480 void 481 EventDispatcher::SetKeyboardFilter(EventFilter* filter) 482 { 483 BAutolock _(this); 484 485 if (fKeyboardFilter == filter) 486 return; 487 488 delete fKeyboardFilter; 489 fKeyboardFilter = filter; 490 } 491 492 493 void 494 EventDispatcher::GetMouse(BPoint& where, int32& buttons) 495 { 496 BAutolock _(this); 497 498 where = fLastCursorPosition; 499 buttons = fLastButtons; 500 } 501 502 503 void 504 EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken) 505 { 506 if (fStream == NULL) 507 return; 508 509 BMessage* fakeMove = new BMessage(kFakeMouseMoved); 510 if (fakeMove == NULL) 511 return; 512 513 fakeMove->AddMessenger("target", target.Messenger()); 514 fakeMove->AddInt32("view_token", viewToken); 515 516 fStream->InsertEvent(fakeMove); 517 } 518 519 520 void 521 EventDispatcher::_SendFakeMouseMoved(BMessage* message) 522 { 523 BMessenger target; 524 int32 viewToken; 525 if (message->FindInt32("view_token", &viewToken) != B_OK 526 || message->FindMessenger("target", &target) != B_OK) 527 return; 528 529 if (fDesktop == NULL) 530 return; 531 532 // Check if the target is still valid 533 ::EventTarget* eventTarget = NULL; 534 535 fDesktop->LockSingleWindow(); 536 537 if (target.IsValid()) 538 eventTarget = fDesktop->FindTarget(target); 539 540 fDesktop->UnlockSingleWindow(); 541 542 if (eventTarget == NULL) 543 return; 544 545 BMessage moved(B_MOUSE_MOVED); 546 moved.AddPoint("screen_where", fLastCursorPosition); 547 moved.AddInt32("buttons", fLastButtons); 548 549 if (fDraggingMessage) 550 moved.AddMessage("be:drag_message", &fDragMessage); 551 552 if (fPreviousMouseTarget != NULL 553 && fPreviousMouseTarget->Messenger() != target) { 554 _AddTokens(&moved, fPreviousMouseTarget, B_POINTER_EVENTS); 555 _SendMessage(fPreviousMouseTarget->Messenger(), &moved, 556 kMouseTransitImportance); 557 558 _RemoveTokens(&moved); 559 } 560 561 moved.AddInt32("_view_token", viewToken); 562 // this only belongs to the new target 563 564 moved.AddBool("be:transit_only", true); 565 // let the view know this what not user generated 566 567 _SendMessage(target, &moved, kMouseTransitImportance); 568 569 fPreviousMouseTarget = eventTarget; 570 } 571 572 573 bigtime_t 574 EventDispatcher::IdleTime() 575 { 576 BAutolock _(this); 577 return system_time() - fLastUpdate; 578 } 579 580 581 bool 582 EventDispatcher::HasCursorThread() 583 { 584 return fCursorThread >= B_OK; 585 } 586 587 588 /*! 589 \brief Sets the HWInterface to use when moving the mouse cursor. 590 \a interface is allowed to be NULL. 591 */ 592 void 593 EventDispatcher::SetHWInterface(HWInterface* interface) 594 { 595 BAutolock _(fCursorLock); 596 597 fHWInterface = interface; 598 599 // adopt the cursor position of the new HW interface 600 if (interface != NULL) 601 fLastCursorPosition = interface->CursorPosition(); 602 } 603 604 605 void 606 EventDispatcher::SetDragMessage(BMessage& message, 607 ServerBitmap* bitmap, const BPoint& offsetFromCursor) 608 { 609 ETRACE(("EventDispatcher::SetDragMessage()\n")); 610 611 BAutolock _(this); 612 613 if (fLastButtons == 0) { 614 // mouse buttons has already been released or was never pressed 615 if (bitmap != NULL) 616 bitmap->ReleaseReference(); 617 return; 618 } 619 620 if (fDragBitmap != bitmap) { 621 if (fDragBitmap) 622 fDragBitmap->ReleaseReference(); 623 624 fDragBitmap = bitmap; 625 626 if (fDragBitmap != NULL) 627 fDragBitmap->AcquireReference(); 628 } 629 630 fHWInterface->SetDragBitmap(bitmap, offsetFromCursor); 631 632 fDragMessage = message; 633 fDraggingMessage = true; 634 fDragOffset = offsetFromCursor; 635 } 636 637 638 void 639 EventDispatcher::SetDesktop(Desktop* desktop) 640 { 641 fDesktop = desktop; 642 } 643 644 645 // #pragma mark - Message methods 646 647 648 /*! 649 \brief Sends \a message to the provided \a messenger. 650 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. 655 656 Returns "false" if the target port does not exist anymore, "true" 657 if it doesn't. 658 */ 659 bool 660 EventDispatcher::_SendMessage(BMessenger& messenger, BMessage* message, 661 float importance) 662 { 663 // TODO: add failed messages to a queue, and start dropping them by importance 664 // (and use the same mechanism in ServerWindow::SendMessageToClient()) 665 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)); 670 } 671 672 if (status == B_BAD_PORT_ID) { 673 // the target port is gone 674 return false; 675 } 676 677 return true; 678 } 679 680 681 bool 682 EventDispatcher::_AddTokens(BMessage* message, EventTarget* target, 683 uint32 eventMask, BMessage* nextMouseMoved, int32* _viewToken) 684 { 685 _RemoveTokens(message); 686 687 int32 count = target->CountListeners(); 688 int32 added = 0; 689 690 for (int32 i = 0; i < count; i++) { 691 event_listener* listener = target->ListenerAt(i); 692 if ((listener->EffectiveEventMask() & eventMask) == 0) 693 continue; 694 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; 702 } 703 continue; 704 } 705 706 ETRACE((" add token %ld\n", listener->token)); 707 708 if (message->AddInt32(kTokenName, listener->token) == B_OK) 709 added++; 710 } 711 712 return added != 0; 713 } 714 715 716 void 717 EventDispatcher::_RemoveTokens(BMessage* message) 718 { 719 message->RemoveName(kTokenName); 720 } 721 722 723 void 724 EventDispatcher::_SetFeedFocus(BMessage* message) 725 { 726 if (message->ReplaceBool("_feed_focus", true) != B_OK) 727 message->AddBool("_feed_focus", true); 728 } 729 730 731 void 732 EventDispatcher::_UnsetFeedFocus(BMessage* message) 733 { 734 message->RemoveName("_feed_focus"); 735 } 736 737 738 void 739 EventDispatcher::_DeliverDragMessage() 740 { 741 ETRACE(("EventDispatcher::_DeliverDragMessage()\n")); 742 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_; 750 751 _SendMessage(fPreviousMouseTarget->Messenger(), 752 &fDragMessage, 100.0); 753 } 754 755 fDragMessage.MakeEmpty(); 756 fDragMessage.what = 0; 757 fDraggingMessage = false; 758 759 fHWInterface->SetDragBitmap(NULL, B_ORIGIN); 760 if (fDragBitmap != NULL) { 761 fDragBitmap->ReleaseReference(); 762 fDragBitmap = NULL; 763 } 764 } 765 766 767 // #pragma mark - Event loops 768 769 770 void 771 EventDispatcher::_EventLoop() 772 { 773 BMessage* event; 774 while (fStream->GetNextEvent(&event)) { 775 BAutolock _(this); 776 fLastUpdate = system_time(); 777 778 EventTarget* current = NULL; 779 EventTarget* previous = NULL; 780 bool pointerEvent = false; 781 bool keyboardEvent = false; 782 bool addedTokens = false; 783 784 switch (event->what) { 785 case kFakeMouseMoved: 786 _SendFakeMouseMoved(event); 787 break; 788 case B_MOUSE_MOVED: 789 { 790 BPoint where; 791 if (event->FindPoint("where", &where) == B_OK) 792 fLastCursorPosition = where; 793 794 if (fDraggingMessage) 795 event->AddMessage("be:drag_message", &fDragMessage); 796 797 if (!HasCursorThread()) { 798 // There is no cursor thread, we need to move the cursor 799 // ourselves 800 BAutolock _(fCursorLock); 801 802 if (fHWInterface != NULL) { 803 fHWInterface->MoveCursorTo(fLastCursorPosition.x, 804 fLastCursorPosition.y); 805 } 806 } 807 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; 819 } 820 } 821 822 // supposed to fall through 823 } 824 case B_MOUSE_DOWN: 825 case B_MOUSE_UP: 826 case B_MOUSE_IDLE: 827 { 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; 833 834 if (fMouseFilter == NULL) 835 break; 836 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(); 847 } 848 break; 849 } 850 851 int32 buttons; 852 if (event->FindInt32("buttons", &buttons) == B_OK) 853 fLastButtons = buttons; 854 else 855 fLastButtons = 0; 856 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); 861 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); 871 872 _SendMessage(fPreviousMouseTarget->Messenger(), event, 873 kMouseTransitImportance); 874 previous = fPreviousMouseTarget; 875 } 876 877 current = fPreviousMouseTarget = mouseTarget; 878 879 if (current != NULL) { 880 int32 focusView = viewToken; 881 addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS, 882 fNextLatestMouseMoved, &focusView); 883 884 bool noPointerHistoryFocus = focusView != viewToken; 885 886 if (viewToken != B_NULL_TOKEN) 887 event->AddInt32("_view_token", viewToken); 888 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; 895 } 896 897 _SendMessage(current->Messenger(), event, 898 event->what == B_MOUSE_MOVED 899 ? kMouseMovedImportance : kStandardImportance); 900 } 901 break; 902 } 903 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)); 911 912 if (fKeyboardFilter != NULL 913 && fKeyboardFilter->Filter(event, &fFocus) 914 == B_SKIP_MESSAGE) { 915 break; 916 } 917 918 keyboardEvent = true; 919 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; 926 927 if (!fSuspendFocus) 928 _SetFeedFocus(event); 929 } 930 931 // supposed to fall through 932 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; 941 942 if (current != NULL && (!fSuspendFocus || addedTokens)) { 943 _SendMessage(current->Messenger(), event, 944 kStandardImportance); 945 } 946 break; 947 } 948 949 if (keyboardEvent || pointerEvent) { 950 // send the event to the additional listeners 951 952 if (addedTokens) { 953 _RemoveTokens(event); 954 _UnsetFeedFocus(event); 955 } 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"); 960 } 961 962 for (int32 i = fTargets.CountItems(); i-- > 0;) { 963 EventTarget* target = fTargets.ItemAt(i); 964 965 // We already sent the event to the all focus and last focus 966 // tokens 967 if (current == target || previous == target) 968 continue; 969 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; 976 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); 982 } 983 } 984 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(); 991 } 992 } 993 994 if (fNextLatestMouseMoved == event) 995 fNextLatestMouseMoved = NULL; 996 delete event; 997 } 998 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(); 1004 1005 if (fDesktop) 1006 fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED); 1007 } 1008 1009 1010 void 1011 EventDispatcher::_CursorLoop() 1012 { 1013 BPoint where; 1014 const bigtime_t toolTipDelay = BToolTipManager::Manager()->ShowDelay(); 1015 bool mouseIdleSent = true; 1016 status_t status = B_OK; 1017 1018 while (status != B_ERROR) { 1019 const bigtime_t timeout = mouseIdleSent ? 1020 B_INFINITE_TIMEOUT : toolTipDelay; 1021 status = fStream->GetNextCursorPosition(where, timeout); 1022 1023 if (status == B_OK) { 1024 mouseIdleSent = false; 1025 BAutolock _(fCursorLock); 1026 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); 1034 } 1035 } 1036 1037 fCursorThread = -1; 1038 } 1039 1040 1041 /*static*/ 1042 status_t 1043 EventDispatcher::_event_looper(void* _dispatcher) 1044 { 1045 EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher; 1046 1047 ETRACE(("Start event loop\n")); 1048 dispatcher->_EventLoop(); 1049 return B_OK; 1050 } 1051 1052 1053 /*static*/ 1054 status_t 1055 EventDispatcher::_cursor_looper(void* _dispatcher) 1056 { 1057 EventDispatcher* dispatcher = (EventDispatcher*)_dispatcher; 1058 1059 ETRACE(("Start cursor loop\n")); 1060 dispatcher->_CursorLoop(); 1061 return B_OK; 1062 } 1063