diff --git a/clients/qt4/qt4client.cpp b/clients/qt4/qt4client.cpp index 5bf80c7e..41be49c1 100644 --- a/clients/qt4/qt4client.cpp +++ b/clients/qt4/qt4client.cpp @@ -3398,6 +3398,11 @@ void QtClient::loadWindows(const char* file) } } +bool QtClient::isUIThread() +{ + return (QApplication::instance() && QApplication::instance()->thread() == QThread::currentThread()); +} + // Open a file open dialog window // Parameters that can be specified include 'caption', // 'dir', 'filter', 'selectedfilter', 'confirmoverwrite', 'choosedir' @@ -4271,8 +4276,8 @@ void QtClient::setWidgetHeight(QWidget* w, const String& height) /** * QtDriver */ -QtDriver::QtDriver() - : m_init(false) +QtDriver::QtDriver(bool buildClientThread) + : m_init(false), m_clientThread(buildClientThread) { qInstallMsgHandler(qtMsgHandler); } @@ -4289,7 +4294,8 @@ void QtDriver::initialize() if (!QtClient::self()) { debugCopy(); new QtClient; - QtClient::self()->startup(); + if (m_clientThread) + QtClient::self()->startup(); } if (!m_init) { m_init = true; diff --git a/clients/qt4/qt4client.h b/clients/qt4/qt4client.h index 7fa538f6..d7473aa7 100644 --- a/clients/qt4/qt4client.h +++ b/clients/qt4/qt4client.h @@ -152,8 +152,7 @@ public: virtual void quit() { if (m_app) m_app->quit(); - else - Engine::halt(0); + Engine::halt(0); } /** @@ -546,6 +545,7 @@ public: protected: virtual void loadWindows(const char* file = 0); + virtual bool isUIThread(); private: QApplication* m_app; ObjList m_events; // Proxy events objects @@ -554,11 +554,12 @@ private: class YQT4_API QtDriver : public ClientDriver { public: - QtDriver(); + QtDriver(bool buildClientThread = true); virtual ~QtDriver(); virtual void initialize(); private: bool m_init; // Already initialized flag + bool m_clientThread; // does the client need a thread to run on? }; class YQT4_API QtWindow : public QWidget, public Window diff --git a/engine/Client.cpp b/engine/Client.cpp index c34dba08..9dfad649 100644 --- a/engine/Client.cpp +++ b/engine/Client.cpp @@ -155,6 +155,52 @@ private: TrayIconDef() : NamedPointer("") {} // No default constructor }; +namespace { // anonymous +/** + * Helper class providing a thread on which the Client to run on + * A thread for the client + */ +class ClientThread : public Thread +{ +public: + /** + * Constructor + * @param name Static name of the thread (for debugging purpose only) + * @param prio Thread priority + */ + ClientThread(Client* client, Priority prio = Normal) + : Thread("Client",prio), + m_client(client) + { } + + /** + * Destructor + */ + inline ~ClientThread() + {} + + /** + * Run thread, inherited from Thread + */ + virtual void run() + { + m_client->run(); + } + + /** + * Clean up, inherited from Thread + */ + virtual void cleanup() + { + m_client->cleanup(); + m_client->setThread(0); + } + +private: + Client* m_client; +}; + +}; // anonymous namespace /** * Static classes/function/data @@ -869,8 +915,8 @@ bool ClientThreadProxy::execute() */ // Constructor Client::Client(const char *name) - : Thread(name), m_initialized(false), m_line(0), m_oneThread(true), - m_defaultLogic(0) + : m_initialized(false), m_line(0), m_oneThread(true), + m_defaultLogic(0), m_clientThread(0) { s_client = this; @@ -912,6 +958,28 @@ Client::~Client() Engine::halt(0); } +bool Client::startup() +{ + DDebug(ClientDriver::self(),DebugAll,"Client::startup() [%p]",this); + if (m_clientThread) { + Debug(ClientDriver::self(),DebugNote,"Trying to build a client thread when you already have one '%s' [%p]", + m_clientThread->name(),m_clientThread); + return true; + } + else { + m_clientThread = new ClientThread(this); + if (!m_clientThread->startup()) { + Debug(ClientDriver::self(),DebugWarn,"Failed to startup the client thread '%s' [%p]",m_clientThread->name(),m_clientThread); + delete static_cast(m_clientThread); + m_clientThread = 0; + return false; + } + Debug(ClientDriver::self(),DebugInfo,"Starting up client thread '%s' [%p]",m_clientThread->name(),m_clientThread); + return true; + } + return false; +} + // Cleanup before halting void Client::cleanup() { @@ -2116,7 +2184,7 @@ bool Client::received(Message& msg, int id) // Postpone messages to be redispatched from UI thread bool Client::postpone(const Message& msg, int id, bool copyUserData) { - if (isCurrent()) + if (isUIThread()) return false; PostponedMessage* postponed = new PostponedMessage(msg,id,copyUserData); s_postponeMutex.lock(); @@ -2323,14 +2391,14 @@ bool Client::driverLock(long maxwait) bool Client::driverLockLoop() { - if (!(isCurrent() && ClientDriver::self())) + if (!(isUIThread() && ClientDriver::self())) return false; while (!driverLock()) { if (Engine::exiting() || !ClientDriver::self()) return false; idleActions(); - yield(); + Thread::yield(); } return true; } diff --git a/yatecbase.h b/yatecbase.h index bb693691..caec5e7d 100644 --- a/yatecbase.h +++ b/yatecbase.h @@ -762,10 +762,10 @@ private: }; /** - * Singleton class that holds the User Interface's main thread and methods - * @short Thread that runs the User Interface + * Singleton class that holds the User Interface's main methods + * @short Class that runs the User Interface */ -class YATE_API Client : public Thread, public MessageReceiver +class YATE_API Client : public MessageReceiver { friend class Window; friend class ClientChannel; @@ -843,7 +843,13 @@ public: virtual ~Client(); /** - * Run the client's thread + * Start up the client thread + * @return True if the client thread is started, false otherwise + */ + virtual bool startup(); + + /** + * Run the client's main loop */ virtual void run(); @@ -879,6 +885,13 @@ public: inline void unlockOther() { if (!m_oneThread) unlock(); } + /** + * Set the client's thread + * @param th The thread on which the client will run on + */ + inline void setThread(Thread* th) + { m_clientThread = th; } + /** * Handle all windows closed event from UI */ @@ -1269,7 +1282,7 @@ public: * @return True if the client is valid (running) or the method is called from client's thread */ static inline bool valid() - { return self() && (self() == Thread::current() || !(exiting() || Engine::exiting())); } + { return self() && (self()->isUIThread() || !(exiting() || Engine::exiting())); } /** * Check if a message is sent by the client @@ -1712,8 +1725,10 @@ protected: virtual void initClient(); virtual void exitClient() {} + virtual bool isUIThread() + { return Thread::current() == m_clientThread; } inline bool needProxy() const - { return m_oneThread && !isCurrent(); } + { return m_oneThread && !(Client::self() && Client::self()->isUIThread()); } bool driverLockLoop(); static bool driverLock(long maxwait = 0); static void driverUnlock(); @@ -1731,6 +1746,7 @@ protected: static int s_changing; static ObjList s_logics; static bool s_idleLogicsTick; // Call logics' timerTick() + Thread* m_clientThread; }; /**