Added switch delay and double-tap options to win32 and added a

tray icon to the client and server that gives status feedback to
the user and allows the user to kill the app.
This commit is contained in:
crs
2003-03-12 22:34:07 +00:00
parent f411df65fb
commit 1d17f865ea
82 changed files with 4420 additions and 396 deletions

View File

@@ -23,6 +23,7 @@
#undef ARCH_NETWORK
#undef ARCH_SLEEP
#undef ARCH_STRING
#undef ARCH_TASKBAR
#undef ARCH_TIME
// include appropriate architecture implementation
@@ -35,6 +36,7 @@
# include "CArchNetworkWinsock.h"
# include "CArchSleepWindows.h"
# include "CArchStringWindows.h"
# include "CArchTaskBarWindows.h"
# include "CArchTimeWindows.h"
#elif UNIX_LIKE
# include "CArchConsoleUnix.h"
@@ -47,6 +49,7 @@
# include "CArchNetworkBSD.h"
# include "CArchSleepUnix.h"
# include "CArchStringUnix.h"
# include "CArchTaskBarXWindows.h"
# include "CArchTimeUnix.h"
#endif
@@ -82,6 +85,10 @@
# error unsupported platform for string
#endif
#if !defined(ARCH_TASKBAR)
# error unsupported platform for taskbar
#endif
#if !defined(ARCH_TIME)
# error unsupported platform for time
#endif
@@ -92,7 +99,7 @@
CArch* CArch::s_instance = NULL;
CArch::CArch(ARCH_ARGS)
CArch::CArch(ARCH_ARGS* args)
{
// only once instance of CArch
assert(s_instance == NULL);
@@ -108,11 +115,13 @@ CArch::CArch(ARCH_ARGS)
m_time = new ARCH_TIME;
m_console = new ARCH_CONSOLE;
m_daemon = new ARCH_DAEMON;
m_taskbar = new ARCH_TASKBAR(args);
}
CArch::~CArch()
{
// clean up
delete m_taskbar;
delete m_daemon;
delete m_console;
delete m_time;
@@ -337,10 +346,10 @@ CArch::wait(CArchThread thread, double timeout)
return m_mt->wait(thread, timeout);
}
bool
CArch::waitForEvent(double timeout)
IArchMultithread::EWaitResult
CArch::waitForEvent(CArchThread thread, double timeout)
{
return m_mt->waitForEvent(timeout);
return m_mt->waitForEvent(thread, timeout);
}
bool
@@ -577,6 +586,24 @@ CArch::getWideCharEncoding()
return m_string->getWideCharEncoding();
}
void
CArch::addReceiver(IArchTaskBarReceiver* receiver)
{
m_taskbar->addReceiver(receiver);
}
void
CArch::removeReceiver(IArchTaskBarReceiver* receiver)
{
m_taskbar->removeReceiver(receiver);
}
void
CArch::updateReceiver(IArchTaskBarReceiver* receiver)
{
m_taskbar->updateReceiver(receiver);
}
double
CArch::time()
{

View File

@@ -23,6 +23,7 @@
#include "IArchNetwork.h"
#include "IArchSleep.h"
#include "IArchString.h"
#include "IArchTaskBar.h"
#include "IArchTime.h"
/*!
@@ -31,7 +32,7 @@ This macro evaluates to the singleton CArch object.
*/
#define ARCH (CArch::getInstance())
#define ARCH_ARGS
#define ARCH_ARGS void
//! Delegating mplementation of architecture dependent interfaces
/*!
@@ -51,9 +52,10 @@ class CArch : public IArchConsole,
public IArchNetwork,
public IArchSleep,
public IArchString,
public IArchTaskBar,
public IArchTime {
public:
CArch(ARCH_ARGS);
CArch(ARCH_ARGS* args = NULL);
~CArch();
//
@@ -114,7 +116,7 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual bool waitForEvent(double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);
@@ -164,6 +166,11 @@ public:
virtual EWideCharEncoding
getWideCharEncoding();
// IArchTaskBar
virtual void addReceiver(IArchTaskBarReceiver*);
virtual void removeReceiver(IArchTaskBarReceiver*);
virtual void updateReceiver(IArchTaskBarReceiver*);
// IArchTime overrides
virtual double time();
@@ -178,6 +185,7 @@ private:
IArchNetwork* m_net;
IArchSleep* m_sleep;
IArchString* m_string;
IArchTaskBar* m_taskbar;
IArchTime* m_time;
};

View File

@@ -13,6 +13,7 @@
*/
#include "CArchConsoleWindows.h"
#include "IArchMultithread.h"
#include "CArch.h"
#include <cstdio>
@@ -20,12 +21,12 @@
// CArchConsoleWindows
//
DWORD CArchConsoleWindows::s_thread = 0;
CArchThread CArchConsoleWindows::s_thread = 0;
CArchConsoleWindows::CArchConsoleWindows() :
m_output(NULL)
{
s_thread = GetCurrentThreadId();
s_thread = ARCH->newCurrentThread();
m_mutex = ARCH->newMutex();
}
@@ -33,6 +34,7 @@ CArchConsoleWindows::CArchConsoleWindows() :
CArchConsoleWindows::~CArchConsoleWindows()
{
ARCH->closeMutex(m_mutex);
ARCH->closeThread(s_thread);
}
void
@@ -101,7 +103,7 @@ CArchConsoleWindows::getNewlineForConsole()
BOOL WINAPI
CArchConsoleWindows::signalHandler(DWORD)
{
// terminate cleanly and skip remaining handlers
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
// terminate thread and skip remaining handlers
ARCH->cancelThread(s_thread);
return TRUE;
}

View File

@@ -39,7 +39,7 @@ private:
static BOOL WINAPI signalHandler(DWORD);
private:
static DWORD s_thread;
static CArchThread s_thread;
CArchMutex m_mutex;
HANDLE m_output;

View File

@@ -25,6 +25,7 @@
# include "CArchNetworkWinsock.cpp"
# include "CArchSleepWindows.cpp"
# include "CArchStringWindows.cpp"
# include "CArchTaskBarWindows.cpp"
# include "CArchTimeWindows.cpp"
# include "XArchWindows.cpp"
#elif UNIX_LIKE
@@ -38,6 +39,7 @@
# include "CArchNetworkBSD.cpp"
# include "CArchSleepUnix.cpp"
# include "CArchStringUnix.cpp"
# include "CArchTaskBarXWindows.cpp"
# include "CArchTimeUnix.cpp"
# include "XArchUnix.cpp"
#endif

View File

@@ -517,11 +517,11 @@ CArchMultithreadPosix::wait(CArchThread target, double timeout)
}
}
bool
CArchMultithreadPosix::waitForEvent(double /*timeout*/)
IArchMultithread::EWaitResult
CArchMultithreadPosix::waitForEvent(CArchThread, double /*timeout*/)
{
// not implemented
return false;
return kTimeout;
}
bool

