BLooper: Add DispatchExternalMessage()

* This is primarily a service method for ports of widget tool kits
  that require single-threaded GUI. DispatchExternalMessage() calls
  DispatchMessage(), but also sets fLastMessage, so that
  [Detach]CurrentMessage() work correctly. This allows to detach a
  message in DispatchMessage() when called from the window thread,
  add it to a global queue, and later process the queued messages in
  a different thread that calls DispatchExternalMessage().
* BLooper/BWindow: Make sure fLastMessage is accessed only when locked.
This commit is contained in:
Ingo Weinhold 2013-12-20 15:47:23 +01:00
parent 57973ac96b
commit 5d7f782d4e
3 changed files with 36 additions and 9 deletions

View File

@ -52,6 +52,8 @@ public:
virtual void MessageReceived(BMessage* message);
BMessage* CurrentMessage() const;
BMessage* DetachCurrentMessage();
void DispatchExternalMessage(BMessage* message,
BHandler* handler, bool& _detached);
BMessageQueue* MessageQueue() const;
bool IsMessageWaiting() const;

View File

@ -300,6 +300,22 @@ BLooper::DetachCurrentMessage()
}
void
BLooper::DispatchExternalMessage(BMessage* message, BHandler* handler,
bool& _detached)
{
AssertLocked();
BMessage* previousMessage = fLastMessage;
fLastMessage = message;
DispatchMessage(message, handler);
_detached = fLastMessage == NULL;
fLastMessage = previousMessage;
}
BMessageQueue*
BLooper::MessageQueue() const
{
@ -1115,11 +1131,14 @@ BLooper::task_looper()
bool dispatchNextMessage = true;
while (!fTerminating && dispatchNextMessage) {
PRINT(("LOOPER: inner loop\n"));
// Get next message from queue (assign to fLastMessage)
fLastMessage = fDirectTarget->Queue()->NextMessage();
// Get next message from queue (assign to fLastMessage after
// locking)
BMessage* message = fDirectTarget->Queue()->NextMessage();
Lock();
fLastMessage = message;
if (!fLastMessage) {
// No more messages: Unlock the looper and terminate the
// dispatch loop.
@ -1173,14 +1192,15 @@ BLooper::task_looper()
return;
}
message = fLastMessage;
fLastMessage = NULL;
// Unlock the looper
Unlock();
// Delete the current message (fLastMessage)
if (fLastMessage) {
delete fLastMessage;
fLastMessage = NULL;
}
if (message != NULL)
delete message;
// Are any messages on the port?
if (port_count(fMsgPort) > 0) {

View File

@ -3037,12 +3037,17 @@ BWindow::task_looper()
bool dispatchNextMessage = true;
while (!fTerminating && dispatchNextMessage) {
// Get next message from queue (assign to fLastMessage)
fLastMessage = fDirectTarget->Queue()->NextMessage();
// Get next message from queue (assign to fLastMessage after
// locking)
BMessage* message = fDirectTarget->Queue()->NextMessage();
// Lock the looper
if (!Lock())
if (!Lock()) {
delete message;
break;
}
fLastMessage = message;
if (fLastMessage == NULL) {
// No more messages: Unlock the looper and terminate the