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.
|
@ -0,0 +1,183 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 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 "CConfig.h"
|
||||||
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CAdvancedOptions.h"
|
||||||
|
#include "LaunchUtil.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CAdvancedOptions
|
||||||
|
//
|
||||||
|
|
||||||
|
CAdvancedOptions* CAdvancedOptions::s_singleton = NULL;
|
||||||
|
|
||||||
|
CAdvancedOptions::CAdvancedOptions(HWND parent, CConfig* config) :
|
||||||
|
m_parent(parent),
|
||||||
|
m_config(config),
|
||||||
|
m_isClient(false),
|
||||||
|
m_screenName(ARCH->getHostName()),
|
||||||
|
m_port(kDefaultPort)
|
||||||
|
{
|
||||||
|
assert(s_singleton == NULL);
|
||||||
|
s_singleton = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CAdvancedOptions::~CAdvancedOptions()
|
||||||
|
{
|
||||||
|
s_singleton = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAdvancedOptions::doModal(bool isClient)
|
||||||
|
{
|
||||||
|
// save state
|
||||||
|
m_isClient = isClient;
|
||||||
|
|
||||||
|
// do dialog
|
||||||
|
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_ADVANCED_OPTIONS),
|
||||||
|
m_parent, dlgProc, (LPARAM)this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CAdvancedOptions::getScreenName() const
|
||||||
|
{
|
||||||
|
return m_screenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CAdvancedOptions::getPort() const
|
||||||
|
{
|
||||||
|
return m_port;
|
||||||
|
}
|
||||||
|
|
||||||
|
CString
|
||||||
|
CAdvancedOptions::getCommandLine(bool isClient, const CString& serverName) const
|
||||||
|
{
|
||||||
|
CString cmdLine;
|
||||||
|
|
||||||
|
// screen name
|
||||||
|
if (!m_screenName.empty()) {
|
||||||
|
cmdLine += " --name ";
|
||||||
|
cmdLine += m_screenName;
|
||||||
|
}
|
||||||
|
|
||||||
|
// port
|
||||||
|
char portString[20];
|
||||||
|
sprintf(portString, "%d", m_port);
|
||||||
|
if (isClient) {
|
||||||
|
cmdLine += " ";
|
||||||
|
cmdLine += serverName;
|
||||||
|
cmdLine += ":";
|
||||||
|
cmdLine += portString;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
cmdLine += " --address :";
|
||||||
|
cmdLine += portString;
|
||||||
|
}
|
||||||
|
|
||||||
|
return cmdLine;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CAdvancedOptions::init(HWND hwnd)
|
||||||
|
{
|
||||||
|
HWND child;
|
||||||
|
char buffer[20];
|
||||||
|
sprintf(buffer, "%d", m_port);
|
||||||
|
child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
|
||||||
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
||||||
|
|
||||||
|
child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
|
||||||
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)m_screenName.c_str());
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CAdvancedOptions::save(HWND hwnd)
|
||||||
|
{
|
||||||
|
HWND child = getItem(hwnd, IDC_ADVANCED_NAME_EDIT);
|
||||||
|
CString name = getWindowText(child);
|
||||||
|
if (!m_config->isValidScreenName(name)) {
|
||||||
|
showError(hwnd, CStringUtil::format(
|
||||||
|
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
||||||
|
name.c_str()));
|
||||||
|
SetFocus(child);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
if (!m_isClient && !m_config->isScreen(name)) {
|
||||||
|
showError(hwnd, CStringUtil::format(
|
||||||
|
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
|
||||||
|
name.c_str()));
|
||||||
|
SetFocus(child);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get and verify port
|
||||||
|
child = getItem(hwnd, IDC_ADVANCED_PORT_EDIT);
|
||||||
|
CString portString = getWindowText(child);
|
||||||
|
int port = atoi(portString.c_str());
|
||||||
|
if (port < 1 || port > 65535) {
|
||||||
|
CString defaultPortString = CStringUtil::print("%d", kDefaultPort);
|
||||||
|
showError(hwnd, CStringUtil::format(
|
||||||
|
getString(IDS_INVALID_PORT).c_str(),
|
||||||
|
portString.c_str(),
|
||||||
|
defaultPortString.c_str()));
|
||||||
|
SetFocus(child);
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
|
||||||
|
// save state
|
||||||
|
m_screenName = name;
|
||||||
|
m_port = port;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CAdvancedOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
|
||||||
|
{
|
||||||
|
switch (message) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
init(hwnd);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (LOWORD(wParam)) {
|
||||||
|
case IDOK:
|
||||||
|
if (save(hwnd)) {
|
||||||
|
EndDialog(hwnd, 0);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case IDCANCEL:
|
||||||
|
EndDialog(hwnd, 0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK
|
||||||
|
CAdvancedOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
|
||||||
|
}
|
|
@ -0,0 +1,74 @@
|
||||||
|
/*
|
||||||
|
* 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 CADVANCEDOPTIONS_H
|
||||||
|
#define CADVANCEDOPTIONS_H
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
|
#define WINDOWS_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
class CConfig;
|
||||||
|
|
||||||
|
//! Advanced options dialog for Microsoft Windows launcher
|
||||||
|
class CAdvancedOptions {
|
||||||
|
public:
|
||||||
|
CAdvancedOptions(HWND parent, CConfig*);
|
||||||
|
~CAdvancedOptions();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Run dialog
|
||||||
|
/*!
|
||||||
|
Display and handle the dialog until closed by the user.
|
||||||
|
*/
|
||||||
|
void doModal(bool isClient);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get the screen name
|
||||||
|
CString getScreenName() const;
|
||||||
|
|
||||||
|
//! Get the port
|
||||||
|
int getPort() const;
|
||||||
|
|
||||||
|
//! Convert options to command line string
|
||||||
|
CString getCommandLine(bool isClient,
|
||||||
|
const CString& serverName) const;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(HWND hwnd);
|
||||||
|
bool save(HWND hwnd);
|
||||||
|
|
||||||
|
// message handling
|
||||||
|
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CAdvancedOptions* s_singleton;
|
||||||
|
|
||||||
|
HWND m_parent;
|
||||||
|
CConfig* m_config;
|
||||||
|
bool m_isClient;
|
||||||
|
CString m_screenName;
|
||||||
|
int m_port;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,211 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 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 "CConfig.h"
|
||||||
|
#include "ProtocolTypes.h"
|
||||||
|
#include "CStringUtil.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CGlobalOptions.h"
|
||||||
|
#include "LaunchUtil.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
static const int s_defaultDelay = 250;
|
||||||
|
|
||||||
|
//
|
||||||
|
// CGlobalOptions
|
||||||
|
//
|
||||||
|
|
||||||
|
CGlobalOptions* CGlobalOptions::s_singleton = NULL;
|
||||||
|
|
||||||
|
CGlobalOptions::CGlobalOptions(HWND parent, CConfig* config) :
|
||||||
|
m_parent(parent),
|
||||||
|
m_config(config),
|
||||||
|
m_delayTime(s_defaultDelay),
|
||||||
|
m_twoTapTime(s_defaultDelay)
|
||||||
|
{
|
||||||
|
assert(s_singleton == NULL);
|
||||||
|
s_singleton = this;
|
||||||
|
}
|
||||||
|
|
||||||
|
CGlobalOptions::~CGlobalOptions()
|
||||||
|
{
|
||||||
|
s_singleton = NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CGlobalOptions::doModal()
|
||||||
|
{
|
||||||
|
// do dialog
|
||||||
|
DialogBoxParam(s_instance, MAKEINTRESOURCE(IDD_GLOBAL_OPTIONS),
|
||||||
|
m_parent, dlgProc, (LPARAM)this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CGlobalOptions::init(HWND hwnd)
|
||||||
|
{
|
||||||
|
HWND child;
|
||||||
|
char buffer[30];
|
||||||
|
|
||||||
|
// reset options
|
||||||
|
sprintf(buffer, "%d", m_delayTime);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
|
||||||
|
setItemChecked(child, false);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
|
||||||
|
setWindowText(child, buffer);
|
||||||
|
sprintf(buffer, "%d", m_twoTapTime);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
|
||||||
|
setItemChecked(child, false);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
|
||||||
|
setWindowText(child, buffer);
|
||||||
|
|
||||||
|
// get the global options
|
||||||
|
const CConfig::CScreenOptions* options = m_config->getOptions("");
|
||||||
|
if (options != NULL) {
|
||||||
|
for (CConfig::CScreenOptions::const_iterator index = options->begin();
|
||||||
|
index != options->end(); ++index) {
|
||||||
|
const OptionID id = index->first;
|
||||||
|
const OptionValue value = index->second;
|
||||||
|
if (id == kOptionScreenSwitchDelay) {
|
||||||
|
if (value > 0) {
|
||||||
|
sprintf(buffer, "%d", value);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
|
||||||
|
setItemChecked(child, true);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
|
||||||
|
setWindowText(child, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else if (id == kOptionScreenSwitchTwoTap) {
|
||||||
|
if (value > 0) {
|
||||||
|
sprintf(buffer, "%d", value);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
|
||||||
|
setItemChecked(child, true);
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
|
||||||
|
setWindowText(child, buffer);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
CGlobalOptions::save(HWND hwnd)
|
||||||
|
{
|
||||||
|
HWND child;
|
||||||
|
int newDelayTime = 0;
|
||||||
|
int newTwoTapTime = 0;
|
||||||
|
|
||||||
|
// get requested options
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
|
||||||
|
if (isItemChecked(child)) {
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
|
||||||
|
newDelayTime = getTime(hwnd, child, true);
|
||||||
|
if (newDelayTime == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_TIME);
|
||||||
|
newDelayTime = getTime(hwnd, child, false);
|
||||||
|
if (newDelayTime == 0) {
|
||||||
|
newDelayTime = s_defaultDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
|
||||||
|
if (isItemChecked(child)) {
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
|
||||||
|
newTwoTapTime = getTime(hwnd, child, true);
|
||||||
|
if (newTwoTapTime == 0) {
|
||||||
|
return false;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_TIME);
|
||||||
|
newTwoTapTime = getTime(hwnd, child, false);
|
||||||
|
if (newTwoTapTime == 0) {
|
||||||
|
newTwoTapTime = s_defaultDelay;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove existing config options
|
||||||
|
m_config->removeOption("", kOptionScreenSwitchDelay);
|
||||||
|
m_config->removeOption("", kOptionScreenSwitchTwoTap);
|
||||||
|
|
||||||
|
// add requested options
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_DELAY_CHECK);
|
||||||
|
if (isItemChecked(child)) {
|
||||||
|
m_config->addOption("", kOptionScreenSwitchDelay, newDelayTime);
|
||||||
|
}
|
||||||
|
child = getItem(hwnd, IDC_GLOBAL_TWO_TAP_CHECK);
|
||||||
|
if (isItemChecked(child)) {
|
||||||
|
m_config->addOption("", kOptionScreenSwitchTwoTap, newTwoTapTime);
|
||||||
|
}
|
||||||
|
|
||||||
|
// save last values
|
||||||
|
m_delayTime = newDelayTime;
|
||||||
|
m_twoTapTime = newTwoTapTime;
|
||||||
|
|
||||||
|
return true;
|
||||||
|
}
|
||||||
|
|
||||||
|
int
|
||||||
|
CGlobalOptions::getTime(HWND hwnd, HWND child, bool reportError)
|
||||||
|
{
|
||||||
|
CString valueString = getWindowText(child);
|
||||||
|
int value = atoi(valueString.c_str());
|
||||||
|
if (value < 1) {
|
||||||
|
if (reportError) {
|
||||||
|
showError(hwnd, CStringUtil::format(
|
||||||
|
getString(IDS_INVALID_TIME).c_str(),
|
||||||
|
valueString.c_str()));
|
||||||
|
SetFocus(child);
|
||||||
|
}
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
return value;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CGlobalOptions::doDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM)
|
||||||
|
{
|
||||||
|
switch (message) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
init(hwnd);
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case WM_COMMAND:
|
||||||
|
switch (LOWORD(wParam)) {
|
||||||
|
case IDOK:
|
||||||
|
if (save(hwnd)) {
|
||||||
|
EndDialog(hwnd, 0);
|
||||||
|
}
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case IDCANCEL:
|
||||||
|
EndDialog(hwnd, 0);
|
||||||
|
return TRUE;
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK
|
||||||
|
CGlobalOptions::dlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
return s_singleton->doDlgProc(hwnd, message, wParam, lParam);
|
||||||
|
}
|
|
@ -0,0 +1,66 @@
|
||||||
|
/*
|
||||||
|
* 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 CGLOBALOPTIONS_H
|
||||||
|
#define CGLOBALOPTIONS_H
|
||||||
|
|
||||||
|
#include "CString.h"
|
||||||
|
|
||||||
|
#define WINDOWS_LEAN_AND_MEAN
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
class CConfig;
|
||||||
|
|
||||||
|
//! Global options dialog for Microsoft Windows launcher
|
||||||
|
class CGlobalOptions {
|
||||||
|
public:
|
||||||
|
CGlobalOptions(HWND parent, CConfig*);
|
||||||
|
~CGlobalOptions();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Run dialog
|
||||||
|
/*!
|
||||||
|
Display and handle the dialog until closed by the user.
|
||||||
|
*/
|
||||||
|
void doModal();
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
void init(HWND hwnd);
|
||||||
|
bool save(HWND hwnd);
|
||||||
|
|
||||||
|
int getTime(HWND hwnd, HWND child, bool reportError);
|
||||||
|
|
||||||
|
// message handling
|
||||||
|
BOOL doDlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
static BOOL CALLBACK dlgProc(HWND, UINT, WPARAM, LPARAM);
|
||||||
|
|
||||||
|
private:
|
||||||
|
static CGlobalOptions* s_singleton;
|
||||||
|
|
||||||
|
HWND m_parent;
|
||||||
|
CConfig* m_config;
|
||||||
|
int m_delayTime;
|
||||||
|
int m_twoTapTime;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -103,6 +103,18 @@ enableItem(HWND hwnd, int id, bool enabled)
|
||||||
EnableWindow(GetDlgItem(hwnd, id), enabled);
|
EnableWindow(GetDlgItem(hwnd, id), enabled);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
setItemChecked(HWND hwnd, bool checked)
|
||||||
|
{
|
||||||
|
SendMessage(hwnd, BM_SETCHECK, checked ? BST_CHECKED : BST_UNCHECKED, 0);
|
||||||
|
}
|
||||||
|
|
||||||
|
bool
|
||||||
|
isItemChecked(HWND hwnd)
|
||||||
|
{
|
||||||
|
return (SendMessage(hwnd, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
||||||
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
getAppPath(const CString& appName)
|
getAppPath(const CString& appName)
|
||||||
{
|
{
|
||||||
|
|
|
@ -42,6 +42,9 @@ CString getWindowText(HWND hwnd);
|
||||||
HWND getItem(HWND hwnd, int id);
|
HWND getItem(HWND hwnd, int id);
|
||||||
void enableItem(HWND hwnd, int id, bool enabled);
|
void enableItem(HWND hwnd, int id, bool enabled);
|
||||||
|
|
||||||
|
void setItemChecked(HWND, bool);
|
||||||
|
bool isItemChecked(HWND);
|
||||||
|
|
||||||
CString getAppPath(const CString& appName);
|
CString getAppPath(const CString& appName);
|
||||||
|
|
||||||
bool loadConfig(CConfig& config);
|
bool loadConfig(CConfig& config);
|
||||||
|
|
|
@ -16,8 +16,12 @@ DEPTH = ../..
|
||||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
CAdvancedOptions.cpp \
|
||||||
|
CAdvancedOptions.h \
|
||||||
CAutoStart.cpp \
|
CAutoStart.cpp \
|
||||||
CAutoStart.h \
|
CAutoStart.h \
|
||||||
|
CGlobalOptions.cpp \
|
||||||
|
CGlobalOptions.h \
|
||||||
LaunchUtil.cpp \
|
LaunchUtil.cpp \
|
||||||
LaunchUtil.h \
|
LaunchUtil.h \
|
||||||
launcher.cpp \
|
launcher.cpp \
|
||||||
|
|
|
@ -13,6 +13,8 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CConfig.h"
|
#include "CConfig.h"
|
||||||
|
#include "KeyTypes.h"
|
||||||
|
#include "OptionTypes.h"
|
||||||
#include "ProtocolTypes.h"
|
#include "ProtocolTypes.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "CStringUtil.h"
|
#include "CStringUtil.h"
|
||||||
|
@ -24,6 +26,8 @@
|
||||||
// these must come after the above because it includes windows.h
|
// these must come after the above because it includes windows.h
|
||||||
#include "LaunchUtil.h"
|
#include "LaunchUtil.h"
|
||||||
#include "CAutoStart.h"
|
#include "CAutoStart.h"
|
||||||
|
#include "CGlobalOptions.h"
|
||||||
|
#include "CAdvancedOptions.h"
|
||||||
|
|
||||||
#define CONFIG_NAME "synergy.sgc"
|
#define CONFIG_NAME "synergy.sgc"
|
||||||
#define CLIENT_APP "synergyc.exe"
|
#define CLIENT_APP "synergyc.exe"
|
||||||
|
@ -47,10 +51,28 @@ public:
|
||||||
HANDLE m_stop;
|
HANDLE m_stop;
|
||||||
};
|
};
|
||||||
|
|
||||||
HINSTANCE s_instance = NULL;
|
struct CModifierInfo {
|
||||||
|
public:
|
||||||
|
int m_ctrlID;
|
||||||
|
const char* m_name;
|
||||||
|
KeyModifierID m_modifierID;
|
||||||
|
OptionID m_optionID;
|
||||||
|
};
|
||||||
|
|
||||||
static const TCHAR* s_mainClass = TEXT("GoSynergy");
|
static const CModifierInfo s_modifiers[] = {
|
||||||
static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
|
{ IDC_ADD_MOD_SHIFT, "Shift",
|
||||||
|
kKeyModifierIDShift, kOptionModifierMapForShift },
|
||||||
|
{ IDC_ADD_MOD_CTRL, "Ctrl",
|
||||||
|
kKeyModifierIDControl, kOptionModifierMapForControl },
|
||||||
|
{ IDC_ADD_MOD_ALT, "Alt",
|
||||||
|
kKeyModifierIDAlt, kOptionModifierMapForAlt },
|
||||||
|
{ IDC_ADD_MOD_META, "Meta",
|
||||||
|
kKeyModifierIDMeta, kOptionModifierMapForMeta },
|
||||||
|
{ IDC_ADD_MOD_SUPER, "Super",
|
||||||
|
kKeyModifierIDSuper, kOptionModifierMapForSuper }
|
||||||
|
};
|
||||||
|
|
||||||
|
static const KeyModifierID baseModifier = kKeyModifierIDShift;
|
||||||
|
|
||||||
static const char* s_debugName[][2] = {
|
static const char* s_debugName[][2] = {
|
||||||
{ TEXT("Error"), "ERROR" },
|
{ TEXT("Error"), "ERROR" },
|
||||||
|
@ -63,6 +85,14 @@ static const char* s_debugName[][2] = {
|
||||||
};
|
};
|
||||||
static const int s_defaultDebug = 3; // INFO
|
static const int s_defaultDebug = 3; // INFO
|
||||||
|
|
||||||
|
HINSTANCE s_instance = NULL;
|
||||||
|
|
||||||
|
static CGlobalOptions* s_globalOptions = NULL;
|
||||||
|
static CAdvancedOptions* s_advancedOptions = NULL;
|
||||||
|
|
||||||
|
static const TCHAR* s_mainClass = TEXT("GoSynergy");
|
||||||
|
static const TCHAR* s_layoutClass = TEXT("SynergyLayout");
|
||||||
|
|
||||||
//
|
//
|
||||||
// program arguments
|
// program arguments
|
||||||
//
|
//
|
||||||
|
@ -127,7 +157,7 @@ bool
|
||||||
isClientChecked(HWND hwnd)
|
isClientChecked(HWND hwnd)
|
||||||
{
|
{
|
||||||
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
||||||
return (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
return isItemChecked(child);
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
static
|
||||||
|
@ -476,58 +506,20 @@ static
|
||||||
CString
|
CString
|
||||||
getCommandLine(HWND hwnd, bool testing)
|
getCommandLine(HWND hwnd, bool testing)
|
||||||
{
|
{
|
||||||
// decide if client or server
|
|
||||||
const bool isClient = isClientChecked(hwnd);
|
|
||||||
|
|
||||||
// get and verify screen name
|
|
||||||
HWND child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
|
||||||
CString name = getWindowText(child);
|
|
||||||
if (!ARG->m_config.isValidScreenName(name)) {
|
|
||||||
showError(hwnd, CStringUtil::format(
|
|
||||||
getString(IDS_INVALID_SCREEN_NAME).c_str(),
|
|
||||||
name.c_str()));
|
|
||||||
SetFocus(child);
|
|
||||||
return CString();
|
|
||||||
}
|
|
||||||
if (!isClient && !ARG->m_config.isScreen(name)) {
|
|
||||||
showError(hwnd, CStringUtil::format(
|
|
||||||
getString(IDS_UNKNOWN_SCREEN_NAME).c_str(),
|
|
||||||
name.c_str()));
|
|
||||||
SetFocus(child);
|
|
||||||
return CString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// get and verify port
|
|
||||||
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
|
|
||||||
CString portString = getWindowText(child);
|
|
||||||
UInt32 port = (UInt32)atoi(portString.c_str());
|
|
||||||
if (port < 1 || port > 65535) {
|
|
||||||
CString defaultPortString = CStringUtil::print("%d", kDefaultPort);
|
|
||||||
showError(hwnd, CStringUtil::format(
|
|
||||||
getString(IDS_INVALID_PORT).c_str(),
|
|
||||||
portString.c_str(),
|
|
||||||
defaultPortString.c_str()));
|
|
||||||
SetFocus(child);
|
|
||||||
return CString();
|
|
||||||
}
|
|
||||||
|
|
||||||
// prepare command line
|
|
||||||
CString cmdLine;
|
CString cmdLine;
|
||||||
if (testing) {
|
|
||||||
// constant testing args
|
|
||||||
cmdLine += " -z --no-restart --no-daemon";
|
|
||||||
|
|
||||||
// debug level testing arg
|
// add constant testing args
|
||||||
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
if (testing) {
|
||||||
cmdLine += " --debug ";
|
cmdLine += " -z --no-restart --no-daemon";
|
||||||
cmdLine += s_debugName[SendMessage(child, CB_GETCURSEL, 0, 0)][1];
|
|
||||||
}
|
}
|
||||||
cmdLine += " --name ";
|
|
||||||
cmdLine += name;
|
// get the server name
|
||||||
|
CString server;
|
||||||
|
bool isClient = isClientChecked(hwnd);
|
||||||
if (isClient) {
|
if (isClient) {
|
||||||
// check server name
|
// check server name
|
||||||
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
||||||
CString server = getWindowText(child);
|
server = getWindowText(child);
|
||||||
if (!ARG->m_config.isValidScreenName(server)) {
|
if (!ARG->m_config.isValidScreenName(server)) {
|
||||||
showError(hwnd, CStringUtil::format(
|
showError(hwnd, CStringUtil::format(
|
||||||
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
||||||
|
@ -551,16 +543,19 @@ getCommandLine(HWND hwnd, bool testing)
|
||||||
if (testing) {
|
if (testing) {
|
||||||
cmdLine += " --no-camp";
|
cmdLine += " --no-camp";
|
||||||
}
|
}
|
||||||
cmdLine += " ";
|
|
||||||
cmdLine += server;
|
|
||||||
cmdLine += ":";
|
|
||||||
cmdLine += portString;
|
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
cmdLine += " --address :";
|
// debug level
|
||||||
cmdLine += portString;
|
if (testing) {
|
||||||
|
HWND child = getItem(hwnd, IDC_MAIN_DEBUG);
|
||||||
|
DWORD debug = SendMessage(child, CB_GETCURSEL, 0, 0);
|
||||||
|
cmdLine += " --debug ";
|
||||||
|
cmdLine += s_debugName[debug][1];
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// add advanced options
|
||||||
|
cmdLine += s_advancedOptions->getCommandLine(isClient, server);
|
||||||
|
|
||||||
return cmdLine;
|
return cmdLine;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -711,11 +706,9 @@ initMainWindow(HWND hwnd)
|
||||||
// choose client/server radio buttons
|
// choose client/server radio buttons
|
||||||
HWND child;
|
HWND child;
|
||||||
child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
||||||
SendMessage(child, BM_SETCHECK, !configLoaded ?
|
setItemChecked(child, !configLoaded);
|
||||||
BST_CHECKED : BST_UNCHECKED, 0);
|
|
||||||
child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
|
child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
|
||||||
SendMessage(child, BM_SETCHECK, configLoaded ?
|
setItemChecked(child, configLoaded);
|
||||||
BST_CHECKED : BST_UNCHECKED, 0);
|
|
||||||
|
|
||||||
// if config is loaded then initialize server controls
|
// if config is loaded then initialize server controls
|
||||||
if (configLoaded) {
|
if (configLoaded) {
|
||||||
|
@ -729,16 +722,7 @@ initMainWindow(HWND hwnd)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// initialize other controls
|
// debug level
|
||||||
char buffer[256];
|
|
||||||
sprintf(buffer, "%d", kDefaultPort);
|
|
||||||
child = getItem(hwnd, IDC_MAIN_ADVANCED_PORT_EDIT);
|
|
||||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)buffer);
|
|
||||||
|
|
||||||
CString hostname = ARCH->getHostName();
|
|
||||||
child = getItem(hwnd, IDC_MAIN_ADVANCED_NAME_EDIT);
|
|
||||||
SendMessage(child, WM_SETTEXT, 0, (LPARAM)hostname.c_str());
|
|
||||||
|
|
||||||
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
||||||
for (unsigned int i = 0; i < sizeof(s_debugName) /
|
for (unsigned int i = 0; i < sizeof(s_debugName) /
|
||||||
sizeof(s_debugName[0]); ++i) {
|
sizeof(s_debugName[0]); ++i) {
|
||||||
|
@ -794,19 +778,32 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
CConfig::CScreenOptions::const_iterator index;
|
CConfig::CScreenOptions::const_iterator index;
|
||||||
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
||||||
index = info->m_options.find(kOptionHalfDuplexCapsLock);
|
index = info->m_options.find(kOptionHalfDuplexCapsLock);
|
||||||
if (index != info->m_options.end() && index->second != 0) {
|
setItemChecked(child, (index != info->m_options.end() &&
|
||||||
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
|
index->second != 0));
|
||||||
}
|
|
||||||
else {
|
|
||||||
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
|
|
||||||
}
|
|
||||||
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
|
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
|
||||||
index = info->m_options.find(kOptionHalfDuplexNumLock);
|
index = info->m_options.find(kOptionHalfDuplexNumLock);
|
||||||
if (index != info->m_options.end() && index->second != 0) {
|
setItemChecked(child, (index != info->m_options.end() &&
|
||||||
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
|
index->second != 0));
|
||||||
|
|
||||||
|
// modifier options
|
||||||
|
for (UInt32 i = 0; i < sizeof(s_modifiers) /
|
||||||
|
sizeof(s_modifiers[0]); ++i) {
|
||||||
|
child = getItem(hwnd, s_modifiers[i].m_ctrlID);
|
||||||
|
|
||||||
|
// fill in options
|
||||||
|
for (UInt32 j = 0; j < sizeof(s_modifiers) /
|
||||||
|
sizeof(s_modifiers[0]); ++j) {
|
||||||
|
SendMessage(child, CB_ADDSTRING, 0,
|
||||||
|
(LPARAM)s_modifiers[j].m_name);
|
||||||
}
|
}
|
||||||
else {
|
|
||||||
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
|
// choose current value
|
||||||
|
index = info->m_options.find(s_modifiers[i].m_optionID);
|
||||||
|
KeyModifierID id = s_modifiers[i].m_modifierID;
|
||||||
|
if (index != info->m_options.end()) {
|
||||||
|
id = index->second;
|
||||||
|
}
|
||||||
|
SendMessage(child, CB_SETCURSEL, id - baseModifier, 0);
|
||||||
}
|
}
|
||||||
|
|
||||||
return TRUE;
|
return TRUE;
|
||||||
|
@ -883,20 +880,36 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
|
|
||||||
// save options
|
// save options
|
||||||
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
||||||
if (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
if (isItemChecked(child)) {
|
||||||
info->m_options[kOptionHalfDuplexCapsLock] = 1;
|
info->m_options[kOptionHalfDuplexCapsLock] = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info->m_options.erase(kOptionHalfDuplexCapsLock);
|
info->m_options.erase(kOptionHalfDuplexCapsLock);
|
||||||
}
|
}
|
||||||
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
|
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
|
||||||
if (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED) {
|
if (isItemChecked(child)) {
|
||||||
info->m_options[kOptionHalfDuplexNumLock] = 1;
|
info->m_options[kOptionHalfDuplexNumLock] = 1;
|
||||||
}
|
}
|
||||||
else {
|
else {
|
||||||
info->m_options.erase(kOptionHalfDuplexNumLock);
|
info->m_options.erase(kOptionHalfDuplexNumLock);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// save modifier options
|
||||||
|
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
||||||
|
for (UInt32 i = 0; i < sizeof(s_modifiers) /
|
||||||
|
sizeof(s_modifiers[0]); ++i) {
|
||||||
|
child = getItem(hwnd, s_modifiers[i].m_ctrlID);
|
||||||
|
KeyModifierID id = static_cast<KeyModifierID>(
|
||||||
|
SendMessage(child, CB_GETCURSEL, 0, 0) +
|
||||||
|
baseModifier);
|
||||||
|
if (id != s_modifiers[i].m_modifierID) {
|
||||||
|
info->m_options[s_modifiers[i].m_optionID] = id;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
info->m_options.erase(s_modifiers[i].m_optionID);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// success
|
// success
|
||||||
EndDialog(hwnd, 1);
|
EndDialog(hwnd, 1);
|
||||||
info = NULL;
|
info = NULL;
|
||||||
|
@ -1065,6 +1078,16 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
return 0;
|
return 0;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
case IDC_MAIN_OPTIONS:
|
||||||
|
s_globalOptions->doModal();
|
||||||
|
enableSaveControls(hwnd);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDC_MAIN_ADVANCED:
|
||||||
|
s_advancedOptions->doModal(isClientChecked(hwnd));
|
||||||
|
enableSaveControls(hwnd);
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
|
|
||||||
default:
|
default:
|
||||||
|
@ -1076,7 +1099,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||||
{
|
{
|
||||||
CArch arch;
|
CArch arch(instance);
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
CArgs args;
|
||||||
|
|
||||||
|
@ -1108,8 +1131,10 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||||
HWND m_mainWindow = CreateDialog(s_instance,
|
HWND m_mainWindow = CreateDialog(s_instance,
|
||||||
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
|
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
|
||||||
|
|
||||||
// prep window
|
// prep windows
|
||||||
initMainWindow(m_mainWindow);
|
initMainWindow(m_mainWindow);
|
||||||
|
s_globalOptions = new CGlobalOptions(m_mainWindow, &ARG->m_config);
|
||||||
|
s_advancedOptions = new CAdvancedOptions(m_mainWindow, &ARG->m_config);
|
||||||
|
|
||||||
// show window
|
// show window
|
||||||
ShowWindow(m_mainWindow, nCmdShow);
|
ShowWindow(m_mainWindow, nCmdShow);
|
||||||
|
|
|
@ -95,10 +95,18 @@ LINK32=link.exe
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CAdvancedOptions.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CAutoStart.cpp
|
SOURCE=.\CAutoStart.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CGlobalOptions.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\launcher.cpp
|
SOURCE=.\launcher.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -115,10 +123,18 @@ SOURCE=.\LaunchUtil.cpp
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CAdvancedOptions.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CAutoStart.h
|
SOURCE=.\CAutoStart.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CGlobalOptions.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\LaunchUtil.h
|
SOURCE=.\LaunchUtil.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
|
@ -40,11 +40,14 @@
|
||||||
#define IDS_SERVER_IS_CLIENT 36
|
#define IDS_SERVER_IS_CLIENT 36
|
||||||
#define IDS_ADD_SCREEN 37
|
#define IDS_ADD_SCREEN 37
|
||||||
#define IDS_EDIT_SCREEN 38
|
#define IDS_EDIT_SCREEN 38
|
||||||
|
#define IDS_INVALID_TIME 39
|
||||||
#define IDD_MAIN 101
|
#define IDD_MAIN 101
|
||||||
#define IDD_ADD 102
|
#define IDD_ADD 102
|
||||||
#define IDD_WAIT 103
|
#define IDD_WAIT 103
|
||||||
#define IDI_SYNERGY 104
|
#define IDI_SYNERGY 104
|
||||||
#define IDD_AUTOSTART 105
|
#define IDD_AUTOSTART 105
|
||||||
|
#define IDD_ADVANCED_OPTIONS 106
|
||||||
|
#define IDD_GLOBAL_OPTIONS 107
|
||||||
#define IDC_MAIN_CLIENT_RADIO 1000
|
#define IDC_MAIN_CLIENT_RADIO 1000
|
||||||
#define IDC_MAIN_SERVER_RADIO 1001
|
#define IDC_MAIN_SERVER_RADIO 1001
|
||||||
#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002
|
#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002
|
||||||
|
@ -76,18 +79,31 @@
|
||||||
#define IDC_AUTOSTART_INSTALL_USER 1033
|
#define IDC_AUTOSTART_INSTALL_USER 1033
|
||||||
#define IDC_AUTOSTART_INSTALL_SYSTEM 1034
|
#define IDC_AUTOSTART_INSTALL_SYSTEM 1034
|
||||||
#define IDC_MAIN_AUTOSTART 1035
|
#define IDC_MAIN_AUTOSTART 1035
|
||||||
#define IDC_MAIN_DEBUG 1036
|
#define IDC_MAIN_OPTIONS 1036
|
||||||
#define IDC_ADD_HD_CAPS_CHECK 1037
|
#define IDC_ADD_HD_CAPS_CHECK 1037
|
||||||
|
#define IDC_MAIN_ADVANCED 1037
|
||||||
#define IDC_ADD_HD_NUM_CHECK 1038
|
#define IDC_ADD_HD_NUM_CHECK 1038
|
||||||
|
#define IDC_ADVANCED_NAME_EDIT 1038
|
||||||
|
#define IDC_ADVANCED_PORT_EDIT 1039
|
||||||
|
#define IDC_MAIN_DEBUG 1040
|
||||||
|
#define IDC_GLOBAL_DELAY_CHECK 1041
|
||||||
|
#define IDC_GLOBAL_DELAY_TIME 1042
|
||||||
|
#define IDC_GLOBAL_TWO_TAP_CHECK 1043
|
||||||
|
#define IDC_ADD_MOD_SHIFT 1043
|
||||||
|
#define IDC_GLOBAL_TWO_TAP_TIME 1044
|
||||||
|
#define IDC_ADD_MOD_CTRL 1044
|
||||||
|
#define IDC_ADD_MOD_ALT 1045
|
||||||
|
#define IDC_ADD_MOD_META 1046
|
||||||
|
#define IDC_ADD_MOD_SUPER 1047
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
#ifdef APSTUDIO_INVOKED
|
#ifdef APSTUDIO_INVOKED
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
#define _APS_NO_MFC 1
|
#define _APS_NO_MFC 1
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 106
|
#define _APS_NEXT_RESOURCE_VALUE 108
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1038
|
#define _APS_NEXT_CONTROL_VALUE 1044
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -0,0 +1,163 @@
|
||||||
|
/*
|
||||||
|
* 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 "CClientTaskBarReceiver.h"
|
||||||
|
#include "CClient.h"
|
||||||
|
#include "CLock.h"
|
||||||
|
#include "TMethodJob.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CClientTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CClientTaskBarReceiver::CClientTaskBarReceiver() :
|
||||||
|
m_quit(NULL),
|
||||||
|
m_state(kNotRunning),
|
||||||
|
m_client(NULL)
|
||||||
|
{
|
||||||
|
// create a job for getting notification when the client's
|
||||||
|
// status changes.
|
||||||
|
m_job = new TMethodJob<CClientTaskBarReceiver>(this,
|
||||||
|
&CClientTaskBarReceiver::statusChanged, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientTaskBarReceiver::~CClientTaskBarReceiver()
|
||||||
|
{
|
||||||
|
if (m_client != NULL) {
|
||||||
|
m_client->removeStatusJob(m_job);
|
||||||
|
}
|
||||||
|
delete m_job;
|
||||||
|
delete m_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::setClient(CClient* client)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
if (m_client != client) {
|
||||||
|
if (m_client != NULL) {
|
||||||
|
m_client->removeStatusJob(m_job);
|
||||||
|
}
|
||||||
|
m_client = client;
|
||||||
|
if (m_client != NULL) {
|
||||||
|
m_client->addStatusJob(m_job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ARCH->updateReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::setState(EState state)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
ARCH->updateReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::setQuitJob(IJob* job)
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
delete m_quit;
|
||||||
|
m_quit = job;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClientTaskBarReceiver::EState
|
||||||
|
CClientTaskBarReceiver::getState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
CClient*
|
||||||
|
CClientTaskBarReceiver::getClient() const
|
||||||
|
{
|
||||||
|
return m_client;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::lock() const
|
||||||
|
{
|
||||||
|
m_mutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::unlock() const
|
||||||
|
{
|
||||||
|
m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CClientTaskBarReceiver::getToolTip() const
|
||||||
|
{
|
||||||
|
switch (m_state) {
|
||||||
|
case kNotRunning:
|
||||||
|
return "Synergy: Not running";
|
||||||
|
|
||||||
|
case kNotWorking:
|
||||||
|
return CString("Synergy: ") + m_errorMessage;
|
||||||
|
|
||||||
|
case kNotConnected:
|
||||||
|
return "Synergy: Waiting for clients";
|
||||||
|
|
||||||
|
case kConnected:
|
||||||
|
return "Synergy: Connected";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::quit()
|
||||||
|
{
|
||||||
|
if (m_quit != NULL) {
|
||||||
|
m_quit->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClientTaskBarReceiver::statusChanged(void*)
|
||||||
|
{
|
||||||
|
// update our status
|
||||||
|
switch (m_client->getStatus(&m_errorMessage)) {
|
||||||
|
case CClient::kNotRunning:
|
||||||
|
setState(kNotRunning);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CClient::kRunning:
|
||||||
|
setState(kConnected);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CClient::kError:
|
||||||
|
setState(kNotWorking);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let subclasses have a go
|
||||||
|
onStatusChanged();
|
||||||
|
}
|
|
@ -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 CCLIENTTASKBARRECEIVER_H
|
||||||
|
#define CCLIENTTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#include "CMutex.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
|
||||||
|
class CClient;
|
||||||
|
class IJob;
|
||||||
|
|
||||||
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
|
class CClientTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
enum EState {
|
||||||
|
kNotRunning,
|
||||||
|
kNotWorking,
|
||||||
|
kNotConnected,
|
||||||
|
kConnected,
|
||||||
|
kMaxState
|
||||||
|
};
|
||||||
|
|
||||||
|
CClientTaskBarReceiver();
|
||||||
|
virtual ~CClientTaskBarReceiver();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Set server
|
||||||
|
/*!
|
||||||
|
Sets the server. The receiver will query state from this server.
|
||||||
|
*/
|
||||||
|
void setClient(CClient*);
|
||||||
|
|
||||||
|
//! Set state
|
||||||
|
/*!
|
||||||
|
Sets the current server state.
|
||||||
|
*/
|
||||||
|
void setState(EState);
|
||||||
|
|
||||||
|
//! Set the quit job that causes the server to quit
|
||||||
|
/*!
|
||||||
|
Set the job that causes the server to quit.
|
||||||
|
*/
|
||||||
|
void setQuitJob(IJob* adopted);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get state
|
||||||
|
/*!
|
||||||
|
Returns the current server state. The receiver is not locked
|
||||||
|
by this call; the caller must do the locking.
|
||||||
|
*/
|
||||||
|
EState getState() const;
|
||||||
|
|
||||||
|
//! Get server
|
||||||
|
/*!
|
||||||
|
Returns the server set by \c setClient().
|
||||||
|
*/
|
||||||
|
CClient* getClient() const;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus() = 0;
|
||||||
|
virtual void runMenu(int x, int y) = 0;
|
||||||
|
virtual void primaryAction() = 0;
|
||||||
|
virtual void lock() const;
|
||||||
|
virtual void unlock() const;
|
||||||
|
virtual const Icon getIcon() const = 0;
|
||||||
|
virtual std::string getToolTip() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
//! Status change notification
|
||||||
|
/*!
|
||||||
|
Called when status changes. The default implementation does
|
||||||
|
nothing.
|
||||||
|
*/
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void statusChanged(void*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMutex m_mutex;
|
||||||
|
IJob* m_quit;
|
||||||
|
EState m_state;
|
||||||
|
CClient* m_client;
|
||||||
|
IJob* m_job;
|
||||||
|
CString m_errorMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,280 @@
|
||||||
|
/*
|
||||||
|
* 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 "CMSWindowsClientTaskBarReceiver.h"
|
||||||
|
#include "CClient.h"
|
||||||
|
#include "BasicTypes.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CArchTaskBarWindows.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
static const UINT g_stateToIconID[CMSWindowsClientTaskBarReceiver::kMaxState] =
|
||||||
|
{
|
||||||
|
IDI_TASKBAR_NOT_RUNNING,
|
||||||
|
IDI_TASKBAR_NOT_WORKING,
|
||||||
|
IDI_TASKBAR_NOT_CONNECTED,
|
||||||
|
IDI_TASKBAR_CONNECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMSWindowsClientTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CMSWindowsClientTaskBarReceiver::CMSWindowsClientTaskBarReceiver(
|
||||||
|
HINSTANCE appInstance) :
|
||||||
|
CClientTaskBarReceiver(),
|
||||||
|
m_appInstance(appInstance),
|
||||||
|
m_window(NULL)
|
||||||
|
{
|
||||||
|
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||||
|
m_icon[i] = loadIcon(g_stateToIconID[i]);
|
||||||
|
}
|
||||||
|
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
|
||||||
|
|
||||||
|
// don't create the window yet. we'll create it on demand. this
|
||||||
|
// has the side benefit of being created in the thread used for
|
||||||
|
// the task bar. that's good because it means the existence of
|
||||||
|
// the window won't prevent changing the main thread's desktop.
|
||||||
|
|
||||||
|
// add ourself to the task bar
|
||||||
|
ARCH->addReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSWindowsClientTaskBarReceiver::~CMSWindowsClientTaskBarReceiver()
|
||||||
|
{
|
||||||
|
ARCH->removeReceiver(this);
|
||||||
|
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||||
|
deleteIcon(m_icon[i]);
|
||||||
|
}
|
||||||
|
DestroyMenu(m_menu);
|
||||||
|
destroyWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::showStatus()
|
||||||
|
{
|
||||||
|
// create the window
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
// lock self while getting status
|
||||||
|
lock();
|
||||||
|
|
||||||
|
// get the current status
|
||||||
|
std::string status = getToolTip();
|
||||||
|
|
||||||
|
// done getting status
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
// update dialog
|
||||||
|
HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
|
||||||
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
|
||||||
|
|
||||||
|
if (!IsWindowVisible(m_window)) {
|
||||||
|
// position it by the mouse
|
||||||
|
POINT cursorPos;
|
||||||
|
GetCursorPos(&cursorPos);
|
||||||
|
RECT windowRect;
|
||||||
|
GetWindowRect(m_window, &windowRect);
|
||||||
|
int x = cursorPos.x;
|
||||||
|
int y = cursorPos.y;
|
||||||
|
int fw = GetSystemMetrics(SM_CXDLGFRAME);
|
||||||
|
int fh = GetSystemMetrics(SM_CYDLGFRAME);
|
||||||
|
int ww = windowRect.right - windowRect.left;
|
||||||
|
int wh = windowRect.bottom - windowRect.top;
|
||||||
|
int sw = GetSystemMetrics(SM_CXFULLSCREEN);
|
||||||
|
int sh = GetSystemMetrics(SM_CYFULLSCREEN);
|
||||||
|
if (fw < 1) {
|
||||||
|
fw = 1;
|
||||||
|
}
|
||||||
|
if (fh < 1) {
|
||||||
|
fh = 1;
|
||||||
|
}
|
||||||
|
if (x + ww - fw > sw) {
|
||||||
|
x -= ww - fw;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x -= fw;
|
||||||
|
}
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y + wh - fh > sh) {
|
||||||
|
y -= wh - fh;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y -= fh;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
|
||||||
|
SWP_SHOWWINDOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::runMenu(int x, int y)
|
||||||
|
{
|
||||||
|
// do popup menu. we need a window to pass to TrackPopupMenu().
|
||||||
|
// the SetForegroundWindow() and SendMessage() calls around
|
||||||
|
// TrackPopupMenu() are to get the menu to be dismissed when
|
||||||
|
// another window gets activated and are just one of those
|
||||||
|
// win32 weirdnesses.
|
||||||
|
createWindow();
|
||||||
|
SetForegroundWindow(m_window);
|
||||||
|
HMENU menu = GetSubMenu(m_menu, 0);
|
||||||
|
SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
|
||||||
|
int n = TrackPopupMenu(menu,
|
||||||
|
TPM_NONOTIFY |
|
||||||
|
TPM_RETURNCMD |
|
||||||
|
TPM_LEFTBUTTON |
|
||||||
|
TPM_RIGHTBUTTON,
|
||||||
|
x, y, 0, m_window, NULL);
|
||||||
|
SendMessage(m_window, WM_NULL, 0, 0);
|
||||||
|
|
||||||
|
// perform the requested operation
|
||||||
|
switch (n) {
|
||||||
|
case IDC_TASKBAR_STATUS:
|
||||||
|
showStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDC_TASKBAR_QUIT:
|
||||||
|
quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::primaryAction()
|
||||||
|
{
|
||||||
|
showStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
const IArchTaskBarReceiver::Icon
|
||||||
|
CMSWindowsClientTaskBarReceiver::getIcon() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Icon>(m_icon[getState()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
if (IsWindowVisible(m_window)) {
|
||||||
|
showStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HICON
|
||||||
|
CMSWindowsClientTaskBarReceiver::loadIcon(UINT id)
|
||||||
|
{
|
||||||
|
HANDLE icon = LoadImage(m_appInstance,
|
||||||
|
MAKEINTRESOURCE(id),
|
||||||
|
IMAGE_ICON,
|
||||||
|
0, 0,
|
||||||
|
LR_DEFAULTCOLOR);
|
||||||
|
return reinterpret_cast<HICON>(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::deleteIcon(HICON icon)
|
||||||
|
{
|
||||||
|
if (icon != NULL) {
|
||||||
|
DestroyIcon(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::createWindow()
|
||||||
|
{
|
||||||
|
// ignore if already created
|
||||||
|
if (m_window != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the status dialog
|
||||||
|
m_window = CreateDialogParam(m_appInstance,
|
||||||
|
MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
|
||||||
|
NULL,
|
||||||
|
&CMSWindowsClientTaskBarReceiver::staticDlgProc,
|
||||||
|
reinterpret_cast<LPARAM>(
|
||||||
|
reinterpret_cast<void*>(this)));
|
||||||
|
|
||||||
|
// window should appear on top of everything, including (especially)
|
||||||
|
// the task bar.
|
||||||
|
DWORD style = GetWindowLong(m_window, GWL_EXSTYLE);
|
||||||
|
style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
|
||||||
|
SetWindowLong(m_window, GWL_EXSTYLE, style);
|
||||||
|
|
||||||
|
// tell the task bar about this dialog
|
||||||
|
CArchTaskBarWindows::addDialog(m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsClientTaskBarReceiver::destroyWindow()
|
||||||
|
{
|
||||||
|
if (m_window != NULL) {
|
||||||
|
CArchTaskBarWindows::removeDialog(m_window);
|
||||||
|
DestroyWindow(m_window);
|
||||||
|
m_window = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CMSWindowsClientTaskBarReceiver::dlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM)
|
||||||
|
{
|
||||||
|
switch (msg) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
// use default focus
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case WM_ACTIVATE:
|
||||||
|
// hide when another window is activated
|
||||||
|
if (LOWORD(wParam) == WA_INACTIVE) {
|
||||||
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK
|
||||||
|
CMSWindowsClientTaskBarReceiver::staticDlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
// if msg is WM_INITDIALOG, extract the CMSWindowsClientTaskBarReceiver*
|
||||||
|
// and put it in the extra window data then forward the call.
|
||||||
|
CMSWindowsClientTaskBarReceiver* self = NULL;
|
||||||
|
if (msg == WM_INITDIALOG) {
|
||||||
|
self = reinterpret_cast<CMSWindowsClientTaskBarReceiver*>(
|
||||||
|
reinterpret_cast<void*>(lParam));
|
||||||
|
SetWindowLong(hwnd, GWL_USERDATA, lParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// get the extra window data and forward the call
|
||||||
|
LONG data = GetWindowLong(hwnd, GWL_USERDATA);
|
||||||
|
if (data != 0) {
|
||||||
|
self = reinterpret_cast<CMSWindowsClientTaskBarReceiver*>(
|
||||||
|
reinterpret_cast<void*>(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// forward the message
|
||||||
|
if (self != NULL) {
|
||||||
|
return self->dlgProc(hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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 CMSWINDOWSCLIENTTASKBARRECEIVER_H
|
||||||
|
#define CMSWINDOWSCLIENTTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "CClientTaskBarReceiver.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
//! Implementation of CClientTaskBarReceiver for Microsoft Windows
|
||||||
|
class CMSWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
CMSWindowsClientTaskBarReceiver(HINSTANCE);
|
||||||
|
virtual ~CMSWindowsClientTaskBarReceiver();
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus();
|
||||||
|
virtual void runMenu(int x, int y);
|
||||||
|
virtual void primaryAction();
|
||||||
|
virtual const Icon getIcon() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CClientTaskBarReceiver overrides
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HICON loadIcon(UINT);
|
||||||
|
void deleteIcon(HICON);
|
||||||
|
void createWindow();
|
||||||
|
void destroyWindow();
|
||||||
|
|
||||||
|
BOOL dlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
static BOOL CALLBACK
|
||||||
|
staticDlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HINSTANCE m_appInstance;
|
||||||
|
HWND m_window;
|
||||||
|
HMENU m_menu;
|
||||||
|
HICON m_icon[kMaxState];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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 "CXWindowsClientTaskBarReceiver.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsClientTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsClientTaskBarReceiver::CXWindowsClientTaskBarReceiver()
|
||||||
|
{
|
||||||
|
// add ourself to the task bar
|
||||||
|
ARCH->addReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsClientTaskBarReceiver::~CXWindowsClientTaskBarReceiver()
|
||||||
|
{
|
||||||
|
ARCH->removeReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsClientTaskBarReceiver::showStatus()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsClientTaskBarReceiver::runMenu(int, int)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsClientTaskBarReceiver::primaryAction()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const IArchTaskBarReceiver::Icon
|
||||||
|
CXWindowsClientTaskBarReceiver::getIcon() const
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsClientTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 CXWINDOWSCLIENTTASKBARRECEIVER_H
|
||||||
|
#define CXWINDOWSCLIENTTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#include "CClientTaskBarReceiver.h"
|
||||||
|
|
||||||
|
//! Implementation of CClientTaskBarReceiver for X Windows
|
||||||
|
class CXWindowsClientTaskBarReceiver : public CClientTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
CXWindowsClientTaskBarReceiver();
|
||||||
|
virtual ~CXWindowsClientTaskBarReceiver();
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus();
|
||||||
|
virtual void runMenu(int x, int y);
|
||||||
|
virtual void primaryAction();
|
||||||
|
virtual const Icon getIcon() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CClientTaskBarReceiver overrides
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,10 +16,16 @@ DEPTH = ../..
|
||||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
CMSWindowsClientTaskBarReceiver.cpp \
|
||||||
|
CMSWindowsClientTaskBarReceiver.h \
|
||||||
resource.h \
|
resource.h \
|
||||||
synergyc.dsp \
|
synergyc.dsp \
|
||||||
synergyc.ico \
|
synergyc.ico \
|
||||||
synergyc.rc \
|
synergyc.rc \
|
||||||
|
tb_error.ico \
|
||||||
|
tb_idle.ico \
|
||||||
|
tb_run.ico \
|
||||||
|
tb_wait.ico \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = \
|
MAINTAINERCLEANFILES = \
|
||||||
|
@ -28,6 +34,10 @@ MAINTAINERCLEANFILES = \
|
||||||
|
|
||||||
bin_PROGRAMS = synergyc
|
bin_PROGRAMS = synergyc
|
||||||
synergyc_SOURCES = \
|
synergyc_SOURCES = \
|
||||||
|
CClientTaskBarReceiver.cpp \
|
||||||
|
CClientTaskBarReceiver.h \
|
||||||
|
CXWindowsClientTaskBarReceiver.cpp \
|
||||||
|
CXWindowsClientTaskBarReceiver.h \
|
||||||
synergyc.cpp \
|
synergyc.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
synergyc_LDADD = \
|
synergyc_LDADD = \
|
||||||
|
|
|
@ -4,6 +4,15 @@
|
||||||
//
|
//
|
||||||
#define IDS_FAILED 1
|
#define IDS_FAILED 1
|
||||||
#define IDI_SYNERGY 101
|
#define IDI_SYNERGY 101
|
||||||
|
#define IDI_TASKBAR_NOT_RUNNING 102
|
||||||
|
#define IDI_TASKBAR_NOT_WORKING 103
|
||||||
|
#define IDI_TASKBAR_NOT_CONNECTED 104
|
||||||
|
#define IDI_TASKBAR_CONNECTED 105
|
||||||
|
#define IDR_TASKBAR 107
|
||||||
|
#define IDD_TASKBAR_STATUS 108
|
||||||
|
#define IDC_TASKBAR_STATUS_STATUS 1000
|
||||||
|
#define IDC_TASKBAR_QUIT 40003
|
||||||
|
#define IDC_TASKBAR_STATUS 40004
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "XThread.h"
|
||||||
|
#include "CFunctionJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CString.h"
|
#include "CString.h"
|
||||||
|
@ -34,12 +35,15 @@
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
#include "CMSWindowsSecondaryScreen.h"
|
#include "CMSWindowsSecondaryScreen.h"
|
||||||
|
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#undef DAEMON_RUNNING
|
#undef DAEMON_RUNNING
|
||||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
#include "CXWindowsSecondaryScreen.h"
|
#include "CXWindowsSecondaryScreen.h"
|
||||||
|
#include "CXWindowsClientTaskBarReceiver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// platform dependent name of a daemon
|
// platform dependent name of a daemon
|
||||||
|
@ -112,11 +116,46 @@ CSecondaryScreenFactory::create(IScreenReceiver* receiver)
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! CQuitJob
|
||||||
|
/*!
|
||||||
|
A job that cancels a given thread.
|
||||||
|
*/
|
||||||
|
class CQuitJob : public IJob {
|
||||||
|
public:
|
||||||
|
CQuitJob(const CThread& thread);
|
||||||
|
~CQuitJob();
|
||||||
|
|
||||||
|
// IJob overrides
|
||||||
|
virtual void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CThread m_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
CQuitJob::CQuitJob(const CThread& thread) :
|
||||||
|
m_thread(thread)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CQuitJob::~CQuitJob()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CQuitJob::run()
|
||||||
|
{
|
||||||
|
m_thread.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform independent main
|
// platform independent main
|
||||||
//
|
//
|
||||||
|
|
||||||
static CClient* s_client = NULL;
|
static CClient* s_client = NULL;
|
||||||
|
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
|
@ -137,6 +176,7 @@ realMain(void)
|
||||||
|
|
||||||
// open client
|
// open client
|
||||||
try {
|
try {
|
||||||
|
s_taskBarReceiver->setClient(s_client);
|
||||||
s_client->open();
|
s_client->open();
|
||||||
opened = true;
|
opened = true;
|
||||||
|
|
||||||
|
@ -160,11 +200,10 @@ realMain(void)
|
||||||
DAEMON_RUNNING(false); \
|
DAEMON_RUNNING(false); \
|
||||||
locked = true; \
|
locked = true; \
|
||||||
} \
|
} \
|
||||||
if (s_client != NULL) { \
|
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
s_client->close(); \
|
s_client->close(); \
|
||||||
} \
|
} \
|
||||||
} \
|
s_taskBarReceiver->setClient(NULL); \
|
||||||
delete s_client; \
|
delete s_client; \
|
||||||
s_client = NULL; \
|
s_client = NULL; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
@ -205,6 +244,43 @@ realMain(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
realMainEntry(void*)
|
||||||
|
{
|
||||||
|
CThread::exit(reinterpret_cast<void*>(realMain()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
runMainInThread(void)
|
||||||
|
{
|
||||||
|
CThread appThread(new CFunctionJob(&realMainEntry));
|
||||||
|
try {
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
MSG msg;
|
||||||
|
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
|
||||||
|
// check for a quit event
|
||||||
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
if (msg.message == WM_QUIT) {
|
||||||
|
CThread::getCurrentThread().cancel();
|
||||||
|
}
|
||||||
|
TranslateMessage(&msg);
|
||||||
|
DispatchMessage(&msg);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
appThread.wait(-1.0);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<int>(appThread.getResult());
|
||||||
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
appThread.cancel();
|
||||||
|
appThread.wait(-1.0);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// command line parsing
|
// command line parsing
|
||||||
|
@ -273,7 +349,7 @@ help()
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
isArg(int argi, int argc, const char** argv,
|
isArg(int argi, int argc, const char* const* argv,
|
||||||
const char* name1, const char* name2,
|
const char* name1, const char* name2,
|
||||||
int minRequiredParameters = 0)
|
int minRequiredParameters = 0)
|
||||||
{
|
{
|
||||||
|
@ -294,7 +370,7 @@ isArg(int argi, int argc, const char** argv,
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
parse(int argc, const char** argv)
|
parse(int argc, const char* const* argv)
|
||||||
{
|
{
|
||||||
assert(ARG->m_pname != NULL);
|
assert(ARG->m_pname != NULL);
|
||||||
assert(argv != NULL);
|
assert(argv != NULL);
|
||||||
|
@ -424,16 +500,6 @@ parse(int argc, const char** argv)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
useSystemLog()
|
|
||||||
{
|
|
||||||
// redirect log messages
|
|
||||||
ILogOutputter* logger = new CSystemLogOutputter;
|
|
||||||
logger->open(DAEMON_NAME);
|
|
||||||
CLOG->insert(new CStopLogOutputter);
|
|
||||||
CLOG->insert(logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform dependent entry points
|
// platform dependent entry points
|
||||||
|
@ -441,8 +507,6 @@ useSystemLog()
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
|
||||||
#include "CMSWindowsScreen.h"
|
|
||||||
|
|
||||||
static bool s_hasImportantLogMessages = false;
|
static bool s_hasImportantLogMessages = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -494,7 +558,10 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup(int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
|
||||||
|
// have to cancel this thread to quit
|
||||||
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
|
|
||||||
// catch errors that would normally exit
|
// catch errors that would normally exit
|
||||||
bye = &byeThrow;
|
bye = &byeThrow;
|
||||||
|
@ -513,14 +580,62 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup95(int, const char**)
|
daemonStartup95(int, const char**)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return realMain();
|
return runMainInThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
run(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// windows NT family starts services using no command line options.
|
||||||
|
// since i'm not sure how to tell the difference between that and
|
||||||
|
// a user providing no options we'll assume that if there are no
|
||||||
|
// arguments and we're on NT then we're being invoked as a service.
|
||||||
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
|
// of the service code path.
|
||||||
|
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
|
try {
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
|
}
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse command line
|
||||||
|
parse(argc, argv);
|
||||||
|
|
||||||
|
// daemonize if requested
|
||||||
|
if (ARG->m_daemon) {
|
||||||
|
// start as a daemon
|
||||||
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
|
try {
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
|
}
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// cannot start a service from the command line so just
|
||||||
|
// run normally (except with log messages redirected).
|
||||||
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
return runMainInThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// run
|
||||||
|
return runMainInThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
{
|
{
|
||||||
CArch arch;
|
CArch arch(instance);
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
CArgs args;
|
||||||
|
|
||||||
|
@ -533,51 +648,26 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLOG->insert(new CMessageBoxOutputter);
|
CLOG->insert(new CMessageBoxOutputter);
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// make the task bar receiver. the user can control this app
|
||||||
// since i'm not sure how to tell the difference between that and
|
// through the task bar.
|
||||||
// a user providing no options we'll assume that if there are no
|
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance);
|
||||||
// arguments and we're on NT then we're being invoked as a service.
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
|
||||||
// of the service code path.
|
|
||||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
|
||||||
int result = kExitFailed;
|
|
||||||
try {
|
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
delete CLOG;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(__argc, const_cast<const char**>(__argv));
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
int result;
|
int result;
|
||||||
if (ARG->m_daemon) {
|
|
||||||
// start as a daemon
|
|
||||||
if (CArchMiscWindows::isWindows95Family()) {
|
|
||||||
try {
|
try {
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
// run in foreground or as a daemon
|
||||||
|
result = run(__argc, __argv);
|
||||||
}
|
}
|
||||||
catch (XArchDaemon& e) {
|
catch (...) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
// note that we don't rethrow thread cancellation. we'll
|
||||||
|
// be exiting soon so it doesn't matter. what we'd like
|
||||||
|
// is for everything after this try/catch to be in a
|
||||||
|
// finally block.
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
// done with task bar receiver
|
||||||
// cannot start a service from the command line so just
|
delete s_taskBarReceiver;
|
||||||
// run normally (except with log messages redirected).
|
|
||||||
useSystemLog();
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// run
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
|
@ -598,7 +688,7 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup(int, const char**)
|
daemonStartup(int, const char**)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return realMain();
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -612,8 +702,13 @@ main(int argc, char** argv)
|
||||||
// get program name
|
// get program name
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
// make the task bar receiver. the user can control this app
|
||||||
|
// through the task bar.
|
||||||
|
s_taskBarReceiver = new CXWindowsClientTaskBarReceiver;
|
||||||
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, const_cast<const char**>(argv));
|
parse(argc, argv);
|
||||||
|
|
||||||
// daemonize if requested
|
// daemonize if requested
|
||||||
int result;
|
int result;
|
||||||
|
@ -630,6 +725,9 @@ main(int argc, char** argv)
|
||||||
result = realMain();
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// done with task bar receiver
|
||||||
|
delete s_taskBarReceiver;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,14 @@ LINK32=link.exe
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CClientTaskBarReceiver.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClientTaskBarReceiver.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\synergyc.cpp
|
SOURCE=.\synergyc.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -106,6 +114,14 @@ SOURCE=.\synergyc.rc
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CClientTaskBarReceiver.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsClientTaskBarReceiver.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\resource.h
|
SOURCE=.\resource.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
|
@ -116,6 +132,22 @@ SOURCE=.\resource.h
|
||||||
|
|
||||||
SOURCE=.\synergyc.ico
|
SOURCE=.\synergyc.ico
|
||||||
# End Source File
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_error.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_idle.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_run.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_wait.ico
|
||||||
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
# End Target
|
# End Target
|
||||||
# End Project
|
# End Project
|
||||||
|
|
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
|
@ -0,0 +1,300 @@
|
||||||
|
/*
|
||||||
|
* 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 "CMSWindowsServerTaskBarReceiver.h"
|
||||||
|
#include "CServer.h"
|
||||||
|
#include "BasicTypes.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
#include "CArchTaskBarWindows.h"
|
||||||
|
#include "resource.h"
|
||||||
|
|
||||||
|
static const UINT g_stateToIconID[CMSWindowsServerTaskBarReceiver::kMaxState] =
|
||||||
|
{
|
||||||
|
IDI_TASKBAR_NOT_RUNNING,
|
||||||
|
IDI_TASKBAR_NOT_WORKING,
|
||||||
|
IDI_TASKBAR_NOT_CONNECTED,
|
||||||
|
IDI_TASKBAR_CONNECTED
|
||||||
|
};
|
||||||
|
|
||||||
|
//
|
||||||
|
// CMSWindowsServerTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CMSWindowsServerTaskBarReceiver::CMSWindowsServerTaskBarReceiver(
|
||||||
|
HINSTANCE appInstance) :
|
||||||
|
CServerTaskBarReceiver(),
|
||||||
|
m_appInstance(appInstance),
|
||||||
|
m_window(NULL)
|
||||||
|
{
|
||||||
|
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||||
|
m_icon[i] = loadIcon(g_stateToIconID[i]);
|
||||||
|
}
|
||||||
|
m_menu = LoadMenu(m_appInstance, MAKEINTRESOURCE(IDR_TASKBAR));
|
||||||
|
|
||||||
|
// don't create the window yet. we'll create it on demand. this
|
||||||
|
// has the side benefit of being created in the thread used for
|
||||||
|
// the task bar. that's good because it means the existence of
|
||||||
|
// the window won't prevent changing the main thread's desktop.
|
||||||
|
|
||||||
|
// add ourself to the task bar
|
||||||
|
ARCH->addReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CMSWindowsServerTaskBarReceiver::~CMSWindowsServerTaskBarReceiver()
|
||||||
|
{
|
||||||
|
ARCH->removeReceiver(this);
|
||||||
|
for (UInt32 i = 0; i < kMaxState; ++i) {
|
||||||
|
deleteIcon(m_icon[i]);
|
||||||
|
}
|
||||||
|
DestroyMenu(m_menu);
|
||||||
|
destroyWindow();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::showStatus()
|
||||||
|
{
|
||||||
|
// create the window
|
||||||
|
createWindow();
|
||||||
|
|
||||||
|
// lock self while getting status
|
||||||
|
lock();
|
||||||
|
|
||||||
|
// get the current status
|
||||||
|
std::string status = getToolTip();
|
||||||
|
|
||||||
|
// get the connect clients, if any
|
||||||
|
typedef std::vector<CString> CClientList;
|
||||||
|
CClientList clients;
|
||||||
|
CServer* server = getServer();
|
||||||
|
if (server != NULL) {
|
||||||
|
server->getClients(clients);
|
||||||
|
}
|
||||||
|
|
||||||
|
// done getting status
|
||||||
|
unlock();
|
||||||
|
|
||||||
|
// update dialog
|
||||||
|
HWND child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_STATUS);
|
||||||
|
SendMessage(child, WM_SETTEXT, 0, (LPARAM)status.c_str());
|
||||||
|
child = GetDlgItem(m_window, IDC_TASKBAR_STATUS_CLIENTS);
|
||||||
|
SendMessage(child, LB_RESETCONTENT, 0, 0);
|
||||||
|
for (CClientList::const_iterator index = clients.begin();
|
||||||
|
index != clients.end(); ) {
|
||||||
|
const char* client = index->c_str();
|
||||||
|
if (++index == clients.end()) {
|
||||||
|
SendMessage(child, LB_ADDSTRING, 0, (LPARAM)client);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
SendMessage(child, LB_INSERTSTRING, (WPARAM)-1, (LPARAM)client);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!IsWindowVisible(m_window)) {
|
||||||
|
// position it by the mouse
|
||||||
|
POINT cursorPos;
|
||||||
|
GetCursorPos(&cursorPos);
|
||||||
|
RECT windowRect;
|
||||||
|
GetWindowRect(m_window, &windowRect);
|
||||||
|
int x = cursorPos.x;
|
||||||
|
int y = cursorPos.y;
|
||||||
|
int fw = GetSystemMetrics(SM_CXDLGFRAME);
|
||||||
|
int fh = GetSystemMetrics(SM_CYDLGFRAME);
|
||||||
|
int ww = windowRect.right - windowRect.left;
|
||||||
|
int wh = windowRect.bottom - windowRect.top;
|
||||||
|
int sw = GetSystemMetrics(SM_CXFULLSCREEN);
|
||||||
|
int sh = GetSystemMetrics(SM_CYFULLSCREEN);
|
||||||
|
if (fw < 1) {
|
||||||
|
fw = 1;
|
||||||
|
}
|
||||||
|
if (fh < 1) {
|
||||||
|
fh = 1;
|
||||||
|
}
|
||||||
|
if (x + ww - fw > sw) {
|
||||||
|
x -= ww - fw;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
x -= fw;
|
||||||
|
}
|
||||||
|
if (x < 0) {
|
||||||
|
x = 0;
|
||||||
|
}
|
||||||
|
if (y + wh - fh > sh) {
|
||||||
|
y -= wh - fh;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
y -= fh;
|
||||||
|
}
|
||||||
|
if (y < 0) {
|
||||||
|
y = 0;
|
||||||
|
}
|
||||||
|
SetWindowPos(m_window, HWND_TOPMOST, x, y, ww, wh,
|
||||||
|
SWP_SHOWWINDOW);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::runMenu(int x, int y)
|
||||||
|
{
|
||||||
|
// do popup menu. we need a window to pass to TrackPopupMenu().
|
||||||
|
// the SetForegroundWindow() and SendMessage() calls around
|
||||||
|
// TrackPopupMenu() are to get the menu to be dismissed when
|
||||||
|
// another window gets activated and are just one of those
|
||||||
|
// win32 weirdnesses.
|
||||||
|
createWindow();
|
||||||
|
SetForegroundWindow(m_window);
|
||||||
|
HMENU menu = GetSubMenu(m_menu, 0);
|
||||||
|
SetMenuDefaultItem(menu, IDC_TASKBAR_STATUS, FALSE);
|
||||||
|
int n = TrackPopupMenu(menu,
|
||||||
|
TPM_NONOTIFY |
|
||||||
|
TPM_RETURNCMD |
|
||||||
|
TPM_LEFTBUTTON |
|
||||||
|
TPM_RIGHTBUTTON,
|
||||||
|
x, y, 0, m_window, NULL);
|
||||||
|
SendMessage(m_window, WM_NULL, 0, 0);
|
||||||
|
|
||||||
|
// perform the requested operation
|
||||||
|
switch (n) {
|
||||||
|
case IDC_TASKBAR_STATUS:
|
||||||
|
showStatus();
|
||||||
|
break;
|
||||||
|
|
||||||
|
case IDC_TASKBAR_QUIT:
|
||||||
|
quit();
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::primaryAction()
|
||||||
|
{
|
||||||
|
showStatus();
|
||||||
|
}
|
||||||
|
|
||||||
|
const IArchTaskBarReceiver::Icon
|
||||||
|
CMSWindowsServerTaskBarReceiver::getIcon() const
|
||||||
|
{
|
||||||
|
return reinterpret_cast<Icon>(m_icon[getState()]);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
if (IsWindowVisible(m_window)) {
|
||||||
|
showStatus();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
HICON
|
||||||
|
CMSWindowsServerTaskBarReceiver::loadIcon(UINT id)
|
||||||
|
{
|
||||||
|
HANDLE icon = LoadImage(m_appInstance,
|
||||||
|
MAKEINTRESOURCE(id),
|
||||||
|
IMAGE_ICON,
|
||||||
|
0, 0,
|
||||||
|
LR_DEFAULTCOLOR);
|
||||||
|
return reinterpret_cast<HICON>(icon);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::deleteIcon(HICON icon)
|
||||||
|
{
|
||||||
|
if (icon != NULL) {
|
||||||
|
DestroyIcon(icon);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::createWindow()
|
||||||
|
{
|
||||||
|
// ignore if already created
|
||||||
|
if (m_window != NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// get the status dialog
|
||||||
|
m_window = CreateDialogParam(m_appInstance,
|
||||||
|
MAKEINTRESOURCE(IDD_TASKBAR_STATUS),
|
||||||
|
NULL,
|
||||||
|
&CMSWindowsServerTaskBarReceiver::staticDlgProc,
|
||||||
|
reinterpret_cast<LPARAM>(
|
||||||
|
reinterpret_cast<void*>(this)));
|
||||||
|
|
||||||
|
// window should appear on top of everything, including (especially)
|
||||||
|
// the task bar.
|
||||||
|
DWORD style = GetWindowLong(m_window, GWL_EXSTYLE);
|
||||||
|
style |= WS_EX_TOOLWINDOW | WS_EX_TOPMOST;
|
||||||
|
SetWindowLong(m_window, GWL_EXSTYLE, style);
|
||||||
|
|
||||||
|
// tell the task bar about this dialog
|
||||||
|
CArchTaskBarWindows::addDialog(m_window);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsServerTaskBarReceiver::destroyWindow()
|
||||||
|
{
|
||||||
|
if (m_window != NULL) {
|
||||||
|
CArchTaskBarWindows::removeDialog(m_window);
|
||||||
|
DestroyWindow(m_window);
|
||||||
|
m_window = NULL;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL
|
||||||
|
CMSWindowsServerTaskBarReceiver::dlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM)
|
||||||
|
{
|
||||||
|
switch (msg) {
|
||||||
|
case WM_INITDIALOG:
|
||||||
|
// use default focus
|
||||||
|
return TRUE;
|
||||||
|
|
||||||
|
case WM_ACTIVATE:
|
||||||
|
// hide when another window is activated
|
||||||
|
if (LOWORD(wParam) == WA_INACTIVE) {
|
||||||
|
ShowWindow(hwnd, SW_HIDE);
|
||||||
|
}
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
return FALSE;
|
||||||
|
}
|
||||||
|
|
||||||
|
BOOL CALLBACK
|
||||||
|
CMSWindowsServerTaskBarReceiver::staticDlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam)
|
||||||
|
{
|
||||||
|
// if msg is WM_INITDIALOG, extract the CMSWindowsServerTaskBarReceiver*
|
||||||
|
// and put it in the extra window data then forward the call.
|
||||||
|
CMSWindowsServerTaskBarReceiver* self = NULL;
|
||||||
|
if (msg == WM_INITDIALOG) {
|
||||||
|
self = reinterpret_cast<CMSWindowsServerTaskBarReceiver*>(
|
||||||
|
reinterpret_cast<void*>(lParam));
|
||||||
|
SetWindowLong(hwnd, GWL_USERDATA, lParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// get the extra window data and forward the call
|
||||||
|
LONG data = GetWindowLong(hwnd, GWL_USERDATA);
|
||||||
|
if (data != 0) {
|
||||||
|
self = reinterpret_cast<CMSWindowsServerTaskBarReceiver*>(
|
||||||
|
reinterpret_cast<void*>(data));
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
// forward the message
|
||||||
|
if (self != NULL) {
|
||||||
|
return self->dlgProc(hwnd, msg, wParam, lParam);
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
return (msg == WM_INITDIALOG) ? TRUE : FALSE;
|
||||||
|
}
|
||||||
|
}
|
|
@ -0,0 +1,58 @@
|
||||||
|
/*
|
||||||
|
* 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 CMSWINDOWSSERVERTASKBARRECEIVER_H
|
||||||
|
#define CMSWINDOWSSERVERTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#define WIN32_LEAN_AND_MEAN
|
||||||
|
|
||||||
|
#include "CServerTaskBarReceiver.h"
|
||||||
|
#include <windows.h>
|
||||||
|
|
||||||
|
//! Implementation of CServerTaskBarReceiver for Microsoft Windows
|
||||||
|
class CMSWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
CMSWindowsServerTaskBarReceiver(HINSTANCE);
|
||||||
|
virtual ~CMSWindowsServerTaskBarReceiver();
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus();
|
||||||
|
virtual void runMenu(int x, int y);
|
||||||
|
virtual void primaryAction();
|
||||||
|
virtual const Icon getIcon() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CServerTaskBarReceiver overrides
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
HICON loadIcon(UINT);
|
||||||
|
void deleteIcon(HICON);
|
||||||
|
void createWindow();
|
||||||
|
void destroyWindow();
|
||||||
|
|
||||||
|
BOOL dlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
static BOOL CALLBACK
|
||||||
|
staticDlgProc(HWND hwnd,
|
||||||
|
UINT msg, WPARAM wParam, LPARAM lParam);
|
||||||
|
|
||||||
|
private:
|
||||||
|
HINSTANCE m_appInstance;
|
||||||
|
HWND m_window;
|
||||||
|
HMENU m_menu;
|
||||||
|
HICON m_icon[kMaxState];
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,171 @@
|
||||||
|
/*
|
||||||
|
* 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 "CServerTaskBarReceiver.h"
|
||||||
|
#include "CServer.h"
|
||||||
|
#include "CLock.h"
|
||||||
|
#include "TMethodJob.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CServerTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CServerTaskBarReceiver::CServerTaskBarReceiver() :
|
||||||
|
m_quit(NULL),
|
||||||
|
m_state(kNotRunning),
|
||||||
|
m_server(NULL)
|
||||||
|
{
|
||||||
|
// create a job for getting notification when the server's
|
||||||
|
// status changes.
|
||||||
|
m_job = new TMethodJob<CServerTaskBarReceiver>(this,
|
||||||
|
&CServerTaskBarReceiver::statusChanged, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerTaskBarReceiver::~CServerTaskBarReceiver()
|
||||||
|
{
|
||||||
|
if (m_server != NULL) {
|
||||||
|
m_server->removeStatusJob(m_job);
|
||||||
|
}
|
||||||
|
delete m_job;
|
||||||
|
delete m_quit;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::setServer(CServer* server)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
if (m_server != server) {
|
||||||
|
if (m_server != NULL) {
|
||||||
|
m_server->removeStatusJob(m_job);
|
||||||
|
}
|
||||||
|
m_server = server;
|
||||||
|
if (m_server != NULL) {
|
||||||
|
m_server->addStatusJob(m_job);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
ARCH->updateReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::setState(EState state)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
m_state = state;
|
||||||
|
}
|
||||||
|
ARCH->updateReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::setQuitJob(IJob* job)
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
delete m_quit;
|
||||||
|
m_quit = job;
|
||||||
|
}
|
||||||
|
|
||||||
|
CServerTaskBarReceiver::EState
|
||||||
|
CServerTaskBarReceiver::getState() const
|
||||||
|
{
|
||||||
|
return m_state;
|
||||||
|
}
|
||||||
|
|
||||||
|
CServer*
|
||||||
|
CServerTaskBarReceiver::getServer() const
|
||||||
|
{
|
||||||
|
return m_server;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::lock() const
|
||||||
|
{
|
||||||
|
m_mutex.lock();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::unlock() const
|
||||||
|
{
|
||||||
|
m_mutex.unlock();
|
||||||
|
}
|
||||||
|
|
||||||
|
std::string
|
||||||
|
CServerTaskBarReceiver::getToolTip() const
|
||||||
|
{
|
||||||
|
switch (m_state) {
|
||||||
|
case kNotRunning:
|
||||||
|
return "Synergy: Not running";
|
||||||
|
|
||||||
|
case kNotWorking:
|
||||||
|
return CString("Synergy: ") + m_errorMessage;
|
||||||
|
|
||||||
|
case kNotConnected:
|
||||||
|
return "Synergy: Waiting for clients";
|
||||||
|
|
||||||
|
case kConnected:
|
||||||
|
return "Synergy: Connected";
|
||||||
|
|
||||||
|
default:
|
||||||
|
return "";
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::quit()
|
||||||
|
{
|
||||||
|
if (m_quit != NULL) {
|
||||||
|
m_quit->run();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServerTaskBarReceiver::statusChanged(void*)
|
||||||
|
{
|
||||||
|
// update our status
|
||||||
|
switch (m_server->getStatus(&m_errorMessage)) {
|
||||||
|
case CServer::kNotRunning:
|
||||||
|
setState(kNotRunning);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CServer::kRunning:
|
||||||
|
if (m_server->getNumClients() > 1)
|
||||||
|
setState(kConnected);
|
||||||
|
else
|
||||||
|
setState(kNotConnected);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CServer::kServerNameUnknown:
|
||||||
|
m_errorMessage = "Server name is not in configuration";
|
||||||
|
setState(kNotWorking);
|
||||||
|
break;
|
||||||
|
|
||||||
|
case CServer::kError:
|
||||||
|
setState(kNotWorking);
|
||||||
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
// let subclasses have a go
|
||||||
|
onStatusChanged();
|
||||||
|
}
|
|
@ -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 CSERVERTASKBARRECEIVER_H
|
||||||
|
#define CSERVERTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#include "CMutex.h"
|
||||||
|
#include "CString.h"
|
||||||
|
#include "IArchTaskBarReceiver.h"
|
||||||
|
|
||||||
|
class CServer;
|
||||||
|
class IJob;
|
||||||
|
|
||||||
|
//! Implementation of IArchTaskBarReceiver for the synergy server
|
||||||
|
class CServerTaskBarReceiver : public IArchTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
enum EState {
|
||||||
|
kNotRunning,
|
||||||
|
kNotWorking,
|
||||||
|
kNotConnected,
|
||||||
|
kConnected,
|
||||||
|
kMaxState
|
||||||
|
};
|
||||||
|
|
||||||
|
CServerTaskBarReceiver();
|
||||||
|
virtual ~CServerTaskBarReceiver();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Set server
|
||||||
|
/*!
|
||||||
|
Sets the server. The receiver will query state from this server.
|
||||||
|
*/
|
||||||
|
void setServer(CServer*);
|
||||||
|
|
||||||
|
//! Set state
|
||||||
|
/*!
|
||||||
|
Sets the current server state.
|
||||||
|
*/
|
||||||
|
void setState(EState);
|
||||||
|
|
||||||
|
//! Set the quit job that causes the server to quit
|
||||||
|
/*!
|
||||||
|
Set the job that causes the server to quit.
|
||||||
|
*/
|
||||||
|
void setQuitJob(IJob* adopted);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Get state
|
||||||
|
/*!
|
||||||
|
Returns the current server state. The receiver is not locked
|
||||||
|
by this call; the caller must do the locking.
|
||||||
|
*/
|
||||||
|
EState getState() const;
|
||||||
|
|
||||||
|
//! Get server
|
||||||
|
/*!
|
||||||
|
Returns the server set by \c setServer().
|
||||||
|
*/
|
||||||
|
CServer* getServer() const;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus() = 0;
|
||||||
|
virtual void runMenu(int x, int y) = 0;
|
||||||
|
virtual void primaryAction() = 0;
|
||||||
|
virtual void lock() const;
|
||||||
|
virtual void unlock() const;
|
||||||
|
virtual const Icon getIcon() const = 0;
|
||||||
|
virtual std::string getToolTip() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
void quit();
|
||||||
|
|
||||||
|
//! Status change notification
|
||||||
|
/*!
|
||||||
|
Called when status changes. The default implementation does
|
||||||
|
nothing.
|
||||||
|
*/
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
|
||||||
|
private:
|
||||||
|
void statusChanged(void*);
|
||||||
|
|
||||||
|
private:
|
||||||
|
CMutex m_mutex;
|
||||||
|
IJob* m_quit;
|
||||||
|
EState m_state;
|
||||||
|
CServer* m_server;
|
||||||
|
IJob* m_job;
|
||||||
|
CString m_errorMessage;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -0,0 +1,61 @@
|
||||||
|
/*
|
||||||
|
* 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 "CXWindowsServerTaskBarReceiver.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CXWindowsServerTaskBarReceiver
|
||||||
|
//
|
||||||
|
|
||||||
|
CXWindowsServerTaskBarReceiver::CXWindowsServerTaskBarReceiver()
|
||||||
|
{
|
||||||
|
// add ourself to the task bar
|
||||||
|
ARCH->addReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
CXWindowsServerTaskBarReceiver::~CXWindowsServerTaskBarReceiver()
|
||||||
|
{
|
||||||
|
ARCH->removeReceiver(this);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsServerTaskBarReceiver::showStatus()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsServerTaskBarReceiver::runMenu(int, int)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsServerTaskBarReceiver::primaryAction()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
const IArchTaskBarReceiver::Icon
|
||||||
|
CXWindowsServerTaskBarReceiver::getIcon() const
|
||||||
|
{
|
||||||
|
return NULL;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsServerTaskBarReceiver::onStatusChanged()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
|
@ -0,0 +1,37 @@
|
||||||
|
/*
|
||||||
|
* 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 CXWINDOWSSERVERTASKBARRECEIVER_H
|
||||||
|
#define CXWINDOWSSERVERTASKBARRECEIVER_H
|
||||||
|
|
||||||
|
#include "CServerTaskBarReceiver.h"
|
||||||
|
|
||||||
|
//! Implementation of CServerTaskBarReceiver for X Windows
|
||||||
|
class CXWindowsServerTaskBarReceiver : public CServerTaskBarReceiver {
|
||||||
|
public:
|
||||||
|
CXWindowsServerTaskBarReceiver();
|
||||||
|
virtual ~CXWindowsServerTaskBarReceiver();
|
||||||
|
|
||||||
|
// IArchTaskBarReceiver overrides
|
||||||
|
virtual void showStatus();
|
||||||
|
virtual void runMenu(int x, int y);
|
||||||
|
virtual void primaryAction();
|
||||||
|
virtual const Icon getIcon() const;
|
||||||
|
|
||||||
|
protected:
|
||||||
|
// CServerTaskBarReceiver overrides
|
||||||
|
virtual void onStatusChanged();
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
|
@ -16,10 +16,16 @@ DEPTH = ../..
|
||||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||||
|
|
||||||
EXTRA_DIST = \
|
EXTRA_DIST = \
|
||||||
|
CMSWindowsServerTaskBarReceiver.cpp \
|
||||||
|
CMSWindowsServerTaskBarReceiver.h \
|
||||||
resource.h \
|
resource.h \
|
||||||
synergys.ico \
|
synergys.ico \
|
||||||
synergys.dsp \
|
synergys.dsp \
|
||||||
synergys.rc \
|
synergys.rc \
|
||||||
|
tb_error.ico \
|
||||||
|
tb_idle.ico \
|
||||||
|
tb_run.ico \
|
||||||
|
tb_wait.ico \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
||||||
MAINTAINERCLEANFILES = \
|
MAINTAINERCLEANFILES = \
|
||||||
|
@ -28,6 +34,10 @@ MAINTAINERCLEANFILES = \
|
||||||
|
|
||||||
bin_PROGRAMS = synergys
|
bin_PROGRAMS = synergys
|
||||||
synergys_SOURCES = \
|
synergys_SOURCES = \
|
||||||
|
CServerTaskBarReceiver.cpp \
|
||||||
|
CServerTaskBarReceiver.h \
|
||||||
|
CXWindowsServerTaskBarReceiver.cpp \
|
||||||
|
CXWindowsServerTaskBarReceiver.h \
|
||||||
synergys.cpp \
|
synergys.cpp \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
synergys_LDADD = \
|
synergys_LDADD = \
|
||||||
|
|
|
@ -4,14 +4,24 @@
|
||||||
//
|
//
|
||||||
#define IDS_FAILED 1
|
#define IDS_FAILED 1
|
||||||
#define IDI_SYNERGY 101
|
#define IDI_SYNERGY 101
|
||||||
|
#define IDI_TASKBAR_NOT_RUNNING 102
|
||||||
|
#define IDI_TASKBAR_NOT_WORKING 103
|
||||||
|
#define IDI_TASKBAR_NOT_CONNECTED 104
|
||||||
|
#define IDI_TASKBAR_CONNECTED 105
|
||||||
|
#define IDR_TASKBAR 107
|
||||||
|
#define IDD_TASKBAR_STATUS 108
|
||||||
|
#define IDC_TASKBAR_STATUS_STATUS 1000
|
||||||
|
#define IDC_TASKBAR_STATUS_CLIENTS 1001
|
||||||
|
#define IDC_TASKBAR_QUIT 40003
|
||||||
|
#define IDC_TASKBAR_STATUS 40004
|
||||||
|
|
||||||
// Next default values for new objects
|
// Next default values for new objects
|
||||||
//
|
//
|
||||||
#ifdef APSTUDIO_INVOKED
|
#ifdef APSTUDIO_INVOKED
|
||||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
#define _APS_NEXT_RESOURCE_VALUE 109
|
||||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
#define _APS_NEXT_COMMAND_VALUE 40005
|
||||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
#define _APS_NEXT_CONTROL_VALUE 1003
|
||||||
#define _APS_NEXT_SYMED_VALUE 101
|
#define _APS_NEXT_SYMED_VALUE 101
|
||||||
#endif
|
#endif
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -24,6 +24,7 @@
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
#include "XThread.h"
|
#include "XThread.h"
|
||||||
|
#include "CFunctionJob.h"
|
||||||
#include "CLog.h"
|
#include "CLog.h"
|
||||||
#include "LogOutputters.h"
|
#include "LogOutputters.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
|
@ -33,12 +34,15 @@
|
||||||
|
|
||||||
#define DAEMON_RUNNING(running_)
|
#define DAEMON_RUNNING(running_)
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
#include "CMSWindowsScreen.h"
|
||||||
#include "CMSWindowsPrimaryScreen.h"
|
#include "CMSWindowsPrimaryScreen.h"
|
||||||
|
#include "CMSWindowsServerTaskBarReceiver.h"
|
||||||
#include "resource.h"
|
#include "resource.h"
|
||||||
#undef DAEMON_RUNNING
|
#undef DAEMON_RUNNING
|
||||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
#include "CXWindowsPrimaryScreen.h"
|
#include "CXWindowsPrimaryScreen.h"
|
||||||
|
#include "CXWindowsServerTaskBarReceiver.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
// platform dependent name of a daemon
|
// platform dependent name of a daemon
|
||||||
|
@ -123,11 +127,46 @@ CPrimaryScreenFactory::create(IScreenReceiver* receiver,
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//! CQuitJob
|
||||||
|
/*!
|
||||||
|
A job that cancels a given thread.
|
||||||
|
*/
|
||||||
|
class CQuitJob : public IJob {
|
||||||
|
public:
|
||||||
|
CQuitJob(const CThread& thread);
|
||||||
|
~CQuitJob();
|
||||||
|
|
||||||
|
// IJob overrides
|
||||||
|
virtual void run();
|
||||||
|
|
||||||
|
private:
|
||||||
|
CThread m_thread;
|
||||||
|
};
|
||||||
|
|
||||||
|
CQuitJob::CQuitJob(const CThread& thread) :
|
||||||
|
m_thread(thread)
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
CQuitJob::~CQuitJob()
|
||||||
|
{
|
||||||
|
// do nothing
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CQuitJob::run()
|
||||||
|
{
|
||||||
|
m_thread.cancel();
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform independent main
|
// platform independent main
|
||||||
//
|
//
|
||||||
|
|
||||||
static CServer* s_server = NULL;
|
static CServer* s_server = NULL;
|
||||||
|
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||||
|
|
||||||
static
|
static
|
||||||
int
|
int
|
||||||
|
@ -168,6 +207,7 @@ realMain(void)
|
||||||
|
|
||||||
// open server
|
// open server
|
||||||
try {
|
try {
|
||||||
|
s_taskBarReceiver->setServer(s_server);
|
||||||
s_server->open();
|
s_server->open();
|
||||||
opened = true;
|
opened = true;
|
||||||
|
|
||||||
|
@ -182,11 +222,10 @@ realMain(void)
|
||||||
DAEMON_RUNNING(false); \
|
DAEMON_RUNNING(false); \
|
||||||
locked = true; \
|
locked = true; \
|
||||||
} \
|
} \
|
||||||
if (s_server != NULL) { \
|
|
||||||
if (opened) { \
|
if (opened) { \
|
||||||
s_server->close(); \
|
s_server->close(); \
|
||||||
} \
|
} \
|
||||||
} \
|
s_taskBarReceiver->setServer(NULL); \
|
||||||
delete s_server; \
|
delete s_server; \
|
||||||
s_server = NULL; \
|
s_server = NULL; \
|
||||||
} while (false)
|
} while (false)
|
||||||
|
@ -227,6 +266,41 @@ realMain(void)
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
void
|
||||||
|
realMainEntry(void*)
|
||||||
|
{
|
||||||
|
CThread::exit(reinterpret_cast<void*>(realMain()));
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
runMainInThread(void)
|
||||||
|
{
|
||||||
|
CThread appThread(new CFunctionJob(&realMainEntry));
|
||||||
|
try {
|
||||||
|
#if WINDOWS_LIKE
|
||||||
|
MSG msg;
|
||||||
|
while (appThread.waitForEvent(-1.0) == CThread::kEvent) {
|
||||||
|
// check for a quit event
|
||||||
|
if (PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
if (msg.message == WM_QUIT) {
|
||||||
|
CThread::getCurrentThread().cancel();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
#else
|
||||||
|
appThread.wait(-1.0);
|
||||||
|
#endif
|
||||||
|
return reinterpret_cast<int>(appThread.getResult());
|
||||||
|
}
|
||||||
|
catch (XThread&) {
|
||||||
|
appThread.cancel();
|
||||||
|
appThread.wait(-1.0);
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// command line parsing
|
// command line parsing
|
||||||
|
@ -329,7 +403,7 @@ PLATFORM_EXTRA
|
||||||
|
|
||||||
static
|
static
|
||||||
bool
|
bool
|
||||||
isArg(int argi, int argc, const char** argv,
|
isArg(int argi, int argc, const char* const* argv,
|
||||||
const char* name1, const char* name2,
|
const char* name1, const char* name2,
|
||||||
int minRequiredParameters = 0)
|
int minRequiredParameters = 0)
|
||||||
{
|
{
|
||||||
|
@ -350,7 +424,7 @@ isArg(int argi, int argc, const char** argv,
|
||||||
|
|
||||||
static
|
static
|
||||||
void
|
void
|
||||||
parse(int argc, const char** argv)
|
parse(int argc, const char* const* argv)
|
||||||
{
|
{
|
||||||
assert(ARG->m_pname != NULL);
|
assert(ARG->m_pname != NULL);
|
||||||
assert(argv != NULL);
|
assert(argv != NULL);
|
||||||
|
@ -553,16 +627,6 @@ loadConfig()
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
static
|
|
||||||
void
|
|
||||||
useSystemLog()
|
|
||||||
{
|
|
||||||
// redirect log messages
|
|
||||||
ILogOutputter* logger = new CSystemLogOutputter;
|
|
||||||
logger->open(DAEMON_NAME);
|
|
||||||
CLOG->insert(new CStopLogOutputter);
|
|
||||||
CLOG->insert(logger);
|
|
||||||
}
|
|
||||||
|
|
||||||
//
|
//
|
||||||
// platform dependent entry points
|
// platform dependent entry points
|
||||||
|
@ -570,8 +634,6 @@ useSystemLog()
|
||||||
|
|
||||||
#if WINDOWS_LIKE
|
#if WINDOWS_LIKE
|
||||||
|
|
||||||
#include "CMSWindowsScreen.h"
|
|
||||||
|
|
||||||
static bool s_hasImportantLogMessages = false;
|
static bool s_hasImportantLogMessages = false;
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -623,7 +685,10 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup(int argc, const char** argv)
|
daemonStartup(int argc, const char** argv)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
|
||||||
|
// have to cancel this thread to quit
|
||||||
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
|
|
||||||
// catch errors that would normally exit
|
// catch errors that would normally exit
|
||||||
bye = &byeThrow;
|
bye = &byeThrow;
|
||||||
|
@ -645,14 +710,65 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup95(int, const char**)
|
daemonStartup95(int, const char**)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return realMain();
|
return runMainInThread();
|
||||||
|
}
|
||||||
|
|
||||||
|
static
|
||||||
|
int
|
||||||
|
run(int argc, char** argv)
|
||||||
|
{
|
||||||
|
// windows NT family starts services using no command line options.
|
||||||
|
// since i'm not sure how to tell the difference between that and
|
||||||
|
// a user providing no options we'll assume that if there are no
|
||||||
|
// arguments and we're on NT then we're being invoked as a service.
|
||||||
|
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
||||||
|
// of the service code path.
|
||||||
|
if (argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
||||||
|
try {
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
|
}
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
|
||||||
|
// parse command line
|
||||||
|
parse(argc, argv);
|
||||||
|
|
||||||
|
// load configuration
|
||||||
|
loadConfig();
|
||||||
|
|
||||||
|
// daemonize if requested
|
||||||
|
if (ARG->m_daemon) {
|
||||||
|
// start as a daemon
|
||||||
|
if (CArchMiscWindows::isWindows95Family()) {
|
||||||
|
try {
|
||||||
|
return ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
||||||
|
}
|
||||||
|
catch (XArchDaemon& e) {
|
||||||
|
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
||||||
|
}
|
||||||
|
return kExitFailed;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// cannot start a service from the command line so just
|
||||||
|
// run normally (except with log messages redirected).
|
||||||
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
|
return runMainInThread();
|
||||||
|
}
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// run
|
||||||
|
return runMainInThread();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
int WINAPI
|
int WINAPI
|
||||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
{
|
{
|
||||||
CArch arch;
|
CArch arch(instance);
|
||||||
CLOG;
|
CLOG;
|
||||||
CArgs args;
|
CArgs args;
|
||||||
|
|
||||||
|
@ -665,54 +781,26 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||||
// send PRINT and FATAL output to a message box
|
// send PRINT and FATAL output to a message box
|
||||||
CLOG->insert(new CMessageBoxOutputter);
|
CLOG->insert(new CMessageBoxOutputter);
|
||||||
|
|
||||||
// windows NT family starts services using no command line options.
|
// make the task bar receiver. the user can control this app
|
||||||
// since i'm not sure how to tell the difference between that and
|
// through the task bar.
|
||||||
// a user providing no options we'll assume that if there are no
|
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance);
|
||||||
// arguments and we're on NT then we're being invoked as a service.
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
// users on NT can use `--daemon' or `--no-daemon' to force us out
|
|
||||||
// of the service code path.
|
|
||||||
if (__argc <= 1 && !CArchMiscWindows::isWindows95Family()) {
|
|
||||||
int result = kExitFailed;
|
|
||||||
try {
|
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup);
|
|
||||||
}
|
|
||||||
catch (XArchDaemon& e) {
|
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
|
||||||
}
|
|
||||||
delete CLOG;
|
|
||||||
return result;
|
|
||||||
}
|
|
||||||
|
|
||||||
// parse command line
|
|
||||||
parse(__argc, const_cast<const char**>(__argv));
|
|
||||||
|
|
||||||
// load configuration
|
|
||||||
loadConfig();
|
|
||||||
|
|
||||||
// daemonize if requested
|
|
||||||
int result;
|
int result;
|
||||||
if (ARG->m_daemon) {
|
|
||||||
// start as a daemon
|
|
||||||
if (CArchMiscWindows::isWindows95Family()) {
|
|
||||||
try {
|
try {
|
||||||
result = ARCH->daemonize(DAEMON_NAME, &daemonStartup95);
|
// run in foreground or as a daemon
|
||||||
|
result = run(__argc, __argv);
|
||||||
}
|
}
|
||||||
catch (XArchDaemon& e) {
|
catch (...) {
|
||||||
LOG((CLOG_CRIT "failed to start as a service: %s" BYE, e.what().c_str(), ARG->m_pname));
|
// note that we don't rethrow thread cancellation. we'll
|
||||||
|
// be exiting soon so it doesn't matter. what we'd like
|
||||||
|
// is for everything after this try/catch to be in a
|
||||||
|
// finally block.
|
||||||
result = kExitFailed;
|
result = kExitFailed;
|
||||||
}
|
}
|
||||||
}
|
|
||||||
else {
|
// done with task bar receiver
|
||||||
// cannot start a service from the command line so just
|
delete s_taskBarReceiver;
|
||||||
// run normally (except with log messages redirected).
|
|
||||||
useSystemLog();
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
}
|
|
||||||
else {
|
|
||||||
// run
|
|
||||||
result = realMain();
|
|
||||||
}
|
|
||||||
|
|
||||||
// let user examine any messages if we're running as a backend
|
// let user examine any messages if we're running as a backend
|
||||||
// by putting up a dialog box before exiting.
|
// by putting up a dialog box before exiting.
|
||||||
|
@ -733,7 +821,7 @@ static
|
||||||
int
|
int
|
||||||
daemonStartup(int, const char**)
|
daemonStartup(int, const char**)
|
||||||
{
|
{
|
||||||
useSystemLog();
|
CSystemLogger sysLogger(DAEMON_NAME);
|
||||||
return realMain();
|
return realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -747,8 +835,13 @@ main(int argc, char** argv)
|
||||||
// get program name
|
// get program name
|
||||||
ARG->m_pname = ARCH->getBasename(argv[0]);
|
ARG->m_pname = ARCH->getBasename(argv[0]);
|
||||||
|
|
||||||
|
// make the task bar receiver. the user can control this app
|
||||||
|
// through the task bar.
|
||||||
|
s_taskBarReceiver = new CXWindowsServerTaskBarReceiver;
|
||||||
|
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||||
|
|
||||||
// parse command line
|
// parse command line
|
||||||
parse(argc, const_cast<const char**>(argv));
|
parse(argc, argv);
|
||||||
|
|
||||||
// load configuration
|
// load configuration
|
||||||
loadConfig();
|
loadConfig();
|
||||||
|
@ -768,6 +861,9 @@ main(int argc, char** argv)
|
||||||
result = realMain();
|
result = realMain();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// done with task bar receiver
|
||||||
|
delete s_taskBarReceiver;
|
||||||
|
|
||||||
return result;
|
return result;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -94,6 +94,14 @@ LINK32=link.exe
|
||||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsServerTaskBarReceiver.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CServerTaskBarReceiver.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\synergys.cpp
|
SOURCE=.\synergys.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -106,6 +114,14 @@ SOURCE=.\synergys.rc
|
||||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CMSWindowsServerTaskBarReceiver.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CServerTaskBarReceiver.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\resource.h
|
SOURCE=.\resource.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
|
@ -116,6 +132,22 @@ SOURCE=.\resource.h
|
||||||
|
|
||||||
SOURCE=.\synergys.ico
|
SOURCE=.\synergys.ico
|
||||||
# End Source File
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_error.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_idle.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_run.ico
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\tb_wait.ico
|
||||||
|
# End Source File
|
||||||
# End Group
|
# End Group
|
||||||
# End Target
|
# End Target
|
||||||
# End Project
|
# End Project
|
||||||
|
|
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
After Width: | Height: | Size: 318 B |
|
@ -23,6 +23,7 @@
|
||||||
#undef ARCH_NETWORK
|
#undef ARCH_NETWORK
|
||||||
#undef ARCH_SLEEP
|
#undef ARCH_SLEEP
|
||||||
#undef ARCH_STRING
|
#undef ARCH_STRING
|
||||||
|
#undef ARCH_TASKBAR
|
||||||
#undef ARCH_TIME
|
#undef ARCH_TIME
|
||||||
|
|
||||||
// include appropriate architecture implementation
|
// include appropriate architecture implementation
|
||||||
|
@ -35,6 +36,7 @@
|
||||||
# include "CArchNetworkWinsock.h"
|
# include "CArchNetworkWinsock.h"
|
||||||
# include "CArchSleepWindows.h"
|
# include "CArchSleepWindows.h"
|
||||||
# include "CArchStringWindows.h"
|
# include "CArchStringWindows.h"
|
||||||
|
# include "CArchTaskBarWindows.h"
|
||||||
# include "CArchTimeWindows.h"
|
# include "CArchTimeWindows.h"
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
# include "CArchConsoleUnix.h"
|
# include "CArchConsoleUnix.h"
|
||||||
|
@ -47,6 +49,7 @@
|
||||||
# include "CArchNetworkBSD.h"
|
# include "CArchNetworkBSD.h"
|
||||||
# include "CArchSleepUnix.h"
|
# include "CArchSleepUnix.h"
|
||||||
# include "CArchStringUnix.h"
|
# include "CArchStringUnix.h"
|
||||||
|
# include "CArchTaskBarXWindows.h"
|
||||||
# include "CArchTimeUnix.h"
|
# include "CArchTimeUnix.h"
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
@ -82,6 +85,10 @@
|
||||||
# error unsupported platform for string
|
# error unsupported platform for string
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
#if !defined(ARCH_TASKBAR)
|
||||||
|
# error unsupported platform for taskbar
|
||||||
|
#endif
|
||||||
|
|
||||||
#if !defined(ARCH_TIME)
|
#if !defined(ARCH_TIME)
|
||||||
# error unsupported platform for time
|
# error unsupported platform for time
|
||||||
#endif
|
#endif
|
||||||
|
@ -92,7 +99,7 @@
|
||||||
|
|
||||||
CArch* CArch::s_instance = NULL;
|
CArch* CArch::s_instance = NULL;
|
||||||
|
|
||||||
CArch::CArch(ARCH_ARGS)
|
CArch::CArch(ARCH_ARGS* args)
|
||||||
{
|
{
|
||||||
// only once instance of CArch
|
// only once instance of CArch
|
||||||
assert(s_instance == NULL);
|
assert(s_instance == NULL);
|
||||||
|
@ -108,11 +115,13 @@ CArch::CArch(ARCH_ARGS)
|
||||||
m_time = new ARCH_TIME;
|
m_time = new ARCH_TIME;
|
||||||
m_console = new ARCH_CONSOLE;
|
m_console = new ARCH_CONSOLE;
|
||||||
m_daemon = new ARCH_DAEMON;
|
m_daemon = new ARCH_DAEMON;
|
||||||
|
m_taskbar = new ARCH_TASKBAR(args);
|
||||||
}
|
}
|
||||||
|
|
||||||
CArch::~CArch()
|
CArch::~CArch()
|
||||||
{
|
{
|
||||||
// clean up
|
// clean up
|
||||||
|
delete m_taskbar;
|
||||||
delete m_daemon;
|
delete m_daemon;
|
||||||
delete m_console;
|
delete m_console;
|
||||||
delete m_time;
|
delete m_time;
|
||||||
|
@ -337,10 +346,10 @@ CArch::wait(CArchThread thread, double timeout)
|
||||||
return m_mt->wait(thread, timeout);
|
return m_mt->wait(thread, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
IArchMultithread::EWaitResult
|
||||||
CArch::waitForEvent(double timeout)
|
CArch::waitForEvent(CArchThread thread, double timeout)
|
||||||
{
|
{
|
||||||
return m_mt->waitForEvent(timeout);
|
return m_mt->waitForEvent(thread, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
@ -577,6 +586,24 @@ CArch::getWideCharEncoding()
|
||||||
return m_string->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
|
double
|
||||||
CArch::time()
|
CArch::time()
|
||||||
{
|
{
|
||||||
|
|
|
@ -23,6 +23,7 @@
|
||||||
#include "IArchNetwork.h"
|
#include "IArchNetwork.h"
|
||||||
#include "IArchSleep.h"
|
#include "IArchSleep.h"
|
||||||
#include "IArchString.h"
|
#include "IArchString.h"
|
||||||
|
#include "IArchTaskBar.h"
|
||||||
#include "IArchTime.h"
|
#include "IArchTime.h"
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
|
@ -31,7 +32,7 @@ This macro evaluates to the singleton CArch object.
|
||||||
*/
|
*/
|
||||||
#define ARCH (CArch::getInstance())
|
#define ARCH (CArch::getInstance())
|
||||||
|
|
||||||
#define ARCH_ARGS
|
#define ARCH_ARGS void
|
||||||
|
|
||||||
//! Delegating mplementation of architecture dependent interfaces
|
//! Delegating mplementation of architecture dependent interfaces
|
||||||
/*!
|
/*!
|
||||||
|
@ -51,9 +52,10 @@ class CArch : public IArchConsole,
|
||||||
public IArchNetwork,
|
public IArchNetwork,
|
||||||
public IArchSleep,
|
public IArchSleep,
|
||||||
public IArchString,
|
public IArchString,
|
||||||
|
public IArchTaskBar,
|
||||||
public IArchTime {
|
public IArchTime {
|
||||||
public:
|
public:
|
||||||
CArch(ARCH_ARGS);
|
CArch(ARCH_ARGS* args = NULL);
|
||||||
~CArch();
|
~CArch();
|
||||||
|
|
||||||
//
|
//
|
||||||
|
@ -114,7 +116,7 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual bool waitForEvent(double timeout);
|
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
@ -164,6 +166,11 @@ public:
|
||||||
virtual EWideCharEncoding
|
virtual EWideCharEncoding
|
||||||
getWideCharEncoding();
|
getWideCharEncoding();
|
||||||
|
|
||||||
|
// IArchTaskBar
|
||||||
|
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||||
|
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||||
|
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||||
|
|
||||||
// IArchTime overrides
|
// IArchTime overrides
|
||||||
virtual double time();
|
virtual double time();
|
||||||
|
|
||||||
|
@ -178,6 +185,7 @@ private:
|
||||||
IArchNetwork* m_net;
|
IArchNetwork* m_net;
|
||||||
IArchSleep* m_sleep;
|
IArchSleep* m_sleep;
|
||||||
IArchString* m_string;
|
IArchString* m_string;
|
||||||
|
IArchTaskBar* m_taskbar;
|
||||||
IArchTime* m_time;
|
IArchTime* m_time;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
|
|
@ -13,6 +13,7 @@
|
||||||
*/
|
*/
|
||||||
|
|
||||||
#include "CArchConsoleWindows.h"
|
#include "CArchConsoleWindows.h"
|
||||||
|
#include "IArchMultithread.h"
|
||||||
#include "CArch.h"
|
#include "CArch.h"
|
||||||
#include <cstdio>
|
#include <cstdio>
|
||||||
|
|
||||||
|
@ -20,12 +21,12 @@
|
||||||
// CArchConsoleWindows
|
// CArchConsoleWindows
|
||||||
//
|
//
|
||||||
|
|
||||||
DWORD CArchConsoleWindows::s_thread = 0;
|
CArchThread CArchConsoleWindows::s_thread = 0;
|
||||||
|
|
||||||
CArchConsoleWindows::CArchConsoleWindows() :
|
CArchConsoleWindows::CArchConsoleWindows() :
|
||||||
m_output(NULL)
|
m_output(NULL)
|
||||||
{
|
{
|
||||||
s_thread = GetCurrentThreadId();
|
s_thread = ARCH->newCurrentThread();
|
||||||
|
|
||||||
m_mutex = ARCH->newMutex();
|
m_mutex = ARCH->newMutex();
|
||||||
}
|
}
|
||||||
|
@ -33,6 +34,7 @@ CArchConsoleWindows::CArchConsoleWindows() :
|
||||||
CArchConsoleWindows::~CArchConsoleWindows()
|
CArchConsoleWindows::~CArchConsoleWindows()
|
||||||
{
|
{
|
||||||
ARCH->closeMutex(m_mutex);
|
ARCH->closeMutex(m_mutex);
|
||||||
|
ARCH->closeThread(s_thread);
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
@ -101,7 +103,7 @@ CArchConsoleWindows::getNewlineForConsole()
|
||||||
BOOL WINAPI
|
BOOL WINAPI
|
||||||
CArchConsoleWindows::signalHandler(DWORD)
|
CArchConsoleWindows::signalHandler(DWORD)
|
||||||
{
|
{
|
||||||
// terminate cleanly and skip remaining handlers
|
// terminate thread and skip remaining handlers
|
||||||
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
|
ARCH->cancelThread(s_thread);
|
||||||
return TRUE;
|
return TRUE;
|
||||||
}
|
}
|
||||||
|
|
|
@ -39,7 +39,7 @@ private:
|
||||||
static BOOL WINAPI signalHandler(DWORD);
|
static BOOL WINAPI signalHandler(DWORD);
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static DWORD s_thread;
|
static CArchThread s_thread;
|
||||||
|
|
||||||
CArchMutex m_mutex;
|
CArchMutex m_mutex;
|
||||||
HANDLE m_output;
|
HANDLE m_output;
|
||||||
|
|
|
@ -25,6 +25,7 @@
|
||||||
# include "CArchNetworkWinsock.cpp"
|
# include "CArchNetworkWinsock.cpp"
|
||||||
# include "CArchSleepWindows.cpp"
|
# include "CArchSleepWindows.cpp"
|
||||||
# include "CArchStringWindows.cpp"
|
# include "CArchStringWindows.cpp"
|
||||||
|
# include "CArchTaskBarWindows.cpp"
|
||||||
# include "CArchTimeWindows.cpp"
|
# include "CArchTimeWindows.cpp"
|
||||||
# include "XArchWindows.cpp"
|
# include "XArchWindows.cpp"
|
||||||
#elif UNIX_LIKE
|
#elif UNIX_LIKE
|
||||||
|
@ -38,6 +39,7 @@
|
||||||
# include "CArchNetworkBSD.cpp"
|
# include "CArchNetworkBSD.cpp"
|
||||||
# include "CArchSleepUnix.cpp"
|
# include "CArchSleepUnix.cpp"
|
||||||
# include "CArchStringUnix.cpp"
|
# include "CArchStringUnix.cpp"
|
||||||
|
# include "CArchTaskBarXWindows.cpp"
|
||||||
# include "CArchTimeUnix.cpp"
|
# include "CArchTimeUnix.cpp"
|
||||||
# include "XArchUnix.cpp"
|
# include "XArchUnix.cpp"
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -517,11 +517,11 @@ CArchMultithreadPosix::wait(CArchThread target, double timeout)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
IArchMultithread::EWaitResult
|
||||||
CArchMultithreadPosix::waitForEvent(double /*timeout*/)
|
CArchMultithreadPosix::waitForEvent(CArchThread, double /*timeout*/)
|
||||||
{
|
{
|
||||||
// not implemented
|
// not implemented
|
||||||
return false;
|
return kTimeout;
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
|
|
|
@ -55,7 +55,7 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual bool waitForEvent(double timeout);
|
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
|
|
@ -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
|
bool
|
||||||
CArchMultithreadWindows::waitForEvent(double timeout)
|
CArchMultithreadWindows::waitForEvent(double timeout)
|
||||||
{
|
{
|
||||||
|
@ -499,6 +582,7 @@ CArchMultithreadWindows::waitForEvent(double timeout)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
*/
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||||
|
|
|
@ -69,7 +69,7 @@ public:
|
||||||
virtual void setPriorityOfThread(CArchThread, int n);
|
virtual void setPriorityOfThread(CArchThread, int n);
|
||||||
virtual void testCancelThread();
|
virtual void testCancelThread();
|
||||||
virtual bool wait(CArchThread, double timeout);
|
virtual bool wait(CArchThread, double timeout);
|
||||||
virtual bool waitForEvent(double timeout);
|
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||||
virtual bool isSameThread(CArchThread, CArchThread);
|
virtual bool isSameThread(CArchThread, CArchThread);
|
||||||
virtual bool isExitedThread(CArchThread);
|
virtual bool isExitedThread(CArchThread);
|
||||||
virtual void* getResultOfThread(CArchThread);
|
virtual void* getResultOfThread(CArchThread);
|
||||||
|
|
|
@ -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;
|
||||||
|
}
|
|
@ -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
|
|
@ -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
|
||||||
|
}
|
|
@ -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
|
|
@ -67,6 +67,13 @@ synergy. Each architecture must implement this interface.
|
||||||
*/
|
*/
|
||||||
class IArchMultithread : public IInterface {
|
class IArchMultithread : public IInterface {
|
||||||
public:
|
public:
|
||||||
|
//! Result of waitForEvent()
|
||||||
|
enum EWaitResult {
|
||||||
|
kEvent, //!< An event is pending
|
||||||
|
kExit, //!< Thread exited
|
||||||
|
kTimeout //!< Wait timed out
|
||||||
|
};
|
||||||
|
|
||||||
//! Type of thread entry point
|
//! Type of thread entry point
|
||||||
typedef void* (*ThreadFunc)(void*);
|
typedef void* (*ThreadFunc)(void*);
|
||||||
//! Type of thread identifier
|
//! Type of thread identifier
|
||||||
|
@ -102,10 +109,12 @@ public:
|
||||||
|
|
||||||
//! Wait on a condition variable
|
//! 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
|
If \c timeout is < 0 then there is no timeout. The mutex must
|
||||||
be locked when this method is called. The mutex is unlocked
|
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)
|
(Cancellation point)
|
||||||
*/
|
*/
|
||||||
|
@ -206,14 +215,18 @@ public:
|
||||||
|
|
||||||
//! Wait for a user event
|
//! Wait for a user event
|
||||||
/*!
|
/*!
|
||||||
Waits for up to \c timeout seconds for a pending user event.
|
Waits for up to \c timeout seconds for a pending user event or
|
||||||
Returns true if an event occurred, false otherwise.
|
\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.
|
This method is not required by all platforms.
|
||||||
|
|
||||||
(Cancellation point)
|
(Cancellation point)
|
||||||
*/
|
*/
|
||||||
virtual bool waitForEvent(double timeout) = 0;
|
virtual EWaitResult waitForEvent(CArchThread thread, double timeout) = 0;
|
||||||
|
|
||||||
//! Compare threads
|
//! Compare threads
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -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
|
|
@ -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
|
|
@ -26,6 +26,7 @@ EXTRA_DIST = \
|
||||||
CArchNetworkWinsock.cpp \
|
CArchNetworkWinsock.cpp \
|
||||||
CArchSleepWindows.cpp \
|
CArchSleepWindows.cpp \
|
||||||
CArchStringWindows.cpp \
|
CArchStringWindows.cpp \
|
||||||
|
CArchTaskBarWindows.cpp \
|
||||||
CArchTimeWindows.cpp \
|
CArchTimeWindows.cpp \
|
||||||
XArchWindows.cpp \
|
XArchWindows.cpp \
|
||||||
CArchConsoleWindows.h \
|
CArchConsoleWindows.h \
|
||||||
|
@ -37,6 +38,7 @@ EXTRA_DIST = \
|
||||||
CArchNetworkWinsock.h \
|
CArchNetworkWinsock.h \
|
||||||
CArchSleepWindows.h \
|
CArchSleepWindows.h \
|
||||||
CArchStringWindows.h \
|
CArchStringWindows.h \
|
||||||
|
CArchTaskBarWindows.h \
|
||||||
CArchTimeWindows.h \
|
CArchTimeWindows.h \
|
||||||
XArchWindows.h \
|
XArchWindows.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -59,6 +61,8 @@ libarch_a_SOURCES = \
|
||||||
IArchNetwork.h \
|
IArchNetwork.h \
|
||||||
IArchSleep.h \
|
IArchSleep.h \
|
||||||
IArchString.h \
|
IArchString.h \
|
||||||
|
IArchTaskBar.h \
|
||||||
|
IArchTaskBarReceiver.h \
|
||||||
IArchTime.h \
|
IArchTime.h \
|
||||||
XArch.h \
|
XArch.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
@ -72,6 +76,7 @@ EXTRA_libarch_a_SOURCES = \
|
||||||
CArchNetworkBSD.cpp \
|
CArchNetworkBSD.cpp \
|
||||||
CArchSleepUnix.cpp \
|
CArchSleepUnix.cpp \
|
||||||
CArchStringUnix.cpp \
|
CArchStringUnix.cpp \
|
||||||
|
CArchTaskBarXWindows.cpp \
|
||||||
CArchTimeUnix.cpp \
|
CArchTimeUnix.cpp \
|
||||||
CMultibyte.cpp \
|
CMultibyte.cpp \
|
||||||
CMultibyteOS.cpp \
|
CMultibyteOS.cpp \
|
||||||
|
@ -87,6 +92,7 @@ EXTRA_libarch_a_SOURCES = \
|
||||||
CArchNetworkBSD.h \
|
CArchNetworkBSD.h \
|
||||||
CArchSleepUnix.h \
|
CArchSleepUnix.h \
|
||||||
CArchStringUnix.h \
|
CArchStringUnix.h \
|
||||||
|
CArchTaskBarXWindows.h \
|
||||||
CArchTimeUnix.h \
|
CArchTimeUnix.h \
|
||||||
XArchUnix.h \
|
XArchUnix.h \
|
||||||
$(NULL)
|
$(NULL)
|
||||||
|
|
|
@ -115,6 +115,10 @@ SOURCE=.\CArchDaemonWindows.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchFileWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CArchImpl.h
|
SOURCE=.\CArchImpl.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -143,6 +147,10 @@ SOURCE=.\CArchStringWindows.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchTaskBarWindows.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CArchTimeWindows.h
|
SOURCE=.\CArchTimeWindows.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -151,6 +159,14 @@ SOURCE=.\IArchConsole.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=.\IArchLog.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -171,6 +187,14 @@ SOURCE=.\IArchString.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin 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
|
SOURCE=.\IArchTime.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -232,6 +256,11 @@ SOURCE=.\CArchStringWindows.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CArchTaskBarWindows.cpp
|
||||||
|
# PROP Exclude_From_Build 1
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CArchTimeWindows.cpp
|
SOURCE=.\CArchTimeWindows.cpp
|
||||||
# PROP Exclude_From_Build 1
|
# PROP Exclude_From_Build 1
|
||||||
# End Source File
|
# End Source File
|
||||||
|
|
|
@ -0,0 +1,113 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 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 "CJobList.h"
|
||||||
|
#include "IJob.h"
|
||||||
|
#include "CArch.h"
|
||||||
|
|
||||||
|
//
|
||||||
|
// CJobList
|
||||||
|
//
|
||||||
|
|
||||||
|
CJobList::CJobList()
|
||||||
|
{
|
||||||
|
m_mutex = ARCH->newMutex();
|
||||||
|
}
|
||||||
|
|
||||||
|
CJobList::~CJobList()
|
||||||
|
{
|
||||||
|
ARCH->closeMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CJobList::addJob(IJob* job)
|
||||||
|
{
|
||||||
|
// ignore bogus job
|
||||||
|
if (job == NULL) {
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
// make a temporary list with the job. later we'll splice this
|
||||||
|
// list into our jobs list. since splice() never throws we
|
||||||
|
// don't have to try/catch to unlock the mutex.
|
||||||
|
CJobs tmpList;
|
||||||
|
tmpList.push_front(job);
|
||||||
|
|
||||||
|
// add job to list
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
m_jobs.splice(m_jobs.begin(), tmpList);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CJobList::removeJob(IJob* job)
|
||||||
|
{
|
||||||
|
if (job != NULL) {
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
m_jobs.remove(job);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CJobList::runJobs() const
|
||||||
|
{
|
||||||
|
// this is a little tricky. to allow any number of threads to
|
||||||
|
// traverse the list while jobs are added and removed while
|
||||||
|
// not holding the mutex when running a job (so other threads
|
||||||
|
// or the running job can add and remove jobs), we insert a
|
||||||
|
// new element into the list. this element has a NULL job and
|
||||||
|
// is a "safe place" while we traverse the list. the safe place
|
||||||
|
// is inserted at the start of the list (with the mutex locked)
|
||||||
|
// then, for each job, we lock the mutex and move the safe place
|
||||||
|
// past the next job, unlock the mutex, run the job and repeat
|
||||||
|
// until there are no more jobs. the safe place will not be
|
||||||
|
// removed by any other thread and is after every job that has
|
||||||
|
// been run and before every job that still needs to run. when
|
||||||
|
// all the jobs have been run we remove the safe place.
|
||||||
|
|
||||||
|
// add the safe place
|
||||||
|
CJobs tmpList;
|
||||||
|
tmpList.push_front(NULL);
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
m_jobs.splice(m_jobs.begin(), tmpList);
|
||||||
|
CJobs::iterator safePlace = m_jobs.begin();
|
||||||
|
|
||||||
|
// find the next non-NULL job (NULL jobs are safe places)
|
||||||
|
CJobs::iterator next = safePlace;
|
||||||
|
while (next != m_jobs.end() && *next == NULL)
|
||||||
|
++next;
|
||||||
|
while (next != m_jobs.end()) {
|
||||||
|
// found a job. run it without holding a lock. note the
|
||||||
|
// race condition here: we release the lock, allowing
|
||||||
|
// removeJob() to remove this job before we run the job.
|
||||||
|
// therefore the caller cannot safely destroy the job
|
||||||
|
// until all runJobs() complete.
|
||||||
|
IJob* job = *next;
|
||||||
|
++next;
|
||||||
|
m_jobs.splice(next, m_jobs, safePlace);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
job->run();
|
||||||
|
|
||||||
|
// next real job
|
||||||
|
ARCH->lockMutex(m_mutex);
|
||||||
|
next = safePlace;
|
||||||
|
while (next != m_jobs.end() && *next == NULL)
|
||||||
|
++next;
|
||||||
|
}
|
||||||
|
|
||||||
|
// remove the safe place
|
||||||
|
m_jobs.erase(safePlace);
|
||||||
|
ARCH->unlockMutex(m_mutex);
|
||||||
|
}
|
|
@ -0,0 +1,72 @@
|
||||||
|
/*
|
||||||
|
* synergy -- mouse and keyboard sharing utility
|
||||||
|
* Copyright (C) 2002 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 CJOBLIST_H
|
||||||
|
#define CJOBLIST_H
|
||||||
|
|
||||||
|
#include "IArchMultithread.h"
|
||||||
|
#include "stdlist.h"
|
||||||
|
|
||||||
|
class IJob;
|
||||||
|
|
||||||
|
class CJobList {
|
||||||
|
public:
|
||||||
|
CJobList();
|
||||||
|
~CJobList();
|
||||||
|
|
||||||
|
//! @name manipulators
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Add a job
|
||||||
|
/*!
|
||||||
|
Add a job to the list. The client keeps ownership of the job.
|
||||||
|
Jobs can be safely added while \c runJobs() is executing.
|
||||||
|
*/
|
||||||
|
void addJob(IJob*);
|
||||||
|
|
||||||
|
//! Remove a job
|
||||||
|
/*!
|
||||||
|
Remove a job from the list. The client keeps ownership of the job.
|
||||||
|
Jobs can be safely removed while \c runJobs() is executing.
|
||||||
|
*/
|
||||||
|
void removeJob(IJob*);
|
||||||
|
|
||||||
|
//@}
|
||||||
|
//! @name accessors
|
||||||
|
//@{
|
||||||
|
|
||||||
|
//! Run all jobs
|
||||||
|
/*!
|
||||||
|
Run all jobs in the list. Any number of threads can call
|
||||||
|
\c runJobs() at once. Jobs can be added and removed while
|
||||||
|
\c runJobs() is executing in the same or another thread.
|
||||||
|
Any job added after \c runJobs() starts will not be run
|
||||||
|
by that call to runJobs(). Destroying a removed job
|
||||||
|
while \c runJobs() is executing is not safe unless the
|
||||||
|
removed completed before \c runJobs() started.
|
||||||
|
*/
|
||||||
|
void runJobs() const;
|
||||||
|
|
||||||
|
//@}
|
||||||
|
|
||||||
|
private:
|
||||||
|
typedef std::list<IJob*> CJobs;
|
||||||
|
typedef CJobs::iterator iterator;
|
||||||
|
|
||||||
|
CArchMutex m_mutex;
|
||||||
|
mutable CJobs m_jobs;
|
||||||
|
};
|
||||||
|
|
||||||
|
#endif
|
||||||
|
|
|
@ -156,3 +156,26 @@ CSystemLogOutputter::getNewline() const
|
||||||
{
|
{
|
||||||
return "";
|
return "";
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
//
|
||||||
|
// CSystemLogger
|
||||||
|
//
|
||||||
|
|
||||||
|
CSystemLogger::CSystemLogger(const char* title)
|
||||||
|
{
|
||||||
|
// redirect log messages
|
||||||
|
m_syslog = new CSystemLogOutputter;
|
||||||
|
m_stop = new CStopLogOutputter;
|
||||||
|
m_syslog->open(title);
|
||||||
|
CLOG->insert(m_stop);
|
||||||
|
CLOG->insert(m_syslog);
|
||||||
|
}
|
||||||
|
|
||||||
|
CSystemLogger::~CSystemLogger()
|
||||||
|
{
|
||||||
|
CLOG->remove(m_syslog);
|
||||||
|
CLOG->remove(m_stop);
|
||||||
|
delete m_stop;
|
||||||
|
delete m_syslog;
|
||||||
|
}
|
||||||
|
|
|
@ -68,4 +68,22 @@ public:
|
||||||
virtual const char* getNewline() const;
|
virtual const char* getNewline() const;
|
||||||
};
|
};
|
||||||
|
|
||||||
|
//! Write log to system log only
|
||||||
|
/*!
|
||||||
|
Creating an object of this type inserts a CStopLogOutputter followed
|
||||||
|
by a CSystemLogOutputter into CLog. The destructor removes those
|
||||||
|
outputters. Add one of these to any scope that needs to write to
|
||||||
|
the system log (only) and restore the old outputters when exiting
|
||||||
|
the scope.
|
||||||
|
*/
|
||||||
|
class CSystemLogger {
|
||||||
|
public:
|
||||||
|
CSystemLogger(const char* title);
|
||||||
|
~CSystemLogger();
|
||||||
|
|
||||||
|
private:
|
||||||
|
ILogOutputter* m_syslog;
|
||||||
|
ILogOutputter* m_stop;
|
||||||
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -26,6 +26,7 @@ MAINTAINERCLEANFILES = \
|
||||||
noinst_LIBRARIES = libbase.a
|
noinst_LIBRARIES = libbase.a
|
||||||
libbase_a_SOURCES = \
|
libbase_a_SOURCES = \
|
||||||
CFunctionJob.cpp \
|
CFunctionJob.cpp \
|
||||||
|
CJobList.cpp \
|
||||||
CLog.cpp \
|
CLog.cpp \
|
||||||
CStopwatch.cpp \
|
CStopwatch.cpp \
|
||||||
CStringUtil.cpp \
|
CStringUtil.cpp \
|
||||||
|
@ -33,6 +34,7 @@ libbase_a_SOURCES = \
|
||||||
LogOutputters.cpp \
|
LogOutputters.cpp \
|
||||||
XBase.cpp \
|
XBase.cpp \
|
||||||
CFunctionJob.h \
|
CFunctionJob.h \
|
||||||
|
CJobList.h \
|
||||||
CLog.h \
|
CLog.h \
|
||||||
CStopwatch.h \
|
CStopwatch.h \
|
||||||
CString.h \
|
CString.h \
|
||||||
|
|
|
@ -91,6 +91,10 @@ SOURCE=.\CFunctionJob.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CJobList.cpp
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CLog.cpp
|
SOURCE=.\CLog.cpp
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
@ -123,6 +127,10 @@ SOURCE=.\CFunctionJob.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
||||||
|
SOURCE=.\CJobList.h
|
||||||
|
# End Source File
|
||||||
|
# Begin Source File
|
||||||
|
|
||||||
SOURCE=.\CLog.h
|
SOURCE=.\CLog.h
|
||||||
# End Source File
|
# End Source File
|
||||||
# Begin Source File
|
# Begin Source File
|
||||||
|
|
|
@ -52,7 +52,8 @@ CClient::CClient(const CString& clientName) :
|
||||||
m_streamFilterFactory(NULL),
|
m_streamFilterFactory(NULL),
|
||||||
m_session(NULL),
|
m_session(NULL),
|
||||||
m_active(false),
|
m_active(false),
|
||||||
m_rejected(true)
|
m_rejected(true),
|
||||||
|
m_status(kNotRunning)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -108,15 +109,61 @@ CClient::exitMainLoop()
|
||||||
m_screen->exitMainLoop();
|
m_screen->exitMainLoop();
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClient::addStatusJob(IJob* job)
|
||||||
|
{
|
||||||
|
m_statusJobs.addJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClient::removeStatusJob(IJob* job)
|
||||||
|
{
|
||||||
|
m_statusJobs.removeJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CClient::wasRejected() const
|
CClient::wasRejected() const
|
||||||
{
|
{
|
||||||
return m_rejected;
|
return m_rejected;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
CClient::EStatus
|
||||||
|
CClient::getStatus(CString* msg) const
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
if (msg != NULL) {
|
||||||
|
*msg = m_statusMessage;
|
||||||
|
}
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClient::runStatusJobs() const
|
||||||
|
{
|
||||||
|
m_statusJobs.runJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CClient::setStatus(EStatus status, const char* msg)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
m_status = status;
|
||||||
|
if (m_status == kError) {
|
||||||
|
m_statusMessage = (msg == NULL) ? "Error" : msg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_statusMessage = (msg == NULL) ? "" : msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runStatusJobs();
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CClient::onError()
|
CClient::onError()
|
||||||
{
|
{
|
||||||
|
setStatus(kError);
|
||||||
|
|
||||||
// close down session but don't wait too long
|
// close down session but don't wait too long
|
||||||
deleteSession(3.0);
|
deleteSession(3.0);
|
||||||
}
|
}
|
||||||
|
@ -172,9 +219,11 @@ CClient::open()
|
||||||
try {
|
try {
|
||||||
LOG((CLOG_INFO "opening screen"));
|
LOG((CLOG_INFO "opening screen"));
|
||||||
openSecondaryScreen();
|
openSecondaryScreen();
|
||||||
|
setStatus(kNotRunning);
|
||||||
}
|
}
|
||||||
catch (XScreenOpenFailure&) {
|
catch (XScreenOpenFailure& e) {
|
||||||
// can't open screen
|
// can't open screen
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_INFO "failed to open screen"));
|
LOG((CLOG_INFO "failed to open screen"));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -195,6 +244,7 @@ CClient::mainLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setStatus(kNotRunning);
|
||||||
LOG((CLOG_NOTE "starting client \"%s\"", m_name.c_str()));
|
LOG((CLOG_NOTE "starting client \"%s\"", m_name.c_str()));
|
||||||
|
|
||||||
// start server interactions
|
// start server interactions
|
||||||
|
@ -213,6 +263,7 @@ CClient::mainLoop()
|
||||||
}
|
}
|
||||||
catch (XMT& e) {
|
catch (XMT& e) {
|
||||||
LOG((CLOG_ERR "client error: %s", e.what()));
|
LOG((CLOG_ERR "client error: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
deleteSession();
|
deleteSession();
|
||||||
|
@ -221,6 +272,7 @@ CClient::mainLoop()
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
LOG((CLOG_ERR "client error: %s", e.what()));
|
LOG((CLOG_ERR "client error: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
deleteSession();
|
deleteSession();
|
||||||
|
@ -229,6 +281,8 @@ CClient::mainLoop()
|
||||||
m_rejected = false;
|
m_rejected = false;
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
catch (XThread&) {
|
||||||
|
setStatus(kNotRunning);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
deleteSession();
|
deleteSession();
|
||||||
LOG((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
LOG((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||||
|
@ -236,6 +290,7 @@ CClient::mainLoop()
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
LOG((CLOG_DEBUG "unknown client error"));
|
LOG((CLOG_DEBUG "unknown client error"));
|
||||||
|
setStatus(kError);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
deleteSession();
|
deleteSession();
|
||||||
|
@ -529,11 +584,12 @@ CClient::runServer()
|
||||||
{
|
{
|
||||||
IDataSocket* socket = NULL;
|
IDataSocket* socket = NULL;
|
||||||
CServerProxy* proxy = NULL;
|
CServerProxy* proxy = NULL;
|
||||||
|
bool timedOut;
|
||||||
try {
|
try {
|
||||||
for (;;) {
|
for (;;) {
|
||||||
try {
|
try {
|
||||||
// allow connect this much time to succeed
|
// allow connect this much time to succeed
|
||||||
CTimerThread timer(15.0);
|
CTimerThread timer(15.0, &timedOut);
|
||||||
|
|
||||||
// create socket and attempt to connect to server
|
// create socket and attempt to connect to server
|
||||||
LOG((CLOG_DEBUG1 "connecting to server"));
|
LOG((CLOG_DEBUG1 "connecting to server"));
|
||||||
|
@ -546,6 +602,7 @@ CClient::runServer()
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (XSocketConnect& e) {
|
catch (XSocketConnect& e) {
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_DEBUG "failed to connect to server: %s", e.what()));
|
LOG((CLOG_DEBUG "failed to connect to server: %s", e.what()));
|
||||||
|
|
||||||
// failed to connect. if not camping then rethrow.
|
// failed to connect. if not camping then rethrow.
|
||||||
|
@ -565,31 +622,47 @@ CClient::runServer()
|
||||||
m_server = proxy;
|
m_server = proxy;
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
catch (XThread&) {
|
||||||
|
if (timedOut) {
|
||||||
LOG((CLOG_ERR "connection timed out"));
|
LOG((CLOG_ERR "connection timed out"));
|
||||||
|
setStatus(kError, "connection timed out");
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
// cancelled by some thread other than the timer
|
||||||
|
}
|
||||||
delete socket;
|
delete socket;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
LOG((CLOG_ERR "connection failed: %s", e.what()));
|
LOG((CLOG_ERR "connection failed: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_DEBUG "disconnecting from server"));
|
LOG((CLOG_DEBUG "disconnecting from server"));
|
||||||
delete socket;
|
delete socket;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
LOG((CLOG_ERR "connection failed: <unknown error>"));
|
LOG((CLOG_ERR "connection failed: <unknown error>"));
|
||||||
|
setStatus(kError);
|
||||||
LOG((CLOG_DEBUG "disconnecting from server"));
|
LOG((CLOG_DEBUG "disconnecting from server"));
|
||||||
delete socket;
|
delete socket;
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
// prepare for remote control
|
||||||
|
m_screen->remoteControl();
|
||||||
|
|
||||||
// process messages
|
// process messages
|
||||||
bool rejected = true;
|
bool rejected = true;
|
||||||
if (proxy != NULL) {
|
if (proxy != NULL) {
|
||||||
LOG((CLOG_DEBUG1 "communicating with server"));
|
LOG((CLOG_DEBUG1 "communicating with server"));
|
||||||
|
setStatus(kRunning);
|
||||||
rejected = !proxy->mainLoop();
|
rejected = !proxy->mainLoop();
|
||||||
|
setStatus(kNotRunning);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// prepare for local control
|
||||||
|
m_screen->localControl();
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
m_rejected = rejected;
|
m_rejected = rejected;
|
||||||
|
@ -600,6 +673,8 @@ CClient::runServer()
|
||||||
delete socket;
|
delete socket;
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
setStatus(kNotRunning);
|
||||||
|
m_screen->localControl();
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
m_rejected = false;
|
m_rejected = false;
|
||||||
m_server = NULL;
|
m_server = NULL;
|
||||||
|
@ -664,9 +739,11 @@ CClient::handshakeServer(IDataSocket* socket)
|
||||||
}
|
}
|
||||||
catch (XIncompatibleClient& e) {
|
catch (XIncompatibleClient& e) {
|
||||||
LOG((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor()));
|
LOG((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
LOG((CLOG_WARN "error communicating with server: %s", e.what()));
|
LOG((CLOG_WARN "error communicating with server: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
// probably timed out
|
// probably timed out
|
||||||
|
|
|
@ -20,6 +20,7 @@
|
||||||
#include "IClipboard.h"
|
#include "IClipboard.h"
|
||||||
#include "CNetworkAddress.h"
|
#include "CNetworkAddress.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
|
#include "CJobList.h"
|
||||||
|
|
||||||
class CSecondaryScreen;
|
class CSecondaryScreen;
|
||||||
class CServerProxy;
|
class CServerProxy;
|
||||||
|
@ -36,6 +37,13 @@ This class implements the top-level client algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CClient : public IScreenReceiver, public IClient {
|
class CClient : public IScreenReceiver, public IClient {
|
||||||
public:
|
public:
|
||||||
|
enum EStatus {
|
||||||
|
kNotRunning,
|
||||||
|
kRunning,
|
||||||
|
kError,
|
||||||
|
kMaxStatus
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
This client will attempt to connect the server using \c clientName
|
This client will attempt to connect the server using \c clientName
|
||||||
as its name.
|
as its name.
|
||||||
|
@ -93,6 +101,22 @@ public:
|
||||||
*/
|
*/
|
||||||
void exitMainLoop();
|
void exitMainLoop();
|
||||||
|
|
||||||
|
//! Add a job to notify of status changes
|
||||||
|
/*!
|
||||||
|
The added job is run whenever the server's status changes in
|
||||||
|
certain externally visible ways. The client keeps ownership
|
||||||
|
of the job.
|
||||||
|
*/
|
||||||
|
void addStatusJob(IJob*);
|
||||||
|
|
||||||
|
//! Remove a job to notify of status changes
|
||||||
|
/*!
|
||||||
|
Removes a previously added status notification job. A job can
|
||||||
|
remove itself when called but must not remove any other jobs.
|
||||||
|
The client keeps ownership of the job.
|
||||||
|
*/
|
||||||
|
void removeStatusJob(IJob*);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -103,6 +127,12 @@ public:
|
||||||
*/
|
*/
|
||||||
bool wasRejected() const;
|
bool wasRejected() const;
|
||||||
|
|
||||||
|
//! Get the status
|
||||||
|
/*!
|
||||||
|
Returns the current status and status message.
|
||||||
|
*/
|
||||||
|
EStatus getStatus(CString* = NULL) const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IScreenReceiver overrides
|
// IScreenReceiver overrides
|
||||||
|
@ -140,6 +170,12 @@ public:
|
||||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
|
// notify status jobs of a change
|
||||||
|
void runStatusJobs() const;
|
||||||
|
|
||||||
|
// set new status
|
||||||
|
void setStatus(EStatus, const char* msg = NULL);
|
||||||
|
|
||||||
// open/close the secondary screen
|
// open/close the secondary screen
|
||||||
void openSecondaryScreen();
|
void openSecondaryScreen();
|
||||||
void closeSecondaryScreen();
|
void closeSecondaryScreen();
|
||||||
|
@ -169,6 +205,11 @@ private:
|
||||||
bool m_ownClipboard[kClipboardEnd];
|
bool m_ownClipboard[kClipboardEnd];
|
||||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||||
CString m_dataClipboard[kClipboardEnd];
|
CString m_dataClipboard[kClipboardEnd];
|
||||||
|
|
||||||
|
// the status change jobs and status
|
||||||
|
CJobList m_statusJobs;
|
||||||
|
EStatus m_status;
|
||||||
|
CString m_statusMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -420,6 +420,7 @@ CServerProxy::translateModifierMask(KeyModifierMask mask) const
|
||||||
if ((mask & KeyModifierSuper) != 0) {
|
if ((mask & KeyModifierSuper) != 0) {
|
||||||
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]];
|
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]];
|
||||||
}
|
}
|
||||||
|
return newMask;
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -97,10 +97,16 @@ CThread::wait(double timeout) const
|
||||||
return ARCH->wait(m_thread, timeout);
|
return ARCH->wait(m_thread, timeout);
|
||||||
}
|
}
|
||||||
|
|
||||||
bool
|
CThread::EWaitResult
|
||||||
CThread::waitForEvent(double timeout)
|
CThread::waitForEvent(double timeout) const
|
||||||
{
|
{
|
||||||
return ARCH->waitForEvent(timeout);
|
// IArchMultithread EWaitResults map directly to our EWaitResults
|
||||||
|
static const EWaitResult s_map[] = {
|
||||||
|
kEvent,
|
||||||
|
kExit,
|
||||||
|
kTimeout
|
||||||
|
};
|
||||||
|
return s_map[ARCH->waitForEvent(m_thread, timeout)];
|
||||||
}
|
}
|
||||||
|
|
||||||
void*
|
void*
|
||||||
|
|
|
@ -39,6 +39,13 @@ documentation.
|
||||||
// note -- do not derive from this class
|
// note -- do not derive from this class
|
||||||
class CThread {
|
class CThread {
|
||||||
public:
|
public:
|
||||||
|
//! Result of waitForEvent()
|
||||||
|
enum EWaitResult {
|
||||||
|
kEvent, //!< An event is pending
|
||||||
|
kExit, //!< Thread exited
|
||||||
|
kTimeout //!< Wait timed out
|
||||||
|
};
|
||||||
|
|
||||||
//! Run \c adoptedJob in a new thread
|
//! Run \c adoptedJob in a new thread
|
||||||
/*!
|
/*!
|
||||||
Create and start a new thread executing the \c adoptedJob. The
|
Create and start a new thread executing the \c adoptedJob. The
|
||||||
|
@ -159,18 +166,19 @@ public:
|
||||||
|
|
||||||
//! Wait for an event (win32)
|
//! Wait for an event (win32)
|
||||||
/*!
|
/*!
|
||||||
Wait for the message queue to contain a message for up to \c timeout
|
Wait for the message queue to contain a message or for the thread
|
||||||
seconds. This returns immediately if any message is available
|
to exit for up to \c timeout seconds. This returns immediately if
|
||||||
(including messages that were already in the queue during the last
|
any message is available (including messages that were already in
|
||||||
call to \c GetMessage() or \c PeekMessage() or waitForEvent().
|
the queue during the last call to \c GetMessage() or
|
||||||
Returns true iff a message is available. This will wait forever
|
\c PeekMessage() or waitForEvent(). Returns kEvent if a message
|
||||||
if \c timeout < 0.0.
|
is available, kExit if the thread exited, and kTimeout otherwise.
|
||||||
|
This will wait forever if \c timeout < 0.0.
|
||||||
|
|
||||||
This method is available under win32 only.
|
This method is available under win32 only.
|
||||||
|
|
||||||
(cancellation point)
|
(cancellation point)
|
||||||
*/
|
*/
|
||||||
static bool waitForEvent(double timeout = -1.0);
|
EWaitResult waitForEvent(double timeout = -1.0) const;
|
||||||
|
|
||||||
//! Get the exit result
|
//! Get the exit result
|
||||||
/*!
|
/*!
|
||||||
|
|
|
@ -22,8 +22,13 @@
|
||||||
// CTimerThread
|
// CTimerThread
|
||||||
//
|
//
|
||||||
|
|
||||||
CTimerThread::CTimerThread(double timeout) : m_timeout(timeout)
|
CTimerThread::CTimerThread(double timeout, bool* timedOut) :
|
||||||
|
m_timeout(timeout),
|
||||||
|
m_timedOut(timedOut)
|
||||||
{
|
{
|
||||||
|
if (m_timedOut != NULL) {
|
||||||
|
*m_timedOut = false;
|
||||||
|
}
|
||||||
if (m_timeout >= 0.0) {
|
if (m_timeout >= 0.0) {
|
||||||
m_callingThread = new CThread(CThread::getCurrentThread());
|
m_callingThread = new CThread(CThread::getCurrentThread());
|
||||||
m_timingThread = new CThread(new TMethodJob<CTimerThread>(
|
m_timingThread = new CThread(new TMethodJob<CTimerThread>(
|
||||||
|
@ -53,5 +58,8 @@ CTimerThread::timer(void*)
|
||||||
LOG((CLOG_DEBUG1 "timeout in %f seconds", m_timeout));
|
LOG((CLOG_DEBUG1 "timeout in %f seconds", m_timeout));
|
||||||
ARCH->sleep(m_timeout);
|
ARCH->sleep(m_timeout);
|
||||||
LOG((CLOG_DEBUG1 "timeout"));
|
LOG((CLOG_DEBUG1 "timeout"));
|
||||||
|
if (m_timedOut != NULL) {
|
||||||
|
*m_timedOut = true;
|
||||||
|
}
|
||||||
m_callingThread->cancel();
|
m_callingThread->cancel();
|
||||||
}
|
}
|
||||||
|
|
|
@ -30,9 +30,11 @@ public:
|
||||||
/*!
|
/*!
|
||||||
Cancels the calling thread after \c timeout seconds unless destroyed
|
Cancels the calling thread after \c timeout seconds unless destroyed
|
||||||
before then. If \c timeout is less than zero then it never times
|
before then. If \c timeout is less than zero then it never times
|
||||||
out and this is a no-op.
|
out and this is a no-op. If \c timedOutFlag is not NULL then it's
|
||||||
|
set to false in the c'tor and to true if the timeout exipires before
|
||||||
|
it's cancelled.
|
||||||
*/
|
*/
|
||||||
CTimerThread(double timeout);
|
CTimerThread(double timeout, bool* timedOutFlag = NULL);
|
||||||
//! Cancel the timer thread
|
//! Cancel the timer thread
|
||||||
~CTimerThread();
|
~CTimerThread();
|
||||||
|
|
||||||
|
@ -45,6 +47,7 @@ private:
|
||||||
|
|
||||||
private:
|
private:
|
||||||
double m_timeout;
|
double m_timeout;
|
||||||
|
bool* m_timedOut;
|
||||||
CThread* m_callingThread;
|
CThread* m_callingThread;
|
||||||
CThread* m_timingThread;
|
CThread* m_timingThread;
|
||||||
};
|
};
|
||||||
|
|
|
@ -112,6 +112,12 @@ CMSWindowsPrimaryScreen::setOptions(const COptionsList& /*options*/)
|
||||||
// no options
|
// no options
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UInt32
|
||||||
|
CMSWindowsPrimaryScreen::addOneShotTimer(double timeout)
|
||||||
|
{
|
||||||
|
return m_screen->addOneShotTimer(timeout);
|
||||||
|
}
|
||||||
|
|
||||||
KeyModifierMask
|
KeyModifierMask
|
||||||
CMSWindowsPrimaryScreen::getToggleMask() const
|
CMSWindowsPrimaryScreen::getToggleMask() const
|
||||||
{
|
{
|
||||||
|
@ -376,6 +382,12 @@ CMSWindowsPrimaryScreen::onEvent(CEvent* event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsPrimaryScreen::onOneShotTimerExpired(UInt32 id)
|
||||||
|
{
|
||||||
|
m_receiver->onOneShotTimerExpired(id);
|
||||||
|
}
|
||||||
|
|
||||||
SInt32
|
SInt32
|
||||||
CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
||||||
{
|
{
|
||||||
|
|
|
@ -39,6 +39,7 @@ public:
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual void resetOptions();
|
virtual void resetOptions();
|
||||||
virtual void setOptions(const COptionsList& options);
|
virtual void setOptions(const COptionsList& options);
|
||||||
|
virtual UInt32 addOneShotTimer(double timeout);
|
||||||
virtual KeyModifierMask getToggleMask() const;
|
virtual KeyModifierMask getToggleMask() const;
|
||||||
virtual bool isLockedToScreen() const;
|
virtual bool isLockedToScreen() const;
|
||||||
virtual IScreen* getScreen() const;
|
virtual IScreen* getScreen() const;
|
||||||
|
@ -47,6 +48,7 @@ public:
|
||||||
virtual void onScreensaver(bool activated);
|
virtual void onScreensaver(bool activated);
|
||||||
virtual bool onPreDispatch(const CEvent* event);
|
virtual bool onPreDispatch(const CEvent* event);
|
||||||
virtual bool onEvent(CEvent* event);
|
virtual bool onEvent(CEvent* event);
|
||||||
|
virtual void onOneShotTimerExpired(UInt32 id);
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual void postCreateWindow(HWND);
|
virtual void postCreateWindow(HWND);
|
||||||
virtual void preDestroyWindow(HWND);
|
virtual void preDestroyWindow(HWND);
|
||||||
|
|
|
@ -122,6 +122,11 @@ CMSWindowsScreen::closeDesktop()
|
||||||
// remove timer
|
// remove timer
|
||||||
if (m_timer != 0) {
|
if (m_timer != 0) {
|
||||||
KillTimer(NULL, m_timer);
|
KillTimer(NULL, m_timer);
|
||||||
|
m_timer = 0;
|
||||||
|
}
|
||||||
|
if (m_oneShotTimer != 0) {
|
||||||
|
KillTimer(NULL, m_oneShotTimer);
|
||||||
|
m_oneShotTimer = 0;
|
||||||
}
|
}
|
||||||
|
|
||||||
// disconnect from desktop
|
// disconnect from desktop
|
||||||
|
@ -134,6 +139,18 @@ CMSWindowsScreen::closeDesktop()
|
||||||
assert(m_desk == NULL);
|
assert(m_desk == NULL);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UInt32
|
||||||
|
CMSWindowsScreen::addOneShotTimer(double timeout)
|
||||||
|
{
|
||||||
|
// FIXME -- support multiple one-shot timers
|
||||||
|
if (m_oneShotTimer != 0) {
|
||||||
|
KillTimer(NULL, m_oneShotTimer);
|
||||||
|
}
|
||||||
|
m_oneShotTimer = SetTimer(NULL, 0,
|
||||||
|
static_cast<UINT>(1000.0 * timeout), NULL);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
|
|
||||||
bool
|
bool
|
||||||
CMSWindowsScreen::isMultimon() const
|
CMSWindowsScreen::isMultimon() const
|
||||||
{
|
{
|
||||||
|
@ -205,8 +222,12 @@ CMSWindowsScreen::mainLoop()
|
||||||
event.m_result = 0;
|
event.m_result = 0;
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// wait for an event in a cancellable way
|
// wait for an event in a cancellable way
|
||||||
CThread::waitForEvent();
|
if (CThread::getCurrentThread().waitForEvent(-1.0) != CThread::kEvent) {
|
||||||
GetMessage(&event.m_msg, NULL, 0, 0);
|
continue;
|
||||||
|
}
|
||||||
|
if (!PeekMessage(&event.m_msg, NULL, 0, 0, PM_REMOVE)) {
|
||||||
|
continue;
|
||||||
|
}
|
||||||
|
|
||||||
// handle quit message
|
// handle quit message
|
||||||
if (event.m_msg.message == WM_QUIT) {
|
if (event.m_msg.message == WM_QUIT) {
|
||||||
|
@ -467,6 +488,7 @@ CMSWindowsScreen::onPreDispatch(const CEvent* event)
|
||||||
}
|
}
|
||||||
|
|
||||||
case WM_TIMER:
|
case WM_TIMER:
|
||||||
|
if (msg->wParam == m_timer) {
|
||||||
// if current desktop is not the input desktop then switch to it.
|
// if current desktop is not the input desktop then switch to it.
|
||||||
// windows 95 doesn't support multiple desktops so don't bother
|
// windows 95 doesn't support multiple desktops so don't bother
|
||||||
// to check under it.
|
// to check under it.
|
||||||
|
@ -488,6 +510,13 @@ CMSWindowsScreen::onPreDispatch(const CEvent* event)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
else if (msg->wParam == m_oneShotTimer) {
|
||||||
|
// one shot timer expired
|
||||||
|
KillTimer(NULL, m_oneShotTimer);
|
||||||
|
m_oneShotTimer = 0;
|
||||||
|
m_eventHandler->onOneShotTimerExpired(0);
|
||||||
|
}
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -64,6 +64,14 @@ public:
|
||||||
*/
|
*/
|
||||||
void closeDesktop();
|
void closeDesktop();
|
||||||
|
|
||||||
|
//! Install a one-shot timer
|
||||||
|
/*!
|
||||||
|
Installs a one-shot timer for \c timeout seconds and returns the
|
||||||
|
id of the timer (which will be passed to the receiver's
|
||||||
|
\c onTimerExpired()).
|
||||||
|
*/
|
||||||
|
UInt32 addOneShotTimer(double timeout);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -169,6 +177,9 @@ private:
|
||||||
// the timer used to check for desktop switching
|
// the timer used to check for desktop switching
|
||||||
UINT m_timer;
|
UINT m_timer;
|
||||||
|
|
||||||
|
// the one shot timer
|
||||||
|
UINT m_oneShotTimer;
|
||||||
|
|
||||||
// the current desk and it's name
|
// the current desk and it's name
|
||||||
HDESK m_desk;
|
HDESK m_desk;
|
||||||
CString m_deskName;
|
CString m_deskName;
|
||||||
|
|
|
@ -262,6 +262,12 @@ CMSWindowsSecondaryScreen::onEvent(CEvent* event)
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CMSWindowsSecondaryScreen::onOneShotTimerExpired(UInt32)
|
||||||
|
{
|
||||||
|
// ignore
|
||||||
|
}
|
||||||
|
|
||||||
SInt32
|
SInt32
|
||||||
CMSWindowsSecondaryScreen::getJumpZoneSize() const
|
CMSWindowsSecondaryScreen::getJumpZoneSize() const
|
||||||
{
|
{
|
||||||
|
@ -272,6 +278,11 @@ void
|
||||||
CMSWindowsSecondaryScreen::postCreateWindow(HWND window)
|
CMSWindowsSecondaryScreen::postCreateWindow(HWND window)
|
||||||
{
|
{
|
||||||
m_window = window;
|
m_window = window;
|
||||||
|
|
||||||
|
// update key state
|
||||||
|
updateKeys();
|
||||||
|
|
||||||
|
// hide cursor if this screen isn't active
|
||||||
if (!isActive()) {
|
if (!isActive()) {
|
||||||
showWindow();
|
showWindow();
|
||||||
}
|
}
|
||||||
|
|
|
@ -53,6 +53,7 @@ public:
|
||||||
virtual void onScreensaver(bool activated);
|
virtual void onScreensaver(bool activated);
|
||||||
virtual bool onPreDispatch(const CEvent* event);
|
virtual bool onPreDispatch(const CEvent* event);
|
||||||
virtual bool onEvent(CEvent* event);
|
virtual bool onEvent(CEvent* event);
|
||||||
|
virtual void onOneShotTimerExpired(UInt32 id);
|
||||||
virtual SInt32 getJumpZoneSize() const;
|
virtual SInt32 getJumpZoneSize() const;
|
||||||
virtual void postCreateWindow(HWND);
|
virtual void postCreateWindow(HWND);
|
||||||
virtual void preDestroyWindow(HWND);
|
virtual void preDestroyWindow(HWND);
|
||||||
|
@ -69,6 +70,7 @@ protected:
|
||||||
virtual void hideWindow();
|
virtual void hideWindow();
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual void updateKeys();
|
virtual void updateKeys();
|
||||||
|
virtual void releaseKeys();
|
||||||
virtual void setToggleState(KeyModifierMask);
|
virtual void setToggleState(KeyModifierMask);
|
||||||
virtual KeyModifierMask getToggleState() const;
|
virtual KeyModifierMask getToggleState() const;
|
||||||
|
|
||||||
|
@ -98,7 +100,6 @@ private:
|
||||||
KeyModifierMask, EKeyAction) const;
|
KeyModifierMask, EKeyAction) const;
|
||||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||||
|
|
||||||
void releaseKeys();
|
|
||||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||||
UINT virtualKeyToScanCode(UINT& virtualKey) const;
|
UINT virtualKeyToScanCode(UINT& virtualKey) const;
|
||||||
bool isExtendedKey(UINT virtualKey) const;
|
bool isExtendedKey(UINT virtualKey) const;
|
||||||
|
|
|
@ -260,6 +260,12 @@ mouseHook(int code, WPARAM wParam, LPARAM lParam)
|
||||||
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
|
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
|
||||||
return 1;
|
return 1;
|
||||||
}
|
}
|
||||||
|
else {
|
||||||
|
x += g_xScreen;
|
||||||
|
y += g_yScreen;
|
||||||
|
PostThreadMessage(g_threadID, SYNERGY_MSG_MOUSE_MOVE, x, y);
|
||||||
|
return 0;
|
||||||
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
|
@ -356,7 +356,7 @@ CXWindowsSecondaryScreen::destroyWindow()
|
||||||
CDisplayLock display(m_screen);
|
CDisplayLock display(m_screen);
|
||||||
if (display != NULL) {
|
if (display != NULL) {
|
||||||
// release keys that are still pressed
|
// release keys that are still pressed
|
||||||
releaseKeys(display);
|
doReleaseKeys(display);
|
||||||
|
|
||||||
// no longer impervious to server grabs
|
// no longer impervious to server grabs
|
||||||
XTestGrabControl(display, False);
|
XTestGrabControl(display, False);
|
||||||
|
@ -901,7 +901,7 @@ CXWindowsSecondaryScreen::maskToX(KeyModifierMask inMask) const
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsSecondaryScreen::releaseKeys(Display* display)
|
CXWindowsSecondaryScreen::doReleaseKeys(Display* display)
|
||||||
{
|
{
|
||||||
assert(display != NULL);
|
assert(display != NULL);
|
||||||
|
|
||||||
|
@ -969,6 +969,15 @@ CXWindowsSecondaryScreen::updateKeys()
|
||||||
updateModifiers(display);
|
updateModifiers(display);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CXWindowsSecondaryScreen::releaseKeys()
|
||||||
|
{
|
||||||
|
CDisplayLock display(m_screen);
|
||||||
|
if (display != NULL) {
|
||||||
|
doReleaseKeys(display);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CXWindowsSecondaryScreen::updateModifiers(Display* display)
|
CXWindowsSecondaryScreen::updateModifiers(Display* display)
|
||||||
{
|
{
|
||||||
|
|
|
@ -67,6 +67,7 @@ protected:
|
||||||
virtual void hideWindow();
|
virtual void hideWindow();
|
||||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||||
virtual void updateKeys();
|
virtual void updateKeys();
|
||||||
|
virtual void releaseKeys();
|
||||||
virtual void setToggleState(KeyModifierMask);
|
virtual void setToggleState(KeyModifierMask);
|
||||||
virtual KeyModifierMask getToggleState() const;
|
virtual KeyModifierMask getToggleState() const;
|
||||||
|
|
||||||
|
@ -97,14 +98,10 @@ private:
|
||||||
|
|
||||||
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
|
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
|
||||||
KeyModifierMask, EKeyAction) const;
|
KeyModifierMask, EKeyAction) const;
|
||||||
/*
|
|
||||||
bool findKeyCode(KeyCode&, unsigned int&,
|
|
||||||
KeyID id, unsigned int) const;
|
|
||||||
*/
|
|
||||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||||
unsigned int maskToX(KeyModifierMask) const;
|
unsigned int maskToX(KeyModifierMask) const;
|
||||||
|
|
||||||
void releaseKeys(Display*);
|
void doReleaseKeys(Display*);
|
||||||
void updateKeycodeMap(Display* display);
|
void updateKeycodeMap(Display* display);
|
||||||
void updateModifiers(Display* display);
|
void updateModifiers(Display* display);
|
||||||
void updateModifierMap(Display* display);
|
void updateModifierMap(Display* display);
|
||||||
|
|
|
@ -66,7 +66,8 @@ CServer::CServer(const CString& serverName) :
|
||||||
m_switchWaitEngaged(false),
|
m_switchWaitEngaged(false),
|
||||||
m_switchTwoTapDelay(0.0),
|
m_switchTwoTapDelay(0.0),
|
||||||
m_switchTwoTapEngaged(false),
|
m_switchTwoTapEngaged(false),
|
||||||
m_switchTwoTapArmed(false)
|
m_switchTwoTapArmed(false),
|
||||||
|
m_status(kNotRunning)
|
||||||
{
|
{
|
||||||
// do nothing
|
// do nothing
|
||||||
}
|
}
|
||||||
|
@ -85,14 +86,17 @@ CServer::open()
|
||||||
try {
|
try {
|
||||||
LOG((CLOG_INFO "opening screen"));
|
LOG((CLOG_INFO "opening screen"));
|
||||||
openPrimaryScreen();
|
openPrimaryScreen();
|
||||||
|
setStatus(kNotRunning);
|
||||||
}
|
}
|
||||||
catch (XScreen&) {
|
catch (XScreen& e) {
|
||||||
// can't open screen
|
// can't open screen
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_INFO "failed to open screen"));
|
LOG((CLOG_INFO "failed to open screen"));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
catch (XUnknownClient& e) {
|
catch (XUnknownClient& e) {
|
||||||
// can't open screen
|
// can't open screen
|
||||||
|
setStatus(kServerNameUnknown);
|
||||||
LOG((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str()));
|
LOG((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str()));
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -108,6 +112,7 @@ CServer::mainLoop()
|
||||||
}
|
}
|
||||||
|
|
||||||
try {
|
try {
|
||||||
|
setStatus(kNotRunning);
|
||||||
LOG((CLOG_NOTE "starting server"));
|
LOG((CLOG_NOTE "starting server"));
|
||||||
|
|
||||||
// start listening for new clients
|
// start listening for new clients
|
||||||
|
@ -138,11 +143,13 @@ CServer::mainLoop()
|
||||||
stopThreads(); \
|
stopThreads(); \
|
||||||
delete m_httpServer; \
|
delete m_httpServer; \
|
||||||
m_httpServer = NULL; \
|
m_httpServer = NULL; \
|
||||||
|
runStatusJobs(); \
|
||||||
} while (false)
|
} while (false)
|
||||||
FINALLY;
|
FINALLY;
|
||||||
}
|
}
|
||||||
catch (XMT& e) {
|
catch (XMT& e) {
|
||||||
LOG((CLOG_ERR "server error: %s", e.what()));
|
LOG((CLOG_ERR "server error: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
LOG((CLOG_NOTE "stopping server"));
|
LOG((CLOG_NOTE "stopping server"));
|
||||||
|
@ -151,12 +158,15 @@ CServer::mainLoop()
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
LOG((CLOG_ERR "server error: %s", e.what()));
|
LOG((CLOG_ERR "server error: %s", e.what()));
|
||||||
|
setStatus(kError, e.what());
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
LOG((CLOG_NOTE "stopping server"));
|
LOG((CLOG_NOTE "stopping server"));
|
||||||
FINALLY;
|
FINALLY;
|
||||||
}
|
}
|
||||||
catch (XThread&) {
|
catch (XThread&) {
|
||||||
|
setStatus(kNotRunning);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
LOG((CLOG_NOTE "stopping server"));
|
LOG((CLOG_NOTE "stopping server"));
|
||||||
FINALLY;
|
FINALLY;
|
||||||
|
@ -164,6 +174,7 @@ CServer::mainLoop()
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
LOG((CLOG_DEBUG "unknown server error"));
|
LOG((CLOG_DEBUG "unknown server error"));
|
||||||
|
setStatus(kError);
|
||||||
|
|
||||||
// clean up
|
// clean up
|
||||||
LOG((CLOG_NOTE "stopping server"));
|
LOG((CLOG_NOTE "stopping server"));
|
||||||
|
@ -260,6 +271,9 @@ CServer::setConfig(const CConfig& config)
|
||||||
sendOptions(client);
|
sendOptions(client);
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// notify of status
|
||||||
|
runStatusJobs();
|
||||||
|
|
||||||
return true;
|
return true;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -287,12 +301,52 @@ CServer::setStreamFilterFactory(IStreamFilterFactory* adopted)
|
||||||
m_streamFilterFactory = adopted;
|
m_streamFilterFactory = adopted;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServer::addStatusJob(IJob* job)
|
||||||
|
{
|
||||||
|
m_statusJobs.addJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServer::removeStatusJob(IJob* job)
|
||||||
|
{
|
||||||
|
m_statusJobs.removeJob(job);
|
||||||
|
}
|
||||||
|
|
||||||
CString
|
CString
|
||||||
CServer::getPrimaryScreenName() const
|
CServer::getPrimaryScreenName() const
|
||||||
{
|
{
|
||||||
return m_name;
|
return m_name;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
UInt32
|
||||||
|
CServer::getNumClients() const
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
return m_clients.size();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServer::getClients(std::vector<CString>& list) const
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
list.clear();
|
||||||
|
for (CClientList::const_iterator index = m_clients.begin();
|
||||||
|
index != m_clients.end(); ++index) {
|
||||||
|
list.push_back(index->first);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
CServer::EStatus
|
||||||
|
CServer::getStatus(CString* msg) const
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
if (msg != NULL) {
|
||||||
|
*msg = m_statusMessage;
|
||||||
|
}
|
||||||
|
return m_status;
|
||||||
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServer::getConfig(CConfig* config) const
|
CServer::getConfig(CConfig* config) const
|
||||||
{
|
{
|
||||||
|
@ -302,6 +356,28 @@ CServer::getConfig(CConfig* config) const
|
||||||
*config = m_config;
|
*config = m_config;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServer::runStatusJobs() const
|
||||||
|
{
|
||||||
|
m_statusJobs.runJobs();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CServer::setStatus(EStatus status, const char* msg)
|
||||||
|
{
|
||||||
|
{
|
||||||
|
CLock lock(&m_mutex);
|
||||||
|
m_status = status;
|
||||||
|
if (m_status == kError) {
|
||||||
|
m_statusMessage = (msg == NULL) ? "Error" : msg;
|
||||||
|
}
|
||||||
|
else {
|
||||||
|
m_statusMessage = (msg == NULL) ? "" : msg;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
runStatusJobs();
|
||||||
|
}
|
||||||
|
|
||||||
UInt32
|
UInt32
|
||||||
CServer::getActivePrimarySides() const
|
CServer::getActivePrimarySides() const
|
||||||
{
|
{
|
||||||
|
@ -325,6 +401,8 @@ CServer::getActivePrimarySides() const
|
||||||
void
|
void
|
||||||
CServer::onError()
|
CServer::onError()
|
||||||
{
|
{
|
||||||
|
setStatus(kError);
|
||||||
|
|
||||||
// stop all running threads but don't wait too long since some
|
// stop all running threads but don't wait too long since some
|
||||||
// threads may be unable to proceed until this thread returns.
|
// threads may be unable to proceed until this thread returns.
|
||||||
stopThreads(3.0);
|
stopThreads(3.0);
|
||||||
|
@ -743,6 +821,10 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
|
||||||
case kBottom:
|
case kBottom:
|
||||||
clearWait = (m_y <= ay + ah - 1 + zoneSize);
|
clearWait = (m_y <= ay + ah - 1 + zoneSize);
|
||||||
break;
|
break;
|
||||||
|
|
||||||
|
default:
|
||||||
|
clearWait = false;
|
||||||
|
break;
|
||||||
}
|
}
|
||||||
if (clearWait) {
|
if (clearWait) {
|
||||||
onNoSwitch();
|
onNoSwitch();
|
||||||
|
@ -1174,7 +1256,7 @@ CServer::isSwitchOkay(IClient* newScreen, EDirection dir, SInt32 x, SInt32 y)
|
||||||
|
|
||||||
// if waiting before a switch then prepare to switch later
|
// if waiting before a switch then prepare to switch later
|
||||||
if (!allowSwitch && m_switchWaitDelay > 0.0) {
|
if (!allowSwitch && m_switchWaitDelay > 0.0) {
|
||||||
if (isNewDirection) {
|
if (isNewDirection || !m_switchWaitEngaged) {
|
||||||
m_switchWaitEngaged = true;
|
m_switchWaitEngaged = true;
|
||||||
m_switchWaitX = x;
|
m_switchWaitX = x;
|
||||||
m_switchWaitY = y;
|
m_switchWaitY = y;
|
||||||
|
@ -1413,6 +1495,7 @@ CServer::acceptClients(void*)
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
catch (XSocketAddressInUse& e) {
|
catch (XSocketAddressInUse& e) {
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_WARN "bind failed: %s", e.what()));
|
LOG((CLOG_WARN "bind failed: %s", e.what()));
|
||||||
|
|
||||||
// give up if we've waited too long
|
// give up if we've waited too long
|
||||||
|
@ -1427,6 +1510,7 @@ CServer::acceptClients(void*)
|
||||||
}
|
}
|
||||||
|
|
||||||
// accept connections and begin processing them
|
// accept connections and begin processing them
|
||||||
|
setStatus(kRunning);
|
||||||
LOG((CLOG_DEBUG1 "waiting for client connections"));
|
LOG((CLOG_DEBUG1 "waiting for client connections"));
|
||||||
for (;;) {
|
for (;;) {
|
||||||
// accept connection
|
// accept connection
|
||||||
|
@ -1439,16 +1523,15 @@ CServer::acceptClients(void*)
|
||||||
startThread(new TMethodJob<CServer>(
|
startThread(new TMethodJob<CServer>(
|
||||||
this, &CServer::runClient, socket));
|
this, &CServer::runClient, socket));
|
||||||
}
|
}
|
||||||
|
|
||||||
// clean up
|
|
||||||
delete listen;
|
|
||||||
}
|
}
|
||||||
catch (XBase& e) {
|
catch (XBase& e) {
|
||||||
|
setStatus(kError, e.what());
|
||||||
LOG((CLOG_ERR "cannot listen for clients: %s", e.what()));
|
LOG((CLOG_ERR "cannot listen for clients: %s", e.what()));
|
||||||
delete listen;
|
delete listen;
|
||||||
exitMainLoopWithError();
|
exitMainLoopWithError();
|
||||||
}
|
}
|
||||||
catch (...) {
|
catch (...) {
|
||||||
|
setStatus(kNotRunning);
|
||||||
delete listen;
|
delete listen;
|
||||||
throw;
|
throw;
|
||||||
}
|
}
|
||||||
|
@ -1923,6 +2006,7 @@ CServer::addConnection(IClient* client)
|
||||||
|
|
||||||
LOG((CLOG_DEBUG "adding connection \"%s\"", client->getName().c_str()));
|
LOG((CLOG_DEBUG "adding connection \"%s\"", client->getName().c_str()));
|
||||||
|
|
||||||
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// name must be in our configuration
|
// name must be in our configuration
|
||||||
|
@ -1938,12 +2022,16 @@ CServer::addConnection(IClient* client)
|
||||||
// save screen info
|
// save screen info
|
||||||
m_clients.insert(std::make_pair(client->getName(), client));
|
m_clients.insert(std::make_pair(client->getName(), client));
|
||||||
LOG((CLOG_DEBUG "added connection \"%s\"", client->getName().c_str()));
|
LOG((CLOG_DEBUG "added connection \"%s\"", client->getName().c_str()));
|
||||||
|
}
|
||||||
|
runStatusJobs();
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CServer::removeConnection(const CString& name)
|
CServer::removeConnection(const CString& name)
|
||||||
{
|
{
|
||||||
LOG((CLOG_DEBUG "removing connection \"%s\"", name.c_str()));
|
LOG((CLOG_DEBUG "removing connection \"%s\"", name.c_str()));
|
||||||
|
bool updateStatus;
|
||||||
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
|
||||||
// find client
|
// find client
|
||||||
|
@ -1961,7 +2049,8 @@ CServer::removeConnection(const CString& name)
|
||||||
clearSwitchState();
|
clearSwitchState();
|
||||||
}
|
}
|
||||||
|
|
||||||
// don't notify active screen since it probably already disconnected
|
// don't notify active screen since it probably already
|
||||||
|
// disconnected.
|
||||||
LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->getName().c_str(), m_primaryClient->getName().c_str(), m_x, m_y));
|
LOG((CLOG_INFO "jump from \"%s\" to \"%s\" at %d,%d", active->getName().c_str(), m_primaryClient->getName().c_str(), m_x, m_y));
|
||||||
|
|
||||||
// cut over
|
// cut over
|
||||||
|
@ -1988,6 +2077,13 @@ CServer::removeConnection(const CString& name)
|
||||||
|
|
||||||
// remove any thread for this client
|
// remove any thread for this client
|
||||||
m_clientThreads.erase(name);
|
m_clientThreads.erase(name);
|
||||||
|
|
||||||
|
updateStatus = (m_clients.size() <= 1);
|
||||||
|
}
|
||||||
|
|
||||||
|
if (updateStatus) {
|
||||||
|
runStatusJobs();
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
|
||||||
|
|
|
@ -22,9 +22,11 @@
|
||||||
#include "CCondVar.h"
|
#include "CCondVar.h"
|
||||||
#include "CMutex.h"
|
#include "CMutex.h"
|
||||||
#include "CThread.h"
|
#include "CThread.h"
|
||||||
|
#include "CJobList.h"
|
||||||
#include "CStopwatch.h"
|
#include "CStopwatch.h"
|
||||||
#include "stdlist.h"
|
#include "stdlist.h"
|
||||||
#include "stdmap.h"
|
#include "stdmap.h"
|
||||||
|
#include "stdvector.h"
|
||||||
|
|
||||||
class CClientProxy;
|
class CClientProxy;
|
||||||
class CHTTPServer;
|
class CHTTPServer;
|
||||||
|
@ -42,6 +44,14 @@ This class implements the top-level server algorithms for synergy.
|
||||||
*/
|
*/
|
||||||
class CServer : public IServer, public IPrimaryScreenReceiver {
|
class CServer : public IServer, public IPrimaryScreenReceiver {
|
||||||
public:
|
public:
|
||||||
|
enum EStatus {
|
||||||
|
kNotRunning,
|
||||||
|
kRunning,
|
||||||
|
kServerNameUnknown,
|
||||||
|
kError,
|
||||||
|
kMaxStatus
|
||||||
|
};
|
||||||
|
|
||||||
/*!
|
/*!
|
||||||
The server will look itself up in the configuration using \c serverName
|
The server will look itself up in the configuration using \c serverName
|
||||||
as its name.
|
as its name.
|
||||||
|
@ -116,6 +126,22 @@ public:
|
||||||
*/
|
*/
|
||||||
void setStreamFilterFactory(IStreamFilterFactory*);
|
void setStreamFilterFactory(IStreamFilterFactory*);
|
||||||
|
|
||||||
|
//! Add a job to notify of status changes
|
||||||
|
/*!
|
||||||
|
The added job is run whenever the server's status changes in
|
||||||
|
certain externally visible ways. The client keeps ownership
|
||||||
|
of the job.
|
||||||
|
*/
|
||||||
|
void addStatusJob(IJob*);
|
||||||
|
|
||||||
|
//! Remove a job to notify of status changes
|
||||||
|
/*!
|
||||||
|
Removes a previously added status notification job. A job can
|
||||||
|
remove itself when called but must not remove any other jobs.
|
||||||
|
The client keeps ownership of the job.
|
||||||
|
*/
|
||||||
|
void removeStatusJob(IJob*);
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
//! @name accessors
|
//! @name accessors
|
||||||
//@{
|
//@{
|
||||||
|
@ -132,6 +158,24 @@ public:
|
||||||
*/
|
*/
|
||||||
CString getPrimaryScreenName() const;
|
CString getPrimaryScreenName() const;
|
||||||
|
|
||||||
|
//! Get number of connected clients
|
||||||
|
/*!
|
||||||
|
Returns the number of connected clients, including the server itself.
|
||||||
|
*/
|
||||||
|
UInt32 getNumClients() const;
|
||||||
|
|
||||||
|
//! Get the list of connected clients
|
||||||
|
/*!
|
||||||
|
Set the \c list to the names of the currently connected clients.
|
||||||
|
*/
|
||||||
|
void getClients(std::vector<CString>& list) const;
|
||||||
|
|
||||||
|
//! Get the status
|
||||||
|
/*!
|
||||||
|
Returns the current status and status message.
|
||||||
|
*/
|
||||||
|
EStatus getStatus(CString* = NULL) const;
|
||||||
|
|
||||||
//@}
|
//@}
|
||||||
|
|
||||||
// IServer overrides
|
// IServer overrides
|
||||||
|
@ -170,6 +214,12 @@ protected:
|
||||||
private:
|
private:
|
||||||
typedef std::list<CThread> CThreadList;
|
typedef std::list<CThread> CThreadList;
|
||||||
|
|
||||||
|
// notify status jobs of a change
|
||||||
|
void runStatusJobs() const;
|
||||||
|
|
||||||
|
// set new status
|
||||||
|
void setStatus(EStatus, const char* msg = NULL);
|
||||||
|
|
||||||
// get the sides of the primary screen that have neighbors
|
// get the sides of the primary screen that have neighbors
|
||||||
UInt32 getActivePrimarySides() const;
|
UInt32 getActivePrimarySides() const;
|
||||||
|
|
||||||
|
@ -352,6 +402,11 @@ private:
|
||||||
CStopwatch m_switchTwoTapTimer;
|
CStopwatch m_switchTwoTapTimer;
|
||||||
bool m_switchTwoTapEngaged;
|
bool m_switchTwoTapEngaged;
|
||||||
bool m_switchTwoTapArmed;
|
bool m_switchTwoTapArmed;
|
||||||
|
|
||||||
|
// the status change jobs and status
|
||||||
|
CJobList m_statusJobs;
|
||||||
|
EStatus m_status;
|
||||||
|
CString m_statusMessage;
|
||||||
};
|
};
|
||||||
|
|
||||||
#endif
|
#endif
|
||||||
|
|
|
@ -74,6 +74,30 @@ CSecondaryScreen::open()
|
||||||
// create and prepare our window
|
// create and prepare our window
|
||||||
createWindow();
|
createWindow();
|
||||||
|
|
||||||
|
// subclass hook
|
||||||
|
onPostOpen();
|
||||||
|
|
||||||
|
// reset options
|
||||||
|
resetOptions();
|
||||||
|
}
|
||||||
|
catch (...) {
|
||||||
|
close();
|
||||||
|
throw;
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSecondaryScreen::close()
|
||||||
|
{
|
||||||
|
onPreClose();
|
||||||
|
destroyWindow();
|
||||||
|
getScreen()->close();
|
||||||
|
onPostClose();
|
||||||
|
}
|
||||||
|
|
||||||
|
void
|
||||||
|
CSecondaryScreen::remoteControl()
|
||||||
|
{
|
||||||
// assume primary has all clipboards
|
// assume primary has all clipboards
|
||||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||||
grabClipboard(id);
|
grabClipboard(id);
|
||||||
|
@ -85,17 +109,6 @@ CSecondaryScreen::open()
|
||||||
// disable the screen saver
|
// disable the screen saver
|
||||||
getScreen()->openScreensaver(false);
|
getScreen()->openScreensaver(false);
|
||||||
|
|
||||||
// subclass hook
|
|
||||||
onPostOpen();
|
|
||||||
|
|
||||||
// reset options
|
|
||||||
resetOptions();
|
|
||||||
}
|
|
||||||
catch (...) {
|
|
||||||
close();
|
|
||||||
throw;
|
|
||||||
}
|
|
||||||
|
|
||||||
// hide the cursor
|
// hide the cursor
|
||||||
{
|
{
|
||||||
CLock lock(&m_mutex);
|
CLock lock(&m_mutex);
|
||||||
|
@ -105,13 +118,9 @@ CSecondaryScreen::open()
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
CSecondaryScreen::close()
|
CSecondaryScreen::localControl()
|
||||||
{
|
{
|
||||||
onPreClose();
|
|
||||||
getScreen()->closeScreensaver();
|
getScreen()->closeScreensaver();
|
||||||
destroyWindow();
|
|
||||||
getScreen()->close();
|
|
||||||
onPostClose();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void
|
void
|
||||||
|
|
|
@ -41,11 +41,10 @@ public:
|
||||||
|
|
||||||
//! Open screen
|
//! Open screen
|
||||||
/*!
|
/*!
|
||||||
Opens the screen. This includes initializing the screen,
|
Opens the screen. It also causes events to the reported to an
|
||||||
hiding the cursor, and disabling the screen saver. It also causes
|
IScreenReceiver (which is set through some other interface).
|
||||||
events to the reported to an IScreenReceiver (which is set through
|
Calls close() before returning (rethrowing) if it fails for any
|
||||||
some other interface). Calls close() before returning (rethrowing)
|
reason.
|
||||||
if it fails for any reason.
|
|
||||||
*/
|
*/
|
||||||
void open();
|
void open();
|
||||||
|
|
||||||
|
@ -64,12 +63,26 @@ public:
|
||||||
*/
|
*/
|
||||||
void exitMainLoop();
|
void exitMainLoop();
|
||||||
|
|
||||||
|
//! Prepare for remote control
|
||||||
|
/*!
|
||||||
|
Prepares the screen for remote control by the server. In
|
||||||
|
particular, it disables the screen saver.
|
||||||
|
*/
|
||||||
|
void remoteControl();
|
||||||
|
|
||||||
|
//! Release from remote control
|
||||||
|
/*!
|
||||||
|
Cleans up the screen from remote control by the server. In
|
||||||
|
particular, it enables the screen saver. It also synthesizes
|
||||||
|
key up events for any keys that are logically down; without
|
||||||
|
this the client will leave its keyboard in the wrong logical
|
||||||
|
state.
|
||||||
|
*/
|
||||||
|
void localControl();
|
||||||
|
|
||||||
//! Close screen
|
//! Close screen
|
||||||
/*!
|
/*!
|
||||||
Closes the screen. This restores the screen saver, shows the cursor
|
Closes the screen.
|
||||||
and closes the screen. It also synthesizes key up events for any
|
|
||||||
keys that are logically down; without this the client will leave
|
|
||||||
its keyboard in the wrong logical state.
|
|
||||||
*/
|
*/
|
||||||
void close();
|
void close();
|
||||||
|
|
||||||
|
@ -332,6 +345,13 @@ protected:
|
||||||
*/
|
*/
|
||||||
virtual void updateKeys() = 0;
|
virtual void updateKeys() = 0;
|
||||||
|
|
||||||
|
//! Release keys
|
||||||
|
/*!
|
||||||
|
Synthesizes key release event for any key that our key state
|
||||||
|
says is down.
|
||||||
|
*/
|
||||||
|
virtual void releaseKeys() = 0;
|
||||||
|
|
||||||
//! Synchronize toggle key state
|
//! Synchronize toggle key state
|
||||||
/*!
|
/*!
|
||||||
Toggle modifiers that don't match the given state so that they do.
|
Toggle modifiers that don't match the given state so that they do.
|
||||||
|
|