View File

@@ -55,7 +55,7 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual bool waitForEvent(double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);

View File

@@ -453,6 +453,89 @@ CArchMultithreadWindows::wait(CArchThread target, double timeout)
}
}
IArchMultithread::EWaitResult
CArchMultithreadWindows::waitForEvent(CArchThread target, double timeout)
{
// find current thread. ref the target so it can't go away while
// we're watching it.
lockMutex(m_threadMutex);
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
assert(self != NULL);
if (target != NULL) {
refThread(target);
}
unlockMutex(m_threadMutex);
// see if we've been cancelled before checking if any events
// are pending.
DWORD result = WaitForSingleObject(self->m_cancel, 0);
if (result == WAIT_OBJECT_0) {
if (target != NULL) {
closeThread(target);
}
testCancelThreadImpl(self);
}
// check if messages are available first. if we don't do this then
// MsgWaitForMultipleObjects() will block even if the queue isn't
// empty if the messages in the queue were there before the last
// call to GetMessage()/PeekMessage().
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
return kEvent;
}
// convert timeout
DWORD t;
if (timeout < 0.0) {
t = INFINITE;
}
else {
t = (DWORD)(1000.0 * timeout);
}
// wait for this thread to be cancelled or for the target thread to
// terminate.
DWORD n = (target == NULL || target == self) ? 1 : 2;
HANDLE handles[2];
handles[0] = self->m_cancel;
handles[1] = (n == 2) ? target->m_exit : NULL;
result = MsgWaitForMultipleObjects(n, handles, FALSE, t, QS_ALLINPUT);
// cancel takes priority
if (result != WAIT_OBJECT_0 + 0 &&
WaitForSingleObject(handles[0], 0) == WAIT_OBJECT_0) {
result = WAIT_OBJECT_0 + 0;
}
// release target
if (target != NULL) {
closeThread(target);
}
// handle result
switch (result) {
case WAIT_OBJECT_0 + 0:
// this thread was cancelled. does not return.
testCancelThreadImpl(self);
case WAIT_OBJECT_0 + 1:
// target thread terminated
if (n == 2) {
return kExit;
}
// fall through
case WAIT_OBJECT_0 + 2:
// message is available
return kEvent;
default:
// timeout or error
return kTimeout;
}
}
/*
bool
CArchMultithreadWindows::waitForEvent(double timeout)
{
@@ -499,6 +582,7 @@ CArchMultithreadWindows::waitForEvent(double timeout)
return false;
}
}
*/
bool
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)

