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:
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();
+1 -1
View File
@@ -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,
+3 -7
View File
@@ -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) {
+226 -117
View File
@@ -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<BView *>(target)) {
view->ConvertFromScreen(&where);
view->MouseDown(where);
} else
target->MessageReceived(msg);
}
if (BView *view = dynamic_cast<BView *>(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<BView *>(target)) {
view->ConvertFromScreen(&where);
view->MouseUp(where);
} else
target->MessageReceived(msg);
}
if (BView *view = dynamic_cast<BView *>(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<BView *>(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<BView *>(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<BView*>(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<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
BWindow::_HandleKeyDown(char key, uint32 modifiers)
{
+1 -1
View File
@@ -210,7 +210,7 @@ Desktop::Init()
fRootLayer->Lock();
fRootLayer->MouseEventHandler(message);
fRootLayer->Unlock();
return B_SKIP_MESSAGE;
return B_DISPATCH_MESSAGE;
}
private:
+19 -18
View File
@@ -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
{
+2 -5
View File
@@ -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
+46 -275
View File
@@ -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<WinBorder*>(fNotifyLayer);
if (fNotifyLayer) {
WinBorder *draggedWinBorder = dynamic_cast<WinBorder*>(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<WinBorder*>(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<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);
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<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);
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<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;
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;
+4 -15
View File
@@ -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;
+14 -12
View File
@@ -718,9 +718,7 @@ ServerWindow::_DispatchMessage(int32 code, BPrivate::LinkReceiver &link)
link.Read<uint32>(&eventMask);
if (link.Read<uint32>(&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<BPoint>(fDesktop->HWInterface()->GetCursorPosition());
fLink.Attach<int32>(fDesktop->RootLayer()->Buttons());
BPoint where;
int32 buttons;
fDesktop->EventDispatcher().GetMouse(where, buttons);
fLink.StartMessage(B_OK);
fLink.Attach<BPoint>(where);
fLink.Attach<int32>(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];
+1 -1
View File
@@ -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) {