From d1a60e848ef8a3614f6c7f4448327cecfada20b6 Mon Sep 17 00:00:00 2001 From: crs Date: Wed, 31 Mar 2004 22:15:13 +0000 Subject: [PATCH] Reverted task bar code to 1.0.15 version. That used a window in its own thread for handling messages. It seems to fix most of the task bar bugs but there's still an hourglass cursor on NT when using the popup menu. --- lib/arch/CArchTaskBarWindows.cpp | 186 +++++++++++++++++++++++++------ lib/arch/CArchTaskBarWindows.h | 11 +- lib/arch/IArchTaskBar.h | 3 - 3 files changed, 160 insertions(+), 40 deletions(-) diff --git a/lib/arch/CArchTaskBarWindows.cpp b/lib/arch/CArchTaskBarWindows.cpp index fccba001..a31745d9 100644 --- a/lib/arch/CArchTaskBarWindows.cpp +++ b/lib/arch/CArchTaskBarWindows.cpp @@ -41,45 +41,43 @@ CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) : // save app instance s_appInstance = reinterpret_cast(appInstance); - // register the task bar restart message - m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + // we need a mutex + m_mutex = ARCH->newMutex(); - // register a window class - WNDCLASSEX classInfo; - classInfo.cbSize = sizeof(classInfo); - classInfo.style = CS_NOCLOSE; - classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc; - classInfo.cbClsExtra = 0; - classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*); - classInfo.hInstance = s_appInstance; - classInfo.hIcon = NULL; - classInfo.hCursor = NULL; - classInfo.hbrBackground = NULL; - classInfo.lpszMenuName = NULL; - classInfo.lpszClassName = TEXT("SynergyTaskBar"); - classInfo.hIconSm = NULL; - m_windowClass = RegisterClassEx(&classInfo); + // and a condition variable which uses the above mutex + m_ready = false; + m_condVar = ARCH->newCondVar(); - // create window - m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, - reinterpret_cast(m_windowClass), - TEXT("Synergy Task Bar"), - WS_POPUP, - 0, 0, 1, 1, - NULL, - NULL, - s_appInstance, - reinterpret_cast(this)); + // we're going to want to get a result from the thread we're + // about to create to know if it initialized successfully. + // so we lock the condition variable. + ARCH->lockMutex(m_mutex); + + // open a window and run an event loop in a separate thread. + // this has to happen in a separate thread because if we + // create a window on the current desktop with the current + // thread then the current thread won't be able to switch + // desktops if it needs to. + m_thread = ARCH->newThread(&CArchTaskBarWindows::threadEntry, this); + + // wait for child thread + while (!m_ready) { + ARCH->waitCondVar(m_condVar, m_mutex, -1.0); + } + + // ready + ARCH->unlockMutex(m_mutex); } CArchTaskBarWindows::~CArchTaskBarWindows() { - if (m_hwnd != NULL) { - removeAllIcons(); - DestroyWindow(m_hwnd); + if (m_thread != NULL) { + PostMessage(m_hwnd, WM_QUIT, 0, 0); + ARCH->wait(m_thread, -1.0); + ARCH->closeThread(m_thread); } - UnregisterClass((LPCTSTR)m_windowClass, s_appInstance); - + ARCH->closeCondVar(m_condVar); + ARCH->closeMutex(m_mutex); s_instance = NULL; } @@ -98,10 +96,6 @@ CArchTaskBarWindows::removeDialog(HWND hwnd) void CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver) { - if (m_hwnd == NULL) { - return; - } - // ignore bogus receiver if (receiver == NULL) { return; @@ -176,43 +170,53 @@ CArchTaskBarWindows::recycleID(UINT id) void CArchTaskBarWindows::addIcon(UINT id) { + ARCH->lockMutex(m_mutex); CIDToReceiverMap::const_iterator index = m_idTable.find(id); if (index != m_idTable.end()) { modifyIconNoLock(index->second, NIM_ADD); } + ARCH->unlockMutex(m_mutex); } void CArchTaskBarWindows::removeIcon(UINT id) { + ARCH->lockMutex(m_mutex); removeIconNoLock(id); + ARCH->unlockMutex(m_mutex); } void CArchTaskBarWindows::updateIcon(UINT id) { + ARCH->lockMutex(m_mutex); CIDToReceiverMap::const_iterator index = m_idTable.find(id); if (index != m_idTable.end()) { modifyIconNoLock(index->second, NIM_MODIFY); } + ARCH->unlockMutex(m_mutex); } void CArchTaskBarWindows::addAllIcons() { + ARCH->lockMutex(m_mutex); for (CReceiverToInfoMap::const_iterator index = m_receivers.begin(); index != m_receivers.end(); ++index) { modifyIconNoLock(index, NIM_ADD); } + ARCH->unlockMutex(m_mutex); } void CArchTaskBarWindows::removeAllIcons() { + ARCH->lockMutex(m_mutex); for (CReceiverToInfoMap::const_iterator index = m_receivers.begin(); index != m_receivers.end(); ++index) { removeIconNoLock(index->second.m_id); } + ARCH->unlockMutex(m_mutex); } void @@ -305,6 +309,49 @@ CArchTaskBarWindows::handleIconMessage( } } +bool +CArchTaskBarWindows::processDialogs(MSG* msg) +{ + // only one thread can be in this method on any particular object + // at any given time. that's not a problem since only our event + // loop calls this method and there's just one of those. + + ARCH->lockMutex(m_mutex); + + // remove removed dialogs + m_dialogs.erase(false); + + // merge added dialogs into the dialog list + for (CDialogs::const_iterator index = m_addedDialogs.begin(); + index != m_addedDialogs.end(); ++index) { + m_dialogs.insert(std::make_pair(index->first, index->second)); + } + m_addedDialogs.clear(); + + ARCH->unlockMutex(m_mutex); + + // check message against all dialogs until one handles it. + // note that we don't hold a lock while checking because + // the message is processed and may make calls to this + // object. that's okay because addDialog() and + // removeDialog() don't change the map itself (just the + // values of some elements). + ARCH->lockMutex(m_mutex); + for (CDialogs::const_iterator index = m_dialogs.begin(); + index != m_dialogs.end(); ++index) { + if (index->second) { + ARCH->unlockMutex(m_mutex); + if (IsDialogMessage(index->first, msg)) { + return true; + } + ARCH->lockMutex(m_mutex); + } + } + ARCH->unlockMutex(m_mutex); + + return false; +} + LRESULT CArchTaskBarWindows::wndProc(HWND hwnd, UINT msg, WPARAM wParam, LPARAM lParam) @@ -375,3 +422,70 @@ CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg, return DefWindowProc(hwnd, msg, wParam, lParam); } } + +void +CArchTaskBarWindows::threadMainLoop() +{ + // register the task bar restart message + m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated")); + + // register a window class + WNDCLASSEX classInfo; + classInfo.cbSize = sizeof(classInfo); + classInfo.style = CS_NOCLOSE; + classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc; + classInfo.cbClsExtra = 0; + classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*); + classInfo.hInstance = s_appInstance; + classInfo.hIcon = NULL; + classInfo.hCursor = NULL; + classInfo.hbrBackground = NULL; + classInfo.lpszMenuName = NULL; + classInfo.lpszClassName = TEXT("SynergyTaskBar"); + classInfo.hIconSm = NULL; + ATOM windowClass = RegisterClassEx(&classInfo); + + // create window + m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW, + reinterpret_cast(windowClass), + TEXT("Synergy Task Bar"), + WS_POPUP, + 0, 0, 1, 1, + NULL, + NULL, + s_appInstance, + reinterpret_cast(this)); + + // signal ready + ARCH->lockMutex(m_mutex); + m_ready = true; + ARCH->broadcastCondVar(m_condVar); + ARCH->unlockMutex(m_mutex); + + // handle failure + if (m_hwnd == NULL) { + UnregisterClass((LPCTSTR)windowClass, s_appInstance); + return; + } + + // main loop + MSG msg; + while (GetMessage(&msg, NULL, 0, 0)) { + if (!processDialogs(&msg)) { + TranslateMessage(&msg); + DispatchMessage(&msg); + } + } + + // clean up + removeAllIcons(); + DestroyWindow(m_hwnd); + UnregisterClass((LPCTSTR)windowClass, s_appInstance); +} + +void* +CArchTaskBarWindows::threadEntry(void* self) +{ + reinterpret_cast(self)->threadMainLoop(); + return NULL; +} diff --git a/lib/arch/CArchTaskBarWindows.h b/lib/arch/CArchTaskBarWindows.h index 5877637c..67e9af17 100644 --- a/lib/arch/CArchTaskBarWindows.h +++ b/lib/arch/CArchTaskBarWindows.h @@ -18,6 +18,7 @@ #define WIN32_LEAN_AND_MEAN #include "IArchTaskBar.h" +#include "IArchMultithread.h" #include "stdmap.h" #include "stdvector.h" #include @@ -77,13 +78,21 @@ private: LRESULT wndProc(HWND, UINT, WPARAM, LPARAM); static LRESULT CALLBACK staticWndProc(HWND, UINT, WPARAM, LPARAM); + void threadMainLoop(); + static void* threadEntry(void*); private: static CArchTaskBarWindows* s_instance; static HINSTANCE s_appInstance; + // multithread data + CArchMutex m_mutex; + CArchCond m_condVar; + bool m_ready; + int m_result; + CArchThread m_thread; + // child thread data - ATOM m_windowClass; HWND m_hwnd; UINT m_taskBarRestart; diff --git a/lib/arch/IArchTaskBar.h b/lib/arch/IArchTaskBar.h index 2cd20ded..e9471566 100644 --- a/lib/arch/IArchTaskBar.h +++ b/lib/arch/IArchTaskBar.h @@ -27,9 +27,6 @@ though each operation can be a no-op. */ class IArchTaskBar : public IInterface { public: - // Event data is architecture dependent - typedef void* Event; - //! @name manipulators //@{