View File

@@ -69,7 +69,7 @@ public:
virtual void setPriorityOfThread(CArchThread, int n);
virtual void testCancelThread();
virtual bool wait(CArchThread, double timeout);
virtual bool waitForEvent(double timeout);
virtual EWaitResult waitForEvent(CArchThread, double timeout);
virtual bool isSameThread(CArchThread, CArchThread);
virtual bool isExitedThread(CArchThread);
virtual void* getResultOfThread(CArchThread);

View File

@@ -0,0 +1,518 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CArchTaskBarWindows.h"
#include "IArchTaskBarReceiver.h"
#include "CArch.h"
#include "XArch.h"
#include <string.h>
#include <shellapi.h>
static const UINT kAddReceiver = WM_USER + 10;
static const UINT kRemoveReceiver = WM_USER + 11;
static const UINT kUpdateReceiver = WM_USER + 12;
static const UINT kNotifyReceiver = WM_USER + 13;
static const UINT kFirstReceiverID = WM_USER + 14;
//
// CArchTaskBarWindows
//
CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
HINSTANCE CArchTaskBarWindows::s_appInstance = NULL;
CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
m_nextID(kFirstReceiverID)
{
// save the singleton instance
s_instance = this;
// save app instance
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
// we need a mutex
m_mutex = ARCH->newMutex();
// and a condition variable which uses the above mutex
m_ready = false;
m_condVar = ARCH->newCondVar();
// 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_thread != NULL) {
ARCH->cancelThread(m_thread);
ARCH->wait(m_thread, -1.0);
ARCH->closeThread(m_thread);
}
ARCH->closeCondVar(m_condVar);
ARCH->closeMutex(m_mutex);
s_instance = NULL;
}
void
CArchTaskBarWindows::addDialog(HWND hwnd)
{
// add dialog to added dialogs list
ARCH->lockMutex(s_instance->m_mutex);
s_instance->m_addedDialogs.insert(std::make_pair(hwnd, true));
ARCH->unlockMutex(s_instance->m_mutex);
}
void
CArchTaskBarWindows::removeDialog(HWND hwnd)
{
// mark dialog as removed
ARCH->lockMutex(s_instance->m_mutex);
CDialogs::iterator index = s_instance->m_dialogs.find(hwnd);
if (index != s_instance->m_dialogs.end()) {
index->second = false;
}
s_instance->m_addedDialogs.erase(hwnd);
ARCH->unlockMutex(s_instance->m_mutex);
}
void
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
{
// ignore bogus receiver
if (receiver == NULL) {
return;
}
// add receiver if necessary
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
if (index == m_receivers.end()) {
// add it, creating a new message ID for it
CReceiverInfo info;
info.m_id = getNextID();
index = m_receivers.insert(std::make_pair(receiver, info)).first;
// add ID to receiver mapping
m_idTable.insert(std::make_pair(info.m_id, index));
}
// add receiver
PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0);
}
void
CArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver)
{
// find receiver
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
if (index == m_receivers.end()) {
return;
}
// remove icon. wait for this to finish before returning.
SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0);
// recycle the ID
recycleID(index->second.m_id);
// discard
m_idTable.erase(index->second.m_id);
m_receivers.erase(index);
}
void
CArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver)
{
// find receiver
CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
if (index == m_receivers.end()) {
return;
}
// update icon and tool tip
PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0);
}
UINT
CArchTaskBarWindows::getNextID()
{
if (m_oldIDs.empty()) {
return m_nextID++;
}
UINT id = m_oldIDs.back();
m_oldIDs.pop_back();
return id;
}
void
CArchTaskBarWindows::recycleID(UINT id)
{
m_oldIDs.push_back(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
CArchTaskBarWindows::modifyIconNoLock(
CReceiverToInfoMap::const_iterator index, DWORD taskBarMessage)
{
// get receiver
UINT id = index->second.m_id;
IArchTaskBarReceiver* receiver = index->first;
// lock receiver so icon and tool tip are guaranteed to be consistent
receiver->lock();
// get icon data
HICON icon = reinterpret_cast<HICON>(
const_cast<IArchTaskBarReceiver::Icon>(receiver->getIcon()));
// get tool tip
std::string toolTip = receiver->getToolTip();
// done querying
receiver->unlock();
// prepare to add icon
NOTIFYICONDATA data;
data.cbSize = sizeof(NOTIFYICONDATA);
data.hWnd = m_hwnd;
data.uID = id;
data.uFlags = NIF_MESSAGE;
data.uCallbackMessage = kNotifyReceiver;
data.hIcon = icon;
if (icon != NULL) {
data.uFlags |= NIF_ICON;
}
if (!toolTip.empty()) {
strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
data.szTip[sizeof(data.szTip) - 1] = '\0';
data.uFlags |= NIF_TIP;
}
else {
data.szTip[0] = '\0';
}
// add icon
if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
// failed
}
}
void
CArchTaskBarWindows::removeIconNoLock(UINT id)
{
NOTIFYICONDATA data;
data.cbSize = sizeof(NOTIFYICONDATA);
data.hWnd = m_hwnd;
data.uID = id;
if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
// failed
}
}
void
CArchTaskBarWindows::handleIconMessage(
IArchTaskBarReceiver* receiver, LPARAM lParam)
{
// process message
switch (lParam) {
case WM_LBUTTONDOWN:
receiver->showStatus();
break;
case WM_LBUTTONDBLCLK:
receiver->primaryAction();
break;
case WM_RBUTTONUP: {
POINT p;
GetCursorPos(&p);
receiver->runMenu(p.x, p.y);
break;
}
case WM_MOUSEMOVE:
// currently unused
break;
default:
// unused
break;
}
}
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)
{
switch (msg) {
case kNotifyReceiver: {
// lookup receiver
CIDToReceiverMap::const_iterator index = m_idTable.find(wParam);
if (index != m_idTable.end()) {
IArchTaskBarReceiver* receiver = index->second->first;
handleIconMessage(receiver, lParam);
return 0;
}
break;
}
case kAddReceiver:
addIcon(wParam);
break;
case kRemoveReceiver:
removeIcon(wParam);
break;
case kUpdateReceiver:
updateIcon(wParam);
break;
default:
if (msg == m_taskBarRestart) {
// task bar was recreated so re-add our icons
addAllIcons();
}
break;
}
return DefWindowProc(hwnd, msg, wParam, lParam);
}
LRESULT CALLBACK
CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
WPARAM wParam, LPARAM lParam)
{
// if msg is WM_NCCREATE, extract the CArchTaskBarWindows* and put
// it in the extra window data then forward the call.
CArchTaskBarWindows* self = NULL;
if (msg == WM_NCCREATE) {
CREATESTRUCT* createInfo;
createInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
self = reinterpret_cast<CArchTaskBarWindows*>(
createInfo->lpCreateParams);
SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(self));
}
else {
// get the extra window data and forward the call
LONG data = GetWindowLong(hwnd, 0);
if (data != 0) {
self = reinterpret_cast<CArchTaskBarWindows*>(
reinterpret_cast<void*>(data));
}
}
// forward the message
if (self != NULL) {
return self->wndProc(hwnd, msg, wParam, lParam);
}
else {
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<LPCTSTR>(windowClass),
TEXT("Synergy Task Bar"),
WS_POPUP,
0, 0, 1, 1,
NULL,
NULL,
s_appInstance,
reinterpret_cast<void*>(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;
}
try {
// main loop
MSG msg;
for (;;) {
// wait for message
if (ARCH->waitForEvent(NULL, -1.0) != IArchMultithread::kEvent) {
continue;
}
// peek for message and remove it. we don't GetMessage()
// because we should never block here, only in waitForEvent().
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
continue;
}
// check message against dialogs
if (!processDialogs(&msg)) {
// process message
TranslateMessage(&msg);
DispatchMessage(&msg);
}
}
}
catch (XThread&) {
// clean up
removeAllIcons();
DestroyWindow(m_hwnd);
UnregisterClass((LPCTSTR)windowClass, s_appInstance);
throw;
}
}
void*
CArchTaskBarWindows::threadEntry(void* self)
{
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
return NULL;
}

