From 5d7f782d4e505cb5788cdfb2abf7bdd174af084e Mon Sep 17 00:00:00 2001 From: Ingo Weinhold Date: Fri, 20 Dec 2013 15:47:23 +0100 Subject: [PATCH] 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. --- headers/os/app/Looper.h | 2 ++ src/kits/app/Looper.cpp | 32 ++++++++++++++++++++++++++------ src/kits/interface/Window.cpp | 11 ++++++++--- 3 files changed, 36 insertions(+), 9 deletions(-) diff --git a/headers/os/app/Looper.h b/headers/os/app/Looper.h index 76016bc4f5..5aa7eadec8 100644 --- a/headers/os/app/Looper.h +++ b/headers/os/app/Looper.h @@ -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; diff --git a/src/kits/app/Looper.cpp b/src/kits/app/Looper.cpp index ecf4637198..4af20167fa 100644 --- a/src/kits/app/Looper.cpp +++ b/src/kits/app/Looper.cpp @@ -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) { diff --git a/src/kits/interface/Window.cpp b/src/kits/interface/Window.cpp index 5e3de7918d..f23681f23d 100644 --- a/src/kits/interface/Window.cpp +++ b/src/kits/interface/Window.cpp @@ -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