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.
183
cmd/launcher/CAdvancedOptions.cpp
Normal file
@ -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);
|
||||
}
|
74
cmd/launcher/CAdvancedOptions.h
Normal file
@ -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
|
211
cmd/launcher/CGlobalOptions.cpp
Normal file
@ -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);
|
||||
}
|
66
cmd/launcher/CGlobalOptions.h
Normal file
@ -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);
|
||||
}
|
||||
|
||||
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
|
||||
getAppPath(const CString& appName)
|
||||
{
|
||||
|
@ -42,6 +42,9 @@ CString getWindowText(HWND hwnd);
|
||||
HWND getItem(HWND hwnd, int id);
|
||||
void enableItem(HWND hwnd, int id, bool enabled);
|
||||
|
||||
void setItemChecked(HWND, bool);
|
||||
bool isItemChecked(HWND);
|
||||
|
||||
CString getAppPath(const CString& appName);
|
||||
|
||||
bool loadConfig(CConfig& config);
|
||||
|
@ -16,8 +16,12 @@ DEPTH = ../..
|
||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||
|
||||
EXTRA_DIST = \
|
||||
CAdvancedOptions.cpp \
|
||||
CAdvancedOptions.h \
|
||||
CAutoStart.cpp \
|
||||
CAutoStart.h \
|
||||
CGlobalOptions.cpp \
|
||||
CGlobalOptions.h \
|
||||
LaunchUtil.cpp \
|
||||
LaunchUtil.h \
|
||||
launcher.cpp \
|
||||
|
@ -13,6 +13,8 @@
|
||||
*/
|
||||
|
||||
#include "CConfig.h"
|
||||
#include "KeyTypes.h"
|
||||
#include "OptionTypes.h"
|
||||
#include "ProtocolTypes.h"
|
||||
#include "CLog.h"
|
||||
#include "CStringUtil.h"
|
||||
@ -24,6 +26,8 @@
|
||||
// these must come after the above because it includes windows.h
|
||||
#include "LaunchUtil.h"
|
||||
#include "CAutoStart.h"
|
||||
#include "CGlobalOptions.h"
|
||||
#include "CAdvancedOptions.h"
|
||||
|
||||
#define CONFIG_NAME "synergy.sgc"
|
||||
#define CLIENT_APP "synergyc.exe"
|
||||
@ -47,10 +51,28 @@ public:
|
||||
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 TCHAR* s_layoutClass = TEXT("SynergyLayout");
|
||||
static const CModifierInfo s_modifiers[] = {
|
||||
{ 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] = {
|
||||
{ TEXT("Error"), "ERROR" },
|
||||
@ -63,6 +85,14 @@ static const char* s_debugName[][2] = {
|
||||
};
|
||||
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
|
||||
//
|
||||
@ -127,7 +157,7 @@ bool
|
||||
isClientChecked(HWND hwnd)
|
||||
{
|
||||
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
||||
return (SendMessage(child, BM_GETCHECK, 0, 0) == BST_CHECKED);
|
||||
return isItemChecked(child);
|
||||
}
|
||||
|
||||
static
|
||||
@ -476,58 +506,20 @@ static
|
||||
CString
|
||||
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;
|
||||
if (testing) {
|
||||
// constant testing args
|
||||
cmdLine += " -z --no-restart --no-daemon";
|
||||
|
||||
// debug level testing arg
|
||||
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
||||
cmdLine += " --debug ";
|
||||
cmdLine += s_debugName[SendMessage(child, CB_GETCURSEL, 0, 0)][1];
|
||||
// add constant testing args
|
||||
if (testing) {
|
||||
cmdLine += " -z --no-restart --no-daemon";
|
||||
}
|
||||
cmdLine += " --name ";
|
||||
cmdLine += name;
|
||||
|
||||
// get the server name
|
||||
CString server;
|
||||
bool isClient = isClientChecked(hwnd);
|
||||
if (isClient) {
|
||||
// check server name
|
||||
child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
||||
CString server = getWindowText(child);
|
||||
HWND child = getItem(hwnd, IDC_MAIN_CLIENT_SERVER_NAME_EDIT);
|
||||
server = getWindowText(child);
|
||||
if (!ARG->m_config.isValidScreenName(server)) {
|
||||
showError(hwnd, CStringUtil::format(
|
||||
getString(IDS_INVALID_SERVER_NAME).c_str(),
|
||||
@ -551,16 +543,19 @@ getCommandLine(HWND hwnd, bool testing)
|
||||
if (testing) {
|
||||
cmdLine += " --no-camp";
|
||||
}
|
||||
cmdLine += " ";
|
||||
cmdLine += server;
|
||||
cmdLine += ":";
|
||||
cmdLine += portString;
|
||||
}
|
||||
else {
|
||||
cmdLine += " --address :";
|
||||
cmdLine += portString;
|
||||
|
||||
// debug level
|
||||
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;
|
||||
}
|
||||
|
||||
@ -711,11 +706,9 @@ initMainWindow(HWND hwnd)
|
||||
// choose client/server radio buttons
|
||||
HWND child;
|
||||
child = getItem(hwnd, IDC_MAIN_CLIENT_RADIO);
|
||||
SendMessage(child, BM_SETCHECK, !configLoaded ?
|
||||
BST_CHECKED : BST_UNCHECKED, 0);
|
||||
setItemChecked(child, !configLoaded);
|
||||
child = getItem(hwnd, IDC_MAIN_SERVER_RADIO);
|
||||
SendMessage(child, BM_SETCHECK, configLoaded ?
|
||||
BST_CHECKED : BST_UNCHECKED, 0);
|
||||
setItemChecked(child, configLoaded);
|
||||
|
||||
// if config is loaded then initialize server controls
|
||||
if (configLoaded) {
|
||||
@ -729,16 +722,7 @@ initMainWindow(HWND hwnd)
|
||||
}
|
||||
}
|
||||
|
||||
// initialize other controls
|
||||
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());
|
||||
|
||||
// debug level
|
||||
child = getItem(hwnd, IDC_MAIN_DEBUG);
|
||||
for (unsigned int i = 0; i < sizeof(s_debugName) /
|
||||
sizeof(s_debugName[0]); ++i) {
|
||||
@ -794,19 +778,32 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
CConfig::CScreenOptions::const_iterator index;
|
||||
child = getItem(hwnd, IDC_ADD_HD_CAPS_CHECK);
|
||||
index = info->m_options.find(kOptionHalfDuplexCapsLock);
|
||||
if (index != info->m_options.end() && index->second != 0) {
|
||||
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
|
||||
}
|
||||
else {
|
||||
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
|
||||
}
|
||||
setItemChecked(child, (index != info->m_options.end() &&
|
||||
index->second != 0));
|
||||
child = getItem(hwnd, IDC_ADD_HD_NUM_CHECK);
|
||||
index = info->m_options.find(kOptionHalfDuplexNumLock);
|
||||
if (index != info->m_options.end() && index->second != 0) {
|
||||
SendMessage(child, BM_SETCHECK, BST_CHECKED, 0);
|
||||
}
|
||||
else {
|
||||
SendMessage(child, BM_SETCHECK, BST_UNCHECKED, 0);
|
||||
setItemChecked(child, (index != info->m_options.end() &&
|
||||
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);
|
||||
}
|
||||
|
||||
// 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;
|
||||
@ -883,20 +880,36 @@ addDlgProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
|
||||
// save options
|
||||
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;
|
||||
}
|
||||
else {
|
||||
info->m_options.erase(kOptionHalfDuplexCapsLock);
|
||||
}
|
||||
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;
|
||||
}
|
||||
else {
|
||||
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
|
||||
EndDialog(hwnd, 1);
|
||||
info = NULL;
|
||||
@ -1065,6 +1078,16 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
|
||||
case IDC_MAIN_OPTIONS:
|
||||
s_globalOptions->doModal();
|
||||
enableSaveControls(hwnd);
|
||||
break;
|
||||
|
||||
case IDC_MAIN_ADVANCED:
|
||||
s_advancedOptions->doModal(isClientChecked(hwnd));
|
||||
enableSaveControls(hwnd);
|
||||
break;
|
||||
}
|
||||
|
||||
default:
|
||||
@ -1076,7 +1099,7 @@ mainWndProc(HWND hwnd, UINT message, WPARAM wParam, LPARAM lParam)
|
||||
int WINAPI
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||
{
|
||||
CArch arch;
|
||||
CArch arch(instance);
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
@ -1108,8 +1131,10 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int nCmdShow)
|
||||
HWND m_mainWindow = CreateDialog(s_instance,
|
||||
MAKEINTRESOURCE(IDD_MAIN), 0, NULL);
|
||||
|
||||
// prep window
|
||||
// prep windows
|
||||
initMainWindow(m_mainWindow);
|
||||
s_globalOptions = new CGlobalOptions(m_mainWindow, &ARG->m_config);
|
||||
s_advancedOptions = new CAdvancedOptions(m_mainWindow, &ARG->m_config);
|
||||
|
||||
// show window
|
||||
ShowWindow(m_mainWindow, nCmdShow);
|
||||
|
@ -95,10 +95,18 @@ LINK32=link.exe
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CAdvancedOptions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CAutoStart.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CGlobalOptions.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\launcher.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -115,10 +123,18 @@ SOURCE=.\LaunchUtil.cpp
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CAdvancedOptions.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CAutoStart.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CGlobalOptions.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\LaunchUtil.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -40,11 +40,14 @@
|
||||
#define IDS_SERVER_IS_CLIENT 36
|
||||
#define IDS_ADD_SCREEN 37
|
||||
#define IDS_EDIT_SCREEN 38
|
||||
#define IDS_INVALID_TIME 39
|
||||
#define IDD_MAIN 101
|
||||
#define IDD_ADD 102
|
||||
#define IDD_WAIT 103
|
||||
#define IDI_SYNERGY 104
|
||||
#define IDD_AUTOSTART 105
|
||||
#define IDD_ADVANCED_OPTIONS 106
|
||||
#define IDD_GLOBAL_OPTIONS 107
|
||||
#define IDC_MAIN_CLIENT_RADIO 1000
|
||||
#define IDC_MAIN_SERVER_RADIO 1001
|
||||
#define IDC_MAIN_CLIENT_SERVER_NAME_EDIT 1002
|
||||
@ -76,18 +79,31 @@
|
||||
#define IDC_AUTOSTART_INSTALL_USER 1033
|
||||
#define IDC_AUTOSTART_INSTALL_SYSTEM 1034
|
||||
#define IDC_MAIN_AUTOSTART 1035
|
||||
#define IDC_MAIN_DEBUG 1036
|
||||
#define IDC_MAIN_OPTIONS 1036
|
||||
#define IDC_ADD_HD_CAPS_CHECK 1037
|
||||
#define IDC_MAIN_ADVANCED 1037
|
||||
#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
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#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_CONTROL_VALUE 1038
|
||||
#define _APS_NEXT_CONTROL_VALUE 1044
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
163
cmd/synergyc/CClientTaskBarReceiver.cpp
Normal file
@ -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();
|
||||
}
|
110
cmd/synergyc/CClientTaskBarReceiver.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef 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
|
280
cmd/synergyc/CMSWindowsClientTaskBarReceiver.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
58
cmd/synergyc/CMSWindowsClientTaskBarReceiver.h
Normal file
@ -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
|
61
cmd/synergyc/CXWindowsClientTaskBarReceiver.cpp
Normal file
@ -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
|
||||
}
|
37
cmd/synergyc/CXWindowsClientTaskBarReceiver.h
Normal file
@ -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
|
@ -15,19 +15,29 @@ NULL =
|
||||
DEPTH = ../..
|
||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||
|
||||
EXTRA_DIST = \
|
||||
resource.h \
|
||||
synergyc.dsp \
|
||||
synergyc.ico \
|
||||
synergyc.rc \
|
||||
EXTRA_DIST = \
|
||||
CMSWindowsClientTaskBarReceiver.cpp \
|
||||
CMSWindowsClientTaskBarReceiver.h \
|
||||
resource.h \
|
||||
synergyc.dsp \
|
||||
synergyc.ico \
|
||||
synergyc.rc \
|
||||
tb_error.ico \
|
||||
tb_idle.ico \
|
||||
tb_run.ico \
|
||||
tb_wait.ico \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in \
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = synergyc
|
||||
synergyc_SOURCES = \
|
||||
CClientTaskBarReceiver.cpp \
|
||||
CClientTaskBarReceiver.h \
|
||||
CXWindowsClientTaskBarReceiver.cpp \
|
||||
CXWindowsClientTaskBarReceiver.h \
|
||||
synergyc.cpp \
|
||||
$(NULL)
|
||||
synergyc_LDADD = \
|
||||
|
@ -4,6 +4,15 @@
|
||||
//
|
||||
#define IDS_FAILED 1
|
||||
#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
|
||||
//
|
||||
|
@ -25,6 +25,7 @@
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CFunctionJob.h"
|
||||
#include "CLog.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CString.h"
|
||||
@ -34,12 +35,15 @@
|
||||
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CMSWindowsSecondaryScreen.h"
|
||||
#include "CMSWindowsClientTaskBarReceiver.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsSecondaryScreen.h"
|
||||
#include "CXWindowsClientTaskBarReceiver.h"
|
||||
#endif
|
||||
|
||||
// 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
|
||||
//
|
||||
|
||||
static CClient* s_client = NULL;
|
||||
static CClient* s_client = NULL;
|
||||
static CClientTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||
|
||||
static
|
||||
int
|
||||
@ -137,6 +176,7 @@ realMain(void)
|
||||
|
||||
// open client
|
||||
try {
|
||||
s_taskBarReceiver->setClient(s_client);
|
||||
s_client->open();
|
||||
opened = true;
|
||||
|
||||
@ -160,11 +200,10 @@ realMain(void)
|
||||
DAEMON_RUNNING(false); \
|
||||
locked = true; \
|
||||
} \
|
||||
if (s_client != NULL) { \
|
||||
if (opened) { \
|
||||
s_client->close(); \
|
||||
} \
|
||||
if (opened) { \
|
||||
s_client->close(); \
|
||||
} \
|
||||
s_taskBarReceiver->setClient(NULL); \
|
||||
delete s_client; \
|
||||
s_client = NULL; \
|
||||
} while (false)
|
||||
@ -205,6 +244,43 @@ realMain(void)
|
||||
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
|
||||
@ -273,7 +349,7 @@ help()
|
||||
|
||||
static
|
||||
bool
|
||||
isArg(int argi, int argc, const char** argv,
|
||||
isArg(int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters = 0)
|
||||
{
|
||||
@ -294,7 +370,7 @@ isArg(int argi, int argc, const char** argv,
|
||||
|
||||
static
|
||||
void
|
||||
parse(int argc, const char** argv)
|
||||
parse(int argc, const char* const* argv)
|
||||
{
|
||||
assert(ARG->m_pname != 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
|
||||
@ -441,8 +507,6 @@ useSystemLog()
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
|
||||
#include "CMSWindowsScreen.h"
|
||||
|
||||
static bool s_hasImportantLogMessages = false;
|
||||
|
||||
//
|
||||
@ -494,7 +558,10 @@ static
|
||||
int
|
||||
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
|
||||
bye = &byeThrow;
|
||||
@ -513,14 +580,62 @@ static
|
||||
int
|
||||
daemonStartup95(int, const char**)
|
||||
{
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
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
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
CArch arch;
|
||||
CArch arch(instance);
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
@ -533,52 +648,27 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
// send PRINT and FATAL output to a message box
|
||||
CLOG->insert(new CMessageBoxOutputter);
|
||||
|
||||
// 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()) {
|
||||
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;
|
||||
}
|
||||
// make the task bar receiver. the user can control this app
|
||||
// through the task bar.
|
||||
s_taskBarReceiver = new CMSWindowsClientTaskBarReceiver(instance);
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
// parse command line
|
||||
parse(__argc, const_cast<const char**>(__argv));
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
result = 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));
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
useSystemLog();
|
||||
result = realMain();
|
||||
}
|
||||
try {
|
||||
// run in foreground or as a daemon
|
||||
result = run(__argc, __argv);
|
||||
}
|
||||
else {
|
||||
// run
|
||||
result = realMain();
|
||||
catch (...) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
@ -598,7 +688,7 @@ static
|
||||
int
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
useSystemLog();
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return realMain();
|
||||
}
|
||||
|
||||
@ -612,8 +702,13 @@ main(int argc, char** argv)
|
||||
// get program name
|
||||
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(argc, const_cast<const char**>(argv));
|
||||
parse(argc, argv);
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
@ -630,6 +725,9 @@ main(int argc, char** argv)
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,14 @@ LINK32=link.exe
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CClientTaskBarReceiver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsClientTaskBarReceiver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\synergyc.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -106,6 +114,14 @@ SOURCE=.\synergyc.rc
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CClientTaskBarReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsClientTaskBarReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.h
|
||||
# End Source File
|
||||
# End Group
|
||||
@ -116,6 +132,22 @@ SOURCE=.\resource.h
|
||||
|
||||
SOURCE=.\synergyc.ico
|
||||
# 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 Target
|
||||
# End Project
|
||||
|
BIN
cmd/synergyc/tb_error.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergyc/tb_idle.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergyc/tb_run.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergyc/tb_wait.ico
Normal file
After Width: | Height: | Size: 318 B |
300
cmd/synergys/CMSWindowsServerTaskBarReceiver.cpp
Normal file
@ -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;
|
||||
}
|
||||
}
|
58
cmd/synergys/CMSWindowsServerTaskBarReceiver.h
Normal file
@ -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
|
171
cmd/synergys/CServerTaskBarReceiver.cpp
Normal file
@ -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();
|
||||
}
|
110
cmd/synergys/CServerTaskBarReceiver.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef 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
|
61
cmd/synergys/CXWindowsServerTaskBarReceiver.cpp
Normal file
@ -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
|
||||
}
|
37
cmd/synergys/CXWindowsServerTaskBarReceiver.h
Normal file
@ -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
|
@ -15,19 +15,29 @@ NULL =
|
||||
DEPTH = ../..
|
||||
VDEPTH = ./$(VPATH)/$(DEPTH)
|
||||
|
||||
EXTRA_DIST = \
|
||||
resource.h \
|
||||
synergys.ico \
|
||||
synergys.dsp \
|
||||
synergys.rc \
|
||||
EXTRA_DIST = \
|
||||
CMSWindowsServerTaskBarReceiver.cpp \
|
||||
CMSWindowsServerTaskBarReceiver.h \
|
||||
resource.h \
|
||||
synergys.ico \
|
||||
synergys.dsp \
|
||||
synergys.rc \
|
||||
tb_error.ico \
|
||||
tb_idle.ico \
|
||||
tb_run.ico \
|
||||
tb_wait.ico \
|
||||
$(NULL)
|
||||
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in \
|
||||
MAINTAINERCLEANFILES = \
|
||||
Makefile.in \
|
||||
$(NULL)
|
||||
|
||||
bin_PROGRAMS = synergys
|
||||
synergys_SOURCES = \
|
||||
CServerTaskBarReceiver.cpp \
|
||||
CServerTaskBarReceiver.h \
|
||||
CXWindowsServerTaskBarReceiver.cpp \
|
||||
CXWindowsServerTaskBarReceiver.h \
|
||||
synergys.cpp \
|
||||
$(NULL)
|
||||
synergys_LDADD = \
|
||||
|
@ -4,14 +4,24 @@
|
||||
//
|
||||
#define IDS_FAILED 1
|
||||
#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
|
||||
//
|
||||
#ifdef APSTUDIO_INVOKED
|
||||
#ifndef APSTUDIO_READONLY_SYMBOLS
|
||||
#define _APS_NEXT_RESOURCE_VALUE 102
|
||||
#define _APS_NEXT_COMMAND_VALUE 40001
|
||||
#define _APS_NEXT_CONTROL_VALUE 1000
|
||||
#define _APS_NEXT_RESOURCE_VALUE 109
|
||||
#define _APS_NEXT_COMMAND_VALUE 40005
|
||||
#define _APS_NEXT_CONTROL_VALUE 1003
|
||||
#define _APS_NEXT_SYMED_VALUE 101
|
||||
#endif
|
||||
#endif
|
||||
|
@ -24,6 +24,7 @@
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "XThread.h"
|
||||
#include "CFunctionJob.h"
|
||||
#include "CLog.h"
|
||||
#include "LogOutputters.h"
|
||||
#include "CArch.h"
|
||||
@ -33,12 +34,15 @@
|
||||
|
||||
#define DAEMON_RUNNING(running_)
|
||||
#if WINDOWS_LIKE
|
||||
#include "CMSWindowsScreen.h"
|
||||
#include "CMSWindowsPrimaryScreen.h"
|
||||
#include "CMSWindowsServerTaskBarReceiver.h"
|
||||
#include "resource.h"
|
||||
#undef DAEMON_RUNNING
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
#elif UNIX_LIKE
|
||||
#include "CXWindowsPrimaryScreen.h"
|
||||
#include "CXWindowsServerTaskBarReceiver.h"
|
||||
#endif
|
||||
|
||||
// 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
|
||||
//
|
||||
|
||||
static CServer* s_server = NULL;
|
||||
static CServer* s_server = NULL;
|
||||
static CServerTaskBarReceiver* s_taskBarReceiver = NULL;
|
||||
|
||||
static
|
||||
int
|
||||
@ -168,6 +207,7 @@ realMain(void)
|
||||
|
||||
// open server
|
||||
try {
|
||||
s_taskBarReceiver->setServer(s_server);
|
||||
s_server->open();
|
||||
opened = true;
|
||||
|
||||
@ -177,18 +217,17 @@ realMain(void)
|
||||
s_server->mainLoop();
|
||||
|
||||
// clean up
|
||||
#define FINALLY do { \
|
||||
if (!locked) { \
|
||||
DAEMON_RUNNING(false); \
|
||||
locked = true; \
|
||||
} \
|
||||
if (s_server != NULL) { \
|
||||
if (opened) { \
|
||||
s_server->close(); \
|
||||
} \
|
||||
} \
|
||||
delete s_server; \
|
||||
s_server = NULL; \
|
||||
#define FINALLY do { \
|
||||
if (!locked) { \
|
||||
DAEMON_RUNNING(false); \
|
||||
locked = true; \
|
||||
} \
|
||||
if (opened) { \
|
||||
s_server->close(); \
|
||||
} \
|
||||
s_taskBarReceiver->setServer(NULL); \
|
||||
delete s_server; \
|
||||
s_server = NULL; \
|
||||
} while (false)
|
||||
FINALLY;
|
||||
}
|
||||
@ -227,6 +266,41 @@ realMain(void)
|
||||
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
|
||||
@ -329,7 +403,7 @@ PLATFORM_EXTRA
|
||||
|
||||
static
|
||||
bool
|
||||
isArg(int argi, int argc, const char** argv,
|
||||
isArg(int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters = 0)
|
||||
{
|
||||
@ -350,7 +424,7 @@ isArg(int argi, int argc, const char** argv,
|
||||
|
||||
static
|
||||
void
|
||||
parse(int argc, const char** argv)
|
||||
parse(int argc, const char* const* argv)
|
||||
{
|
||||
assert(ARG->m_pname != 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
|
||||
@ -570,8 +634,6 @@ useSystemLog()
|
||||
|
||||
#if WINDOWS_LIKE
|
||||
|
||||
#include "CMSWindowsScreen.h"
|
||||
|
||||
static bool s_hasImportantLogMessages = false;
|
||||
|
||||
//
|
||||
@ -623,7 +685,10 @@ static
|
||||
int
|
||||
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
|
||||
bye = &byeThrow;
|
||||
@ -645,14 +710,65 @@ static
|
||||
int
|
||||
daemonStartup95(int, const char**)
|
||||
{
|
||||
useSystemLog();
|
||||
return realMain();
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
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
|
||||
WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
{
|
||||
CArch arch;
|
||||
CArch arch(instance);
|
||||
CLOG;
|
||||
CArgs args;
|
||||
|
||||
@ -665,55 +781,27 @@ WinMain(HINSTANCE instance, HINSTANCE, LPSTR, int)
|
||||
// send PRINT and FATAL output to a message box
|
||||
CLOG->insert(new CMessageBoxOutputter);
|
||||
|
||||
// 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()) {
|
||||
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;
|
||||
}
|
||||
// make the task bar receiver. the user can control this app
|
||||
// through the task bar.
|
||||
s_taskBarReceiver = new CMSWindowsServerTaskBarReceiver(instance);
|
||||
s_taskBarReceiver->setQuitJob(new CQuitJob(CThread::getCurrentThread()));
|
||||
|
||||
// parse command line
|
||||
parse(__argc, const_cast<const char**>(__argv));
|
||||
|
||||
// load configuration
|
||||
loadConfig();
|
||||
|
||||
// daemonize if requested
|
||||
int result;
|
||||
if (ARG->m_daemon) {
|
||||
// start as a daemon
|
||||
if (CArchMiscWindows::isWindows95Family()) {
|
||||
try {
|
||||
result = 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));
|
||||
result = kExitFailed;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// cannot start a service from the command line so just
|
||||
// run normally (except with log messages redirected).
|
||||
useSystemLog();
|
||||
result = realMain();
|
||||
}
|
||||
try {
|
||||
// run in foreground or as a daemon
|
||||
result = run(__argc, __argv);
|
||||
}
|
||||
else {
|
||||
// run
|
||||
result = realMain();
|
||||
catch (...) {
|
||||
// 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;
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
// let user examine any messages if we're running as a backend
|
||||
// by putting up a dialog box before exiting.
|
||||
if (ARG->m_backend && s_hasImportantLogMessages) {
|
||||
@ -733,7 +821,7 @@ static
|
||||
int
|
||||
daemonStartup(int, const char**)
|
||||
{
|
||||
useSystemLog();
|
||||
CSystemLogger sysLogger(DAEMON_NAME);
|
||||
return realMain();
|
||||
}
|
||||
|
||||
@ -747,8 +835,13 @@ main(int argc, char** argv)
|
||||
// get program name
|
||||
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(argc, const_cast<const char**>(argv));
|
||||
parse(argc, argv);
|
||||
|
||||
// load configuration
|
||||
loadConfig();
|
||||
@ -768,6 +861,9 @@ main(int argc, char** argv)
|
||||
result = realMain();
|
||||
}
|
||||
|
||||
// done with task bar receiver
|
||||
delete s_taskBarReceiver;
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
|
@ -94,6 +94,14 @@ LINK32=link.exe
|
||||
# PROP Default_Filter "cpp;c;cxx;rc;def;r;odl;idl;hpj;bat"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsServerTaskBarReceiver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServerTaskBarReceiver.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\synergys.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -106,6 +114,14 @@ SOURCE=.\synergys.rc
|
||||
# PROP Default_Filter "h;hpp;hxx;hm;inl"
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CMSWindowsServerTaskBarReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CServerTaskBarReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\resource.h
|
||||
# End Source File
|
||||
# End Group
|
||||
@ -116,6 +132,22 @@ SOURCE=.\resource.h
|
||||
|
||||
SOURCE=.\synergys.ico
|
||||
# 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 Target
|
||||
# End Project
|
||||
|
BIN
cmd/synergys/tb_error.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergys/tb_idle.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergys/tb_run.ico
Normal file
After Width: | Height: | Size: 318 B |
BIN
cmd/synergys/tb_wait.ico
Normal file
After Width: | Height: | Size: 318 B |
@ -23,6 +23,7 @@
|
||||
#undef ARCH_NETWORK
|
||||
#undef ARCH_SLEEP
|
||||
#undef ARCH_STRING
|
||||
#undef ARCH_TASKBAR
|
||||
#undef ARCH_TIME
|
||||
|
||||
// include appropriate architecture implementation
|
||||
@ -35,6 +36,7 @@
|
||||
# include "CArchNetworkWinsock.h"
|
||||
# include "CArchSleepWindows.h"
|
||||
# include "CArchStringWindows.h"
|
||||
# include "CArchTaskBarWindows.h"
|
||||
# include "CArchTimeWindows.h"
|
||||
#elif UNIX_LIKE
|
||||
# include "CArchConsoleUnix.h"
|
||||
@ -47,6 +49,7 @@
|
||||
# include "CArchNetworkBSD.h"
|
||||
# include "CArchSleepUnix.h"
|
||||
# include "CArchStringUnix.h"
|
||||
# include "CArchTaskBarXWindows.h"
|
||||
# include "CArchTimeUnix.h"
|
||||
#endif
|
||||
|
||||
@ -82,6 +85,10 @@
|
||||
# error unsupported platform for string
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_TASKBAR)
|
||||
# error unsupported platform for taskbar
|
||||
#endif
|
||||
|
||||
#if !defined(ARCH_TIME)
|
||||
# error unsupported platform for time
|
||||
#endif
|
||||
@ -92,7 +99,7 @@
|
||||
|
||||
CArch* CArch::s_instance = NULL;
|
||||
|
||||
CArch::CArch(ARCH_ARGS)
|
||||
CArch::CArch(ARCH_ARGS* args)
|
||||
{
|
||||
// only once instance of CArch
|
||||
assert(s_instance == NULL);
|
||||
@ -108,11 +115,13 @@ CArch::CArch(ARCH_ARGS)
|
||||
m_time = new ARCH_TIME;
|
||||
m_console = new ARCH_CONSOLE;
|
||||
m_daemon = new ARCH_DAEMON;
|
||||
m_taskbar = new ARCH_TASKBAR(args);
|
||||
}
|
||||
|
||||
CArch::~CArch()
|
||||
{
|
||||
// clean up
|
||||
delete m_taskbar;
|
||||
delete m_daemon;
|
||||
delete m_console;
|
||||
delete m_time;
|
||||
@ -337,10 +346,10 @@ CArch::wait(CArchThread thread, double timeout)
|
||||
return m_mt->wait(thread, timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
CArch::waitForEvent(double timeout)
|
||||
IArchMultithread::EWaitResult
|
||||
CArch::waitForEvent(CArchThread thread, double timeout)
|
||||
{
|
||||
return m_mt->waitForEvent(timeout);
|
||||
return m_mt->waitForEvent(thread, timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
@ -577,6 +586,24 @@ CArch::getWideCharEncoding()
|
||||
return m_string->getWideCharEncoding();
|
||||
}
|
||||
|
||||
void
|
||||
CArch::addReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
m_taskbar->addReceiver(receiver);
|
||||
}
|
||||
|
||||
void
|
||||
CArch::removeReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
m_taskbar->removeReceiver(receiver);
|
||||
}
|
||||
|
||||
void
|
||||
CArch::updateReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
m_taskbar->updateReceiver(receiver);
|
||||
}
|
||||
|
||||
double
|
||||
CArch::time()
|
||||
{
|
||||
|
@ -23,6 +23,7 @@
|
||||
#include "IArchNetwork.h"
|
||||
#include "IArchSleep.h"
|
||||
#include "IArchString.h"
|
||||
#include "IArchTaskBar.h"
|
||||
#include "IArchTime.h"
|
||||
|
||||
/*!
|
||||
@ -31,7 +32,7 @@ This macro evaluates to the singleton CArch object.
|
||||
*/
|
||||
#define ARCH (CArch::getInstance())
|
||||
|
||||
#define ARCH_ARGS
|
||||
#define ARCH_ARGS void
|
||||
|
||||
//! Delegating mplementation of architecture dependent interfaces
|
||||
/*!
|
||||
@ -51,9 +52,10 @@ class CArch : public IArchConsole,
|
||||
public IArchNetwork,
|
||||
public IArchSleep,
|
||||
public IArchString,
|
||||
public IArchTaskBar,
|
||||
public IArchTime {
|
||||
public:
|
||||
CArch(ARCH_ARGS);
|
||||
CArch(ARCH_ARGS* args = NULL);
|
||||
~CArch();
|
||||
|
||||
//
|
||||
@ -114,7 +116,7 @@ public:
|
||||
virtual void setPriorityOfThread(CArchThread, int n);
|
||||
virtual void testCancelThread();
|
||||
virtual bool wait(CArchThread, double timeout);
|
||||
virtual bool waitForEvent(double timeout);
|
||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||
virtual bool isSameThread(CArchThread, CArchThread);
|
||||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
@ -164,6 +166,11 @@ public:
|
||||
virtual EWideCharEncoding
|
||||
getWideCharEncoding();
|
||||
|
||||
// IArchTaskBar
|
||||
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||
|
||||
// IArchTime overrides
|
||||
virtual double time();
|
||||
|
||||
@ -178,6 +185,7 @@ private:
|
||||
IArchNetwork* m_net;
|
||||
IArchSleep* m_sleep;
|
||||
IArchString* m_string;
|
||||
IArchTaskBar* m_taskbar;
|
||||
IArchTime* m_time;
|
||||
};
|
||||
|
||||
|
@ -13,6 +13,7 @@
|
||||
*/
|
||||
|
||||
#include "CArchConsoleWindows.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "CArch.h"
|
||||
#include <cstdio>
|
||||
|
||||
@ -20,12 +21,12 @@
|
||||
// CArchConsoleWindows
|
||||
//
|
||||
|
||||
DWORD CArchConsoleWindows::s_thread = 0;
|
||||
CArchThread CArchConsoleWindows::s_thread = 0;
|
||||
|
||||
CArchConsoleWindows::CArchConsoleWindows() :
|
||||
m_output(NULL)
|
||||
{
|
||||
s_thread = GetCurrentThreadId();
|
||||
s_thread = ARCH->newCurrentThread();
|
||||
|
||||
m_mutex = ARCH->newMutex();
|
||||
}
|
||||
@ -33,6 +34,7 @@ CArchConsoleWindows::CArchConsoleWindows() :
|
||||
CArchConsoleWindows::~CArchConsoleWindows()
|
||||
{
|
||||
ARCH->closeMutex(m_mutex);
|
||||
ARCH->closeThread(s_thread);
|
||||
}
|
||||
|
||||
void
|
||||
@ -101,7 +103,7 @@ CArchConsoleWindows::getNewlineForConsole()
|
||||
BOOL WINAPI
|
||||
CArchConsoleWindows::signalHandler(DWORD)
|
||||
{
|
||||
// terminate cleanly and skip remaining handlers
|
||||
PostThreadMessage(s_thread, WM_QUIT, 0, 0);
|
||||
// terminate thread and skip remaining handlers
|
||||
ARCH->cancelThread(s_thread);
|
||||
return TRUE;
|
||||
}
|
||||
|
@ -39,7 +39,7 @@ private:
|
||||
static BOOL WINAPI signalHandler(DWORD);
|
||||
|
||||
private:
|
||||
static DWORD s_thread;
|
||||
static CArchThread s_thread;
|
||||
|
||||
CArchMutex m_mutex;
|
||||
HANDLE m_output;
|
||||
|
@ -25,6 +25,7 @@
|
||||
# include "CArchNetworkWinsock.cpp"
|
||||
# include "CArchSleepWindows.cpp"
|
||||
# include "CArchStringWindows.cpp"
|
||||
# include "CArchTaskBarWindows.cpp"
|
||||
# include "CArchTimeWindows.cpp"
|
||||
# include "XArchWindows.cpp"
|
||||
#elif UNIX_LIKE
|
||||
@ -38,6 +39,7 @@
|
||||
# include "CArchNetworkBSD.cpp"
|
||||
# include "CArchSleepUnix.cpp"
|
||||
# include "CArchStringUnix.cpp"
|
||||
# include "CArchTaskBarXWindows.cpp"
|
||||
# include "CArchTimeUnix.cpp"
|
||||
# include "XArchUnix.cpp"
|
||||
#endif
|
||||
|
@ -517,11 +517,11 @@ CArchMultithreadPosix::wait(CArchThread target, double timeout)
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchMultithreadPosix::waitForEvent(double /*timeout*/)
|
||||
IArchMultithread::EWaitResult
|
||||
CArchMultithreadPosix::waitForEvent(CArchThread, double /*timeout*/)
|
||||
{
|
||||
// not implemented
|
||||
return false;
|
||||
return kTimeout;
|
||||
}
|
||||
|
||||
bool
|
||||
|
@ -55,7 +55,7 @@ public:
|
||||
virtual void setPriorityOfThread(CArchThread, int n);
|
||||
virtual void testCancelThread();
|
||||
virtual bool wait(CArchThread, double timeout);
|
||||
virtual bool waitForEvent(double timeout);
|
||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||
virtual bool isSameThread(CArchThread, CArchThread);
|
||||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
|
@ -453,6 +453,89 @@ CArchMultithreadWindows::wait(CArchThread target, double timeout)
|
||||
}
|
||||
}
|
||||
|
||||
IArchMultithread::EWaitResult
|
||||
CArchMultithreadWindows::waitForEvent(CArchThread target, double timeout)
|
||||
{
|
||||
// find current thread. ref the target so it can't go away while
|
||||
// we're watching it.
|
||||
lockMutex(m_threadMutex);
|
||||
CArchThreadImpl* self = findNoRef(GetCurrentThreadId());
|
||||
assert(self != NULL);
|
||||
if (target != NULL) {
|
||||
refThread(target);
|
||||
}
|
||||
unlockMutex(m_threadMutex);
|
||||
|
||||
// see if we've been cancelled before checking if any events
|
||||
// are pending.
|
||||
DWORD result = WaitForSingleObject(self->m_cancel, 0);
|
||||
if (result == WAIT_OBJECT_0) {
|
||||
if (target != NULL) {
|
||||
closeThread(target);
|
||||
}
|
||||
testCancelThreadImpl(self);
|
||||
}
|
||||
|
||||
// check if messages are available first. if we don't do this then
|
||||
// MsgWaitForMultipleObjects() will block even if the queue isn't
|
||||
// empty if the messages in the queue were there before the last
|
||||
// call to GetMessage()/PeekMessage().
|
||||
if (HIWORD(GetQueueStatus(QS_ALLINPUT)) != 0) {
|
||||
return kEvent;
|
||||
}
|
||||
|
||||
// convert timeout
|
||||
DWORD t;
|
||||
if (timeout < 0.0) {
|
||||
t = INFINITE;
|
||||
}
|
||||
else {
|
||||
t = (DWORD)(1000.0 * timeout);
|
||||
}
|
||||
|
||||
// wait for this thread to be cancelled or for the target thread to
|
||||
// terminate.
|
||||
DWORD n = (target == NULL || target == self) ? 1 : 2;
|
||||
HANDLE handles[2];
|
||||
handles[0] = self->m_cancel;
|
||||
handles[1] = (n == 2) ? target->m_exit : NULL;
|
||||
result = MsgWaitForMultipleObjects(n, handles, FALSE, t, QS_ALLINPUT);
|
||||
|
||||
// cancel takes priority
|
||||
if (result != WAIT_OBJECT_0 + 0 &&
|
||||
WaitForSingleObject(handles[0], 0) == WAIT_OBJECT_0) {
|
||||
result = WAIT_OBJECT_0 + 0;
|
||||
}
|
||||
|
||||
// release target
|
||||
if (target != NULL) {
|
||||
closeThread(target);
|
||||
}
|
||||
|
||||
// handle result
|
||||
switch (result) {
|
||||
case WAIT_OBJECT_0 + 0:
|
||||
// this thread was cancelled. does not return.
|
||||
testCancelThreadImpl(self);
|
||||
|
||||
case WAIT_OBJECT_0 + 1:
|
||||
// target thread terminated
|
||||
if (n == 2) {
|
||||
return kExit;
|
||||
}
|
||||
// fall through
|
||||
|
||||
case WAIT_OBJECT_0 + 2:
|
||||
// message is available
|
||||
return kEvent;
|
||||
|
||||
default:
|
||||
// timeout or error
|
||||
return kTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
/*
|
||||
bool
|
||||
CArchMultithreadWindows::waitForEvent(double timeout)
|
||||
{
|
||||
@ -499,6 +582,7 @@ CArchMultithreadWindows::waitForEvent(double timeout)
|
||||
return false;
|
||||
}
|
||||
}
|
||||
*/
|
||||
|
||||
bool
|
||||
CArchMultithreadWindows::isSameThread(CArchThread thread1, CArchThread thread2)
|
||||
|
@ -69,7 +69,7 @@ public:
|
||||
virtual void setPriorityOfThread(CArchThread, int n);
|
||||
virtual void testCancelThread();
|
||||
virtual bool wait(CArchThread, double timeout);
|
||||
virtual bool waitForEvent(double timeout);
|
||||
virtual EWaitResult waitForEvent(CArchThread, double timeout);
|
||||
virtual bool isSameThread(CArchThread, CArchThread);
|
||||
virtual bool isExitedThread(CArchThread);
|
||||
virtual void* getResultOfThread(CArchThread);
|
||||
|
518
lib/arch/CArchTaskBarWindows.cpp
Normal file
@ -0,0 +1,518 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CArchTaskBarWindows.h"
|
||||
#include "IArchTaskBarReceiver.h"
|
||||
#include "CArch.h"
|
||||
#include "XArch.h"
|
||||
#include <string.h>
|
||||
#include <shellapi.h>
|
||||
|
||||
static const UINT kAddReceiver = WM_USER + 10;
|
||||
static const UINT kRemoveReceiver = WM_USER + 11;
|
||||
static const UINT kUpdateReceiver = WM_USER + 12;
|
||||
static const UINT kNotifyReceiver = WM_USER + 13;
|
||||
static const UINT kFirstReceiverID = WM_USER + 14;
|
||||
|
||||
//
|
||||
// CArchTaskBarWindows
|
||||
//
|
||||
|
||||
CArchTaskBarWindows* CArchTaskBarWindows::s_instance = NULL;
|
||||
HINSTANCE CArchTaskBarWindows::s_appInstance = NULL;
|
||||
|
||||
CArchTaskBarWindows::CArchTaskBarWindows(void* appInstance) :
|
||||
m_nextID(kFirstReceiverID)
|
||||
{
|
||||
// save the singleton instance
|
||||
s_instance = this;
|
||||
|
||||
// save app instance
|
||||
s_appInstance = reinterpret_cast<HINSTANCE>(appInstance);
|
||||
|
||||
// we need a mutex
|
||||
m_mutex = ARCH->newMutex();
|
||||
|
||||
// and a condition variable which uses the above mutex
|
||||
m_ready = false;
|
||||
m_condVar = ARCH->newCondVar();
|
||||
|
||||
// we're going to want to get a result from the thread we're
|
||||
// about to create to know if it initialized successfully.
|
||||
// so we lock the condition variable.
|
||||
ARCH->lockMutex(m_mutex);
|
||||
|
||||
// open a window and run an event loop in a separate thread.
|
||||
// this has to happen in a separate thread because if we
|
||||
// create a window on the current desktop with the current
|
||||
// thread then the current thread won't be able to switch
|
||||
// desktops if it needs to.
|
||||
m_thread = ARCH->newThread(&CArchTaskBarWindows::threadEntry, this);
|
||||
|
||||
// wait for child thread
|
||||
while (!m_ready) {
|
||||
ARCH->waitCondVar(m_condVar, m_mutex, -1.0);
|
||||
}
|
||||
|
||||
// ready
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
CArchTaskBarWindows::~CArchTaskBarWindows()
|
||||
{
|
||||
if (m_thread != NULL) {
|
||||
ARCH->cancelThread(m_thread);
|
||||
ARCH->wait(m_thread, -1.0);
|
||||
ARCH->closeThread(m_thread);
|
||||
}
|
||||
ARCH->closeCondVar(m_condVar);
|
||||
ARCH->closeMutex(m_mutex);
|
||||
s_instance = NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addDialog(HWND hwnd)
|
||||
{
|
||||
// add dialog to added dialogs list
|
||||
ARCH->lockMutex(s_instance->m_mutex);
|
||||
s_instance->m_addedDialogs.insert(std::make_pair(hwnd, true));
|
||||
ARCH->unlockMutex(s_instance->m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeDialog(HWND hwnd)
|
||||
{
|
||||
// mark dialog as removed
|
||||
ARCH->lockMutex(s_instance->m_mutex);
|
||||
CDialogs::iterator index = s_instance->m_dialogs.find(hwnd);
|
||||
if (index != s_instance->m_dialogs.end()) {
|
||||
index->second = false;
|
||||
}
|
||||
s_instance->m_addedDialogs.erase(hwnd);
|
||||
ARCH->unlockMutex(s_instance->m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// ignore bogus receiver
|
||||
if (receiver == NULL) {
|
||||
return;
|
||||
}
|
||||
|
||||
// add receiver if necessary
|
||||
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
// add it, creating a new message ID for it
|
||||
CReceiverInfo info;
|
||||
info.m_id = getNextID();
|
||||
index = m_receivers.insert(std::make_pair(receiver, info)).first;
|
||||
|
||||
// add ID to receiver mapping
|
||||
m_idTable.insert(std::make_pair(info.m_id, index));
|
||||
}
|
||||
|
||||
// add receiver
|
||||
PostMessage(m_hwnd, kAddReceiver, index->second.m_id, 0);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// find receiver
|
||||
CReceiverToInfoMap::iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// remove icon. wait for this to finish before returning.
|
||||
SendMessage(m_hwnd, kRemoveReceiver, index->second.m_id, 0);
|
||||
|
||||
// recycle the ID
|
||||
recycleID(index->second.m_id);
|
||||
|
||||
// discard
|
||||
m_idTable.erase(index->second.m_id);
|
||||
m_receivers.erase(index);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::updateReceiver(IArchTaskBarReceiver* receiver)
|
||||
{
|
||||
// find receiver
|
||||
CReceiverToInfoMap::const_iterator index = m_receivers.find(receiver);
|
||||
if (index == m_receivers.end()) {
|
||||
return;
|
||||
}
|
||||
|
||||
// update icon and tool tip
|
||||
PostMessage(m_hwnd, kUpdateReceiver, index->second.m_id, 0);
|
||||
}
|
||||
|
||||
UINT
|
||||
CArchTaskBarWindows::getNextID()
|
||||
{
|
||||
if (m_oldIDs.empty()) {
|
||||
return m_nextID++;
|
||||
}
|
||||
UINT id = m_oldIDs.back();
|
||||
m_oldIDs.pop_back();
|
||||
return id;
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::recycleID(UINT id)
|
||||
{
|
||||
m_oldIDs.push_back(id);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||
if (index != m_idTable.end()) {
|
||||
modifyIconNoLock(index->second, NIM_ADD);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
removeIconNoLock(id);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::updateIcon(UINT id)
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find(id);
|
||||
if (index != m_idTable.end()) {
|
||||
modifyIconNoLock(index->second, NIM_MODIFY);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::addAllIcons()
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||
index != m_receivers.end(); ++index) {
|
||||
modifyIconNoLock(index, NIM_ADD);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeAllIcons()
|
||||
{
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CReceiverToInfoMap::const_iterator index = m_receivers.begin();
|
||||
index != m_receivers.end(); ++index) {
|
||||
removeIconNoLock(index->second.m_id);
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::modifyIconNoLock(
|
||||
CReceiverToInfoMap::const_iterator index, DWORD taskBarMessage)
|
||||
{
|
||||
// get receiver
|
||||
UINT id = index->second.m_id;
|
||||
IArchTaskBarReceiver* receiver = index->first;
|
||||
|
||||
// lock receiver so icon and tool tip are guaranteed to be consistent
|
||||
receiver->lock();
|
||||
|
||||
// get icon data
|
||||
HICON icon = reinterpret_cast<HICON>(
|
||||
const_cast<IArchTaskBarReceiver::Icon>(receiver->getIcon()));
|
||||
|
||||
// get tool tip
|
||||
std::string toolTip = receiver->getToolTip();
|
||||
|
||||
// done querying
|
||||
receiver->unlock();
|
||||
|
||||
// prepare to add icon
|
||||
NOTIFYICONDATA data;
|
||||
data.cbSize = sizeof(NOTIFYICONDATA);
|
||||
data.hWnd = m_hwnd;
|
||||
data.uID = id;
|
||||
data.uFlags = NIF_MESSAGE;
|
||||
data.uCallbackMessage = kNotifyReceiver;
|
||||
data.hIcon = icon;
|
||||
if (icon != NULL) {
|
||||
data.uFlags |= NIF_ICON;
|
||||
}
|
||||
if (!toolTip.empty()) {
|
||||
strncpy(data.szTip, toolTip.c_str(), sizeof(data.szTip));
|
||||
data.szTip[sizeof(data.szTip) - 1] = '\0';
|
||||
data.uFlags |= NIF_TIP;
|
||||
}
|
||||
else {
|
||||
data.szTip[0] = '\0';
|
||||
}
|
||||
|
||||
// add icon
|
||||
if (Shell_NotifyIcon(taskBarMessage, &data) == 0) {
|
||||
// failed
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::removeIconNoLock(UINT id)
|
||||
{
|
||||
NOTIFYICONDATA data;
|
||||
data.cbSize = sizeof(NOTIFYICONDATA);
|
||||
data.hWnd = m_hwnd;
|
||||
data.uID = id;
|
||||
if (Shell_NotifyIcon(NIM_DELETE, &data) == 0) {
|
||||
// failed
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::handleIconMessage(
|
||||
IArchTaskBarReceiver* receiver, LPARAM lParam)
|
||||
{
|
||||
// process message
|
||||
switch (lParam) {
|
||||
case WM_LBUTTONDOWN:
|
||||
receiver->showStatus();
|
||||
break;
|
||||
|
||||
case WM_LBUTTONDBLCLK:
|
||||
receiver->primaryAction();
|
||||
break;
|
||||
|
||||
case WM_RBUTTONUP: {
|
||||
POINT p;
|
||||
GetCursorPos(&p);
|
||||
receiver->runMenu(p.x, p.y);
|
||||
break;
|
||||
}
|
||||
|
||||
case WM_MOUSEMOVE:
|
||||
// currently unused
|
||||
break;
|
||||
|
||||
default:
|
||||
// unused
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
bool
|
||||
CArchTaskBarWindows::processDialogs(MSG* msg)
|
||||
{
|
||||
// only one thread can be in this method on any particular object
|
||||
// at any given time. that's not a problem since only our event
|
||||
// loop calls this method and there's just one of those.
|
||||
|
||||
ARCH->lockMutex(m_mutex);
|
||||
|
||||
// remove removed dialogs
|
||||
m_dialogs.erase(false);
|
||||
|
||||
// merge added dialogs into the dialog list
|
||||
for (CDialogs::const_iterator index = m_addedDialogs.begin();
|
||||
index != m_addedDialogs.end(); ++index) {
|
||||
m_dialogs.insert(std::make_pair(index->first, index->second));
|
||||
}
|
||||
m_addedDialogs.clear();
|
||||
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
// check message against all dialogs until one handles it.
|
||||
// note that we don't hold a lock while checking because
|
||||
// the message is processed and may make calls to this
|
||||
// object. that's okay because addDialog() and
|
||||
// removeDialog() don't change the map itself (just the
|
||||
// values of some elements).
|
||||
ARCH->lockMutex(m_mutex);
|
||||
for (CDialogs::const_iterator index = m_dialogs.begin();
|
||||
index != m_dialogs.end(); ++index) {
|
||||
if (index->second) {
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
if (IsDialogMessage(index->first, msg)) {
|
||||
return true;
|
||||
}
|
||||
ARCH->lockMutex(m_mutex);
|
||||
}
|
||||
}
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
LRESULT
|
||||
CArchTaskBarWindows::wndProc(HWND hwnd,
|
||||
UINT msg, WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
switch (msg) {
|
||||
case kNotifyReceiver: {
|
||||
// lookup receiver
|
||||
CIDToReceiverMap::const_iterator index = m_idTable.find(wParam);
|
||||
if (index != m_idTable.end()) {
|
||||
IArchTaskBarReceiver* receiver = index->second->first;
|
||||
handleIconMessage(receiver, lParam);
|
||||
return 0;
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
case kAddReceiver:
|
||||
addIcon(wParam);
|
||||
break;
|
||||
|
||||
case kRemoveReceiver:
|
||||
removeIcon(wParam);
|
||||
break;
|
||||
|
||||
case kUpdateReceiver:
|
||||
updateIcon(wParam);
|
||||
break;
|
||||
|
||||
default:
|
||||
if (msg == m_taskBarRestart) {
|
||||
// task bar was recreated so re-add our icons
|
||||
addAllIcons();
|
||||
}
|
||||
break;
|
||||
}
|
||||
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
|
||||
LRESULT CALLBACK
|
||||
CArchTaskBarWindows::staticWndProc(HWND hwnd, UINT msg,
|
||||
WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
// if msg is WM_NCCREATE, extract the CArchTaskBarWindows* and put
|
||||
// it in the extra window data then forward the call.
|
||||
CArchTaskBarWindows* self = NULL;
|
||||
if (msg == WM_NCCREATE) {
|
||||
CREATESTRUCT* createInfo;
|
||||
createInfo = reinterpret_cast<CREATESTRUCT*>(lParam);
|
||||
self = reinterpret_cast<CArchTaskBarWindows*>(
|
||||
createInfo->lpCreateParams);
|
||||
SetWindowLong(hwnd, 0, reinterpret_cast<LONG>(self));
|
||||
}
|
||||
else {
|
||||
// get the extra window data and forward the call
|
||||
LONG data = GetWindowLong(hwnd, 0);
|
||||
if (data != 0) {
|
||||
self = reinterpret_cast<CArchTaskBarWindows*>(
|
||||
reinterpret_cast<void*>(data));
|
||||
}
|
||||
}
|
||||
|
||||
// forward the message
|
||||
if (self != NULL) {
|
||||
return self->wndProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
else {
|
||||
return DefWindowProc(hwnd, msg, wParam, lParam);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarWindows::threadMainLoop()
|
||||
{
|
||||
// register the task bar restart message
|
||||
m_taskBarRestart = RegisterWindowMessage(TEXT("TaskbarCreated"));
|
||||
|
||||
// register a window class
|
||||
WNDCLASSEX classInfo;
|
||||
classInfo.cbSize = sizeof(classInfo);
|
||||
classInfo.style = CS_NOCLOSE;
|
||||
classInfo.lpfnWndProc = &CArchTaskBarWindows::staticWndProc;
|
||||
classInfo.cbClsExtra = 0;
|
||||
classInfo.cbWndExtra = sizeof(CArchTaskBarWindows*);
|
||||
classInfo.hInstance = s_appInstance;
|
||||
classInfo.hIcon = NULL;
|
||||
classInfo.hCursor = NULL;
|
||||
classInfo.hbrBackground = NULL;
|
||||
classInfo.lpszMenuName = NULL;
|
||||
classInfo.lpszClassName = TEXT("SynergyTaskBar");
|
||||
classInfo.hIconSm = NULL;
|
||||
ATOM windowClass = RegisterClassEx(&classInfo);
|
||||
|
||||
// create window
|
||||
m_hwnd = CreateWindowEx(WS_EX_TOOLWINDOW,
|
||||
reinterpret_cast<LPCTSTR>(windowClass),
|
||||
TEXT("Synergy Task Bar"),
|
||||
WS_POPUP,
|
||||
0, 0, 1, 1,
|
||||
NULL,
|
||||
NULL,
|
||||
s_appInstance,
|
||||
reinterpret_cast<void*>(this));
|
||||
|
||||
// signal ready
|
||||
ARCH->lockMutex(m_mutex);
|
||||
m_ready = true;
|
||||
ARCH->broadcastCondVar(m_condVar);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
|
||||
// handle failure
|
||||
if (m_hwnd == NULL) {
|
||||
UnregisterClass((LPCTSTR)windowClass, s_appInstance);
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// main loop
|
||||
MSG msg;
|
||||
for (;;) {
|
||||
// wait for message
|
||||
if (ARCH->waitForEvent(NULL, -1.0) != IArchMultithread::kEvent) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// peek for message and remove it. we don't GetMessage()
|
||||
// because we should never block here, only in waitForEvent().
|
||||
if (!PeekMessage(&msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// check message against dialogs
|
||||
if (!processDialogs(&msg)) {
|
||||
// process message
|
||||
TranslateMessage(&msg);
|
||||
DispatchMessage(&msg);
|
||||
}
|
||||
}
|
||||
}
|
||||
catch (XThread&) {
|
||||
// clean up
|
||||
removeAllIcons();
|
||||
DestroyWindow(m_hwnd);
|
||||
UnregisterClass((LPCTSTR)windowClass, s_appInstance);
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void*
|
||||
CArchTaskBarWindows::threadEntry(void* self)
|
||||
{
|
||||
reinterpret_cast<CArchTaskBarWindows*>(self)->threadMainLoop();
|
||||
return NULL;
|
||||
}
|
110
lib/arch/CArchTaskBarWindows.h
Normal file
@ -0,0 +1,110 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTASKBARWINDOWS_H
|
||||
#define CARCHTASKBARWINDOWS_H
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
|
||||
#include "IArchTaskBar.h"
|
||||
#include "IArchMultithread.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
#include <windows.h>
|
||||
|
||||
#define ARCH_TASKBAR CArchTaskBarWindows
|
||||
|
||||
//! Win32 implementation of IArchTaskBar
|
||||
class CArchTaskBarWindows : public IArchTaskBar {
|
||||
public:
|
||||
CArchTaskBarWindows(void*);
|
||||
virtual ~CArchTaskBarWindows();
|
||||
|
||||
//! Add a dialog window
|
||||
/*!
|
||||
Tell the task bar event loop about a dialog. Win32 annoyingly
|
||||
requires messages destined for modeless dialog boxes to be
|
||||
dispatched differently than other messages.
|
||||
*/
|
||||
static void addDialog(HWND);
|
||||
|
||||
//! Remove a dialog window
|
||||
/*!
|
||||
Remove a dialog window added via \c addDialog().
|
||||
*/
|
||||
static void removeDialog(HWND);
|
||||
|
||||
// IArchTaskBar overrides
|
||||
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||
|
||||
private:
|
||||
class CReceiverInfo {
|
||||
public:
|
||||
UINT m_id;
|
||||
};
|
||||
|
||||
typedef std::map<IArchTaskBarReceiver*, CReceiverInfo> CReceiverToInfoMap;
|
||||
typedef std::map<UINT, CReceiverToInfoMap::iterator> CIDToReceiverMap;
|
||||
typedef std::vector<UINT> CIDStack;
|
||||
typedef std::map<HWND, bool> CDialogs;
|
||||
|
||||
UINT getNextID();
|
||||
void recycleID(UINT);
|
||||
|
||||
void addIcon(UINT);
|
||||
void removeIcon(UINT);
|
||||
void updateIcon(UINT);
|
||||
void addAllIcons();
|
||||
void removeAllIcons();
|
||||
void modifyIconNoLock(CReceiverToInfoMap::const_iterator,
|
||||
DWORD taskBarMessage);
|
||||
void removeIconNoLock(UINT id);
|
||||
void handleIconMessage(IArchTaskBarReceiver*, LPARAM);
|
||||
|
||||
bool processDialogs(MSG*);
|
||||
LRESULT wndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
static LRESULT CALLBACK
|
||||
staticWndProc(HWND, UINT, WPARAM, LPARAM);
|
||||
void threadMainLoop();
|
||||
static void* threadEntry(void*);
|
||||
|
||||
private:
|
||||
static CArchTaskBarWindows* s_instance;
|
||||
static HINSTANCE s_appInstance;
|
||||
|
||||
// multithread data
|
||||
CArchMutex m_mutex;
|
||||
CArchCond m_condVar;
|
||||
bool m_ready;
|
||||
int m_result;
|
||||
CArchThread m_thread;
|
||||
|
||||
// child thread data
|
||||
HWND m_hwnd;
|
||||
UINT m_taskBarRestart;
|
||||
|
||||
// shared data
|
||||
CReceiverToInfoMap m_receivers;
|
||||
CIDToReceiverMap m_idTable;
|
||||
CIDStack m_oldIDs;
|
||||
UINT m_nextID;
|
||||
|
||||
// dialogs
|
||||
CDialogs m_dialogs;
|
||||
CDialogs m_addedDialogs;
|
||||
};
|
||||
|
||||
#endif
|
47
lib/arch/CArchTaskBarXWindows.cpp
Normal file
@ -0,0 +1,47 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#include "CArchTaskBarXWindows.h"
|
||||
|
||||
//
|
||||
// CArchTaskBarXWindows
|
||||
//
|
||||
|
||||
CArchTaskBarXWindows::CArchTaskBarXWindows(void*)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
CArchTaskBarXWindows::~CArchTaskBarXWindows()
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::addReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::removeReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
|
||||
void
|
||||
CArchTaskBarXWindows::updateReceiver(IArchTaskBarReceiver* /*receiver*/)
|
||||
{
|
||||
// do nothing
|
||||
}
|
34
lib/arch/CArchTaskBarXWindows.h
Normal file
@ -0,0 +1,34 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef CARCHTASKBARXWINDOWS_H
|
||||
#define CARCHTASKBARXWINDOWS_H
|
||||
|
||||
#include "IArchTaskBar.h"
|
||||
|
||||
#define ARCH_TASKBAR CArchTaskBarXWindows
|
||||
|
||||
//! X11 implementation of IArchTaskBar
|
||||
class CArchTaskBarXWindows : public IArchTaskBar {
|
||||
public:
|
||||
CArchTaskBarXWindows(void*);
|
||||
virtual ~CArchTaskBarXWindows();
|
||||
|
||||
// IArchTaskBar overrides
|
||||
virtual void addReceiver(IArchTaskBarReceiver*);
|
||||
virtual void removeReceiver(IArchTaskBarReceiver*);
|
||||
virtual void updateReceiver(IArchTaskBarReceiver*);
|
||||
};
|
||||
|
||||
#endif
|
@ -67,6 +67,13 @@ synergy. Each architecture must implement this interface.
|
||||
*/
|
||||
class IArchMultithread : public IInterface {
|
||||
public:
|
||||
//! Result of waitForEvent()
|
||||
enum EWaitResult {
|
||||
kEvent, //!< An event is pending
|
||||
kExit, //!< Thread exited
|
||||
kTimeout //!< Wait timed out
|
||||
};
|
||||
|
||||
//! Type of thread entry point
|
||||
typedef void* (*ThreadFunc)(void*);
|
||||
//! Type of thread identifier
|
||||
@ -102,10 +109,12 @@ public:
|
||||
|
||||
//! Wait on a condition variable
|
||||
/*!
|
||||
Waiting on a conditation variable for up to \c timeout seconds.
|
||||
Wait on a conditation variable for up to \c timeout seconds.
|
||||
If \c timeout is < 0 then there is no timeout. The mutex must
|
||||
be locked when this method is called. The mutex is unlocked
|
||||
during the wait and locked again before returning.
|
||||
during the wait and locked again before returning. Returns
|
||||
true if the condition variable was signalled and false on
|
||||
timeout.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
@ -206,14 +215,18 @@ public:
|
||||
|
||||
//! Wait for a user event
|
||||
/*!
|
||||
Waits for up to \c timeout seconds for a pending user event.
|
||||
Returns true if an event occurred, false otherwise.
|
||||
Waits for up to \c timeout seconds for a pending user event or
|
||||
\c thread to exit (normally or by cancellation). Waits forever
|
||||
if \c timeout < 0. Returns kEvent if an event occurred, kExit
|
||||
if \c thread exited, or kTimeout if the timeout expired. If
|
||||
\c thread is NULL then it doesn't wait for any thread to exit
|
||||
and it will not return kExit.
|
||||
|
||||
This method is not required by all platforms.
|
||||
|
||||
(Cancellation point)
|
||||
*/
|
||||
virtual bool waitForEvent(double timeout) = 0;
|
||||
virtual EWaitResult waitForEvent(CArchThread thread, double timeout) = 0;
|
||||
|
||||
//! Compare threads
|
||||
/*!
|
||||
|
63
lib/arch/IArchTaskBar.h
Normal file
@ -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
|
90
lib/arch/IArchTaskBarReceiver.h
Normal file
@ -0,0 +1,90 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2003 Chris Schoeneman
|
||||
*
|
||||
* This package is free software; you can redistribute it and/or
|
||||
* modify it under the terms of the GNU General Public License
|
||||
* found in the file COPYING that should have accompanied this file.
|
||||
*
|
||||
* This package is distributed in the hope that it will be useful,
|
||||
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
||||
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
||||
* GNU General Public License for more details.
|
||||
*/
|
||||
|
||||
#ifndef IARCHTASKBARRECEIVER_H
|
||||
#define IARCHTASKBARRECEIVER_H
|
||||
|
||||
#include "IInterface.h"
|
||||
#include "stdstring.h"
|
||||
|
||||
//! Interface for architecture dependent task bar event handling
|
||||
/*!
|
||||
This interface defines the task bar icon event handlers required
|
||||
by synergy. Each architecture must implement this interface
|
||||
though each operation can be a no-op.
|
||||
*/
|
||||
class IArchTaskBarReceiver : public IInterface {
|
||||
public:
|
||||
// Icon data is architecture dependent
|
||||
typedef void* Icon;
|
||||
|
||||
//! @name manipulators
|
||||
//@{
|
||||
|
||||
//! Show status window
|
||||
/*!
|
||||
Open a window displaying current status. This should return
|
||||
immediately without waiting for the window to be closed.
|
||||
*/
|
||||
virtual void showStatus() = 0;
|
||||
|
||||
//! Popup menu
|
||||
/*!
|
||||
Popup a menu of operations at or around \c x,y and perform the
|
||||
chosen operation.
|
||||
*/
|
||||
virtual void runMenu(int x, int y) = 0;
|
||||
|
||||
//! Perform primary action
|
||||
/*!
|
||||
Perform the primary (default) action.
|
||||
*/
|
||||
virtual void primaryAction() = 0;
|
||||
|
||||
//@}
|
||||
//! @name accessors
|
||||
//@{
|
||||
|
||||
//! Lock receiver
|
||||
/*!
|
||||
Locks the receiver from changing state. The receiver should be
|
||||
locked when querying it's state to ensure consistent results.
|
||||
Each call to \c lock() must have a matching \c unlock() and
|
||||
locks cannot be nested.
|
||||
*/
|
||||
virtual void lock() const = 0;
|
||||
|
||||
//! Unlock receiver
|
||||
virtual void unlock() const = 0;
|
||||
|
||||
//! Get icon
|
||||
/*!
|
||||
Returns the icon to display in the task bar. The interface
|
||||
to set the icon is left to subclasses. Getting and setting
|
||||
the icon must be thread safe.
|
||||
*/
|
||||
virtual const Icon getIcon() const = 0;
|
||||
|
||||
//! Get tooltip
|
||||
/*!
|
||||
Returns the tool tip to display in the task bar. The interface
|
||||
to set the tooltip is left to sublclasses. Getting and setting
|
||||
the icon must be thread safe.
|
||||
*/
|
||||
virtual std::string getToolTip() const = 0;
|
||||
|
||||
//@}
|
||||
};
|
||||
|
||||
#endif
|
@ -26,6 +26,7 @@ EXTRA_DIST = \
|
||||
CArchNetworkWinsock.cpp \
|
||||
CArchSleepWindows.cpp \
|
||||
CArchStringWindows.cpp \
|
||||
CArchTaskBarWindows.cpp \
|
||||
CArchTimeWindows.cpp \
|
||||
XArchWindows.cpp \
|
||||
CArchConsoleWindows.h \
|
||||
@ -37,6 +38,7 @@ EXTRA_DIST = \
|
||||
CArchNetworkWinsock.h \
|
||||
CArchSleepWindows.h \
|
||||
CArchStringWindows.h \
|
||||
CArchTaskBarWindows.h \
|
||||
CArchTimeWindows.h \
|
||||
XArchWindows.h \
|
||||
$(NULL)
|
||||
@ -59,6 +61,8 @@ libarch_a_SOURCES = \
|
||||
IArchNetwork.h \
|
||||
IArchSleep.h \
|
||||
IArchString.h \
|
||||
IArchTaskBar.h \
|
||||
IArchTaskBarReceiver.h \
|
||||
IArchTime.h \
|
||||
XArch.h \
|
||||
$(NULL)
|
||||
@ -72,6 +76,7 @@ EXTRA_libarch_a_SOURCES = \
|
||||
CArchNetworkBSD.cpp \
|
||||
CArchSleepUnix.cpp \
|
||||
CArchStringUnix.cpp \
|
||||
CArchTaskBarXWindows.cpp \
|
||||
CArchTimeUnix.cpp \
|
||||
CMultibyte.cpp \
|
||||
CMultibyteOS.cpp \
|
||||
@ -87,6 +92,7 @@ EXTRA_libarch_a_SOURCES = \
|
||||
CArchNetworkBSD.h \
|
||||
CArchSleepUnix.h \
|
||||
CArchStringUnix.h \
|
||||
CArchTaskBarXWindows.h \
|
||||
CArchTimeUnix.h \
|
||||
XArchUnix.h \
|
||||
$(NULL)
|
||||
|
@ -115,6 +115,10 @@ SOURCE=.\CArchDaemonWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchFileWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchImpl.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -143,6 +147,10 @@ SOURCE=.\CArchStringWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchTaskBarWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchTimeWindows.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -151,6 +159,14 @@ SOURCE=.\IArchConsole.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchDaemon.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchFile.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchLog.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -171,6 +187,14 @@ SOURCE=.\IArchString.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchTaskBar.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchTaskBarReceiver.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\IArchTime.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -232,6 +256,11 @@ SOURCE=.\CArchStringWindows.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchTaskBarWindows.cpp
|
||||
# PROP Exclude_From_Build 1
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CArchTimeWindows.cpp
|
||||
# PROP Exclude_From_Build 1
|
||||
# End Source File
|
||||
|
113
lib/base/CJobList.cpp
Normal 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);
|
||||
}
|
72
lib/base/CJobList.h
Normal file
@ -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 "";
|
||||
}
|
||||
|
||||
|
||||
//
|
||||
// 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;
|
||||
};
|
||||
|
||||
//! 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
|
||||
|
@ -26,6 +26,7 @@ MAINTAINERCLEANFILES = \
|
||||
noinst_LIBRARIES = libbase.a
|
||||
libbase_a_SOURCES = \
|
||||
CFunctionJob.cpp \
|
||||
CJobList.cpp \
|
||||
CLog.cpp \
|
||||
CStopwatch.cpp \
|
||||
CStringUtil.cpp \
|
||||
@ -33,6 +34,7 @@ libbase_a_SOURCES = \
|
||||
LogOutputters.cpp \
|
||||
XBase.cpp \
|
||||
CFunctionJob.h \
|
||||
CJobList.h \
|
||||
CLog.h \
|
||||
CStopwatch.h \
|
||||
CString.h \
|
||||
|
@ -91,6 +91,10 @@ SOURCE=.\CFunctionJob.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CJobList.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CLog.cpp
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
@ -123,6 +127,10 @@ SOURCE=.\CFunctionJob.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CJobList.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
||||
SOURCE=.\CLog.h
|
||||
# End Source File
|
||||
# Begin Source File
|
||||
|
@ -52,7 +52,8 @@ CClient::CClient(const CString& clientName) :
|
||||
m_streamFilterFactory(NULL),
|
||||
m_session(NULL),
|
||||
m_active(false),
|
||||
m_rejected(true)
|
||||
m_rejected(true),
|
||||
m_status(kNotRunning)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@ -108,15 +109,61 @@ CClient::exitMainLoop()
|
||||
m_screen->exitMainLoop();
|
||||
}
|
||||
|
||||
void
|
||||
CClient::addStatusJob(IJob* job)
|
||||
{
|
||||
m_statusJobs.addJob(job);
|
||||
}
|
||||
|
||||
void
|
||||
CClient::removeStatusJob(IJob* job)
|
||||
{
|
||||
m_statusJobs.removeJob(job);
|
||||
}
|
||||
|
||||
bool
|
||||
CClient::wasRejected() const
|
||||
{
|
||||
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
|
||||
CClient::onError()
|
||||
{
|
||||
setStatus(kError);
|
||||
|
||||
// close down session but don't wait too long
|
||||
deleteSession(3.0);
|
||||
}
|
||||
@ -172,9 +219,11 @@ CClient::open()
|
||||
try {
|
||||
LOG((CLOG_INFO "opening screen"));
|
||||
openSecondaryScreen();
|
||||
setStatus(kNotRunning);
|
||||
}
|
||||
catch (XScreenOpenFailure&) {
|
||||
catch (XScreenOpenFailure& e) {
|
||||
// can't open screen
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_INFO "failed to open screen"));
|
||||
throw;
|
||||
}
|
||||
@ -195,6 +244,7 @@ CClient::mainLoop()
|
||||
}
|
||||
|
||||
try {
|
||||
setStatus(kNotRunning);
|
||||
LOG((CLOG_NOTE "starting client \"%s\"", m_name.c_str()));
|
||||
|
||||
// start server interactions
|
||||
@ -213,6 +263,7 @@ CClient::mainLoop()
|
||||
}
|
||||
catch (XMT& e) {
|
||||
LOG((CLOG_ERR "client error: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
@ -221,6 +272,7 @@ CClient::mainLoop()
|
||||
}
|
||||
catch (XBase& e) {
|
||||
LOG((CLOG_ERR "client error: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
@ -229,6 +281,8 @@ CClient::mainLoop()
|
||||
m_rejected = false;
|
||||
}
|
||||
catch (XThread&) {
|
||||
setStatus(kNotRunning);
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
LOG((CLOG_NOTE "stopping client \"%s\"", m_name.c_str()));
|
||||
@ -236,6 +290,7 @@ CClient::mainLoop()
|
||||
}
|
||||
catch (...) {
|
||||
LOG((CLOG_DEBUG "unknown client error"));
|
||||
setStatus(kError);
|
||||
|
||||
// clean up
|
||||
deleteSession();
|
||||
@ -529,11 +584,12 @@ CClient::runServer()
|
||||
{
|
||||
IDataSocket* socket = NULL;
|
||||
CServerProxy* proxy = NULL;
|
||||
bool timedOut;
|
||||
try {
|
||||
for (;;) {
|
||||
try {
|
||||
// allow connect this much time to succeed
|
||||
CTimerThread timer(15.0);
|
||||
CTimerThread timer(15.0, &timedOut);
|
||||
|
||||
// create socket and attempt to connect to server
|
||||
LOG((CLOG_DEBUG1 "connecting to server"));
|
||||
@ -546,6 +602,7 @@ CClient::runServer()
|
||||
break;
|
||||
}
|
||||
catch (XSocketConnect& e) {
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_DEBUG "failed to connect to server: %s", e.what()));
|
||||
|
||||
// failed to connect. if not camping then rethrow.
|
||||
@ -565,31 +622,47 @@ CClient::runServer()
|
||||
m_server = proxy;
|
||||
}
|
||||
catch (XThread&) {
|
||||
LOG((CLOG_ERR "connection timed out"));
|
||||
if (timedOut) {
|
||||
LOG((CLOG_ERR "connection timed out"));
|
||||
setStatus(kError, "connection timed out");
|
||||
}
|
||||
else {
|
||||
// cancelled by some thread other than the timer
|
||||
}
|
||||
delete socket;
|
||||
throw;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
LOG((CLOG_ERR "connection failed: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_DEBUG "disconnecting from server"));
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
catch (...) {
|
||||
LOG((CLOG_ERR "connection failed: <unknown error>"));
|
||||
setStatus(kError);
|
||||
LOG((CLOG_DEBUG "disconnecting from server"));
|
||||
delete socket;
|
||||
return;
|
||||
}
|
||||
|
||||
try {
|
||||
// prepare for remote control
|
||||
m_screen->remoteControl();
|
||||
|
||||
// process messages
|
||||
bool rejected = true;
|
||||
if (proxy != NULL) {
|
||||
LOG((CLOG_DEBUG1 "communicating with server"));
|
||||
setStatus(kRunning);
|
||||
rejected = !proxy->mainLoop();
|
||||
setStatus(kNotRunning);
|
||||
}
|
||||
|
||||
// prepare for local control
|
||||
m_screen->localControl();
|
||||
|
||||
// clean up
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = rejected;
|
||||
@ -600,6 +673,8 @@ CClient::runServer()
|
||||
delete socket;
|
||||
}
|
||||
catch (...) {
|
||||
setStatus(kNotRunning);
|
||||
m_screen->localControl();
|
||||
CLock lock(&m_mutex);
|
||||
m_rejected = false;
|
||||
m_server = NULL;
|
||||
@ -664,9 +739,11 @@ CClient::handshakeServer(IDataSocket* socket)
|
||||
}
|
||||
catch (XIncompatibleClient& e) {
|
||||
LOG((CLOG_ERR "server has incompatible version %d.%d", e.getMajor(), e.getMinor()));
|
||||
setStatus(kError, e.what());
|
||||
}
|
||||
catch (XBase& e) {
|
||||
LOG((CLOG_WARN "error communicating with server: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
}
|
||||
catch (...) {
|
||||
// probably timed out
|
||||
|
@ -20,6 +20,7 @@
|
||||
#include "IClipboard.h"
|
||||
#include "CNetworkAddress.h"
|
||||
#include "CMutex.h"
|
||||
#include "CJobList.h"
|
||||
|
||||
class CSecondaryScreen;
|
||||
class CServerProxy;
|
||||
@ -36,6 +37,13 @@ This class implements the top-level client algorithms for synergy.
|
||||
*/
|
||||
class CClient : public IScreenReceiver, public IClient {
|
||||
public:
|
||||
enum EStatus {
|
||||
kNotRunning,
|
||||
kRunning,
|
||||
kError,
|
||||
kMaxStatus
|
||||
};
|
||||
|
||||
/*!
|
||||
This client will attempt to connect the server using \c clientName
|
||||
as its name.
|
||||
@ -93,6 +101,22 @@ public:
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
@ -103,6 +127,12 @@ public:
|
||||
*/
|
||||
bool wasRejected() const;
|
||||
|
||||
//! Get the status
|
||||
/*!
|
||||
Returns the current status and status message.
|
||||
*/
|
||||
EStatus getStatus(CString* = NULL) const;
|
||||
|
||||
//@}
|
||||
|
||||
// IScreenReceiver overrides
|
||||
@ -140,6 +170,12 @@ public:
|
||||
virtual void getCursorCenter(SInt32& x, SInt32& y) const;
|
||||
|
||||
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
|
||||
void openSecondaryScreen();
|
||||
void closeSecondaryScreen();
|
||||
@ -169,6 +205,11 @@ private:
|
||||
bool m_ownClipboard[kClipboardEnd];
|
||||
IClipboard::Time m_timeClipboard[kClipboardEnd];
|
||||
CString m_dataClipboard[kClipboardEnd];
|
||||
|
||||
// the status change jobs and status
|
||||
CJobList m_statusJobs;
|
||||
EStatus m_status;
|
||||
CString m_statusMessage;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -420,6 +420,7 @@ CServerProxy::translateModifierMask(KeyModifierMask mask) const
|
||||
if ((mask & KeyModifierSuper) != 0) {
|
||||
newMask |= s_masks[m_modifierTranslationTable[kKeyModifierIDSuper]];
|
||||
}
|
||||
return newMask;
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -97,10 +97,16 @@ CThread::wait(double timeout) const
|
||||
return ARCH->wait(m_thread, timeout);
|
||||
}
|
||||
|
||||
bool
|
||||
CThread::waitForEvent(double timeout)
|
||||
CThread::EWaitResult
|
||||
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*
|
||||
|
@ -39,6 +39,13 @@ documentation.
|
||||
// note -- do not derive from this class
|
||||
class CThread {
|
||||
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
|
||||
/*!
|
||||
Create and start a new thread executing the \c adoptedJob. The
|
||||
@ -159,18 +166,19 @@ public:
|
||||
|
||||
//! Wait for an event (win32)
|
||||
/*!
|
||||
Wait for the message queue to contain a message for up to \c timeout
|
||||
seconds. This returns immediately if any message is available
|
||||
(including messages that were already in the queue during the last
|
||||
call to \c GetMessage() or \c PeekMessage() or waitForEvent().
|
||||
Returns true iff a message is available. This will wait forever
|
||||
if \c timeout < 0.0.
|
||||
Wait for the message queue to contain a message or for the thread
|
||||
to exit for up to \c timeout seconds. This returns immediately if
|
||||
any message is available (including messages that were already in
|
||||
the queue during the last call to \c GetMessage() or
|
||||
\c PeekMessage() or waitForEvent(). Returns kEvent if a message
|
||||
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.
|
||||
|
||||
(cancellation point)
|
||||
*/
|
||||
static bool waitForEvent(double timeout = -1.0);
|
||||
EWaitResult waitForEvent(double timeout = -1.0) const;
|
||||
|
||||
//! Get the exit result
|
||||
/*!
|
||||
|
@ -22,8 +22,13 @@
|
||||
// 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) {
|
||||
m_callingThread = new CThread(CThread::getCurrentThread());
|
||||
m_timingThread = new CThread(new TMethodJob<CTimerThread>(
|
||||
@ -53,5 +58,8 @@ CTimerThread::timer(void*)
|
||||
LOG((CLOG_DEBUG1 "timeout in %f seconds", m_timeout));
|
||||
ARCH->sleep(m_timeout);
|
||||
LOG((CLOG_DEBUG1 "timeout"));
|
||||
if (m_timedOut != NULL) {
|
||||
*m_timedOut = true;
|
||||
}
|
||||
m_callingThread->cancel();
|
||||
}
|
||||
|
@ -30,9 +30,11 @@ public:
|
||||
/*!
|
||||
Cancels the calling thread after \c timeout seconds unless destroyed
|
||||
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
|
||||
~CTimerThread();
|
||||
|
||||
@ -45,6 +47,7 @@ private:
|
||||
|
||||
private:
|
||||
double m_timeout;
|
||||
bool* m_timedOut;
|
||||
CThread* m_callingThread;
|
||||
CThread* m_timingThread;
|
||||
};
|
||||
|
@ -112,6 +112,12 @@ CMSWindowsPrimaryScreen::setOptions(const COptionsList& /*options*/)
|
||||
// no options
|
||||
}
|
||||
|
||||
UInt32
|
||||
CMSWindowsPrimaryScreen::addOneShotTimer(double timeout)
|
||||
{
|
||||
return m_screen->addOneShotTimer(timeout);
|
||||
}
|
||||
|
||||
KeyModifierMask
|
||||
CMSWindowsPrimaryScreen::getToggleMask() const
|
||||
{
|
||||
@ -376,6 +382,12 @@ CMSWindowsPrimaryScreen::onEvent(CEvent* event)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsPrimaryScreen::onOneShotTimerExpired(UInt32 id)
|
||||
{
|
||||
m_receiver->onOneShotTimerExpired(id);
|
||||
}
|
||||
|
||||
SInt32
|
||||
CMSWindowsPrimaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
|
@ -39,6 +39,7 @@ public:
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void resetOptions();
|
||||
virtual void setOptions(const COptionsList& options);
|
||||
virtual UInt32 addOneShotTimer(double timeout);
|
||||
virtual KeyModifierMask getToggleMask() const;
|
||||
virtual bool isLockedToScreen() const;
|
||||
virtual IScreen* getScreen() const;
|
||||
@ -47,6 +48,7 @@ public:
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual void onOneShotTimerExpired(UInt32 id);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void postCreateWindow(HWND);
|
||||
virtual void preDestroyWindow(HWND);
|
||||
|
@ -122,6 +122,11 @@ CMSWindowsScreen::closeDesktop()
|
||||
// remove timer
|
||||
if (m_timer != 0) {
|
||||
KillTimer(NULL, m_timer);
|
||||
m_timer = 0;
|
||||
}
|
||||
if (m_oneShotTimer != 0) {
|
||||
KillTimer(NULL, m_oneShotTimer);
|
||||
m_oneShotTimer = 0;
|
||||
}
|
||||
|
||||
// disconnect from desktop
|
||||
@ -134,6 +139,18 @@ CMSWindowsScreen::closeDesktop()
|
||||
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
|
||||
CMSWindowsScreen::isMultimon() const
|
||||
{
|
||||
@ -205,8 +222,12 @@ CMSWindowsScreen::mainLoop()
|
||||
event.m_result = 0;
|
||||
for (;;) {
|
||||
// wait for an event in a cancellable way
|
||||
CThread::waitForEvent();
|
||||
GetMessage(&event.m_msg, NULL, 0, 0);
|
||||
if (CThread::getCurrentThread().waitForEvent(-1.0) != CThread::kEvent) {
|
||||
continue;
|
||||
}
|
||||
if (!PeekMessage(&event.m_msg, NULL, 0, 0, PM_REMOVE)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
// handle quit message
|
||||
if (event.m_msg.message == WM_QUIT) {
|
||||
@ -467,27 +488,35 @@ CMSWindowsScreen::onPreDispatch(const CEvent* event)
|
||||
}
|
||||
|
||||
case WM_TIMER:
|
||||
// if current desktop is not the input desktop then switch to it.
|
||||
// windows 95 doesn't support multiple desktops so don't bother
|
||||
// to check under it.
|
||||
if (!m_is95Family) {
|
||||
HDESK desk = openInputDesktop();
|
||||
if (desk != NULL) {
|
||||
if (isCurrentDesktop(desk)) {
|
||||
CloseDesktop(desk);
|
||||
}
|
||||
else if (!m_screensaver->isActive()) {
|
||||
// don't switch desktops when the screensaver is
|
||||
// active. we'd most likely switch to the
|
||||
// screensaver desktop which would have the side
|
||||
// effect of forcing the screensaver to stop.
|
||||
switchDesktop(desk);
|
||||
}
|
||||
else {
|
||||
CloseDesktop(desk);
|
||||
if (msg->wParam == m_timer) {
|
||||
// if current desktop is not the input desktop then switch to it.
|
||||
// windows 95 doesn't support multiple desktops so don't bother
|
||||
// to check under it.
|
||||
if (!m_is95Family) {
|
||||
HDESK desk = openInputDesktop();
|
||||
if (desk != NULL) {
|
||||
if (isCurrentDesktop(desk)) {
|
||||
CloseDesktop(desk);
|
||||
}
|
||||
else if (!m_screensaver->isActive()) {
|
||||
// don't switch desktops when the screensaver is
|
||||
// active. we'd most likely switch to the
|
||||
// screensaver desktop which would have the side
|
||||
// effect of forcing the screensaver to stop.
|
||||
switchDesktop(desk);
|
||||
}
|
||||
else {
|
||||
CloseDesktop(desk);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
else if (msg->wParam == m_oneShotTimer) {
|
||||
// one shot timer expired
|
||||
KillTimer(NULL, m_oneShotTimer);
|
||||
m_oneShotTimer = 0;
|
||||
m_eventHandler->onOneShotTimerExpired(0);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
|
@ -64,6 +64,14 @@ public:
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
@ -169,6 +177,9 @@ private:
|
||||
// the timer used to check for desktop switching
|
||||
UINT m_timer;
|
||||
|
||||
// the one shot timer
|
||||
UINT m_oneShotTimer;
|
||||
|
||||
// the current desk and it's name
|
||||
HDESK m_desk;
|
||||
CString m_deskName;
|
||||
|
@ -262,6 +262,12 @@ CMSWindowsSecondaryScreen::onEvent(CEvent* event)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsSecondaryScreen::onOneShotTimerExpired(UInt32)
|
||||
{
|
||||
// ignore
|
||||
}
|
||||
|
||||
SInt32
|
||||
CMSWindowsSecondaryScreen::getJumpZoneSize() const
|
||||
{
|
||||
@ -272,6 +278,11 @@ void
|
||||
CMSWindowsSecondaryScreen::postCreateWindow(HWND window)
|
||||
{
|
||||
m_window = window;
|
||||
|
||||
// update key state
|
||||
updateKeys();
|
||||
|
||||
// hide cursor if this screen isn't active
|
||||
if (!isActive()) {
|
||||
showWindow();
|
||||
}
|
||||
|
@ -53,6 +53,7 @@ public:
|
||||
virtual void onScreensaver(bool activated);
|
||||
virtual bool onPreDispatch(const CEvent* event);
|
||||
virtual bool onEvent(CEvent* event);
|
||||
virtual void onOneShotTimerExpired(UInt32 id);
|
||||
virtual SInt32 getJumpZoneSize() const;
|
||||
virtual void postCreateWindow(HWND);
|
||||
virtual void preDestroyWindow(HWND);
|
||||
@ -69,6 +70,7 @@ protected:
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void releaseKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
virtual KeyModifierMask getToggleState() const;
|
||||
|
||||
@ -98,7 +100,6 @@ private:
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
|
||||
void releaseKeys();
|
||||
void toggleKey(UINT virtualKey, KeyModifierMask mask);
|
||||
UINT virtualKeyToScanCode(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);
|
||||
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);
|
||||
if (display != NULL) {
|
||||
// release keys that are still pressed
|
||||
releaseKeys(display);
|
||||
doReleaseKeys(display);
|
||||
|
||||
// no longer impervious to server grabs
|
||||
XTestGrabControl(display, False);
|
||||
@ -901,7 +901,7 @@ CXWindowsSecondaryScreen::maskToX(KeyModifierMask inMask) const
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::releaseKeys(Display* display)
|
||||
CXWindowsSecondaryScreen::doReleaseKeys(Display* display)
|
||||
{
|
||||
assert(display != NULL);
|
||||
|
||||
@ -969,6 +969,15 @@ CXWindowsSecondaryScreen::updateKeys()
|
||||
updateModifiers(display);
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::releaseKeys()
|
||||
{
|
||||
CDisplayLock display(m_screen);
|
||||
if (display != NULL) {
|
||||
doReleaseKeys(display);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CXWindowsSecondaryScreen::updateModifiers(Display* display)
|
||||
{
|
||||
|
@ -67,6 +67,7 @@ protected:
|
||||
virtual void hideWindow();
|
||||
virtual void warpCursor(SInt32 x, SInt32 y);
|
||||
virtual void updateKeys();
|
||||
virtual void releaseKeys();
|
||||
virtual void setToggleState(KeyModifierMask);
|
||||
virtual KeyModifierMask getToggleState() const;
|
||||
|
||||
@ -97,14 +98,10 @@ private:
|
||||
|
||||
unsigned int mapKey(Keystrokes&, KeyCode&, KeyID,
|
||||
KeyModifierMask, EKeyAction) const;
|
||||
/*
|
||||
bool findKeyCode(KeyCode&, unsigned int&,
|
||||
KeyID id, unsigned int) const;
|
||||
*/
|
||||
void doKeystrokes(const Keystrokes&, SInt32 count);
|
||||
unsigned int maskToX(KeyModifierMask) const;
|
||||
|
||||
void releaseKeys(Display*);
|
||||
void doReleaseKeys(Display*);
|
||||
void updateKeycodeMap(Display* display);
|
||||
void updateModifiers(Display* display);
|
||||
void updateModifierMap(Display* display);
|
||||
|
@ -66,7 +66,8 @@ CServer::CServer(const CString& serverName) :
|
||||
m_switchWaitEngaged(false),
|
||||
m_switchTwoTapDelay(0.0),
|
||||
m_switchTwoTapEngaged(false),
|
||||
m_switchTwoTapArmed(false)
|
||||
m_switchTwoTapArmed(false),
|
||||
m_status(kNotRunning)
|
||||
{
|
||||
// do nothing
|
||||
}
|
||||
@ -85,14 +86,17 @@ CServer::open()
|
||||
try {
|
||||
LOG((CLOG_INFO "opening screen"));
|
||||
openPrimaryScreen();
|
||||
setStatus(kNotRunning);
|
||||
}
|
||||
catch (XScreen&) {
|
||||
catch (XScreen& e) {
|
||||
// can't open screen
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_INFO "failed to open screen"));
|
||||
throw;
|
||||
}
|
||||
catch (XUnknownClient& e) {
|
||||
// can't open screen
|
||||
setStatus(kServerNameUnknown);
|
||||
LOG((CLOG_CRIT "unknown screen name `%s'", e.getName().c_str()));
|
||||
throw;
|
||||
}
|
||||
@ -108,6 +112,7 @@ CServer::mainLoop()
|
||||
}
|
||||
|
||||
try {
|
||||
setStatus(kNotRunning);
|
||||
LOG((CLOG_NOTE "starting server"));
|
||||
|
||||
// start listening for new clients
|
||||
@ -138,11 +143,13 @@ CServer::mainLoop()
|
||||
stopThreads(); \
|
||||
delete m_httpServer; \
|
||||
m_httpServer = NULL; \
|
||||
runStatusJobs(); \
|
||||
} while (false)
|
||||
FINALLY;
|
||||
}
|
||||
catch (XMT& e) {
|
||||
LOG((CLOG_ERR "server error: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
|
||||
// clean up
|
||||
LOG((CLOG_NOTE "stopping server"));
|
||||
@ -151,12 +158,15 @@ CServer::mainLoop()
|
||||
}
|
||||
catch (XBase& e) {
|
||||
LOG((CLOG_ERR "server error: %s", e.what()));
|
||||
setStatus(kError, e.what());
|
||||
|
||||
// clean up
|
||||
LOG((CLOG_NOTE "stopping server"));
|
||||
FINALLY;
|
||||
}
|
||||
catch (XThread&) {
|
||||
setStatus(kNotRunning);
|
||||
|
||||
// clean up
|
||||
LOG((CLOG_NOTE "stopping server"));
|
||||
FINALLY;
|
||||
@ -164,6 +174,7 @@ CServer::mainLoop()
|
||||
}
|
||||
catch (...) {
|
||||
LOG((CLOG_DEBUG "unknown server error"));
|
||||
setStatus(kError);
|
||||
|
||||
// clean up
|
||||
LOG((CLOG_NOTE "stopping server"));
|
||||
@ -260,6 +271,9 @@ CServer::setConfig(const CConfig& config)
|
||||
sendOptions(client);
|
||||
}
|
||||
|
||||
// notify of status
|
||||
runStatusJobs();
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
@ -287,12 +301,52 @@ CServer::setStreamFilterFactory(IStreamFilterFactory* adopted)
|
||||
m_streamFilterFactory = adopted;
|
||||
}
|
||||
|
||||
void
|
||||
CServer::addStatusJob(IJob* job)
|
||||
{
|
||||
m_statusJobs.addJob(job);
|
||||
}
|
||||
|
||||
void
|
||||
CServer::removeStatusJob(IJob* job)
|
||||
{
|
||||
m_statusJobs.removeJob(job);
|
||||
}
|
||||
|
||||
CString
|
||||
CServer::getPrimaryScreenName() const
|
||||
{
|
||||
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
|
||||
CServer::getConfig(CConfig* config) const
|
||||
{
|
||||
@ -302,6 +356,28 @@ CServer::getConfig(CConfig* config) const
|
||||
*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
|
||||
CServer::getActivePrimarySides() const
|
||||
{
|
||||
@ -325,6 +401,8 @@ CServer::getActivePrimarySides() const
|
||||
void
|
||||
CServer::onError()
|
||||
{
|
||||
setStatus(kError);
|
||||
|
||||
// stop all running threads but don't wait too long since some
|
||||
// threads may be unable to proceed until this thread returns.
|
||||
stopThreads(3.0);
|
||||
@ -743,6 +821,10 @@ CServer::onMouseMoveSecondaryNoLock(SInt32 dx, SInt32 dy)
|
||||
case kBottom:
|
||||
clearWait = (m_y <= ay + ah - 1 + zoneSize);
|
||||
break;
|
||||
|
||||
default:
|
||||
clearWait = false;
|
||||
break;
|
||||
}
|
||||
if (clearWait) {
|
||||
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 (!allowSwitch && m_switchWaitDelay > 0.0) {
|
||||
if (isNewDirection) {
|
||||
if (isNewDirection || !m_switchWaitEngaged) {
|
||||
m_switchWaitEngaged = true;
|
||||
m_switchWaitX = x;
|
||||
m_switchWaitY = y;
|
||||
@ -1413,6 +1495,7 @@ CServer::acceptClients(void*)
|
||||
break;
|
||||
}
|
||||
catch (XSocketAddressInUse& e) {
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_WARN "bind failed: %s", e.what()));
|
||||
|
||||
// give up if we've waited too long
|
||||
@ -1427,6 +1510,7 @@ CServer::acceptClients(void*)
|
||||
}
|
||||
|
||||
// accept connections and begin processing them
|
||||
setStatus(kRunning);
|
||||
LOG((CLOG_DEBUG1 "waiting for client connections"));
|
||||
for (;;) {
|
||||
// accept connection
|
||||
@ -1439,16 +1523,15 @@ CServer::acceptClients(void*)
|
||||
startThread(new TMethodJob<CServer>(
|
||||
this, &CServer::runClient, socket));
|
||||
}
|
||||
|
||||
// clean up
|
||||
delete listen;
|
||||
}
|
||||
catch (XBase& e) {
|
||||
setStatus(kError, e.what());
|
||||
LOG((CLOG_ERR "cannot listen for clients: %s", e.what()));
|
||||
delete listen;
|
||||
exitMainLoopWithError();
|
||||
}
|
||||
catch (...) {
|
||||
setStatus(kNotRunning);
|
||||
delete listen;
|
||||
throw;
|
||||
}
|
||||
@ -1923,71 +2006,84 @@ CServer::addConnection(IClient* client)
|
||||
|
||||
LOG((CLOG_DEBUG "adding connection \"%s\"", client->getName().c_str()));
|
||||
|
||||
CLock lock(&m_mutex);
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// name must be in our configuration
|
||||
if (!m_config.isScreen(client->getName())) {
|
||||
throw XUnknownClient(client->getName());
|
||||
// name must be in our configuration
|
||||
if (!m_config.isScreen(client->getName())) {
|
||||
throw XUnknownClient(client->getName());
|
||||
}
|
||||
|
||||
// can only have one screen with a given name at any given time
|
||||
if (m_clients.count(client->getName()) != 0) {
|
||||
throw XDuplicateClient(client->getName());
|
||||
}
|
||||
|
||||
// save screen info
|
||||
m_clients.insert(std::make_pair(client->getName(), client));
|
||||
LOG((CLOG_DEBUG "added connection \"%s\"", client->getName().c_str()));
|
||||
}
|
||||
|
||||
// can only have one screen with a given name at any given time
|
||||
if (m_clients.count(client->getName()) != 0) {
|
||||
throw XDuplicateClient(client->getName());
|
||||
}
|
||||
|
||||
// save screen info
|
||||
m_clients.insert(std::make_pair(client->getName(), client));
|
||||
LOG((CLOG_DEBUG "added connection \"%s\"", client->getName().c_str()));
|
||||
runStatusJobs();
|
||||
}
|
||||
|
||||
void
|
||||
CServer::removeConnection(const CString& name)
|
||||
{
|
||||
LOG((CLOG_DEBUG "removing connection \"%s\"", name.c_str()));
|
||||
CLock lock(&m_mutex);
|
||||
bool updateStatus;
|
||||
{
|
||||
CLock lock(&m_mutex);
|
||||
|
||||
// find client
|
||||
CClientList::iterator index = m_clients.find(name);
|
||||
assert(index != m_clients.end());
|
||||
// find client
|
||||
CClientList::iterator index = m_clients.find(name);
|
||||
assert(index != m_clients.end());
|
||||
|
||||
// if this is active screen then we have to jump off of it
|
||||
IClient* active = (m_activeSaver != NULL) ? m_activeSaver : m_active;
|
||||
if (active == index->second && active != m_primaryClient) {
|
||||
// record new position (center of primary screen)
|
||||
m_primaryClient->getCursorCenter(m_x, m_y);
|
||||
// if this is active screen then we have to jump off of it
|
||||
IClient* active = (m_activeSaver != NULL) ? m_activeSaver : m_active;
|
||||
if (active == index->second && active != m_primaryClient) {
|
||||
// record new position (center of primary screen)
|
||||
m_primaryClient->getCursorCenter(m_x, m_y);
|
||||
|
||||
// stop waiting to switch if we were
|
||||
if (active == m_switchScreen) {
|
||||
clearSwitchState();
|
||||
// stop waiting to switch if we were
|
||||
if (active == m_switchScreen) {
|
||||
clearSwitchState();
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// cut over
|
||||
m_active = m_primaryClient;
|
||||
|
||||
// enter new screen (unless we already have because of the
|
||||
// screen saver)
|
||||
if (m_activeSaver == NULL) {
|
||||
m_primaryClient->enter(m_x, m_y, m_seqNum,
|
||||
m_primaryClient->getToggleMask(), false);
|
||||
}
|
||||
}
|
||||
|
||||
// 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));
|
||||
|
||||
// cut over
|
||||
m_active = m_primaryClient;
|
||||
|
||||
// enter new screen (unless we already have because of the
|
||||
// screen saver)
|
||||
if (m_activeSaver == NULL) {
|
||||
m_primaryClient->enter(m_x, m_y, m_seqNum,
|
||||
m_primaryClient->getToggleMask(), false);
|
||||
// if this screen had the cursor when the screen saver activated
|
||||
// then we can't switch back to it when the screen saver
|
||||
// deactivates.
|
||||
if (m_activeSaver == index->second) {
|
||||
m_activeSaver = NULL;
|
||||
}
|
||||
|
||||
// done with client
|
||||
delete index->second;
|
||||
m_clients.erase(index);
|
||||
|
||||
// remove any thread for this client
|
||||
m_clientThreads.erase(name);
|
||||
|
||||
updateStatus = (m_clients.size() <= 1);
|
||||
}
|
||||
|
||||
// if this screen had the cursor when the screen saver activated
|
||||
// then we can't switch back to it when the screen saver
|
||||
// deactivates.
|
||||
if (m_activeSaver == index->second) {
|
||||
m_activeSaver = NULL;
|
||||
if (updateStatus) {
|
||||
runStatusJobs();
|
||||
}
|
||||
|
||||
// done with client
|
||||
delete index->second;
|
||||
m_clients.erase(index);
|
||||
|
||||
// remove any thread for this client
|
||||
m_clientThreads.erase(name);
|
||||
}
|
||||
|
||||
|
||||
|
@ -22,9 +22,11 @@
|
||||
#include "CCondVar.h"
|
||||
#include "CMutex.h"
|
||||
#include "CThread.h"
|
||||
#include "CJobList.h"
|
||||
#include "CStopwatch.h"
|
||||
#include "stdlist.h"
|
||||
#include "stdmap.h"
|
||||
#include "stdvector.h"
|
||||
|
||||
class CClientProxy;
|
||||
class CHTTPServer;
|
||||
@ -42,6 +44,14 @@ This class implements the top-level server algorithms for synergy.
|
||||
*/
|
||||
class CServer : public IServer, public IPrimaryScreenReceiver {
|
||||
public:
|
||||
enum EStatus {
|
||||
kNotRunning,
|
||||
kRunning,
|
||||
kServerNameUnknown,
|
||||
kError,
|
||||
kMaxStatus
|
||||
};
|
||||
|
||||
/*!
|
||||
The server will look itself up in the configuration using \c serverName
|
||||
as its name.
|
||||
@ -116,6 +126,22 @@ public:
|
||||
*/
|
||||
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
|
||||
//@{
|
||||
@ -132,6 +158,24 @@ public:
|
||||
*/
|
||||
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
|
||||
@ -170,6 +214,12 @@ protected:
|
||||
private:
|
||||
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
|
||||
UInt32 getActivePrimarySides() const;
|
||||
|
||||
@ -352,6 +402,11 @@ private:
|
||||
CStopwatch m_switchTwoTapTimer;
|
||||
bool m_switchTwoTapEngaged;
|
||||
bool m_switchTwoTapArmed;
|
||||
|
||||
// the status change jobs and status
|
||||
CJobList m_statusJobs;
|
||||
EStatus m_status;
|
||||
CString m_statusMessage;
|
||||
};
|
||||
|
||||
#endif
|
||||
|
@ -74,17 +74,6 @@ CSecondaryScreen::open()
|
||||
// create and prepare our window
|
||||
createWindow();
|
||||
|
||||
// assume primary has all clipboards
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
grabClipboard(id);
|
||||
}
|
||||
|
||||
// update keyboard state
|
||||
updateKeys();
|
||||
|
||||
// disable the screen saver
|
||||
getScreen()->openScreensaver(false);
|
||||
|
||||
// subclass hook
|
||||
onPostOpen();
|
||||
|
||||
@ -95,6 +84,30 @@ CSecondaryScreen::open()
|
||||
close();
|
||||
throw;
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::close()
|
||||
{
|
||||
onPreClose();
|
||||
destroyWindow();
|
||||
getScreen()->close();
|
||||
onPostClose();
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::remoteControl()
|
||||
{
|
||||
// assume primary has all clipboards
|
||||
for (ClipboardID id = 0; id < kClipboardEnd; ++id) {
|
||||
grabClipboard(id);
|
||||
}
|
||||
|
||||
// update keyboard state
|
||||
updateKeys();
|
||||
|
||||
// disable the screen saver
|
||||
getScreen()->openScreensaver(false);
|
||||
|
||||
// hide the cursor
|
||||
{
|
||||
@ -105,13 +118,9 @@ CSecondaryScreen::open()
|
||||
}
|
||||
|
||||
void
|
||||
CSecondaryScreen::close()
|
||||
CSecondaryScreen::localControl()
|
||||
{
|
||||
onPreClose();
|
||||
getScreen()->closeScreensaver();
|
||||
destroyWindow();
|
||||
getScreen()->close();
|
||||
onPostClose();
|
||||
}
|
||||
|
||||
void
|
||||
|
@ -41,11 +41,10 @@ public:
|
||||
|
||||
//! Open screen
|
||||
/*!
|
||||
Opens the screen. This includes initializing the screen,
|
||||
hiding the cursor, and disabling the screen saver. It also causes
|
||||
events to the reported to an IScreenReceiver (which is set through
|
||||
some other interface). Calls close() before returning (rethrowing)
|
||||
if it fails for any reason.
|
||||
Opens the screen. It also causes events to the reported to an
|
||||
IScreenReceiver (which is set through some other interface).
|
||||
Calls close() before returning (rethrowing) if it fails for any
|
||||
reason.
|
||||
*/
|
||||
void open();
|
||||
|
||||
@ -64,12 +63,26 @@ public:
|
||||
*/
|
||||
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
|
||||
/*!
|
||||
Closes the screen. This restores the screen saver, shows the cursor
|
||||
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.
|
||||
Closes the screen.
|
||||
*/
|
||||
void close();
|
||||
|
||||
@ -332,6 +345,13 @@ protected:
|
||||
*/
|
||||
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
|
||||
/*!
|
||||
Toggle modifiers that don't match the given state so that they do.
|
||||
|