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 fCursorLock("cursor loop lock"), 251 fHWInterface(NULL), 252 fDesktop(NULL) 253 { 254 } 255 256 257 EventDispatcher::~EventDispatcher() 258 { 259 _Unset(); 260 } 261 262 263 status_t 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 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 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 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 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.Get() != NULL) 347 fKeyboardFilter->RemoveTarget(&target); 348 if (fMouseFilter.Get() != NULL) 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 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 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 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 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 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 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 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 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 491 EventDispatcher::GetMouse(BPoint& where, int32& buttons) 492 { 493 BAutolock _(this); 494 495 where = fLastCursorPosition; 496 buttons = fLastButtons; 497 } 498 499 500 void 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 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 571 EventDispatcher::IdleTime() 572 { 573 BAutolock _(this); 574 return system_time() - fLastUpdate; 575 } 576 577 578 bool 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 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 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 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 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 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 702 EventDispatcher::_RemoveTokens(BMessage* message) 703 { 704 message->RemoveName(kTokenName); 705 } 706 707 708 void 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 717 EventDispatcher::_UnsetFeedFocus(BMessage* message) 718 { 719 message->RemoveName("_feed_focus"); 720 } 721 722 723 void 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 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.Get() == NULL) 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.Get() != NULL 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 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 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 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