View File

@@ -0,0 +1,110 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CARCHTASKBARWINDOWS_H
#define CARCHTASKBARWINDOWS_H
#define WIN32_LEAN_AND_MEAN
#include "IArchTaskBar.h"
#include "IArchMultithread.h"
#include "stdmap.h"
#include "stdvector.h"
#include <windows.h>
#define ARCH_TASKBAR CArchTaskBarWindows
//! Win32 implementation of IArchTaskBar
class CArchTaskBarWindows : public IArchTaskBar {
public:
CArchTaskBarWindows(void*);
virtual ~CArchTaskBarWindows();
//! Add a dialog window
/*!
Tell the task bar event loop about a dialog. Win32 annoyingly
requires messages destined for modeless dialog boxes to be
dispatched differently than other messages.
*/
static void addDialog(HWND);
//! Remove a dialog window
/*!
Remove a dialog window added via \c addDialog().
*/
static void removeDialog(HWND);
// IArchTaskBar overrides
virtual void addReceiver(IArchTaskBarReceiver*);
virtual void removeReceiver(IArchTaskBarReceiver*);
virtual void updateReceiver(IArchTaskBarReceiver*);
private:
class CReceiverInfo {
public:
UINT m_id;
};
typedef std::map<IArchTaskBarReceiver*, CReceiverInfo> CReceiverToInfoMap;
typedef std::map<UINT, CReceiverToInfoMap::iterator> CIDToReceiverMap;
typedef std::vector<UINT> CIDStack;
typedef std::map<HWND, bool> CDialogs;
UINT getNextID();
void recycleID(UINT);
void addIcon(UINT);
void removeIcon(UINT);
void updateIcon(UINT);
void addAllIcons();
void removeAllIcons();
void modifyIconNoLock(CReceiverToInfoMap::const_iterator,
DWORD taskBarMessage);
void removeIconNoLock(UINT id);
void handleIconMessage(IArchTaskBarReceiver*, LPARAM);
bool processDialogs(MSG*);
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
HWND m_hwnd;
UINT m_taskBarRestart;
// shared data
CReceiverToInfoMap m_receivers;
CIDToReceiverMap m_idTable;
CIDStack m_oldIDs;
UINT m_nextID;
// dialogs
CDialogs m_dialogs;
CDialogs m_addedDialogs;
};
#endif

