From 6450b76dd4cef8cf04e8d31471517b40a35fa09a Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Axel=20D=C3=B6rfler?= Date: Wed, 23 Nov 2005 15:17:58 +0000 Subject: [PATCH] Next big step in the event handling: * RootLayer's mouse event processing is now at its minimum - the EventDispatcher handles them now. As a result, a window will now get only one message per event. * RootLayer adds "_view_token" to mouse moved messages that specify the view currently under the cursor. * There is now a mouse event layer in RootLayer that gets preferred when it's set - this is now used for the window moving instead of the previous mechanism. * changed the previous DistributeMessage() to an UnpackMessage() method following Adi's suggestion. * caveat: some things might be functionally broken in RootLayer now because of removing the mouse notification stuff. * "be:transit" handling is now done completely client side by BWindow::_SanitizeMessage(() (similar to what the input_server does). This should also make the mechanism pretty robust, since every B_MOUSE_MOVED message can now trigger the view transit (in case a message is lost). B_WINDOW_ACTIVATED messages should be generated client side as well. * renamed AS_LAYER_GET_MOUSE_COORDS to AS_GET_MOUSE as it's not a layer specific command, and also gets the mouse buttons. * B_MOUSE_* messages from the up server now contain only a "screen_where" field; "where" (in window's coordinates) and "be:view_where" are added in BMessage::_SanitizeMessage(). * messages that don't have a valid target in the looper are now dropped instead of being sent to the looper - this should be done in BLooper as well, though. git-svn-id: file:///srv/svn/repos/haiku/haiku/trunk@15087 a95241bf-73f2-0310-859d-f6bbb57e9c96 --- headers/os/interface/Window.h | 6 +- headers/private/app/ServerProtocol.h | 2 +- src/kits/interface/View.cpp | 10 +- src/kits/interface/Window.cpp | 343 ++++++++++++++++++--------- src/servers/app/Desktop.cpp | 2 +- src/servers/app/Layer.cpp | 37 +-- src/servers/app/Layer.h | 7 +- src/servers/app/RootLayer.cpp | 321 ++++--------------------- src/servers/app/RootLayer.h | 19 +- src/servers/app/ServerWindow.cpp | 26 +- src/servers/app/WinBorder.cpp | 2 +- 11 files changed, 322 insertions(+), 453 deletions(-) diff --git a/headers/os/interface/Window.h b/headers/os/interface/Window.h index 87dddee799..da29109add 100644 --- a/headers/os/interface/Window.h +++ b/headers/os/interface/Window.h @@ -226,6 +226,7 @@ public: private: typedef BLooper inherited; + struct unpack_cookie; class Shortcut; friend class BApplication; @@ -267,7 +268,10 @@ private: void AddShortcut(uint32 key, uint32 modifiers, BMenuItem* item); BHandler* _DetermineTarget(BMessage* message, BHandler* target); - bool _DistributeMessage(BMessage* message, BHandler* target); + bool _UnpackMessage(unpack_cookie& state, BMessage** _message, + BHandler** _target, bool* _usePreferred); + void _SanitizeMessage(BMessage* message, BHandler* target, + bool usePreferred); bool InUpdate(); void _DequeueAll(); diff --git a/headers/private/app/ServerProtocol.h b/headers/private/app/ServerProtocol.h index 9d87c2a834..660191266a 100644 --- a/headers/private/app/ServerProtocol.h +++ b/headers/private/app/ServerProtocol.h @@ -186,6 +186,7 @@ enum { AS_RUN_BE_ABOUT, AS_SET_MOUSE_MODE, AS_GET_MOUSE_MODE, + AS_GET_MOUSE, // Hook function messages AS_WORKSPACE_ACTIVATED, @@ -260,7 +261,6 @@ enum { AS_LAYER_END_RECT_TRACK, AS_LAYER_DRAG_RECT, AS_LAYER_DRAG_IMAGE, - AS_LAYER_GET_MOUSE_COORDS, AS_LAYER_SCROLL, AS_LAYER_SET_LINE_MODE, AS_LAYER_GET_LINE_MODE, diff --git a/src/kits/interface/View.cpp b/src/kits/interface/View.cpp index dfa156195a..02c1b787d1 100644 --- a/src/kits/interface/View.cpp +++ b/src/kits/interface/View.cpp @@ -1353,12 +1353,9 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue) case B_MOUSE_UP: case B_MOUSE_DOWN: case B_MOUSE_MOVED: - { - msg->FindPoint("where", location); + msg->FindPoint("screen_where", location); msg->FindInt32("buttons", (int32 *)buttons); - // ToDo: the "where" coordinates are screen coordinates - // unlike R5 - this might break applications! ConvertFromScreen(location); queue->RemoveMessage(msg); @@ -1366,7 +1363,6 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue) queue->Unlock(); return; - } } } queue->Unlock(); @@ -1375,8 +1371,8 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue) // If no mouse update message has been found in the message queue, // we get the current mouse location and buttons from the app_server - fOwner->fLink->StartMessage(AS_LAYER_GET_MOUSE_COORDS); - + fOwner->fLink->StartMessage(AS_GET_MOUSE); + int32 code; if (fOwner->fLink->FlushWithReply(code) == B_OK && code == SERVER_TRUE) { diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index 3badc1d0b8..7038447bac 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -43,6 +43,18 @@ #endif +struct BWindow::unpack_cookie { + unpack_cookie(); + + BMessage* message; + int32 index; + BHandler* focus; + int32 focus_token; + int32 last_view_token; + bool found_focus; + bool tokens_scanned; +}; + class BWindow::Shortcut { public: Shortcut(uint32 key, uint32 modifiers, BMenuItem* item); @@ -135,6 +147,22 @@ _set_menu_sem_(BWindow *window, sem_id sem) // #pragma mark - +BWindow::unpack_cookie::unpack_cookie() + : + message((BMessage*)~0UL), + // message == NULL is our exit condition + index(0), + focus_token(B_NULL_TOKEN), + last_view_token(B_NULL_TOKEN), + found_focus(false), + tokens_scanned(false) +{ +} + + +// #pragma mark - + + BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item) : fKey(PrepareKey(key)), @@ -810,38 +838,24 @@ BWindow::DispatchMessage(BMessage *msg, BHandler *target) case B_MOUSE_DOWN: { BPoint where; - uint32 modifiers; - uint32 buttons; - int32 clicks; - msg->FindPoint("where", &where); - msg->FindInt32("modifiers", (int32 *)&modifiers); - msg->FindInt32("buttons", (int32 *)&buttons); - msg->FindInt32("clicks", &clicks); + msg->FindPoint("be:view_where", &where); - if (target && target != this && target != fTopView) { - if (BView *view = dynamic_cast(target)) { - view->ConvertFromScreen(&where); - view->MouseDown(where); - } else - target->MessageReceived(msg); - } + if (BView *view = dynamic_cast(target)) + view->MouseDown(where); + else + target->MessageReceived(msg); break; } case B_MOUSE_UP: { BPoint where; - uint32 modifiers; - msg->FindPoint("where", &where); - msg->FindInt32("modifiers", (int32 *)&modifiers); + msg->FindPoint("be:view_where", &where); - if (target && target != this && target != fTopView) { - if (BView *view = dynamic_cast(target)) { - view->ConvertFromScreen(&where); - view->MouseUp(where); - } else - target->MessageReceived(msg); - } + if (BView *view = dynamic_cast(target)) + view->MouseUp(where); + else + target->MessageReceived(msg); break; } @@ -850,24 +864,14 @@ BWindow::DispatchMessage(BMessage *msg, BHandler *target) BPoint where; uint32 buttons; uint32 transit; - msg->FindPoint("where", &where); + msg->FindPoint("be:view_where", &where); msg->FindInt32("buttons", (int32 *)&buttons); - msg->FindInt32("transit", (int32 *)&transit); - if (target && target != this && target != fTopView) { - if (BView *view = dynamic_cast(target)) { - if (fLastMouseMovedView != view) { - if (fLastMouseMovedView) { - BPoint p(where); - fLastMouseMovedView->ConvertFromScreen(&p); - fLastMouseMovedView->MouseMoved(p, B_EXITED_VIEW, NULL); - } - fLastMouseMovedView = view; - } - view->ConvertFromScreen(&where); - view->MouseMoved(where, transit, NULL); - } else - target->MessageReceived(msg); - } + msg->FindInt32("be:transit", (int32 *)&transit); + + if (BView *view = dynamic_cast(target)) + view->MouseMoved(where, transit, NULL); + else + target->MessageReceived(msg); break; } @@ -2167,36 +2171,39 @@ BWindow::_DequeueAll() } -/*! This here is a nearly full code duplication to BLooper::task_looper() - but with one little difference: It uses the _DetermineTarget() method - to tell what the later target of a message will be, if no explicit target - is supplied. - This is important because the app_server sends all events to the preferred - handler, and these must be correctly retargeted and eventually distributed - to several handlers using _DistributeMessage(). +/*! This here is an almost complete code duplication to BLooper::task_looper() + but with some important differences: + a) it uses the _DetermineTarget() method to tell what the later target of + a message will be, if no explicit target is supplied. + b) it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message + to all of its intended targets, and to add all fields the target would + expect in such a message. + + This is important because the app_server sends all input events to the + preferred handler, and expects them to be correctly distributed to their + intended targets. */ void BWindow::task_looper() { STRACE(("info: BWindow::task_looper() started.\n")); - // Check that looper is locked (should be) + // Check that looper is locked (should be) AssertLocked(); - // Unlock the looper Unlock(); if (IsLocked()) debugger("window must not be locked!"); - // loop: As long as we are not terminating. + // loop: As long as we are not terminating. while (!fTerminating) { // TODO: timeout determination algo // Read from message port (how do we determine what the timeout is?) BMessage* msg = MessageFromPort(); - // Did we get a message? + // Did we get a message? if (msg) { - // Add to queue + // Add to queue fQueue->AddMessage(msg); } else continue; @@ -2204,22 +2211,22 @@ BWindow::task_looper() // Get message count from port int32 msgCount = port_count(fMsgPort); for (int32 i = 0; i < msgCount; ++i) { - // Read 'count' messages from port (so we will not block) - // We use zero as our timeout since we know there is stuff there + // Read 'count' messages from port (so we will not block) + // We use zero as our timeout since we know there is stuff there msg = MessageFromPort(0); - // Add messages to queue + // Add messages to queue if (msg) fQueue->AddMessage(msg); } - // loop: As long as there are messages in the queue and the port is - // empty... and we are not terminating, of course. + // loop: As long as there are messages in the queue and the port is + // empty... and we are not terminating, of course. bool dispatchNextMessage = true; while (!fTerminating && dispatchNextMessage) { // Get next message from queue (assign to fLastMessage) fLastMessage = fQueue->NextMessage(); - // Lock the looper + // Lock the looper Lock(); if (!fLastMessage) { // No more messages: Unlock the looper and terminate the @@ -2241,40 +2248,41 @@ BWindow::task_looper() B_HANDLER_TOKEN, (void **)&handler); } - // if a target was given, and we should not use the preferred - // handler, we can just use that one if (handler == NULL || usePreferred) handler = _DetermineTarget(fLastMessage, handler); - if (!usePreferred || _DistributeMessage(fLastMessage, handler)) { - if (handler == NULL) - handler = this; - // Is this a scripting message? (BMessage::HasSpecifiers()) - if (fLastMessage->HasSpecifiers()) { - int32 index = 0; - // Make sure the current specifier is kosher - if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) - handler = resolve_specifier(handler, fLastMessage); - } + unpack_cookie cookie; + while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) { + // if there is no target handler, the message is dropped + if (handler != NULL) { + // Is this a scripting message? + if (fLastMessage->HasSpecifiers()) { + int32 index = 0; + // Make sure the current specifier is kosher + if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) + handler = resolve_specifier(handler, fLastMessage); + } - if (handler) { - // Do filtering and dispatch message - handler = _TopLevelFilter(fLastMessage, handler); - if (handler && handler->Looper() == this) + if (handler != NULL) + handler = _TopLevelFilter(fLastMessage, handler); + + if (handler != NULL) { + _SanitizeMessage(fLastMessage, handler, usePreferred); DispatchMessage(fLastMessage, handler); + } } + + // Delete the current message + delete fLastMessage; + fLastMessage = NULL; } } Unlock(); - // Delete the current message (fLastMessage) - delete fLastMessage; - fLastMessage = NULL; - - // Are any messages on the port? + // Are any messages on the port? if (port_count(fMsgPort) > 0) { - // Do outer loop + // Do outer loop dispatchNextMessage = false; } } @@ -2409,8 +2417,6 @@ BWindow::_SetFocus(BView *focusView, bool notifyInputServer) BHandler * BWindow::_DetermineTarget(BMessage *message, BHandler *target) { - // TODO: this is mostly guessed; check for correctness. - switch (message->what) { case B_KEY_DOWN: case B_KEY_UP: @@ -2428,14 +2434,24 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target) case B_UNMAPPED_KEY_DOWN: case B_UNMAPPED_KEY_UP: case B_MODIFIERS_CHANGED: - // these messages will be dispatched by the focus view later + // these messages should be dispatched by the focus view return CurrentFocus(); case B_MOUSE_DOWN: case B_MOUSE_UP: case B_MOUSE_MOVED: case B_MOUSE_WHEEL_CHANGED: - // TODO: the app_server should tell us which view is the target + // is there a token of the view that is currently under the mouse? + int32 token; + if (message->FindInt32("_view_token", &token) == B_OK) { + BHandler* handler; + if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN, + (void**)&handler) == B_OK) { + BView* view = dynamic_cast(handler); + if (view != NULL) + return view; + } + } break; case B_PULSE: @@ -2443,19 +2459,6 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target) // TODO: test wether R5 will let BView dispatch these messages return this; - case B_VIEW_RESIZED: - case B_VIEW_MOVED: - { - int32 token; - if (message->FindInt32("_token", &token) != B_OK) - token = B_NULL_TOKEN; - - BView *view = _FindView(token); - if (view) - return view; - break; - } - default: break; } @@ -2471,44 +2474,150 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target) Returns \c true in case the message should still be dispatched */ bool -BWindow::_DistributeMessage(BMessage* message, BHandler* focus) +BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message, BHandler** _target, + bool* _usePreferred) { - bool foundFocus = false; - int32 focusToken = B_NULL_TOKEN; - if (focus != NULL) - focusToken = _get_object_token_(focus); + if (cookie.message == NULL) + return false; - int32 index = 0; - int32 token; - for (; message->FindInt32("_token", index, &token) == B_OK; index++) { - if (token == focusToken) - foundFocus = true; + if (cookie.index == 0 && !cookie.tokens_scanned) { + if (!*_usePreferred) { + // we only consider messages targeted at the preferred handler + cookie.message = NULL; + return true; + } + + // initialize our cookie + cookie.message = *_message; + cookie.focus = *_target; + + if (cookie.focus != NULL) + cookie.focus_token = _get_object_token_(*_target); + + if (fLastMouseMovedView != NULL && cookie.message->what == B_MOUSE_MOVED) + cookie.last_view_token = _get_object_token_(fLastMouseMovedView); + + *_usePreferred = false; + } + + _DequeueAll(); + + // distribute the message to all targets specified in the + // message directly (but not to the focus view) + + for (int32 token; !cookie.tokens_scanned + && cookie.message->FindInt32("_token", cookie.index, &token) == B_OK; + cookie.index++) { + // focus view is preferred and should get its message directly + if (token == cookie.focus_token) { + cookie.found_focus = true; + continue; + } + if (token == cookie.last_view_token) + continue; BView* target = _FindView(token); if (target == NULL) continue; - BMessenger messenger(target); - messenger.SendMessage(message); + *_message = new BMessage(*cookie.message); + *_target = target; + cookie.index++; + return true; } - if (index > 0) { - if (foundFocus) { - // the focus view already got this message - return false; - } + cookie.tokens_scanned = true; + // if there is a last mouse moved view, and the new focus is + // different, the previous view wants to get its B_EXITED_VIEW + // message + if (cookie.last_view_token != B_NULL_TOKEN && fLastMouseMovedView != cookie.focus) { + *_message = new BMessage(*cookie.message); + *_target = fLastMouseMovedView; + cookie.last_view_token = B_NULL_TOKEN; + return true; + } + + if (cookie.index > 0) { // should this message still be dispatched by the focus view? bool feedFocus; - if (message->FindBool("_feed_focus", &feedFocus) != B_OK - || feedFocus == false) + if (!cookie.found_focus + && (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK + || feedFocus == false)) { + delete cookie.message; + cookie.message = NULL; return false; + } } + *_message = cookie.message; + *_target = cookie.focus; + *_usePreferred = true; + cookie.message = NULL; return true; } +void +BWindow::_SanitizeMessage(BMessage* message, BHandler* target, bool usePreferred) +{ + if (target == NULL) + return; + + switch (message->what) { + case B_MOUSE_MOVED: + case B_MOUSE_UP: + case B_MOUSE_DOWN: + BPoint where; + if (message->FindPoint("screen_where", &where) != B_OK) + break; + + // add local window coordinates + message->AddPoint("where", ConvertFromScreen(where)); + + BView* view = dynamic_cast(target); + if (view != NULL) { + // add local view coordinates + message->AddPoint("be:view_where", view->ConvertFromScreen(where)); + + // is there a token of the view that is currently under the mouse? + BView* viewUnderMouse = NULL; + int32 token; + if (message->FindInt32("_view_token", &token) == B_OK) { + BHandler* handler; + if (gDefaultTokens.GetToken(token, B_HANDLER_TOKEN, + (void**)&handler) == B_OK) + viewUnderMouse = dynamic_cast(handler); + } + + // add transit information + int32 transit; + if (message->FindInt32("be:transit", &transit) != B_OK) { + if (viewUnderMouse == view) { + // the mouse is over the target view + if (fLastMouseMovedView != view) + transit = B_ENTERED_VIEW; + else + transit = B_INSIDE_VIEW; + } else { + // the mouse is not over the target view + if (view == fLastMouseMovedView) + transit = B_EXITED_VIEW; + else + transit = B_OUTSIDE_VIEW; + } + + message->AddInt32("be:transit", transit); + } + + if (usePreferred || viewUnderMouse == NULL) + fLastMouseMovedView = viewUnderMouse; + } + break; + } +} + + bool BWindow::_HandleKeyDown(char key, uint32 modifiers) { diff --git a/src/servers/app/Desktop.cpp b/src/servers/app/Desktop.cpp index 5dd58f5e46..5130c81215 100644 --- a/src/servers/app/Desktop.cpp +++ b/src/servers/app/Desktop.cpp @@ -210,7 +210,7 @@ Desktop::Init() fRootLayer->Lock(); fRootLayer->MouseEventHandler(message); fRootLayer->Unlock(); - return B_SKIP_MESSAGE; + return B_DISPATCH_MESSAGE; } private: diff --git a/src/servers/app/Layer.cpp b/src/servers/app/Layer.cpp index 3920c49766..6d06a60015 100644 --- a/src/servers/app/Layer.cpp +++ b/src/servers/app/Layer.cpp @@ -424,7 +424,7 @@ Layer::SetName(const char* name) fName.SetTo(name); } -// SetUserClipping + void Layer::SetUserClipping(const BRegion& region) { @@ -434,7 +434,7 @@ Layer::SetUserClipping(const BRegion& region) _RebuildDrawingRegion(); } -// SetFlags + void Layer::SetFlags(uint32 flags) { @@ -442,7 +442,15 @@ Layer::SetFlags(uint32 flags) fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); } -// Draw + +void +Layer::SetEventMask(uint32 eventMask, uint32 options) +{ + fEventMask = eventMask; + fEventOptions = options; +} + + void Layer::Draw(const BRect &rect) { @@ -823,55 +831,46 @@ Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset) } } + void Layer::MouseDown(const BMessage *msg) { - if (Window() && !IsTopLayer()) { - Window()->SendMessageToClient(msg, fViewToken); - } } + void Layer::MouseUp(const BMessage *msg) { - if (Window() && !IsTopLayer()) { - Window()->SendMessageToClient(msg, fViewToken); - } } + void Layer::MouseMoved(const BMessage *msg) { - if (Window() && !IsTopLayer()) { - Window()->SendMessageToClient(msg, fViewToken); - } } + void Layer::MouseWheelChanged(const BMessage *msg) { - if (Window() && !IsTopLayer()) { - Window()->SendMessageToClient(msg, fViewToken); - } } void Layer::WorkspaceActivated(int32 index, bool active) { - // Empty } + void Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) { - // Empty } + void Layer::Activated(bool active) { - // Empty } @@ -881,6 +880,7 @@ Layer::ScrollingOffset() const return fScrollingOffset; } + void Layer::SetDrawingOrigin(BPoint origin) { @@ -1497,6 +1497,7 @@ Layer::_AllRedraw(const BRegion &invalid) } } + void Layer::_AddToViewsWithInvalidCoords() const { diff --git a/src/servers/app/Layer.h b/src/servers/app/Layer.h index a411f7a95b..da93ba5315 100644 --- a/src/servers/app/Layer.h +++ b/src/servers/app/Layer.h @@ -182,15 +182,12 @@ class Layer { DrawingEngine* GetDrawingEngine() const { return fDriver; } - // flags + void SetEventMask(uint32 eventMask, uint32 options); uint32 EventMask() const { return fEventMask; } uint32 EventOptions() const { return fEventOptions; } - inline void QuietlySetEventMask(uint32 em) - { fEventMask = em; } - inline void QuietlySetEventOptions(uint32 eo) - { fEventOptions = eo; } + inline uint32 ResizeMode() const { return fResizeMode; } inline uint32 Flags() const diff --git a/src/servers/app/RootLayer.cpp b/src/servers/app/RootLayer.cpp index 7bce99d736..751b139daa 100644 --- a/src/servers/app/RootLayer.cpp +++ b/src/servers/app/RootLayer.cpp @@ -61,17 +61,13 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount, fDesktop(desktop), fDragMessage(NULL), - fLastLayerUnderMouse(this), - fNotifyLayer(NULL), + fMouseEventLayer(NULL), fSavedEventMask(0), fSavedEventOptions(0), fAllRegionsLock("root layer region lock"), fDirtyForRedraw(), - fButtons(0), - fLastMousePosition(0.0, 0.0), - fActiveWksIndex(0), fWsCount(0), fWorkspace(new Workspace*[kMaxWorkspaceCount]), @@ -371,18 +367,17 @@ bool RootLayer::SetActiveWorkspace(int32 index) return false; // you cannot switch workspaces on R5 if there is an event mask BView - if (fNotifyLayer && fNotifyLayer->Owner()) - return false; +// if (fNotifyLayer && fNotifyLayer->Owner()) +// return false; // if you're dragging something you are allowed to change workspaces only if // the Layer being dragged is a B_NORMAL_WINDOW_FEEL WinBorder. - WinBorder *draggedWinBorder = dynamic_cast(fNotifyLayer); - if (fNotifyLayer) { + WinBorder *draggedWinBorder = dynamic_cast(fMouseEventLayer); + if (fMouseEventLayer != NULL) { if (draggedWinBorder) { if (draggedWinBorder->Feel() != B_NORMAL_WINDOW_FEEL) return false; - } - else + } else return false; } @@ -478,9 +473,9 @@ RootLayer::SetWinBorderWorskpaces(WinBorder *winBorder, uint32 oldIndex, uint32 { // if the active notify Layer is somehow related to winBorder, then // this window/WinBorder is not allowed to leave this workspace. - if (fNotifyLayer && (fNotifyLayer == winBorder || fNotifyLayer->Owner() == winBorder)) { - newIndex |= (0x00000001UL << fActiveWksIndex); - } +// TODO: this looks wrong: I doubt the window is supposed to open in two workspaces then +// if (fNotifyLayer && (fNotifyLayer == winBorder || fNotifyLayer->Owner() == winBorder)) +// newIndex |= (0x00000001UL << fActiveWksIndex); uint32 localOldIndex = oldIndex; uint32 localNewIndex = newIndex; @@ -851,25 +846,13 @@ RootLayer::SetActive(WinBorder* newActive, bool activate) return returnValue; } -//--------------------------------------------------------------------------- -// Workspace related methods -//--------------------------------------------------------------------------- -//--------------------------------------------------------------------------- -// Input related methods -//--------------------------------------------------------------------------- +// #pragma mark - Input related methods + + void -RootLayer::_ProcessMouseMovedEvent(BMessage *msg) +RootLayer::_ProcessMouseMovedEvent(BMessage *msg, BPoint where, Layer* target) { - BPoint where(0,0); - msg->FindPoint("where", &where); - - Layer* target = LayerAt(where); - if (target == NULL) { - CRITICAL("RootLayer::_ProcessMouseMovedEvent() 'target' can't be null.\n"); - return; - } - // change focus in FFM mode WinBorder* winBorderTarget = dynamic_cast(target); if (winBorderTarget) { @@ -886,266 +869,60 @@ RootLayer::_ProcessMouseMovedEvent(BMessage *msg) } } - // add the layer under mouse to the list of layers to be notified on mouse moved - bool alreadyPresent = fMouseNotificationList.HasItem(target); - if (!alreadyPresent) - fMouseNotificationList.AddItem(target); + target->MouseMoved(msg); +} - int32 count = fMouseNotificationList.CountItems(); - int32 viewAction; - Layer *lay; - for (int32 i = 0; i <= count; i++) { - lay = static_cast(fMouseNotificationList.ItemAt(i)); - if (lay) { - // set transit state - if (lay == target) - if (lay == fLastLayerUnderMouse) - viewAction = B_INSIDE_VIEW; - else - viewAction = B_ENTERED_VIEW; - else - if (lay == fLastLayerUnderMouse) - viewAction = B_EXITED_VIEW; - else - viewAction = B_OUTSIDE_VIEW; - msg->AddInt32("transit", viewAction); - lay->MouseMoved(msg); +void +RootLayer::MouseEventHandler(BMessage *event) +{ + BPoint where; + if (event->FindPoint("where", &where) != B_OK) + return; + + Layer* layer = fMouseEventLayer; + if (layer == NULL) { + if (fWMState.Focus != NULL) { + layer = fWMState.Focus->LayerAt(where); + if (layer != NULL) + event->AddInt32("_view_token", layer->ViewToken()); + } + if (layer == NULL) { + layer = LayerAt(where); + if (layer == NULL) + return; } } - if (!alreadyPresent) - fMouseNotificationList.RemoveItem(target); - - fLastLayerUnderMouse = target; - fLastMousePosition = where; -} - -void -RootLayer::MouseEventHandler(BMessage *msg) -{ - switch (msg->what) { - case B_MOUSE_DOWN: { - //printf("RootLayer::MouseEventHandler(B_MOUSE_DOWN)\n"); - - BPoint where(0,0); - - msg->FindPoint("where", &where); - // We'll need this so that GetMouse can query for which buttons are down. - msg->FindInt32("buttons", &fButtons); - - where.ConstrainTo(Frame()); - - if (fLastMousePosition != where) { - // If this happens, it's input server's fault. - // There might be additional fields an application expects in B_MOUSE_MOVED - // message, and in this way it won't get them. - int64 when = 0; - int32 buttons = 0; - - msg->FindInt64("when", &when); - msg->FindInt32("buttons", &buttons); - - BMessage mouseMovedMsg(B_MOUSE_MOVED); - mouseMovedMsg.AddInt64("when", when); - mouseMovedMsg.AddInt32("buttons", buttons); - mouseMovedMsg.AddPoint("where", where); - - _ProcessMouseMovedEvent(msg); - } - - if (fLastLayerUnderMouse == NULL) { - CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_DOWN) fLastLayerUnderMouse is null!\n"); - break; - } - - if (fLastLayerUnderMouse == this) - break; - - int32 count = fMouseNotificationList.CountItems(); - Layer *lay; - for (int32 i = 0; i <= count; i++) { - lay = static_cast(fMouseNotificationList.ItemAt(i)); - if (lay) - // NOTE: testing under R5 shows that it doesn't matter if a window is created - // with B_ASYNCHRONOUS_CONTROLS flag or not. B_MOUSE_DOWN is always transmited. - lay->MouseDown(msg); - } - - // get the pointer for one of the first RootLayer's descendants - Layer *primaryTarget = LayerAt(where, false); - primaryTarget->MouseDown(msg); - + switch (event->what) { + case B_MOUSE_DOWN: + layer->MouseDown(event); break; - } - case B_MOUSE_UP: { - //printf("RootLayer::MouseEventHandler(B_MOUSE_UP)\n"); - BPoint where(0,0); - - msg->FindPoint("where", &where); - - where.ConstrainTo(fFrame); - - if (fLastMousePosition != where) { - // If this happens, it's input server's fault. - // There might be additional fields an application expects in B_MOUSE_MOVED - // message, and in this way it won't get them. - int64 when = 0; - int32 buttons = 0; - - msg->FindInt64("when", &when); - msg->FindInt32("buttons", &buttons); - - BMessage mouseMovedMsg(B_MOUSE_MOVED); - mouseMovedMsg.AddInt64("when", when); - mouseMovedMsg.AddInt32("buttons", buttons); - mouseMovedMsg.AddPoint("where", where); - - _ProcessMouseMovedEvent(msg); - } - - if (fLastLayerUnderMouse == NULL) { - CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_UP) fLastLayerUnderMouse is null!\n"); - break; - } - - bool foundCurrent = fMouseNotificationList.HasItem(fLastLayerUnderMouse); - int32 count = fMouseNotificationList.CountItems(); - Layer *lay; - for (int32 i = 0; i <= count; i++) { - lay = static_cast(fMouseNotificationList.ItemAt(i)); - if (lay) - lay->MouseUp(msg); - } - ClearNotifyLayer(); - - if (!foundCurrent) - fLastLayerUnderMouse->MouseUp(msg); - - // TODO: This is a quick fix to avoid the endless loop with windows created - // with the B_ASYNCHRONOUS_CONTROLS flag, but please someone have a look into this. - fButtons = 0; - + case B_MOUSE_UP: + layer->MouseUp(event); + SetMouseEventLayer(NULL); break; - } + case B_MOUSE_MOVED: - _ProcessMouseMovedEvent(msg); + _ProcessMouseMovedEvent(event, where, layer); break; - - case B_MOUSE_WHEEL_CHANGED: { - //printf("RootLayer::MouseEventHandler(B_MOUSE_WHEEL_CHANGED)\n"); - // FEATURE: This is a tentative change: mouse wheel messages are always sent to the window - // under the cursor. It's pretty stupid to send it to the active window unless a particular - // view has locked focus via SetMouseEventMask - - if (fLastLayerUnderMouse == NULL) { - CRITICAL("RootLayer::MouseEventHandler(B_MOUSE_DOWN) fLastLayerUnderMouse is null!\n"); - break; - } - - fLastLayerUnderMouse->MouseWheelChanged(msg); - break; - } - default: - { - printf("RootLayer::MouseEventHandler(): WARNING: unknown message\n"); - break; - } } } -bool -RootLayer::AddToInputNotificationLists(Layer *lay, uint32 mask, uint32 options) -{ - if (!lay) - return false; - - bool returnValue = true; - - Lock(); - - if (mask & B_POINTER_EVENTS) { - if (!fMouseNotificationList.HasItem(lay)) - fMouseNotificationList.AddItem(lay); - } - else { - if (options == 0) - fMouseNotificationList.RemoveItem(lay); - } - - if (mask & B_KEYBOARD_EVENTS) { - if (!fKeyboardNotificationList.HasItem(lay)) - fKeyboardNotificationList.AddItem(lay); - } - else { - if (options == 0) - fKeyboardNotificationList.RemoveItem(lay); - } - - // TODO: set options!!! - // B_NO_POINTER_HISTORY only! How? By telling to the input_server? - - Unlock(); - - return returnValue; -} - -bool -RootLayer::SetNotifyLayer(Layer *lay, uint32 mask, uint32 options) -{ - if (!lay) - return false; - - bool returnValue = true; - - Lock(); - - fNotifyLayer = lay; - fSavedEventMask = lay->EventMask(); - fSavedEventOptions = lay->EventOptions(); - - AddToInputNotificationLists(lay, mask, options); - - // TODO: set other options!!! - // B_SUSPEND_VIEW_FOCUS - // B_LOCK_WINDOW_FOCUS - Unlock(); - - return returnValue; -} - void -RootLayer::ClearNotifyLayer() +RootLayer::SetMouseEventLayer(Layer* layer) { - if (fNotifyLayer) { - Lock(); - // remove from notification list. - AddToInputNotificationLists(fNotifyLayer, 0UL, 0UL); - // set event masks - fNotifyLayer->QuietlySetEventMask(fSavedEventMask); - fNotifyLayer->QuietlySetEventOptions(fSavedEventOptions); - // add to notification list with event masks set my BView::SetEventMask() - AddToInputNotificationLists(fNotifyLayer, fSavedEventMask, fSavedEventOptions); - - fNotifyLayer = NULL; - fSavedEventMask = 0UL; - fSavedEventOptions = 0UL; - - Unlock(); - } + fMouseEventLayer = layer; } void RootLayer::LayerRemoved(Layer* layer) { - if (layer == fNotifyLayer) - fNotifyLayer = NULL; -// TODO: this must not happen!!! Fix this, quickly! - if (layer == fLastLayerUnderMouse) - fLastLayerUnderMouse = NULL; + if (fMouseEventLayer == layer) + fMouseEventLayer = NULL; } @@ -1158,7 +935,7 @@ RootLayer::SetDragMessage(BMessage* msg) } if (msg) - fDragMessage = new BMessage(*msg); + fDragMessage = new BMessage(*msg); } @@ -1245,12 +1022,6 @@ RootLayer::hide_winBorder(WinBorder *winBorder) void RootLayer::change_winBorder_feel(WinBorder *winBorder, int32 newFeel) { - // if the notify Layer is somehow related to winBorder, then - // this window/WinBorder is not allowed to change feel. - if (fNotifyLayer && (fNotifyLayer == winBorder || fNotifyLayer->Owner() == winBorder)) { - return; - } - bool isVisible = false; bool isVisibleInActiveWorkspace = false; diff --git a/src/servers/app/RootLayer.h b/src/servers/app/RootLayer.h index d9e07a34c3..a5eaaaba66 100644 --- a/src/servers/app/RootLayer.h +++ b/src/servers/app/RootLayer.h @@ -96,16 +96,11 @@ public: void SetBGColor(const RGBColor &col); RGBColor BGColor(void) const; - - inline int32 Buttons(void) { return fButtons; } - + void SetDragMessage(BMessage *msg); BMessage* DragMessage(void) const; - bool AddToInputNotificationLists(Layer *lay, uint32 mask, - uint32 options); - bool SetNotifyLayer(Layer *lay, uint32 mask, uint32 options); - void ClearNotifyLayer(); + void SetMouseEventLayer(Layer* layer); void LayerRemoved(Layer* layer); @@ -139,25 +134,19 @@ friend class Desktop; // Input related methods void MouseEventHandler(BMessage *msg); - void _ProcessMouseMovedEvent(BMessage *msg); + void _ProcessMouseMovedEvent(BMessage *msg, BPoint where, Layer* target); Desktop* fDesktop; BMessage* fDragMessage; - Layer* fLastLayerUnderMouse; + Layer* fMouseEventLayer; - Layer* fNotifyLayer; uint32 fSavedEventMask; uint32 fSavedEventOptions; - BList fMouseNotificationList; - BList fKeyboardNotificationList; BLocker fAllRegionsLock; BRegion fDirtyForRedraw; - int32 fButtons; - BPoint fLastMousePosition; - int32 fActiveWksIndex; int32 fWsCount; Workspace** fWorkspace; diff --git a/src/servers/app/ServerWindow.cpp b/src/servers/app/ServerWindow.cpp index 191925625f..1fda646767 100644 --- a/src/servers/app/ServerWindow.cpp +++ b/src/servers/app/ServerWindow.cpp @@ -718,9 +718,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link) link.Read(&eventMask); if (link.Read(&options) == B_OK) { -printf("got %s: eventMask = %ld, options = %ld\n", fCurrentLayer->Name(), eventMask, options); - fCurrentLayer->QuietlySetEventMask(eventMask); - fCurrentLayer->QuietlySetEventOptions(options); + fCurrentLayer->SetEventMask(eventMask, options); if (eventMask != 0 || options != 0) { fDesktop->EventDispatcher().AddListener(FocusMessenger(), @@ -749,8 +747,7 @@ printf("got %s: eventMask = %ld, options = %ld\n", fCurrentLayer->Name(), eventM } } - if (rootLayer) - rootLayer->SetNotifyLayer(fCurrentLayer, eventMask, options); + // TODO: support B_LOCK_WINDOW_FOCUS option in RootLayer break; } case AS_LAYER_MOVE_TO: @@ -1602,23 +1599,25 @@ if (rootLayer) DTRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n", Title())); break; } - case AS_LAYER_GET_MOUSE_COORDS: + case AS_GET_MOUSE: { - DTRACE(("ServerWindow %s: Message AS_GET_MOUSE_COORDS\n", fTitle)); - - fLink.StartMessage(SERVER_TRUE); + DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle)); // Returns // 1) BPoint mouse location // 2) int32 button state - fLink.Attach(fDesktop->HWInterface()->GetCursorPosition()); - fLink.Attach(fDesktop->RootLayer()->Buttons()); + BPoint where; + int32 buttons; + fDesktop->EventDispatcher().GetMouse(where, buttons); + fLink.StartMessage(B_OK); + fLink.Attach(where); + fLink.Attach(buttons); fLink.Flush(); break; } - + case AS_DW_GET_SYNC_DATA: { // TODO: Use token or get rid of it. @@ -2116,6 +2115,9 @@ ServerWindow::_MessageLooper() status_t ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const { + if (target == B_NULL_TOKEN) + target = fClientToken; + #ifndef USING_MESSAGE4 ssize_t size = msg->FlattenedSize(); char* buffer = new(nothrow) char[size]; diff --git a/src/servers/app/WinBorder.cpp b/src/servers/app/WinBorder.cpp index 4767620e3a..648868bec2 100644 --- a/src/servers/app/WinBorder.cpp +++ b/src/servers/app/WinBorder.cpp @@ -481,7 +481,7 @@ WinBorder::MouseDown(const BMessage *msg) if (action == DEC_MOVETOBACK) { GetRootLayer()->SetActive(this, false); } else { - GetRootLayer()->SetNotifyLayer(this, B_POINTER_EVENTS, 0UL); + GetRootLayer()->SetMouseEventLayer(this); GetRootLayer()->SetActive(this); } } else if (target != NULL) {