#15254: BWindow shouldn't dispatch messages on behalf of BView
--------------------------------+------------------------------
Reporter: simonsouth | Owner: nobody
Type: bug | Status: new
Priority: normal | Milestone: Unscheduled
Component: Kits/Interface Kit | Version: R1/Development
Keywords: | Blocked By:
Blocking: | Has a Patch: 0
Platform: All |
--------------------------------+------------------------------
(**TLDR:** I think our BWindow isn't sending to BView all the messages it
should. If you have access to BeOS, please compile and run on it the
attached program. Use the mouse and keyboard to try to get as many
checkboxes checked as possible, then post a screenshot with the results
and I'll work on a patch for BWindow::DispatchMessage().)
----
In a number of cases, when BWindow's DispatchMessage() method receives a
message targeting one of its BView instances it will invoke a handler
method on the BView object directly rather than passing the message on and
letting the BView handle it itself. In some cases (and there may be more)
this means BView isn't receiving messages it should be.
A clear example is BWindow's handling of keystroke-related messages.
[https://git.haiku-
os.org/haiku/tree/src/kits/interface/Window.cpp?id=72b37d9ffc7e083a3f44ebf24e064596e0392b63#n1164
For example]:
{{{
#!c++
case B_KEY_DOWN:
{
if (!_HandleKeyDown(message)) {
if (BView* view = dynamic_cast<BView*>(target)) {
// TODO: cannot use "string" here if we support having
// different font encoding per view (it's supposed to be
// converted by _HandleKeyDown() one day)
const char* string;
ssize_t bytes;
if (message->FindData("bytes", B_STRING_TYPE,
(const void**)&string, &bytes) == B_OK) {
view->KeyDown(string, bytes - 1);
}
} else
target->MessageReceived(message);
}
break;
}
}}}
Here, if BWindow decides not to capture the keypress itself it "reaches
into" the target BView and invokes its KeyDown() method directly, rather
than passing the message on and letting the BView itself decide how to
handle it (by invoking KeyDown() on its own, presumably). As a result,
it's difficult for a BView subclass to override or extend this behaviour.
This strikes me as incorrect, for several reasons:
1. It embeds in BWindow knowledge about BView and its behaviour, coupling
the two classes in much the way message-passing systems are meant to
eliminate.
2. Since BView's KeyDown() handler is passed only limited information
about the original message, subclasses that need to work at a lower level
have to do so in a roundabout manner, re-requesting the message currently
being handled as [https://git.haiku-
os.org/haiku/tree/src/apps/terminal/TermViewStates.cpp?id=72b37d9ffc7e083a3f44ebf24e064596e0392b63#n195
this example from Terminal] illustrates:
{{{
#!c++
void
TermView::DefaultState::KeyDown(const char* bytes, int32 numBytes)
{
// (...)
BMessage* currentMessage = fView->Looper()->CurrentMessage();
if (currentMessage == NULL)
return;
currentMessage->FindInt32("modifiers", &mod);
currentMessage->FindInt32("key", &key);
currentMessage->FindInt32("raw_char", &rawChar);
}}}
This kind of processing should really be done in an overridden
MessageReceived() method, but that's not possible right now because the
object never actually receives the message.
3. **This is a departure from BeOS' behaviour.** The Be Book's
[https://www.haiku-os.org/legacy-
docs/bebook/TheKeyboard_JourneyOfAKeystroke.html section on keystroke-
event handling] makes this clear:
The [B_KEY_DOWN] message finally arrives at the view that's currently
focused in the active window. This view's MessageReceived() function
processes the keypress in whatever way it wants to.
Note there are at least eight messages that BWindow "forcibly" dispatches
in this manner; it's not just keyboard events.
I'd like to fix this, and to me it makes sense that BWindow should pass on
to the target BView ''any'' relevant message it decides not to handle on
its own. However, to make sure this matches what was originally intended,
I'm attaching to this ticket a little program with a BView subclass that
listens for specific messages and indicates their receipt by checking a
checkbox in its UI. This should help reveal which messages our BView
should be receiving but presently isn't.
If you have access to BeOS, please compile and run the attached program,
then use the mouse and keyboard to generate events and try to get all the
checkboxes to "light up". Post a screenshot with the results, and I can
work on updating BWindow::DispatchMessage() to match.
--
Ticket URL: <https://dev.haiku-os.org/ticket/15254>
Haiku <https://dev.haiku-os.org>
The Haiku operating system.