View File

@@ -0,0 +1,47 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#include "CArchTaskBarXWindows.h"
//
// CArchTaskBarXWindows
//
CArchTaskBarXWindows::CArchTaskBarXWindows(void*)
{
// do nothing
}
CArchTaskBarXWindows::~CArchTaskBarXWindows()
{
// do nothing
}
void
CArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/)
{
// do nothing
}
void
CArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/)
{
// do nothing
}
void
CArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/)
{
// do nothing
}

View File

@@ -0,0 +1,34 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef CARCHTASKBARXWINDOWS_H
#define CARCHTASKBARXWINDOWS_H
#include "IArchTaskBar.h"
#define ARCH_TASKBAR CArchTaskBarXWindows
//! X11 implementation of IArchTaskBar
class CArchTaskBarXWindows : public IArchTaskBar {
public:
CArchTaskBarXWindows(void*);
virtual ~CArchTaskBarXWindows();
// IArchTaskBar overrides
virtual void addReceiver(IArchTaskBarReceiver*);
virtual void removeReceiver(IArchTaskBarReceiver*);
virtual void updateReceiver(IArchTaskBarReceiver*);
};
#endif

View File

@@ -67,6 +67,13 @@ synergy. Each architecture must implement this interface.
*/
class IArchMultithread : public IInterface {
public:
//! Result of waitForEvent()
enum EWaitResult {
kEvent, //!< An event is pending
kExit, //!< Thread exited
kTimeout //!< Wait timed out
};
//! Type of thread entry point
typedef void* (*ThreadFunc)(void*);
//! Type of thread identifier
@@ -102,10 +109,12 @@ public:
//! Wait on a condition variable
/*!
Waiting on a conditation variable for up to \c timeout seconds.
Wait on a conditation variable for up to \c timeout seconds.
If \c timeout is < 0 then there is no timeout. The mutex must
be locked when this method is called. The mutex is unlocked
during the wait and locked again before returning.
during the wait and locked again before returning. Returns
true if the condition variable was signalled and false on
timeout.
(Cancellation point)
*/
@@ -206,14 +215,18 @@ public:
//! Wait for a user event
/*!
Waits for up to \c timeout seconds for a pending user event.
Returns true if an event occurred, false otherwise.
Waits for up to \c timeout seconds for a pending user event or
\c thread to exit (normally or by cancellation). Waits forever
if \c timeout < 0. Returns kEvent if an event occurred, kExit
if \c thread exited, or kTimeout if the timeout expired. If
\c thread is NULL then it doesn't wait for any thread to exit
and it will not return kExit.
This method is not required by all platforms.
(Cancellation point)
*/
virtual bool waitForEvent(double timeout) = 0;
virtual EWaitResult waitForEvent(CArchThread thread, double timeout) = 0;
//! Compare threads
/*!

63
lib/arch/IArchTaskBar.h Normal file
View File

@@ -0,0 +1,63 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IARCHTASKBAR_H
#define IARCHTASKBAR_H
#include "IInterface.h"
class IArchTaskBarReceiver;
//! Interface for architecture dependent task bar control
/*!
This interface defines the task bar icon operations required
by synergy. Each architecture must implement this interface
though each operation can be a no-op.
*/
class IArchTaskBar : public IInterface {
public:
// Event data is architecture dependent
typedef void* Event;
//! @name manipulators
//@{
//! Add a receiver
/*!
Add a receiver object to be notified of user and application
events. This should be called before other methods. When
the receiver is added to the task bar, its icon appears on
the task bar.
*/
virtual void addReceiver(IArchTaskBarReceiver*) = 0;
//! Remove a receiver
/*!
Remove a receiver object from the task bar. This removes the
icon from the task bar.
*/
virtual void removeReceiver(IArchTaskBarReceiver*) = 0;
//! Update a receiver
/*!
Updates the display of the receiver on the task bar. This
should be called when the receiver appearance may have changed
(e.g. it's icon or tool tip has changed).
*/
virtual void updateReceiver(IArchTaskBarReceiver*) = 0;
//@}
};
#endif

View File

@@ -0,0 +1,90 @@
/*
* synergy -- mouse and keyboard sharing utility
* Copyright (C) 2003 Chris Schoeneman
*
* This package is free software; you can redistribute it and/or
* modify it under the terms of the GNU General Public License
* found in the file COPYING that should have accompanied this file.
*
* This package is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*/
#ifndef IARCHTASKBARRECEIVER_H
#define IARCHTASKBARRECEIVER_H
#include "IInterface.h"
#include "stdstring.h"
//! Interface for architecture dependent task bar event handling
/*!
This interface defines the task bar icon event handlers required
by synergy. Each architecture must implement this interface
though each operation can be a no-op.
*/
class IArchTaskBarReceiver : public IInterface {
public:
// Icon data is architecture dependent
typedef void* Icon;
//! @name manipulators
//@{
//! Show status window
/*!
Open a window displaying current status. This should return
immediately without waiting for the window to be closed.
*/
virtual void showStatus() = 0;
//! Popup menu
/*!
Popup a menu of operations at or around \c x,y and perform the
chosen operation.
*/
virtual void runMenu(int x, int y) = 0;
//! Perform primary action
/*!
Perform the primary (default) action.
*/
virtual void primaryAction() = 0;
//@}
//! @name accessors
//@{
//! Lock receiver
/*!
Locks the receiver from changing state. The receiver should be
locked when querying it's state to ensure consistent results.
Each call to \c lock() must have a matching \c unlock() and
locks cannot be nested.
*/
virtual void lock() const = 0;
//! Unlock receiver
virtual void unlock() const = 0;
//! Get icon
/*!
Returns the icon to display in the task bar. The interface
to set the icon is left to subclasses. Getting and setting
the icon must be thread safe.
*/
virtual const Icon getIcon() const = 0;
//! Get tooltip
/*!
Returns the tool tip to display in the task bar. The interface
to set the tooltip is left to sublclasses. Getting and setting
the icon must be thread safe.
*/
virtual std::string getToolTip() const = 0;
//@}
};
#endif

View File

@@ -26,6 +26,7 @@ EXTRA_DIST = \
CArchNetworkWinsock.cpp \
CArchSleepWindows.cpp \
CArchStringWindows.cpp \
CArchTaskBarWindows.cpp \
CArchTimeWindows.cpp \
XArchWindows.cpp \
CArchConsoleWindows.h \
@@ -37,6 +38,7 @@ EXTRA_DIST = \
CArchNetworkWinsock.h \
CArchSleepWindows.h \
CArchStringWindows.h \
CArchTaskBarWindows.h \
CArchTimeWindows.h \
XArchWindows.h \
$(NULL)
@@ -59,6 +61,8 @@ libarch_a_SOURCES = \
IArchNetwork.h \
IArchSleep.h \
IArchString.h \
IArchTaskBar.h \
IArchTaskBarReceiver.h \
IArchTime.h \
XArch.h \
$(NULL)
@@ -72,6 +76,7 @@ EXTRA_libarch_a_SOURCES = \
CArchNetworkBSD.cpp \
CArchSleepUnix.cpp \
CArchStringUnix.cpp \
CArchTaskBarXWindows.cpp \
CArchTimeUnix.cpp \
CMultibyte.cpp \
CMultibyteOS.cpp \
@@ -87,6 +92,7 @@ EXTRA_libarch_a_SOURCES = \
CArchNetworkBSD.h \
CArchSleepUnix.h \
CArchStringUnix.h \
CArchTaskBarXWindows.h \
CArchTimeUnix.h \
XArchUnix.h \
$(NULL)

View File

@@ -115,6 +115,10 @@ SOURCE=.\CArchDaemonWindows.h
# End Source File
# Begin Source File
SOURCE=.\CArchFileWindows.h
# End Source File
# Begin Source File
SOURCE=.\CArchImpl.h
# End Source File
# Begin Source File
@@ -143,6 +147,10 @@ SOURCE=.\CArchStringWindows.h
# End Source File
# Begin Source File
SOURCE=.\CArchTaskBarWindows.h
# End Source File
# Begin Source File
SOURCE=.\CArchTimeWindows.h
# End Source File
# Begin Source File
@@ -151,6 +159,14 @@ SOURCE=.\IArchConsole.h
# End Source File
# Begin Source File
SOURCE=.\IArchDaemon.h
# End Source File
# Begin Source File
SOURCE=.\IArchFile.h
# End Source File
# Begin Source File
SOURCE=.\IArchLog.h
# End Source File
# Begin Source File
@@ -171,6 +187,14 @@ SOURCE=.\IArchString.h
# End Source File
# Begin Source File
SOURCE=.\IArchTaskBar.h
# End Source File
# Begin Source File
SOURCE=.\IArchTaskBarReceiver.h
# End Source File
# Begin Source File
SOURCE=.\IArchTime.h
# End Source File
# Begin Source File
@@ -232,6 +256,11 @@ SOURCE=.\CArchStringWindows.cpp
# End Source File
# Begin Source File
SOURCE=.\CArchTaskBarWindows.cpp
# PROP Exclude_From_Build 1
# End Source File
# Begin Source File
SOURCE=.\CArchTimeWindows.cpp
# PROP Exclude_From_Build 1
# End Source File