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
This commit is contained in:
Axel Dörfler
2005-11-23 15:17:58 +00:00
parent 8196fa8da4
commit 6450b76dd4
11 changed files with 322 additions and 453 deletions
+5 -1
View File
@@ -226,6 +226,7 @@ public:
private: private:
typedef BLooper inherited; typedef BLooper inherited;
struct unpack_cookie;
class Shortcut; class Shortcut;
friend class BApplication; friend class BApplication;
@@ -267,7 +268,10 @@ private:
void AddShortcut(uint32 key, uint32 modifiers, void AddShortcut(uint32 key, uint32 modifiers,
BMenuItem* item); BMenuItem* item);
BHandler* _DetermineTarget(BMessage* message, BHandler* target); 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(); bool InUpdate();
void _DequeueAll(); void _DequeueAll();
+1 -1
View File
@@ -186,6 +186,7 @@ enum {
AS_RUN_BE_ABOUT, AS_RUN_BE_ABOUT,
AS_SET_MOUSE_MODE, AS_SET_MOUSE_MODE,
AS_GET_MOUSE_MODE, AS_GET_MOUSE_MODE,
AS_GET_MOUSE,
// Hook function messages // Hook function messages
AS_WORKSPACE_ACTIVATED, AS_WORKSPACE_ACTIVATED,
@@ -260,7 +261,6 @@ enum {
AS_LAYER_END_RECT_TRACK, AS_LAYER_END_RECT_TRACK,
AS_LAYER_DRAG_RECT, AS_LAYER_DRAG_RECT,
AS_LAYER_DRAG_IMAGE, AS_LAYER_DRAG_IMAGE,
AS_LAYER_GET_MOUSE_COORDS,
AS_LAYER_SCROLL, AS_LAYER_SCROLL,
AS_LAYER_SET_LINE_MODE, AS_LAYER_SET_LINE_MODE,
AS_LAYER_GET_LINE_MODE, AS_LAYER_GET_LINE_MODE,
+3 -7
View File
@@ -1353,12 +1353,9 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue)
case B_MOUSE_UP: case B_MOUSE_UP:
case B_MOUSE_DOWN: case B_MOUSE_DOWN:
case B_MOUSE_MOVED: case B_MOUSE_MOVED:
{ msg->FindPoint("screen_where", location);
msg->FindPoint("where", location);
msg->FindInt32("buttons", (int32 *)buttons); msg->FindInt32("buttons", (int32 *)buttons);
// ToDo: the "where" coordinates are screen coordinates
// unlike R5 - this might break applications!
ConvertFromScreen(location); ConvertFromScreen(location);
queue->RemoveMessage(msg); queue->RemoveMessage(msg);
@@ -1366,7 +1363,6 @@ BView::GetMouse(BPoint *location, uint32 *buttons, bool checkMessageQueue)
queue->Unlock(); queue->Unlock();
return; return;
}
} }
} }
queue->Unlock(); 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, // If no mouse update message has been found in the message queue,
// we get the current mouse location and buttons from the app_server // 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; int32 code;
if (fOwner->fLink->FlushWithReply(code) == B_OK if (fOwner->fLink->FlushWithReply(code) == B_OK
&& code == SERVER_TRUE) { && code == SERVER_TRUE) {
+226 -117
View File
@@ -43,6 +43,18 @@
#endif #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 { class BWindow::Shortcut {
public: public:
Shortcut(uint32 key, uint32 modifiers, BMenuItem* item); Shortcut(uint32 key, uint32 modifiers, BMenuItem* item);
@@ -135,6 +147,22 @@ _set_menu_sem_(BWindow *window, sem_id sem)
// #pragma mark - // #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) BWindow::Shortcut::Shortcut(uint32 key, uint32 modifiers, BMenuItem* item)
: :
fKey(PrepareKey(key)), fKey(PrepareKey(key)),
@@ -810,38 +838,24 @@ BWindow::DispatchMessage(BMessage *msg, BHandler *target)
case B_MOUSE_DOWN: case B_MOUSE_DOWN:
{ {
BPoint where; BPoint where;
uint32 modifiers; msg->FindPoint("be:view_where", &where);
uint32 buttons;
int32 clicks;
msg->FindPoint("where", &where);
msg->FindInt32("modifiers", (int32 *)&modifiers);
msg->FindInt32("buttons", (int32 *)&buttons);
msg->FindInt32("clicks", &clicks);
if (target && target != this && target != fTopView) { if (BView *view = dynamic_cast<BView *>(target))
if (BView *view = dynamic_cast<BView *>(target)) { view->MouseDown(where);
view->ConvertFromScreen(&where); else
view->MouseDown(where); target->MessageReceived(msg);
} else
target->MessageReceived(msg);
}
break; break;
} }
case B_MOUSE_UP: case B_MOUSE_UP:
{ {
BPoint where; BPoint where;
uint32 modifiers; msg->FindPoint("be:view_where", &where);
msg->FindPoint("where", &where);
msg->FindInt32("modifiers", (int32 *)&modifiers);
if (target && target != this && target != fTopView) { if (BView *view = dynamic_cast<BView *>(target))
if (BView *view = dynamic_cast<BView *>(target)) { view->MouseUp(where);
view->ConvertFromScreen(&where); else
view->MouseUp(where); target->MessageReceived(msg);
} else
target->MessageReceived(msg);
}
break; break;
} }
@@ -850,24 +864,14 @@ BWindow::DispatchMessage(BMessage *msg, BHandler *target)
BPoint where; BPoint where;
uint32 buttons; uint32 buttons;
uint32 transit; uint32 transit;
msg->FindPoint("where", &where); msg->FindPoint("be:view_where", &where);
msg->FindInt32("buttons", (int32 *)&buttons); msg->FindInt32("buttons", (int32 *)&buttons);
msg->FindInt32("transit", (int32 *)&transit); msg->FindInt32("be:transit", (int32 *)&transit);
if (target && target != this && target != fTopView) {
if (BView *view = dynamic_cast<BView *>(target)) { if (BView *view = dynamic_cast<BView *>(target))
if (fLastMouseMovedView != view) { view->MouseMoved(where, transit, NULL);
if (fLastMouseMovedView) { else
BPoint p(where); target->MessageReceived(msg);
fLastMouseMovedView->ConvertFromScreen(&p);
fLastMouseMovedView->MouseMoved(p, B_EXITED_VIEW, NULL);
}
fLastMouseMovedView = view;
}
view->ConvertFromScreen(&where);
view->MouseMoved(where, transit, NULL);
} else
target->MessageReceived(msg);
}
break; break;
} }
@@ -2167,36 +2171,39 @@ BWindow::_DequeueAll()
} }
/*! This here is a nearly full code duplication to BLooper::task_looper() /*! This here is an almost complete code duplication to BLooper::task_looper()
but with one little difference: It uses the _DetermineTarget() method but with some important differences:
to tell what the later target of a message will be, if no explicit target a) it uses the _DetermineTarget() method to tell what the later target of
is supplied. a message will be, if no explicit target is supplied.
This is important because the app_server sends all events to the preferred b) it calls _UnpackMessage() and _SanitizeMessage() to duplicate the message
handler, and these must be correctly retargeted and eventually distributed to all of its intended targets, and to add all fields the target would
to several handlers using _DistributeMessage(). 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 void
BWindow::task_looper() BWindow::task_looper()
{ {
STRACE(("info: BWindow::task_looper() started.\n")); STRACE(("info: BWindow::task_looper() started.\n"));
// Check that looper is locked (should be) // Check that looper is locked (should be)
AssertLocked(); AssertLocked();
// Unlock the looper
Unlock(); Unlock();
if (IsLocked()) if (IsLocked())
debugger("window must not be locked!"); debugger("window must not be locked!");
// loop: As long as we are not terminating. // loop: As long as we are not terminating.
while (!fTerminating) { while (!fTerminating) {
// TODO: timeout determination algo // TODO: timeout determination algo
// Read from message port (how do we determine what the timeout is?) // Read from message port (how do we determine what the timeout is?)
BMessage* msg = MessageFromPort(); BMessage* msg = MessageFromPort();
// Did we get a message? // Did we get a message?
if (msg) { if (msg) {
// Add to queue // Add to queue
fQueue->AddMessage(msg); fQueue->AddMessage(msg);
} else } else
continue; continue;
@@ -2204,22 +2211,22 @@ BWindow::task_looper()
// Get message count from port // Get message count from port
int32 msgCount = port_count(fMsgPort); int32 msgCount = port_count(fMsgPort);
for (int32 i = 0; i < msgCount; ++i) { for (int32 i = 0; i < msgCount; ++i) {
// Read 'count' messages from port (so we will not block) // Read 'count' messages from port (so we will not block)
// We use zero as our timeout since we know there is stuff there // We use zero as our timeout since we know there is stuff there
msg = MessageFromPort(0); msg = MessageFromPort(0);
// Add messages to queue // Add messages to queue
if (msg) if (msg)
fQueue->AddMessage(msg); fQueue->AddMessage(msg);
} }
// loop: As long as there are messages in the queue and the port is // loop: As long as there are messages in the queue and the port is
// empty... and we are not terminating, of course. // empty... and we are not terminating, of course.
bool dispatchNextMessage = true; bool dispatchNextMessage = true;
while (!fTerminating && dispatchNextMessage) { while (!fTerminating && dispatchNextMessage) {
// Get next message from queue (assign to fLastMessage) // Get next message from queue (assign to fLastMessage)
fLastMessage = fQueue->NextMessage(); fLastMessage = fQueue->NextMessage();
// Lock the looper // Lock the looper
Lock(); Lock();
if (!fLastMessage) { if (!fLastMessage) {
// No more messages: Unlock the looper and terminate the // No more messages: Unlock the looper and terminate the
@@ -2241,40 +2248,41 @@ BWindow::task_looper()
B_HANDLER_TOKEN, (void **)&handler); 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) if (handler == NULL || usePreferred)
handler = _DetermineTarget(fLastMessage, handler); handler = _DetermineTarget(fLastMessage, handler);
if (!usePreferred || _DistributeMessage(fLastMessage, handler)) {
if (handler == NULL)
handler = this;
// Is this a scripting message? (BMessage::HasSpecifiers()) unpack_cookie cookie;
if (fLastMessage->HasSpecifiers()) { while (_UnpackMessage(cookie, &fLastMessage, &handler, &usePreferred)) {
int32 index = 0; // if there is no target handler, the message is dropped
// Make sure the current specifier is kosher if (handler != NULL) {
if (fLastMessage->GetCurrentSpecifier(&index) == B_OK) // Is this a scripting message?
handler = resolve_specifier(handler, fLastMessage); 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) { if (handler != NULL)
// Do filtering and dispatch message handler = _TopLevelFilter(fLastMessage, handler);
handler = _TopLevelFilter(fLastMessage, handler);
if (handler && handler->Looper() == this) if (handler != NULL) {
_SanitizeMessage(fLastMessage, handler, usePreferred);
DispatchMessage(fLastMessage, handler); DispatchMessage(fLastMessage, handler);
}
} }
// Delete the current message
delete fLastMessage;
fLastMessage = NULL;
} }
} }
Unlock(); Unlock();
// Delete the current message (fLastMessage) // Are any messages on the port?
delete fLastMessage;
fLastMessage = NULL;
// Are any messages on the port?
if (port_count(fMsgPort) > 0) { if (port_count(fMsgPort) > 0) {
// Do outer loop // Do outer loop
dispatchNextMessage = false; dispatchNextMessage = false;
} }
} }
@@ -2409,8 +2417,6 @@ BWindow::_SetFocus(BView *focusView, bool notifyInputServer)
BHandler * BHandler *
BWindow::_DetermineTarget(BMessage *message, BHandler *target) BWindow::_DetermineTarget(BMessage *message, BHandler *target)
{ {
// TODO: this is mostly guessed; check for correctness.
switch (message->what) { switch (message->what) {
case B_KEY_DOWN: case B_KEY_DOWN:
case B_KEY_UP: case B_KEY_UP:
@@ -2428,14 +2434,24 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target)
case B_UNMAPPED_KEY_DOWN: case B_UNMAPPED_KEY_DOWN:
case B_UNMAPPED_KEY_UP: case B_UNMAPPED_KEY_UP:
case B_MODIFIERS_CHANGED: 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(); return CurrentFocus();
case B_MOUSE_DOWN: case B_MOUSE_DOWN:
case B_MOUSE_UP: case B_MOUSE_UP:
case B_MOUSE_MOVED: case B_MOUSE_MOVED:
case B_MOUSE_WHEEL_CHANGED: 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<BView*>(handler);
if (view != NULL)
return view;
}
}
break; break;
case B_PULSE: case B_PULSE:
@@ -2443,19 +2459,6 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target)
// TODO: test wether R5 will let BView dispatch these messages // TODO: test wether R5 will let BView dispatch these messages
return this; 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: default:
break; break;
} }
@@ -2471,44 +2474,150 @@ BWindow::_DetermineTarget(BMessage *message, BHandler *target)
Returns \c true in case the message should still be dispatched Returns \c true in case the message should still be dispatched
*/ */
bool bool
BWindow::_DistributeMessage(BMessage* message, BHandler* focus) BWindow::_UnpackMessage(unpack_cookie& cookie, BMessage** _message, BHandler** _target,
bool* _usePreferred)
{ {
bool foundFocus = false; if (cookie.message == NULL)
int32 focusToken = B_NULL_TOKEN; return false;
if (focus != NULL)
focusToken = _get_object_token_(focus);
int32 index = 0; if (cookie.index == 0 && !cookie.tokens_scanned) {
int32 token; if (!*_usePreferred) {
for (; message->FindInt32("_token", index, &token) == B_OK; index++) { // we only consider messages targeted at the preferred handler
if (token == focusToken) cookie.message = NULL;
foundFocus = true; 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); BView* target = _FindView(token);
if (target == NULL) if (target == NULL)
continue; continue;
BMessenger messenger(target); *_message = new BMessage(*cookie.message);
messenger.SendMessage(message); *_target = target;
cookie.index++;
return true;
} }
if (index > 0) { cookie.tokens_scanned = true;
if (foundFocus) {
// the focus view already got this message
return false;
}
// 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? // should this message still be dispatched by the focus view?
bool feedFocus; bool feedFocus;
if (message->FindBool("_feed_focus", &feedFocus) != B_OK if (!cookie.found_focus
|| feedFocus == false) && (cookie.message->FindBool("_feed_focus", &feedFocus) != B_OK
|| feedFocus == false)) {
delete cookie.message;
cookie.message = NULL;
return false; return false;
}
} }
*_message = cookie.message;
*_target = cookie.focus;
*_usePreferred = true;
cookie.message = NULL;
return true; 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<BView*>(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<BView*>(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 bool
BWindow::_HandleKeyDown(char key, uint32 modifiers) BWindow::_HandleKeyDown(char key, uint32 modifiers)
{ {
+1 -1
View File
@@ -210,7 +210,7 @@ Desktop::Init()
fRootLayer->Lock(); fRootLayer->Lock();
fRootLayer->MouseEventHandler(message); fRootLayer->MouseEventHandler(message);
fRootLayer->Unlock(); fRootLayer->Unlock();
return B_SKIP_MESSAGE; return B_DISPATCH_MESSAGE;
} }
private: private:
+19 -18
View File
@@ -424,7 +424,7 @@ Layer::SetName(const char* name)
fName.SetTo(name); fName.SetTo(name);
} }
// SetUserClipping
void void
Layer::SetUserClipping(const BRegion& region) Layer::SetUserClipping(const BRegion& region)
{ {
@@ -434,7 +434,7 @@ Layer::SetUserClipping(const BRegion& region)
_RebuildDrawingRegion(); _RebuildDrawingRegion();
} }
// SetFlags
void void
Layer::SetFlags(uint32 flags) Layer::SetFlags(uint32 flags)
{ {
@@ -442,7 +442,15 @@ Layer::SetFlags(uint32 flags)
fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE); fDrawState->SetSubPixelPrecise(fFlags & B_SUBPIXEL_PRECISE);
} }
// Draw
void
Layer::SetEventMask(uint32 eventMask, uint32 options)
{
fEventMask = eventMask;
fEventOptions = options;
}
void void
Layer::Draw(const BRect &rect) Layer::Draw(const BRect &rect)
{ {
@@ -823,55 +831,46 @@ Layer::CopyBits(BRect& src, BRect& dst, int32 xOffset, int32 yOffset)
} }
} }
void void
Layer::MouseDown(const BMessage *msg) Layer::MouseDown(const BMessage *msg)
{ {
if (Window() && !IsTopLayer()) {
Window()->SendMessageToClient(msg, fViewToken);
}
} }
void void
Layer::MouseUp(const BMessage *msg) Layer::MouseUp(const BMessage *msg)
{ {
if (Window() && !IsTopLayer()) {
Window()->SendMessageToClient(msg, fViewToken);
}
} }
void void
Layer::MouseMoved(const BMessage *msg) Layer::MouseMoved(const BMessage *msg)
{ {
if (Window() && !IsTopLayer()) {
Window()->SendMessageToClient(msg, fViewToken);
}
} }
void void
Layer::MouseWheelChanged(const BMessage *msg) Layer::MouseWheelChanged(const BMessage *msg)
{ {
if (Window() && !IsTopLayer()) {
Window()->SendMessageToClient(msg, fViewToken);
}
} }
void void
Layer::WorkspaceActivated(int32 index, bool active) Layer::WorkspaceActivated(int32 index, bool active)
{ {
// Empty
} }
void void
Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces) Layer::WorkspacesChanged(uint32 oldWorkspaces, uint32 newWorkspaces)
{ {
// Empty
} }
void void
Layer::Activated(bool active) Layer::Activated(bool active)
{ {
// Empty
} }
@@ -881,6 +880,7 @@ Layer::ScrollingOffset() const
return fScrollingOffset; return fScrollingOffset;
} }
void void
Layer::SetDrawingOrigin(BPoint origin) Layer::SetDrawingOrigin(BPoint origin)
{ {
@@ -1497,6 +1497,7 @@ Layer::_AllRedraw(const BRegion &invalid)
} }
} }
void void
Layer::_AddToViewsWithInvalidCoords() const Layer::_AddToViewsWithInvalidCoords() const
{ {
+2 -5
View File
@@ -182,15 +182,12 @@ class Layer {
DrawingEngine* GetDrawingEngine() const DrawingEngine* GetDrawingEngine() const
{ return fDriver; } { return fDriver; }
// flags void SetEventMask(uint32 eventMask, uint32 options);
uint32 EventMask() const uint32 EventMask() const
{ return fEventMask; } { return fEventMask; }
uint32 EventOptions() const uint32 EventOptions() const
{ return fEventOptions; } { return fEventOptions; }
inline void QuietlySetEventMask(uint32 em)
{ fEventMask = em; }
inline void QuietlySetEventOptions(uint32 eo)
{ fEventOptions = eo; }
inline uint32 ResizeMode() const inline uint32 ResizeMode() const
{ return fResizeMode; } { return fResizeMode; }
inline uint32 Flags() const inline uint32 Flags() const
+46 -275
View File
@@ -61,17 +61,13 @@ RootLayer::RootLayer(const char *name, int32 workspaceCount,
fDesktop(desktop), fDesktop(desktop),
fDragMessage(NULL), fDragMessage(NULL),
fLastLayerUnderMouse(this), fMouseEventLayer(NULL),
fNotifyLayer(NULL),
fSavedEventMask(0), fSavedEventMask(0),
fSavedEventOptions(0), fSavedEventOptions(0),
fAllRegionsLock("root layer region lock"), fAllRegionsLock("root layer region lock"),
fDirtyForRedraw(), fDirtyForRedraw(),
fButtons(0),
fLastMousePosition(0.0, 0.0),
fActiveWksIndex(0), fActiveWksIndex(0),
fWsCount(0), fWsCount(0),
fWorkspace(new Workspace*[kMaxWorkspaceCount]), fWorkspace(new Workspace*[kMaxWorkspaceCount]),
@@ -371,18 +367,17 @@ bool RootLayer::SetActiveWorkspace(int32 index)
return false; return false;
// you cannot switch workspaces on R5 if there is an event mask BView // you cannot switch workspaces on R5 if there is an event mask BView
if (fNotifyLayer && fNotifyLayer->Owner()) // if (fNotifyLayer && fNotifyLayer->Owner())
return false; // return false;
// if you're dragging something you are allowed to change workspaces only if // if you're dragging something you are allowed to change workspaces only if
// the Layer being dragged is a B_NORMAL_WINDOW_FEEL WinBorder. // the Layer being dragged is a B_NORMAL_WINDOW_FEEL WinBorder.
WinBorder *draggedWinBorder = dynamic_cast<WinBorder*>(fNotifyLayer); WinBorder *draggedWinBorder = dynamic_cast<WinBorder*>(fMouseEventLayer);
if (fNotifyLayer) { if (fMouseEventLayer != NULL) {
if (draggedWinBorder) { if (draggedWinBorder) {
if (draggedWinBorder->Feel() != B_NORMAL_WINDOW_FEEL) if (draggedWinBorder->Feel() != B_NORMAL_WINDOW_FEEL)
return false; return false;
} } else
else
return false; return false;
} }
@@ -478,9 +473,9 @@ RootLayer::SetWinBorderWorskpaces(WinBorder *winBorder, uint32 oldIndex, uint32
{ {
// if the active notify Layer is somehow related to winBorder, then // if the active notify Layer is somehow related to winBorder, then
// this window/WinBorder is not allowed to leave this workspace. // this window/WinBorder is not allowed to leave this workspace.
if (fNotifyLayer && (fNotifyLayer == winBorder || fNotifyLayer->Owner() == winBorder)) { // TODO: this looks wrong: I doubt the window is supposed to open in two workspaces then
newIndex |= (0x00000001UL << fActiveWksIndex); // if (fNotifyLayer && (fNotifyLayer == winBorder || fNotifyLayer->Owner() == winBorder))
} // newIndex |= (0x00000001UL << fActiveWksIndex);
uint32 localOldIndex = oldIndex; uint32 localOldIndex = oldIndex;
uint32 localNewIndex = newIndex; uint32 localNewIndex = newIndex;
@@ -851,25 +846,13 @@ RootLayer::SetActive(WinBorder* newActive, bool activate)
return returnValue; return returnValue;
} }
//---------------------------------------------------------------------------
// Workspace related methods
//---------------------------------------------------------------------------
//--------------------------------------------------------------------------- // #pragma mark - Input related methods
// Input related methods
//---------------------------------------------------------------------------
void 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 // change focus in FFM mode
WinBorder* winBorderTarget = dynamic_cast<WinBorder*>(target); WinBorder* winBorderTarget = dynamic_cast<WinBorder*>(target);
if (winBorderTarget) { 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 target->MouseMoved(msg);
bool alreadyPresent = fMouseNotificationList.HasItem(target); }
if (!alreadyPresent)
fMouseNotificationList.AddItem(target);
int32 count = fMouseNotificationList.CountItems();
int32 viewAction;
Layer *lay;
for (int32 i = 0; i <= count; i++) {
lay = static_cast<Layer*>(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); void
lay->MouseMoved(msg); 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) switch (event->what) {
fMouseNotificationList.RemoveItem(target); case B_MOUSE_DOWN:
layer->MouseDown(event);
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<Layer*>(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);
break; break;
}
case B_MOUSE_UP: {
//printf("RootLayer::MouseEventHandler(B_MOUSE_UP)\n");
BPoint where(0,0); case B_MOUSE_UP:
layer->MouseUp(event);
msg->FindPoint("where", &where); SetMouseEventLayer(NULL);
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<Layer*>(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;
break; break;
}
case B_MOUSE_MOVED: case B_MOUSE_MOVED:
_ProcessMouseMovedEvent(msg); _ProcessMouseMovedEvent(event, where, layer);
break; 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 void
RootLayer::ClearNotifyLayer() RootLayer::SetMouseEventLayer(Layer* layer)
{ {
if (fNotifyLayer) { fMouseEventLayer = layer;
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();
}
} }
void void
RootLayer::LayerRemoved(Layer* layer) RootLayer::LayerRemoved(Layer* layer)
{ {
if (layer == fNotifyLayer) if (fMouseEventLayer == layer)
fNotifyLayer = NULL; fMouseEventLayer = NULL;
// TODO: this must not happen!!! Fix this, quickly!
if (layer == fLastLayerUnderMouse)
fLastLayerUnderMouse = NULL;
} }
@@ -1158,7 +935,7 @@ RootLayer::SetDragMessage(BMessage* msg)
} }
if (msg) if (msg)
fDragMessage = new BMessage(*msg); fDragMessage = new BMessage(*msg);
} }
@@ -1245,12 +1022,6 @@ RootLayer::hide_winBorder(WinBorder *winBorder)
void void
RootLayer::change_winBorder_feel(WinBorder *winBorder, int32 newFeel) 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 isVisible = false;
bool isVisibleInActiveWorkspace = false; bool isVisibleInActiveWorkspace = false;
+4 -15
View File
@@ -96,16 +96,11 @@ public:
void SetBGColor(const RGBColor &col); void SetBGColor(const RGBColor &col);
RGBColor BGColor(void) const; RGBColor BGColor(void) const;
inline int32 Buttons(void) { return fButtons; }
void SetDragMessage(BMessage *msg); void SetDragMessage(BMessage *msg);
BMessage* DragMessage(void) const; BMessage* DragMessage(void) const;
bool AddToInputNotificationLists(Layer *lay, uint32 mask, void SetMouseEventLayer(Layer* layer);
uint32 options);
bool SetNotifyLayer(Layer *lay, uint32 mask, uint32 options);
void ClearNotifyLayer();
void LayerRemoved(Layer* layer); void LayerRemoved(Layer* layer);
@@ -139,25 +134,19 @@ friend class Desktop;
// Input related methods // Input related methods
void MouseEventHandler(BMessage *msg); void MouseEventHandler(BMessage *msg);
void _ProcessMouseMovedEvent(BMessage *msg); void _ProcessMouseMovedEvent(BMessage *msg, BPoint where, Layer* target);
Desktop* fDesktop; Desktop* fDesktop;
BMessage* fDragMessage; BMessage* fDragMessage;
Layer* fLastLayerUnderMouse; Layer* fMouseEventLayer;
Layer* fNotifyLayer;
uint32 fSavedEventMask; uint32 fSavedEventMask;
uint32 fSavedEventOptions; uint32 fSavedEventOptions;
BList fMouseNotificationList;
BList fKeyboardNotificationList;
BLocker fAllRegionsLock; BLocker fAllRegionsLock;
BRegion fDirtyForRedraw; BRegion fDirtyForRedraw;
int32 fButtons;
BPoint fLastMousePosition;
int32 fActiveWksIndex; int32 fActiveWksIndex;
int32 fWsCount; int32 fWsCount;
Workspace** fWorkspace; Workspace** fWorkspace;
+14 -12
View File
@@ -718,9 +718,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
link.Read<uint32>(&eventMask); link.Read<uint32>(&eventMask);
if (link.Read<uint32>(&options) == B_OK) { if (link.Read<uint32>(&options) == B_OK) {
printf("got %s: eventMask = %ld, options = %ld\n", fCurrentLayer->Name(), eventMask, options); fCurrentLayer->SetEventMask(eventMask, options);
fCurrentLayer->QuietlySetEventMask(eventMask);
fCurrentLayer->QuietlySetEventOptions(options);
if (eventMask != 0 || options != 0) { if (eventMask != 0 || options != 0) {
fDesktop->EventDispatcher().AddListener(FocusMessenger(), fDesktop->EventDispatcher().AddListener(FocusMessenger(),
@@ -749,8 +747,7 @@ printf("got %s: eventMask = %ld, options = %ld\n", fCurrentLayer->Name(), eventM
} }
} }
if (rootLayer) // TODO: support B_LOCK_WINDOW_FOCUS option in RootLayer
rootLayer->SetNotifyLayer(fCurrentLayer, eventMask, options);
break; break;
} }
case AS_LAYER_MOVE_TO: case AS_LAYER_MOVE_TO:
@@ -1602,23 +1599,25 @@ if (rootLayer)
DTRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n", Title())); DTRACE(("ServerWindow %s: Message AS_DRAG_RECT unimplemented\n", Title()));
break; break;
} }
case AS_LAYER_GET_MOUSE_COORDS: case AS_GET_MOUSE:
{ {
DTRACE(("ServerWindow %s: Message AS_GET_MOUSE_COORDS\n", fTitle)); DTRACE(("ServerWindow %s: Message AS_GET_MOUSE\n", fTitle));
fLink.StartMessage(SERVER_TRUE);
// Returns // Returns
// 1) BPoint mouse location // 1) BPoint mouse location
// 2) int32 button state // 2) int32 button state
fLink.Attach<BPoint>(fDesktop->HWInterface()->GetCursorPosition()); BPoint where;
fLink.Attach<int32>(fDesktop->RootLayer()->Buttons()); int32 buttons;
fDesktop->EventDispatcher().GetMouse(where, buttons);
fLink.StartMessage(B_OK);
fLink.Attach<BPoint>(where);
fLink.Attach<int32>(buttons);
fLink.Flush(); fLink.Flush();
break; break;
} }
case AS_DW_GET_SYNC_DATA: case AS_DW_GET_SYNC_DATA:
{ {
// TODO: Use token or get rid of it. // TODO: Use token or get rid of it.
@@ -2116,6 +2115,9 @@ ServerWindow::_MessageLooper()
status_t status_t
ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const ServerWindow::SendMessageToClient(const BMessage* msg, int32 target) const
{ {
if (target == B_NULL_TOKEN)
target = fClientToken;
#ifndef USING_MESSAGE4 #ifndef USING_MESSAGE4
ssize_t size = msg->FlattenedSize(); ssize_t size = msg->FlattenedSize();
char* buffer = new(nothrow) char[size]; char* buffer = new(nothrow) char[size];
+1 -1
View File
@@ -481,7 +481,7 @@ WinBorder::MouseDown(const BMessage *msg)
if (action == DEC_MOVETOBACK) { if (action == DEC_MOVETOBACK) {
GetRootLayer()->SetActive(this, false); GetRootLayer()->SetActive(this, false);
} else { } else {
GetRootLayer()->SetNotifyLayer(this, B_POINTER_EVENTS, 0UL); GetRootLayer()->SetMouseEventLayer(this);
GetRootLayer()->SetActive(this); GetRootLayer()->SetActive(this);
} }
} else if (target != NULL) { } else if (target != NULL) {