void EventDispatcher::SendFakeMouseMoved(EventTarget& target, int32 viewToken) { if (fStream == NULL) return; BMessage* fakeMove = new BMessage(kFakeMouseMoved); if (fakeMove == NULL) return; fakeMove->AddMessenger("target", target.Messenger()); fakeMove->AddInt32("view_token", viewToken); fStream->InsertEvent(fakeMove); }
void EventDispatcher::_EventLoop() { BMessage* event; while (fStream->GetNextEvent(&event)) { BAutolock _(this); fLastUpdate = system_time(); EventTarget* current = NULL; EventTarget* previous = NULL; bool pointerEvent = false; bool keyboardEvent = false; bool addedTokens = false; switch (event->what) { case kFakeMouseMoved: _SendFakeMouseMoved(event); break; case B_MOUSE_MOVED: { BPoint where; if (event->FindPoint("where", &where) == B_OK) fLastCursorPosition = where; if (fDraggingMessage) event->AddMessage("be:drag_message", &fDragMessage); if (!HasCursorThread()) { // There is no cursor thread, we need to move the cursor // ourselves BAutolock _(fCursorLock); if (fHWInterface != NULL) { fHWInterface->MoveCursorTo(fLastCursorPosition.x, fLastCursorPosition.y); } } // This is for B_NO_POINTER_HISTORY - we always want the // latest mouse moved event in the queue only if (fNextLatestMouseMoved == NULL) fNextLatestMouseMoved = fStream->PeekLatestMouseMoved(); else if (fNextLatestMouseMoved != event) { // Drop older mouse moved messages if the server is lagging // too much (if the message is older than 100 msecs) bigtime_t eventTime; if (event->FindInt64("when", &eventTime) == B_OK) { if (system_time() - eventTime > 100000) break; } } // supposed to fall through } case B_MOUSE_DOWN: case B_MOUSE_UP: { #ifdef TRACE_EVENTS if (event->what != B_MOUSE_MOVED) printf("mouse up/down event, previous target = %p\n", fPreviousMouseTarget); #endif pointerEvent = true; if (fMouseFilter == NULL) break; EventTarget* mouseTarget = fPreviousMouseTarget; int32 viewToken = B_NULL_TOKEN; if (fMouseFilter->Filter(event, &mouseTarget, &viewToken, fNextLatestMouseMoved) == B_SKIP_MESSAGE) { // this is a work-around if the wrong B_MOUSE_UP // event is filtered out if (event->what == B_MOUSE_UP && event->FindInt32("buttons") == 0) { fSuspendFocus = false; _RemoveTemporaryListeners(); } break; } int32 buttons; if (event->FindInt32("buttons", &buttons) == B_OK) fLastButtons = buttons; else fLastButtons = 0; // The "where" field will be filled in by the receiver // (it's supposed to be expressed in local window coordinates) event->RemoveName("where"); event->AddPoint("screen_where", fLastCursorPosition); if (event->what == B_MOUSE_MOVED && fPreviousMouseTarget != NULL && mouseTarget != fPreviousMouseTarget) { // Target has changed, we need to notify the previous target // that the mouse has exited its views addedTokens = _AddTokens(event, fPreviousMouseTarget, B_POINTER_EVENTS); if (addedTokens) _SetFeedFocus(event); _SendMessage(fPreviousMouseTarget->Messenger(), event, kMouseTransitImportance); previous = fPreviousMouseTarget; } current = fPreviousMouseTarget = mouseTarget; if (current != NULL) { int32 focusView = viewToken; addedTokens |= _AddTokens(event, current, B_POINTER_EVENTS, fNextLatestMouseMoved, &focusView); bool noPointerHistoryFocus = focusView != viewToken; if (viewToken != B_NULL_TOKEN) event->AddInt32("_view_token", viewToken); if (addedTokens && !noPointerHistoryFocus) _SetFeedFocus(event); else if (noPointerHistoryFocus) { // No tokens were added or the focus shouldn't get a // mouse moved break; } _SendMessage(current->Messenger(), event, event->what == B_MOUSE_MOVED ? kMouseMovedImportance : kStandardImportance); } break; } case B_KEY_DOWN: case B_KEY_UP: case B_UNMAPPED_KEY_DOWN: case B_UNMAPPED_KEY_UP: case B_MODIFIERS_CHANGED: case B_INPUT_METHOD_EVENT: ETRACE(("key event, focus = %p\n", fFocus)); if (fKeyboardFilter != NULL && fKeyboardFilter->Filter(event, &fFocus) == B_SKIP_MESSAGE) break; keyboardEvent = true; if (fFocus != NULL && _AddTokens(event, fFocus, B_KEYBOARD_EVENTS)) { // if tokens were added, we need to explicetly suspend // focus in the event - if not, the event is simply not // forwarded to the target addedTokens = true; if (!fSuspendFocus) _SetFeedFocus(event); } // supposed to fall through default: // TODO: the keyboard filter sets the focus - ie. no other // focus messages that go through the event dispatcher can // go through. if (event->what == B_MOUSE_WHEEL_CHANGED) current = fPreviousMouseTarget; else current = fFocus; if (current != NULL && (!fSuspendFocus || addedTokens)) { _SendMessage(current->Messenger(), event, kStandardImportance); } break; } if (keyboardEvent || pointerEvent) { // send the event to the additional listeners if (addedTokens) { _RemoveTokens(event); _UnsetFeedFocus(event); } if (pointerEvent) { // this is added in the Desktop mouse processing // but it's only intended for the focus view event->RemoveName("_view_token"); } for (int32 i = fTargets.CountItems(); i-- > 0;) { EventTarget* target = fTargets.ItemAt(i); // We already sent the event to the all focus and last focus // tokens if (current == target || previous == target) continue; // Don't send the message if there are no tokens for this event if (!_AddTokens(event, target, keyboardEvent ? B_KEYBOARD_EVENTS : B_POINTER_EVENTS, event->what == B_MOUSE_MOVED ? fNextLatestMouseMoved : NULL)) continue; if (!_SendMessage(target->Messenger(), event, event->what == B_MOUSE_MOVED ? kMouseMovedImportance : kListenerImportance)) { // the target doesn't seem to exist anymore, let's remove it fTargets.RemoveItemAt(i); } } if (event->what == B_MOUSE_UP && fLastButtons == 0) { // no buttons are pressed anymore fSuspendFocus = false; _RemoveTemporaryListeners(); if (fDraggingMessage) _DeliverDragMessage(); } } if (fNextLatestMouseMoved == event) fNextLatestMouseMoved = NULL; delete event; } // The loop quit, therefore no more events are coming from the input // server, it must have died. Unset ourselves and notify the desktop. fThread = -1; // Needed to avoid problems with wait_for_thread in _Unset() _Unset(); if (fDesktop) fDesktop->PostMessage(AS_EVENT_STREAM_CLOSED); }