diff --git a/headers/os/interface/Window.h b/headers/os/interface/Window.h index 072ef913ed..9f65bac427 100644 --- a/headers/os/interface/Window.h +++ b/headers/os/interface/Window.h @@ -310,6 +310,8 @@ private: void _SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred); + bool _StealMouseMessage(BMessage* message, + bool& deleteMessage); bool InUpdate(); void _DequeueAll(); diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index b0599057f0..ec74c9011d 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -1337,21 +1337,27 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue) // Look out for mouse update messages - BMessage *msg; - for (int32 i = 0; (msg = queue->FindMessage(i)) != NULL; i++) { - switch (msg->what) { + BMessage *message; + for (int32 i = 0; (message = queue->FindMessage(i)) != NULL; i++) { + switch (message->what) { + case B_MOUSE_MOVED: case B_MOUSE_UP: case B_MOUSE_DOWN: - case B_MOUSE_MOVED: - msg->FindPoint("screen_where", location); - msg->FindInt32("buttons", (int32 *)buttons); + bool deleteMessage; + if (!Window()->_StealMouseMessage(message, deleteMessage)) + continue; + + message->FindPoint("screen_where", location); + message->FindInt32("buttons", (int32 *)buttons); + queue->Unlock(); + // we need to hold the queue lock until here, because + // the message might still be used for something else ConvertFromScreen(location); - queue->RemoveMessage(msg); - delete msg; + if (deleteMessage) + delete message; - queue->Unlock(); return; } } diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index b356e6f282..89910d7e69 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -2530,8 +2530,7 @@ BWindow::task_looper() while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) { // if there is no target handler, the message is dropped if (handler != NULL) { - if (handler != NULL) - _SanitizeMessage(fLastMessage, handler, usePreferred); + _SanitizeMessage(fLastMessage, handler, usePreferred); // Is this a scripting message? if (fLastMessage->HasSpecifiers()) { @@ -2802,8 +2801,10 @@ BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message, BHandler** _ return false; if (cookie.index == 0 && !cookie.tokens_scanned) { + // We were called the first time for this message + if (!*_usePreferred) { - // we only consider messages targeted at the preferred handler + // only consider messages targeted at the preferred handler cookie.message = NULL; return true; } @@ -2964,6 +2965,60 @@ BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred } +/*! + This is called by BView::GetMouse() when a B_MOUSE_MOVED message + is removed from the queue. + It allows the window to update the last mouse moved view, and + let it decide if this message should be kept. It will also remove + the message from the queue. + You need to hold the message queue lock when calling this method! + + \return true if this message can be used to get the mouse data from, + \return false if this is not meant for the public. +*/ +bool +BWindow::_StealMouseMessage(BMessage* message, bool& deleteMessage) +{ + BMessage::Private messagePrivate(fLastMessage); + if (!messagePrivate.UsePreferredTarget()) { + // this message is targeted at a specific handler, so we should + // not steal it + return false; + } + + int32 token; + if (message->FindInt32("_token", 0, &token) == B_OK) { + // This message has other targets, so we can't remove it; + // just prevent it from being sent to the preferred handler + // again (if it should have gotten it at all). + bool feedFocus; + if (message->FindBool("_feed_focus", &feedFocus) == B_OK && feedFocus) + return false; + + message->RemoveName("_feed_focus"); + deleteMessage = false; + } else { + // The message is only thought for the preferred handler, so we + // can just remove it. + MessageQueue()->RemoveMessage(message); + deleteMessage = true; + + if (message->what == B_MOUSE_MOVED) { + // We need to update the last mouse moved view, as this message + // won't make it to _SanitizeMessage() anymore + BView* viewUnderMouse = NULL; + int32 token; + if (message->FindInt32("_view_token", &token) == B_OK) + viewUnderMouse = _FindView(token); + + fLastMouseMovedView = viewUnderMouse; + } + } + + return true; +} + + /*! Handles keyboard input before it gets forwarded to the target handler. This includes shortcut evaluation, keyboard navigation, etc.