mirror of
https://github.com/debauchee/barrier.git
synced 2026-02-12 22:55:53 +08:00
Compare commits
97 Commits
| Author | SHA1 | Date | |
|---|---|---|---|
|
|
ddbef300ad | ||
|
|
afa24f4a02 | ||
|
|
37be6ec45f | ||
|
|
785bf4c01b | ||
|
|
060d8da671 | ||
|
|
d347cbd45f | ||
|
|
65fc59eeae | ||
|
|
93d864ad6f | ||
|
|
8024aa9ab1 | ||
|
|
3ebd939f32 | ||
|
|
deed8a28a2 | ||
|
|
546a40a653 | ||
|
|
648d9400f3 | ||
|
|
fe15c4e928 | ||
|
|
1f5c18720a | ||
|
|
e98b3678df | ||
|
|
6dea28d2a0 | ||
|
|
8e05604338 | ||
|
|
5d33d7fa86 | ||
|
|
117208754f | ||
|
|
23670c5f9b | ||
|
|
d2191b6b93 | ||
|
|
4d3fd14ada | ||
|
|
6a5da5aaac | ||
|
|
6756296d85 | ||
|
|
39b534f3b8 | ||
|
|
35e8c88887 | ||
|
|
de68346874 | ||
|
|
4f51d5fa50 | ||
|
|
df29bf8e54 | ||
|
|
5b4e46f8ea | ||
|
|
fed63422a6 | ||
|
|
e707b426cf | ||
|
|
5c6eba8790 | ||
|
|
561d1c6993 | ||
|
|
c364befde2 | ||
|
|
a32cb41342 | ||
|
|
a71ebc78b3 | ||
|
|
943a355359 | ||
|
|
a7a0b0021d | ||
|
|
67f17a0fda | ||
|
|
e3d57af4fd | ||
|
|
e786dbd60f | ||
|
|
e26ccfdce6 | ||
|
|
f9f2d8e8af | ||
|
|
d2814a423c | ||
|
|
cfa10d68ca | ||
|
|
c09d2ad91e | ||
|
|
7abcf13317 | ||
|
|
f3218ff53c | ||
|
|
072e03c6ce | ||
|
|
420ac24b0b | ||
|
|
c18411b9a4 | ||
|
|
74873d763e | ||
|
|
aa8d6c95c7 | ||
|
|
e0101b884f | ||
|
|
326901ef86 | ||
|
|
1c1f0e70f2 | ||
|
|
5a6bdfb5e6 | ||
|
|
fe95ec5bc8 | ||
|
|
90aa90f19f | ||
|
|
b85432aeee | ||
|
|
0f926658dc | ||
|
|
5bd0139734 | ||
|
|
07d56e8e03 | ||
|
|
2709ae48db | ||
|
|
b52f2e0ca7 | ||
|
|
d22418606f | ||
|
|
bc772f98a6 | ||
|
|
c2b3f1414b | ||
|
|
8e4f8e6b92 | ||
|
|
9e358233c3 | ||
|
|
4a24a2117a | ||
|
|
4aa43d6995 | ||
|
|
685f53c7fc | ||
|
|
972922607b | ||
|
|
a58ca97941 | ||
|
|
e746cc401a | ||
|
|
504e41966e | ||
|
|
3a663092cf | ||
|
|
8b4a3a8b92 | ||
|
|
3b3cec4040 | ||
|
|
ec3a9c3f1f | ||
|
|
91423c9c97 | ||
|
|
2dd56efa63 | ||
|
|
b644b1253d | ||
|
|
7dd2db25ec | ||
|
|
38718a362f | ||
|
|
aeab72f724 | ||
|
|
70c8f98615 | ||
|
|
8daa83dbea | ||
|
|
c3aa1963c9 | ||
|
|
a5db4dc8c5 | ||
|
|
2c16180eba | ||
|
|
6da369b5f2 | ||
|
|
7e562273d5 | ||
|
|
1805dd7900 |
29
.gitignore
vendored
29
.gitignore
vendored
@@ -1,19 +1,14 @@
|
||||
#Vim backup files
|
||||
*~
|
||||
#Python compiled files
|
||||
*.pyc
|
||||
|
||||
#Git-svn created .gitignore
|
||||
/Release
|
||||
/Debug
|
||||
/vc90.pdb
|
||||
/synergy.ncb
|
||||
/synergy.vcproj.ADOBENET.ssbarnea.user
|
||||
/bin
|
||||
/tool
|
||||
/config.h
|
||||
/tags
|
||||
|
||||
#doxygen
|
||||
/doc/doxygen
|
||||
/doc/doxygen.cfg
|
||||
/lib
|
||||
/build
|
||||
/ext/cryptopp562
|
||||
/ext/gmock-1.6.0
|
||||
/ext/gtest-1.6.0
|
||||
/src/gui/Makefile*
|
||||
/src/gui/object_script*
|
||||
/src/gui/tmp
|
||||
/src/gui/ui_*
|
||||
src/gui/gui.pro.user
|
||||
src/gui/.qmake.stash
|
||||
config.h
|
||||
|
||||
@@ -17,7 +17,7 @@
|
||||
# Version number for Synergy
|
||||
set(VERSION_MAJOR 1)
|
||||
set(VERSION_MINOR 6)
|
||||
set(VERSION_REV 0)
|
||||
set(VERSION_REV 1)
|
||||
set(VERSION "${VERSION_MAJOR}.${VERSION_MINOR}.${VERSION_REV}")
|
||||
|
||||
cmake_minimum_required(VERSION 2.6)
|
||||
@@ -161,17 +161,20 @@ if (UNIX)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
exec_program(uname ARGS -v OUTPUT_VARIABLE DARWIN_VERSION)
|
||||
string(REGEX MATCH "[0-9]+" DARWIN_VERSION ${DARWIN_VERSION})
|
||||
message(STATUS "DARWIN_VERSION=${DARWIN_VERSION}")
|
||||
if (DARWIN_VERSION LESS 9)
|
||||
# 10.4: universal (32-bit intel and power pc)
|
||||
message(STATUS "OSX_TARGET_MAJOR=${OSX_TARGET_MAJOR}")
|
||||
message(STATUS "OSX_TARGET_MINOR=${OSX_TARGET_MINOR}")
|
||||
|
||||
if (NOT (OSX_TARGET_MAJOR EQUAL 10))
|
||||
message(FATAL_ERROR "Mac OS X target must be 10.x")
|
||||
endif ()
|
||||
|
||||
if (OSX_TARGET_MINOR LESS 6)
|
||||
# <= 10.5: 32-bit Intel and PowerPC
|
||||
set(CMAKE_OSX_ARCHITECTURES "ppc;i386"
|
||||
CACHE STRING "" FORCE)
|
||||
else()
|
||||
# 10.5+: 32-bit only -- missing funcs in 64-bit os libs
|
||||
# such as GetGlobalMouse.
|
||||
set(CMAKE_OSX_ARCHITECTURES "i386"
|
||||
# >= 10.6: Intel only
|
||||
set(CMAKE_OSX_ARCHITECTURES "i386;x86_64"
|
||||
CACHE STRING "" FORCE)
|
||||
endif()
|
||||
|
||||
|
||||
17
ChangeLog
17
ChangeLog
@@ -1,3 +1,20 @@
|
||||
1.6.1
|
||||
=====
|
||||
Bug #4002 - Carbon loop not ready within 5 sec
|
||||
Bug #4191 - Accessibility helper tool crashes
|
||||
Bug #4149 - Mac 10.9.5 or 10.10 gatekeeper blocks Synergy
|
||||
Bug #4139 - Exception thrown when ProcessIdToSessionId() fails
|
||||
Bug #4055 - Shift keys are not sent to clients (Win 8.1 server)
|
||||
Bug #4021 - Copy & paste not working for EFL applications
|
||||
Bug #3749 - Linux Chrome hover doesn't work
|
||||
Bug #4128 - Daemon logging not written with "log to file"
|
||||
Enhancement #4122 - Enable drag and drop by default
|
||||
Enhancement #4158 - Build for Mac OS X 10.10
|
||||
Enhancement #4130 - Auto elevate for Windows UAC and screen lock
|
||||
Enhancement #4126 - 64-bit support for OS X
|
||||
Enhancement #4141 - DMRM message support for μSynergy
|
||||
Enhancement #4124 - More robust argument parsing
|
||||
|
||||
1.6.0
|
||||
=====
|
||||
Feature #65 - Auto config feature using Zeroconf/Bonjour
|
||||
|
||||
27
README
27
README
@@ -1,2 +1,25 @@
|
||||
Help: http://synergy-project.org/help/
|
||||
Wiki: http://synergy-project.org/wiki/
|
||||
About
|
||||
=====
|
||||
|
||||
Synergy brings your computers together in one cohesive experience; its
|
||||
software for sharing one mouse and keyboard between multiple computers
|
||||
on your desk. It works on Windows, Mac OS X and Linux allowing you to
|
||||
seamlessly move your mouse cursor between all computers on your desk.
|
||||
|
||||
Users
|
||||
=====
|
||||
|
||||
Synergy is easy to download and configure.
|
||||
Get it here: http://synergy-project.org/
|
||||
|
||||
Developers
|
||||
==========
|
||||
|
||||
Synergy is free and open source, so you are free to run the program,
|
||||
change the program, and redistribute the program with or without changes.
|
||||
|
||||
Once you've got the source code, just use "hm conf" and "hm build" to
|
||||
compile (./hm.sh on Linux and Mac).
|
||||
|
||||
For detailed compile instructions and a list of dependencies, check
|
||||
out our wiki: http://synergy-project.org/wiki/Compiling
|
||||
|
||||
@@ -451,9 +451,15 @@ class InternalCommands:
|
||||
cmake_args += ' -DCMAKE_BUILD_TYPE=' + target.capitalize()
|
||||
|
||||
elif sys.platform == "darwin":
|
||||
macSdkMatch = re.match("(\d+)\.(\d+)", self.macSdk)
|
||||
if not macSdkMatch:
|
||||
raise Exception("unknown osx version: " + self.macSdk)
|
||||
|
||||
sdkDir = self.getMacSdkDir()
|
||||
cmake_args += " -DCMAKE_OSX_SYSROOT=" + sdkDir
|
||||
cmake_args += " -DCMAKE_OSX_DEPLOYMENT_TARGET=" + self.macSdk
|
||||
cmake_args += " -DOSX_TARGET_MAJOR=" + macSdkMatch.group(1)
|
||||
cmake_args += " -DOSX_TARGET_MINOR=" + macSdkMatch.group(2)
|
||||
|
||||
# if not visual studio, use parent dir
|
||||
sourceDir = generator.getSourceDir()
|
||||
@@ -554,7 +560,24 @@ class InternalCommands:
|
||||
return (major, minor, rev)
|
||||
|
||||
def getMacSdkDir(self):
|
||||
return "/Developer/SDKs/MacOSX" + self.macSdk + ".sdk"
|
||||
sdkName = "macosx" + self.macSdk
|
||||
|
||||
# Ideally we'll use xcrun (which is influenced by $DEVELOPER_DIR), then try a couple
|
||||
# fallbacks to known paths if xcrun is not available
|
||||
status, sdkPath = commands.getstatusoutput("xcrun --show-sdk-path --sdk " + sdkName)
|
||||
if status == 0 and sdkPath:
|
||||
return sdkPath
|
||||
|
||||
developerDir = os.getenv("DEVELOPER_DIR")
|
||||
if not developerDir:
|
||||
developerDir = "/Applications/Xcode.app/Contents/Developer"
|
||||
|
||||
sdkDirName = sdkName.replace("macosx", "MacOSX")
|
||||
sdkPath = developerDir + "/Platforms/MacOSX.platform/Developer/SDKs/" + sdkDirName + ".sdk"
|
||||
if os.path.exists(sdkPath):
|
||||
return sdkPath
|
||||
|
||||
return "/Developer/SDKs/" + sdkDirName + ".sdk"
|
||||
|
||||
# http://tinyurl.com/cs2rxxb
|
||||
def fixCmakeEclipseBug(self):
|
||||
@@ -734,7 +757,13 @@ class InternalCommands:
|
||||
raise Exception('Build command not supported with generator: ' + generator)
|
||||
|
||||
def makeGui(self, targets, args=""):
|
||||
|
||||
name = "Synergy.app"
|
||||
self.try_chdir(self.getGenerator().binDir)
|
||||
if os.path.exists(name):
|
||||
print "removing exisiting bundle"
|
||||
shutil.rmtree(name)
|
||||
self.restore_chdir()
|
||||
|
||||
if sys.platform == 'win32':
|
||||
gui_make_cmd = self.w32_make_cmd
|
||||
elif sys.platform in ['linux2', 'sunos5', 'freebsd7', 'darwin']:
|
||||
@@ -765,7 +794,50 @@ class InternalCommands:
|
||||
if sys.platform == 'darwin' and not "clean" in args:
|
||||
for target in targets:
|
||||
self.macPostMake(target)
|
||||
|
||||
|
||||
self.fixQtFrameworksLayout()
|
||||
|
||||
def symlink(self, source, target):
|
||||
if not os.path.exists(target):
|
||||
os.symlink(source, target)
|
||||
|
||||
def move(self, source, target):
|
||||
if os.path.exists(source):
|
||||
shutil.move(source, target)
|
||||
|
||||
def fixQtFrameworksLayout(self):
|
||||
# reorganize Qt frameworks layout on Mac 10.9.5 or later
|
||||
# http://goo.gl/BFnQ8l
|
||||
# QtCore example:
|
||||
# QtCore.framework/
|
||||
# QtCore -> Versions/Current/QtCore
|
||||
# Resources -> Versions/Current/Resources
|
||||
# Versions/
|
||||
# Current -> 5
|
||||
# 5/
|
||||
# QtCore
|
||||
# Resources/
|
||||
# Info.plist
|
||||
dir = self.getGenerator().binDir
|
||||
target = dir + "/Synergy.app/Contents/Frameworks"
|
||||
(major, minor) = self.getMacVersion()
|
||||
if major == 10:
|
||||
if minor >= 9:
|
||||
for root, dirs, files in os.walk(target):
|
||||
for dir in dirs:
|
||||
if dir.startswith("Qt"):
|
||||
self.try_chdir(target + "/" + dir +"/Versions")
|
||||
self.symlink("5", "Current")
|
||||
self.move("../Resources", "5")
|
||||
self.restore_chdir()
|
||||
|
||||
self.try_chdir(target + "/" + dir)
|
||||
dot = dir.find('.')
|
||||
frameworkName = dir[:dot]
|
||||
self.symlink("Versions/Current/" + frameworkName, frameworkName)
|
||||
self.symlink("Versions/Current/Resources", "Resources")
|
||||
self.restore_chdir()
|
||||
|
||||
def macPostMake(self, target):
|
||||
|
||||
dir = self.getGenerator().binDir
|
||||
@@ -779,7 +851,7 @@ class InternalCommands:
|
||||
shutil.copy(targetDir + "/synergyc", bundleBinDir)
|
||||
shutil.copy(targetDir + "/synergys", bundleBinDir)
|
||||
shutil.copy(targetDir + "/syntool", bundleBinDir)
|
||||
|
||||
|
||||
if self.macSdk == "10.9":
|
||||
launchServicesDir = dir + "/Synergy.app/Contents/Library/LaunchServices/"
|
||||
if not os.path.exists(launchServicesDir):
|
||||
@@ -805,15 +877,16 @@ class InternalCommands:
|
||||
# TODO: auto-detect, qt can now be installed anywhere.
|
||||
frameworkRootDir = "/Developer/Qt5.2.1/5.2.1/clang_64/lib"
|
||||
|
||||
# copy the missing Info.plist files for the frameworks.
|
||||
target = dir + "/Synergy.app/Contents/Frameworks"
|
||||
|
||||
# copy the missing Info.plist files for the frameworks.
|
||||
for root, dirs, files in os.walk(target):
|
||||
for dir in dirs:
|
||||
if dir.startswith("Qt"):
|
||||
shutil.copy(
|
||||
frameworkRootDir + "/" + dir + "/Contents/Info.plist",
|
||||
target + "/" + dir + "/Resources/")
|
||||
|
||||
|
||||
def signmac(self):
|
||||
self.loadConfig()
|
||||
if not self.macIdentity:
|
||||
@@ -941,6 +1014,39 @@ class InternalCommands:
|
||||
print self.find_revision()
|
||||
|
||||
def find_revision(self):
|
||||
return self.getGitRevision()
|
||||
|
||||
def getGitRevision(self):
|
||||
if sys.version_info < (2, 4):
|
||||
raise Exception("Python 2.4 or greater required.")
|
||||
|
||||
p = subprocess.Popen(
|
||||
["git", "log", "--pretty=format:%h", "-n", "1"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode != 0:
|
||||
raise Exception('Could not get revision, git error: ' + str(p.returncode))
|
||||
|
||||
return stdout.strip()
|
||||
|
||||
def getGitBranchName(self):
|
||||
if sys.version_info < (2, 4):
|
||||
raise Exception("Python 2.4 or greater required.")
|
||||
|
||||
p = subprocess.Popen(
|
||||
["git", "rev-parse", "--abbrev-ref", "HEAD"],
|
||||
stdout=subprocess.PIPE, stderr=subprocess.PIPE)
|
||||
|
||||
stdout, stderr = p.communicate()
|
||||
|
||||
if p.returncode != 0:
|
||||
raise Exception('Could not get branch name, git error: ' + str(p.returncode))
|
||||
|
||||
return stdout.strip()
|
||||
|
||||
def find_revision_svn(self):
|
||||
if sys.version_info < (2, 4):
|
||||
stdout = commands.getoutput('svn info')
|
||||
else:
|
||||
@@ -986,10 +1092,7 @@ class InternalCommands:
|
||||
moveExt = ''
|
||||
|
||||
if type == 'src':
|
||||
if sys.platform in ['linux2', 'darwin']:
|
||||
self.distSrc()
|
||||
else:
|
||||
package_unsupported = True
|
||||
self.distSrc()
|
||||
|
||||
elif type == 'rpm':
|
||||
if sys.platform == 'linux2':
|
||||
@@ -1173,10 +1276,15 @@ class InternalCommands:
|
||||
print "Removing existing export..."
|
||||
shutil.rmtree(exportPath)
|
||||
|
||||
os.mkdir(exportPath)
|
||||
|
||||
cmd = "git archive %s | tar -x -C %s" % (
|
||||
self.getGitBranchName(), exportPath)
|
||||
|
||||
print 'Exporting repository to: ' + exportPath
|
||||
err = os.system('svn export . ' + exportPath)
|
||||
err = os.system(cmd)
|
||||
if err != 0:
|
||||
raise Exception('Repository export failed: ' + str(err))
|
||||
raise Exception('Repository export failed: ' + str(err))
|
||||
|
||||
packagePath = '../' + self.getGenerator().binDir + '/' + name + '.tar.gz'
|
||||
|
||||
@@ -1206,7 +1314,7 @@ class InternalCommands:
|
||||
shutil.rmtree(dist)
|
||||
|
||||
os.makedirs(dist)
|
||||
shutil.copytree(dir + "/" + name + ".app", dist + "/" + name + ".app")
|
||||
shutil.move(dir + "/" + name + ".app", dist + "/" + name + ".app")
|
||||
|
||||
self.try_chdir(dist)
|
||||
err = os.system("ln -s /Applications")
|
||||
@@ -1403,9 +1511,10 @@ class InternalCommands:
|
||||
def dist_name_rev(self, type):
|
||||
# find the version number (we're puting the rev in after this)
|
||||
pattern = '(.*\d+\.\d+\.\d+)(.*)'
|
||||
replace = '\g<1>-r' + self.find_revision() + '\g<2>'
|
||||
replace = "\g<1>-%s-%s\g<2>" % (
|
||||
self.getGitBranchName(), self.getGitRevision())
|
||||
return re.sub(pattern, replace, self.dist_name(type))
|
||||
|
||||
|
||||
def dist_usage(self):
|
||||
print ('Usage: %s package [package-type]\n'
|
||||
'\n'
|
||||
|
||||
@@ -25,7 +25,7 @@ if (WIN32)
|
||||
endif()
|
||||
|
||||
if (APPLE)
|
||||
if (DARWIN_VERSION GREATER 12)
|
||||
if (OSX_TARGET_MINOR GREATER 8)
|
||||
add_subdirectory(synmacph)
|
||||
endif()
|
||||
endif()
|
||||
|
||||
194
src/gui/gui.pro
194
src/gui/gui.pro
@@ -1,115 +1,113 @@
|
||||
QT += widgets network
|
||||
QT += widgets \
|
||||
network
|
||||
TEMPLATE = app
|
||||
TARGET = synergy
|
||||
DEPENDPATH += . \
|
||||
res
|
||||
res
|
||||
INCLUDEPATH += . \
|
||||
src
|
||||
src
|
||||
FORMS += res/MainWindowBase.ui \
|
||||
res/AboutDialogBase.ui \
|
||||
res/ServerConfigDialogBase.ui \
|
||||
res/ScreenSettingsDialogBase.ui \
|
||||
res/ActionDialogBase.ui \
|
||||
res/HotkeyDialogBase.ui \
|
||||
res/SettingsDialogBase.ui \
|
||||
res/SetupWizardBase.ui
|
||||
res/AboutDialogBase.ui \
|
||||
res/ServerConfigDialogBase.ui \
|
||||
res/ScreenSettingsDialogBase.ui \
|
||||
res/ActionDialogBase.ui \
|
||||
res/HotkeyDialogBase.ui \
|
||||
res/SettingsDialogBase.ui \
|
||||
res/SetupWizardBase.ui
|
||||
SOURCES += src/main.cpp \
|
||||
src/MainWindow.cpp \
|
||||
src/AboutDialog.cpp \
|
||||
src/ServerConfig.cpp \
|
||||
src/ServerConfigDialog.cpp \
|
||||
src/ScreenSetupView.cpp \
|
||||
src/Screen.cpp \
|
||||
src/ScreenSetupModel.cpp \
|
||||
src/NewScreenWidget.cpp \
|
||||
src/TrashScreenWidget.cpp \
|
||||
src/ScreenSettingsDialog.cpp \
|
||||
src/BaseConfig.cpp \
|
||||
src/HotkeyDialog.cpp \
|
||||
src/ActionDialog.cpp \
|
||||
src/Hotkey.cpp \
|
||||
src/Action.cpp \
|
||||
src/KeySequence.cpp \
|
||||
src/KeySequenceWidget.cpp \
|
||||
src/SettingsDialog.cpp \
|
||||
src/AppConfig.cpp \
|
||||
src/QSynergyApplication.cpp \
|
||||
src/VersionChecker.cpp \
|
||||
src/SetupWizard.cpp \
|
||||
src/IpcClient.cpp \
|
||||
src/IpcReader.cpp \
|
||||
src/Ipc.cpp \
|
||||
src/SynergyLocale.cpp \
|
||||
src/QUtility.cpp \
|
||||
src/PremiumAuth.cpp \
|
||||
src/ZeroconfServer.cpp \
|
||||
src/ZeroconfThread.cpp \
|
||||
src/ZeroconfRegister.cpp \
|
||||
src/ZeroconfBrowser.cpp \
|
||||
src/ZeroconfService.cpp
|
||||
src/MainWindow.cpp \
|
||||
src/AboutDialog.cpp \
|
||||
src/ServerConfig.cpp \
|
||||
src/ServerConfigDialog.cpp \
|
||||
src/ScreenSetupView.cpp \
|
||||
src/Screen.cpp \
|
||||
src/ScreenSetupModel.cpp \
|
||||
src/NewScreenWidget.cpp \
|
||||
src/TrashScreenWidget.cpp \
|
||||
src/ScreenSettingsDialog.cpp \
|
||||
src/BaseConfig.cpp \
|
||||
src/HotkeyDialog.cpp \
|
||||
src/ActionDialog.cpp \
|
||||
src/Hotkey.cpp \
|
||||
src/Action.cpp \
|
||||
src/KeySequence.cpp \
|
||||
src/KeySequenceWidget.cpp \
|
||||
src/SettingsDialog.cpp \
|
||||
src/AppConfig.cpp \
|
||||
src/QSynergyApplication.cpp \
|
||||
src/VersionChecker.cpp \
|
||||
src/SetupWizard.cpp \
|
||||
src/IpcClient.cpp \
|
||||
src/IpcReader.cpp \
|
||||
src/Ipc.cpp \
|
||||
src/SynergyLocale.cpp \
|
||||
src/QUtility.cpp \
|
||||
src/ZeroconfServer.cpp \
|
||||
src/ZeroconfThread.cpp \
|
||||
src/ZeroconfRegister.cpp \
|
||||
src/ZeroconfBrowser.cpp \
|
||||
src/ZeroconfService.cpp
|
||||
HEADERS += src/MainWindow.h \
|
||||
src/AboutDialog.h \
|
||||
src/ServerConfig.h \
|
||||
src/ServerConfigDialog.h \
|
||||
src/ScreenSetupView.h \
|
||||
src/Screen.h \
|
||||
src/ScreenSetupModel.h \
|
||||
src/NewScreenWidget.h \
|
||||
src/TrashScreenWidget.h \
|
||||
src/ScreenSettingsDialog.h \
|
||||
src/BaseConfig.h \
|
||||
src/HotkeyDialog.h \
|
||||
src/ActionDialog.h \
|
||||
src/Hotkey.h \
|
||||
src/Action.h \
|
||||
src/KeySequence.h \
|
||||
src/KeySequenceWidget.h \
|
||||
src/SettingsDialog.h \
|
||||
src/AppConfig.h \
|
||||
src/QSynergyApplication.h \
|
||||
src/VersionChecker.h \
|
||||
src/SetupWizard.h \
|
||||
src/IpcClient.h \
|
||||
src/IpcReader.h \
|
||||
src/Ipc.h \
|
||||
src/SynergyLocale.h \
|
||||
src/QUtility.h \
|
||||
src/PremiumAuth.h \
|
||||
src/ZeroconfServer.h \
|
||||
src/ZeroconfThread.h \
|
||||
src/ZeroconfRegister.h \
|
||||
src/ZeroconfRecord.h \
|
||||
src/ZeroconfBrowser.h \
|
||||
src/ZeroconfService.h
|
||||
src/AboutDialog.h \
|
||||
src/ServerConfig.h \
|
||||
src/ServerConfigDialog.h \
|
||||
src/ScreenSetupView.h \
|
||||
src/Screen.h \
|
||||
src/ScreenSetupModel.h \
|
||||
src/NewScreenWidget.h \
|
||||
src/TrashScreenWidget.h \
|
||||
src/ScreenSettingsDialog.h \
|
||||
src/BaseConfig.h \
|
||||
src/HotkeyDialog.h \
|
||||
src/ActionDialog.h \
|
||||
src/Hotkey.h \
|
||||
src/Action.h \
|
||||
src/KeySequence.h \
|
||||
src/KeySequenceWidget.h \
|
||||
src/SettingsDialog.h \
|
||||
src/AppConfig.h \
|
||||
src/QSynergyApplication.h \
|
||||
src/VersionChecker.h \
|
||||
src/SetupWizard.h \
|
||||
src/IpcClient.h \
|
||||
src/IpcReader.h \
|
||||
src/Ipc.h \
|
||||
src/SynergyLocale.h \
|
||||
src/QUtility.h \
|
||||
src/ZeroconfServer.h \
|
||||
src/ZeroconfThread.h \
|
||||
src/ZeroconfRegister.h \
|
||||
src/ZeroconfRecord.h \
|
||||
src/ZeroconfBrowser.h \
|
||||
src/ZeroconfService.h
|
||||
RESOURCES += res/Synergy.qrc
|
||||
RC_FILE = res/win/Synergy.rc
|
||||
macx {
|
||||
HEADERS += src/AXDatabaseCleaner.h
|
||||
OBJECTIVE_SOURCES += src/AXDatabaseCleaner.mm
|
||||
QMAKE_INFO_PLIST = res/mac/Info.plist
|
||||
TARGET = Synergy
|
||||
QSYNERGY_ICON.files = res/mac/Synergy.icns
|
||||
QSYNERGY_ICON.path = Contents/Resources
|
||||
QMAKE_BUNDLE_DATA += QSYNERGY_ICON
|
||||
LIBS += $$MACX_LIBS
|
||||
}
|
||||
unix:!macx {
|
||||
LIBS += -ldns_sd
|
||||
macx {
|
||||
HEADERS += src/AXDatabaseCleaner.h
|
||||
OBJECTIVE_SOURCES += src/AXDatabaseCleaner.mm
|
||||
QMAKE_INFO_PLIST = res/mac/Info.plist
|
||||
TARGET = Synergy
|
||||
QSYNERGY_ICON.files = res/mac/Synergy.icns
|
||||
QSYNERGY_ICON.path = Contents/Resources
|
||||
QMAKE_BUNDLE_DATA += QSYNERGY_ICON
|
||||
LIBS += $$MACX_LIBS
|
||||
}
|
||||
unix:!macx:LIBS += -ldns_sd
|
||||
debug {
|
||||
OBJECTS_DIR = tmp/debug
|
||||
MOC_DIR = tmp/debug
|
||||
RCC_DIR = tmp/debug
|
||||
OBJECTS_DIR = tmp/debug
|
||||
MOC_DIR = tmp/debug
|
||||
RCC_DIR = tmp/debug
|
||||
}
|
||||
release {
|
||||
OBJECTS_DIR = tmp/release
|
||||
MOC_DIR = tmp/release
|
||||
RCC_DIR = tmp/release
|
||||
OBJECTS_DIR = tmp/release
|
||||
MOC_DIR = tmp/release
|
||||
RCC_DIR = tmp/release
|
||||
}
|
||||
win32 {
|
||||
Debug:DESTDIR = ../../bin/Debug
|
||||
Release:DESTDIR = ../../bin/Release
|
||||
LIBS += -L"../../ext/bonjour/x64" -ldnssd
|
||||
INCLUDEPATH += "$(BONJOUR_SDK_HOME)/Include"
|
||||
Debug:DESTDIR = ../../bin/Debug
|
||||
Release:DESTDIR = ../../bin/Release
|
||||
LIBS += -L"../../ext/bonjour/x64" \
|
||||
-ldnssd
|
||||
INCLUDEPATH += "$(BONJOUR_SDK_HOME)/Include"
|
||||
}
|
||||
else:DESTDIR = ../../bin
|
||||
|
||||
File diff suppressed because it is too large
Load Diff
@@ -114,6 +114,13 @@
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_pComboLanguage"/>
|
||||
</item>
|
||||
<item row="4" column="0">
|
||||
<widget class="QCheckBox" name="m_pCheckBoxElevateMode">
|
||||
<property name="text">
|
||||
<string>Elevate mode</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</item>
|
||||
|
||||
@@ -1,443 +1,245 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SetupWizardBase</class>
|
||||
<widget class="QWizard" name="SetupWizardBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>556</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>390</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Setup Synergy</string>
|
||||
</property>
|
||||
<widget class="QWizardPage" name="m_pWelcomePage">
|
||||
<property name="title">
|
||||
<string>Welcome</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Thanks for installing Synergy!</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">&Language:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>m_pComboLanguage</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_pComboLanguage">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="locale">
|
||||
<locale language="English" country="UnitedKingdom"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="m_pPremiumUserPage">
|
||||
<property name="title">
|
||||
<string>Synergy Premium</string>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_4">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pRadioButtonPremiumLogin">
|
||||
<property name="text">
|
||||
<string>I donated to Synergy and have a premium login...</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_5">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="m_pLabel_28">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Email:</string>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>m_pLineEditPremiumEmail</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QLineEdit" name="m_pLineEditPremiumEmail">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeIncrement">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Normal</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="0">
|
||||
<widget class="QLabel" name="m_pLabel_29">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Password:</string>
|
||||
</property>
|
||||
<property name="indent">
|
||||
<number>10</number>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>m_pLineEditPremiumPassword</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="1" column="1">
|
||||
<widget class="QLineEdit" name="m_pLineEditPremiumPassword">
|
||||
<property name="enabled">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Fixed" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="sizeIncrement">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="baseSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string/>
|
||||
</property>
|
||||
<property name="echoMode">
|
||||
<enum>QLineEdit::Password</enum>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="2" column="1">
|
||||
<widget class="QLabel" name="m_pLabelForgotPassword">
|
||||
<property name="text">
|
||||
<string><a href="http://synergy-project.org/premium/reset/?source=gui">Forgot password</a></string>
|
||||
</property>
|
||||
<property name="openExternalLinks">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_12">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>5</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pRadioButtonPremiumLater">
|
||||
<property name="text">
|
||||
<string>No, I have not donated to Synergy, skip this step</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_9">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Expanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>100</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="m_pNodePage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Server or Client?</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pServerRadioButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Server (share this computer's mouse and keyboard)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_pClientLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pClientRadioButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Client (use another computer's mouse and keyboard)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_pServerLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>m_pComboLanguage</tabstop>
|
||||
<tabstop>m_pRadioButtonPremiumLogin</tabstop>
|
||||
<tabstop>m_pLineEditPremiumEmail</tabstop>
|
||||
<tabstop>m_pLineEditPremiumPassword</tabstop>
|
||||
<tabstop>m_pRadioButtonPremiumLater</tabstop>
|
||||
<tabstop>m_pServerRadioButton</tabstop>
|
||||
<tabstop>m_pClientRadioButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<ui version="4.0">
|
||||
<class>SetupWizardBase</class>
|
||||
<widget class="QWizard" name="SetupWizardBase">
|
||||
<property name="geometry">
|
||||
<rect>
|
||||
<x>0</x>
|
||||
<y>0</y>
|
||||
<width>556</width>
|
||||
<height>464</height>
|
||||
</rect>
|
||||
</property>
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Preferred" vsizetype="Preferred">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>500</width>
|
||||
<height>390</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="windowTitle">
|
||||
<string>Setup Synergy</string>
|
||||
</property>
|
||||
<widget class="QWizardPage" name="m_pWelcomePage">
|
||||
<property name="title">
|
||||
<string>Welcome</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string notr="true"/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_3">
|
||||
<item>
|
||||
<widget class="QLabel" name="label_3">
|
||||
<property name="text">
|
||||
<string>Thanks for installing Synergy!</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_6">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<layout class="QFormLayout" name="formLayout_3">
|
||||
<item row="0" column="0">
|
||||
<widget class="QLabel" name="label_4">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>100</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string notr="true">&Language:</string>
|
||||
</property>
|
||||
<property name="buddy">
|
||||
<cstring>m_pComboLanguage</cstring>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item row="0" column="1">
|
||||
<widget class="QComboBox" name="m_pComboLanguage">
|
||||
<property name="maximumSize">
|
||||
<size>
|
||||
<width>200</width>
|
||||
<height>16777215</height>
|
||||
</size>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_7">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>10</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="label_5">
|
||||
<property name="locale">
|
||||
<locale language="English" country="UnitedKingdom"/>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>Synergy lets you easily share your mouse and keyboard between multiple computers on your desk, and it's Free and Open Source. Just move your mouse off the edge of one computer's screen on to another. You can even share all of your clipboards. All you need is a network connection. Synergy is cross-platform (works on Windows, Mac OS X and Linux).</string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
<widget class="QWizardPage" name="m_pNodePage">
|
||||
<property name="sizePolicy">
|
||||
<sizepolicy hsizetype="Expanding" vsizetype="Expanding">
|
||||
<horstretch>0</horstretch>
|
||||
<verstretch>0</verstretch>
|
||||
</sizepolicy>
|
||||
</property>
|
||||
<property name="title">
|
||||
<string>Server or Client?</string>
|
||||
</property>
|
||||
<property name="subTitle">
|
||||
<string/>
|
||||
</property>
|
||||
<layout class="QVBoxLayout" name="verticalLayout_2">
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pServerRadioButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Server (share this computer's mouse and keyboard)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_pClientLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">My main mouse and keyboard are connected to this computer. This will allow you to move your mouse over to another computer's screen. There can only be one server in your setup.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::Fixed</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>20</width>
|
||||
<height>20</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QRadioButton" name="m_pClientRadioButton">
|
||||
<property name="font">
|
||||
<font>
|
||||
<weight>75</weight>
|
||||
<bold>true</bold>
|
||||
</font>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string>&Client (use another computer's mouse and keyboard)</string>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<widget class="QLabel" name="m_pServerLabel">
|
||||
<property name="minimumSize">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
<property name="text">
|
||||
<string><!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.0//EN" "http://www.w3.org/TR/REC-html40/strict.dtd">
|
||||
<html><head><meta name="qrichtext" content="1" /><style type="text/css">
|
||||
p, li { white-space: pre-wrap; }
|
||||
</style></head><body style=" font-family:'MS Shell Dlg 2'; font-size:8.25pt; font-weight:400; font-style:normal;">
|
||||
<p style=" margin-top:0px; margin-bottom:0px; margin-left:0px; margin-right:0px; -qt-block-indent:0; text-indent:0px;"><span style=" font-size:8pt;">You have already set up a server. This computer will be controlled using the server's mouse and keyboard. There can be many clients in your setup.</span></p></body></html></string>
|
||||
</property>
|
||||
<property name="wordWrap">
|
||||
<bool>true</bool>
|
||||
</property>
|
||||
</widget>
|
||||
</item>
|
||||
<item>
|
||||
<spacer name="verticalSpacer_2">
|
||||
<property name="orientation">
|
||||
<enum>Qt::Vertical</enum>
|
||||
</property>
|
||||
<property name="sizeType">
|
||||
<enum>QSizePolicy::MinimumExpanding</enum>
|
||||
</property>
|
||||
<property name="sizeHint" stdset="0">
|
||||
<size>
|
||||
<width>0</width>
|
||||
<height>0</height>
|
||||
</size>
|
||||
</property>
|
||||
</spacer>
|
||||
</item>
|
||||
</layout>
|
||||
</widget>
|
||||
</widget>
|
||||
<tabstops>
|
||||
<tabstop>m_pComboLanguage</tabstop>
|
||||
<tabstop>m_pServerRadioButton</tabstop>
|
||||
<tabstop>m_pClientRadioButton</tabstop>
|
||||
</tabstops>
|
||||
<resources/>
|
||||
<connections/>
|
||||
</ui>
|
||||
|
||||
@@ -1,7 +1,11 @@
|
||||
<?xml version="1.0" encoding="UTF-8"?>
|
||||
<!DOCTYPE plist SYSTEM "file://localhost/System/Library/DTDs/PropertyList.dtd">
|
||||
<plist version="0.9">
|
||||
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
|
||||
<plist version="1.0">
|
||||
<dict>
|
||||
<key>CFBundleInfoDictionaryVersion</key>
|
||||
<string>6.0</string>
|
||||
<key>NSPrincipalClass</key>
|
||||
<string>NSApplication</string>
|
||||
<key>CFBundleIconFile</key>
|
||||
<string>Synergy.icns</string>
|
||||
<key>CFBundlePackageType</key>
|
||||
|
||||
@@ -54,7 +54,8 @@ AppConfig::AppConfig(QSettings* settings) :
|
||||
m_WizardLastRun(0),
|
||||
m_CryptoPass(),
|
||||
m_ProcessMode(DEFAULT_PROCESS_MODE),
|
||||
m_AutoConnect(true)
|
||||
m_AutoConnect(true),
|
||||
m_ElevateMode(false)
|
||||
{
|
||||
Q_ASSERT(m_pSettings);
|
||||
|
||||
@@ -121,10 +122,9 @@ void AppConfig::loadSettings()
|
||||
m_CryptoPass = settings().value("cryptoPass", "").toString();
|
||||
m_CryptoEnabled = settings().value("cryptoEnabled", false).toBool();
|
||||
m_Language = settings().value("language", QLocale::system().name()).toString();
|
||||
m_PremiumEmail = settings().value("premiumEmail", "").toString();
|
||||
m_PremiumToken = settings().value("premiumToken", "").toString();
|
||||
m_StartedBefore = settings().value("startedBefore", false).toBool();
|
||||
m_AutoConnect = settings().value("autoConnect", true).toBool();
|
||||
m_ElevateMode = settings().value("elevateMode", false).toBool();
|
||||
}
|
||||
|
||||
void AppConfig::saveSettings()
|
||||
@@ -139,10 +139,9 @@ void AppConfig::saveSettings()
|
||||
settings().setValue("cryptoPass", m_CryptoPass);
|
||||
settings().setValue("cryptoEnabled", m_CryptoEnabled);
|
||||
settings().setValue("language", m_Language);
|
||||
settings().setValue("premiumEmail", m_PremiumEmail);
|
||||
settings().setValue("premiumToken", m_PremiumToken);
|
||||
settings().setValue("startedBefore", m_StartedBefore);
|
||||
settings().setValue("autoConnect", m_AutoConnect);
|
||||
settings().setValue("elevateMode", m_ElevateMode);
|
||||
}
|
||||
|
||||
void AppConfig::setCryptoPass(const QString &s)
|
||||
@@ -161,14 +160,12 @@ void AppConfig::setCryptoPass(const QString &s)
|
||||
}
|
||||
}
|
||||
|
||||
bool AppConfig::isPremium()
|
||||
{
|
||||
QString hashSrc = m_PremiumEmail + getFirstMacAddress();
|
||||
QString hashResult = hash(hashSrc);
|
||||
return hashResult == m_PremiumToken;
|
||||
}
|
||||
|
||||
void AppConfig::setAutoConnect(bool autoConnect)
|
||||
{
|
||||
m_AutoConnect = autoConnect;
|
||||
}
|
||||
|
||||
bool AppConfig::elevateMode()
|
||||
{
|
||||
return m_ElevateMode;
|
||||
}
|
||||
|
||||
@@ -30,7 +30,7 @@
|
||||
//
|
||||
// 1: first version
|
||||
// 2: added language page
|
||||
// 3: added premium page
|
||||
// 3: added premium page and removed
|
||||
//
|
||||
const int kWizardVersion = 3;
|
||||
|
||||
@@ -67,8 +67,6 @@ class AppConfig
|
||||
ProcessMode processMode() const { return m_ProcessMode; }
|
||||
bool wizardShouldRun() const { return m_WizardLastRun < kWizardVersion; }
|
||||
const QString& language() const { return m_Language; }
|
||||
const QString& premiumEmail() const { return m_PremiumEmail; }
|
||||
const QString& premiumToken() const { return m_PremiumToken; }
|
||||
bool startedBefore() const { return m_StartedBefore; }
|
||||
bool autoConnect() const { return m_AutoConnect; }
|
||||
void setAutoConnect(bool autoConnect);
|
||||
@@ -80,7 +78,7 @@ class AppConfig
|
||||
|
||||
bool detectPath(const QString& name, QString& path);
|
||||
void persistLogDir();
|
||||
bool isPremium();
|
||||
bool elevateMode();
|
||||
|
||||
protected:
|
||||
QSettings& settings() { return *m_pSettings; }
|
||||
@@ -93,9 +91,8 @@ class AppConfig
|
||||
void setCryptoEnabled(bool b) { m_CryptoEnabled = b; }
|
||||
void setWizardHasRun() { m_WizardLastRun = kWizardVersion; }
|
||||
void setLanguage(const QString language) { m_Language = language; }
|
||||
void setPremiumEmail(const QString premiumEmail) { m_PremiumEmail = premiumEmail; }
|
||||
void setPremiumToken(const QString premiumToken) { m_PremiumToken = premiumToken; }
|
||||
void setStartedBefore(bool b) { m_StartedBefore = b; }
|
||||
void setElevateMode(bool b) { m_ElevateMode = b; }
|
||||
|
||||
void loadSettings();
|
||||
void saveSettings();
|
||||
@@ -115,10 +112,9 @@ class AppConfig
|
||||
QString m_CryptoPass;
|
||||
ProcessMode m_ProcessMode;
|
||||
QString m_Language;
|
||||
QString m_PremiumEmail;
|
||||
QString m_PremiumToken;
|
||||
bool m_StartedBefore;
|
||||
bool m_AutoConnect;
|
||||
bool m_ElevateMode;
|
||||
|
||||
static const char m_SynergysName[];
|
||||
static const char m_SynergycName[];
|
||||
|
||||
@@ -70,8 +70,6 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
|
||||
m_pTrayIcon(NULL),
|
||||
m_pTrayIconMenu(NULL),
|
||||
m_AlreadyHidden(false),
|
||||
m_ElevateProcess(false),
|
||||
m_SuppressElevateWarning(false),
|
||||
m_pMenuBar(NULL),
|
||||
m_pMenuFile(NULL),
|
||||
m_pMenuEdit(NULL),
|
||||
@@ -96,9 +94,6 @@ MainWindow::MainWindow(QSettings& settings, AppConfig& appConfig) :
|
||||
connect(&m_IpcClient, SIGNAL(errorMessage(const QString&)), this, SLOT(appendLogError(const QString&)));
|
||||
connect(&m_IpcClient, SIGNAL(infoMessage(const QString&)), this, SLOT(appendLogNote(const QString&)));
|
||||
m_IpcClient.connectToHost();
|
||||
#else
|
||||
// elevate checkbox is only useful on ms windows.
|
||||
m_pElevateCheckBox->hide();
|
||||
#endif
|
||||
|
||||
// change default size based on os
|
||||
@@ -128,8 +123,6 @@ MainWindow::~MainWindow()
|
||||
|
||||
void MainWindow::open()
|
||||
{
|
||||
updatePremiumInfo();
|
||||
|
||||
createTrayIcon();
|
||||
|
||||
showNormal();
|
||||
@@ -164,8 +157,6 @@ void MainWindow::onModeChanged(bool startDesktop, bool applyService)
|
||||
stopService();
|
||||
startSynergy();
|
||||
}
|
||||
|
||||
m_pElevateCheckBox->setEnabled(appConfig().processMode() == Service);
|
||||
}
|
||||
|
||||
void MainWindow::setStatus(const QString &status)
|
||||
@@ -247,10 +238,6 @@ void MainWindow::loadSettings()
|
||||
m_pLineEditConfigFile->setText(settings().value("configFile", QDir::homePath() + "/" + synergyConfigName).toString());
|
||||
m_pGroupClient->setChecked(settings().value("groupClientChecked", true).toBool());
|
||||
m_pLineEditHostname->setText(settings().value("serverHostname").toString());
|
||||
|
||||
m_SuppressElevateWarning = true;
|
||||
m_pElevateCheckBox->setChecked(settings().value("elevateChecked", false).toBool());
|
||||
m_SuppressElevateWarning = false;
|
||||
}
|
||||
|
||||
void MainWindow::initConnections()
|
||||
@@ -416,10 +403,9 @@ void MainWindow::startSynergy()
|
||||
}
|
||||
|
||||
#ifndef Q_OS_LINUX
|
||||
if (appConfig().isPremium())
|
||||
{
|
||||
args << "--enable-drag-drop";
|
||||
}
|
||||
|
||||
args << "--enable-drag-drop";
|
||||
|
||||
#endif
|
||||
|
||||
if ((synergyType() == synergyClient && !clientArgs(args, app))
|
||||
@@ -479,7 +465,7 @@ void MainWindow::startSynergy()
|
||||
if (serviceMode)
|
||||
{
|
||||
QString command(app + " " + args.join(" "));
|
||||
m_IpcClient.sendCommand(command, m_ElevateProcess);
|
||||
m_IpcClient.sendCommand(command, appConfig().elevateMode());
|
||||
}
|
||||
|
||||
appConfig().setStartedBefore(true);
|
||||
@@ -627,7 +613,7 @@ void MainWindow::stopSynergy()
|
||||
void MainWindow::stopService()
|
||||
{
|
||||
// send empty command to stop service from laucning anything.
|
||||
m_IpcClient.sendCommand("", m_ElevateProcess);
|
||||
m_IpcClient.sendCommand("", appConfig().elevateMode());
|
||||
}
|
||||
|
||||
void MainWindow::stopDesktop()
|
||||
@@ -781,7 +767,6 @@ void MainWindow::changeEvent(QEvent* event)
|
||||
case QEvent::LanguageChange:
|
||||
retranslateUi(this);
|
||||
retranslateMenuBar();
|
||||
updatePremiumInfo();
|
||||
break;
|
||||
|
||||
default:
|
||||
@@ -790,20 +775,6 @@ void MainWindow::changeEvent(QEvent* event)
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updatePremiumInfo()
|
||||
{
|
||||
if (m_AppConfig.isPremium())
|
||||
{
|
||||
m_pWidgetPremium->hide();
|
||||
setWindowTitle(tr("Synergy Premium"));
|
||||
}
|
||||
else
|
||||
{
|
||||
m_pWidgetPremium->show();
|
||||
setWindowTitle(tr("Synergy"));
|
||||
}
|
||||
}
|
||||
|
||||
void MainWindow::updateZeroconfService()
|
||||
{
|
||||
if (!m_AppConfig.wizardShouldRun()) {
|
||||
@@ -912,29 +883,6 @@ void MainWindow::on_m_pActionWizard_triggered()
|
||||
{
|
||||
SetupWizard wizard(*this, false);
|
||||
wizard.exec();
|
||||
updatePremiumInfo();
|
||||
}
|
||||
|
||||
void MainWindow::on_m_pElevateCheckBox_toggled(bool checked)
|
||||
{
|
||||
if (checked && !m_SuppressElevateWarning) {
|
||||
int r = QMessageBox::warning(
|
||||
this, tr("Elevate Synergy"),
|
||||
tr("Are you sure you want to elevate Synergy?\n\n"
|
||||
"This allows Synergy to interact with elevated processes "
|
||||
"and the UAC dialog, but can cause problems with non-elevated "
|
||||
"processes. Elevate Synergy only if you really need to."),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (r != QMessageBox::Yes) {
|
||||
m_pElevateCheckBox->setChecked(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
|
||||
m_ElevateProcess = checked;
|
||||
settings().setValue("elevateChecked", checked);
|
||||
settings().sync();
|
||||
}
|
||||
|
||||
void MainWindow::on_m_pButtonApply_clicked()
|
||||
|
||||
@@ -114,7 +114,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
|
||||
void on_m_pActionAbout_triggered();
|
||||
void on_m_pActionSettings_triggered();
|
||||
void on_m_pActionWizard_triggered();
|
||||
void on_m_pElevateCheckBox_toggled(bool checked);
|
||||
void synergyFinished(int exitCode, QProcess::ExitStatus);
|
||||
void trayActivated(QSystemTrayIcon::ActivationReason reason);
|
||||
void stopSynergy();
|
||||
@@ -147,7 +146,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
|
||||
void stopDesktop();
|
||||
void changeEvent(QEvent* event);
|
||||
void retranslateMenuBar();
|
||||
void updatePremiumInfo();
|
||||
|
||||
private:
|
||||
QSettings& m_Settings;
|
||||
@@ -161,8 +159,6 @@ class MainWindow : public QMainWindow, public Ui::MainWindowBase
|
||||
bool m_AlreadyHidden;
|
||||
VersionChecker m_VersionChecker;
|
||||
IpcClient m_IpcClient;
|
||||
bool m_ElevateProcess;
|
||||
bool m_SuppressElevateWarning;
|
||||
QMenuBar* m_pMenuBar;
|
||||
QMenu* m_pMenuFile;
|
||||
QMenu* m_pMenuEdit;
|
||||
|
||||
@@ -1,67 +0,0 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Bolton Software Ltd.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "PremiumAuth.h"
|
||||
#include "QUtility.h"
|
||||
|
||||
#include <QProcess>
|
||||
#include <QCoreApplication>
|
||||
#include <stdexcept>
|
||||
|
||||
// we use syntool to authenticate because Qt's http library is very
|
||||
// unreliable, and since we're writing platform specific code, use the
|
||||
// synergy code since there we can use integ tests.
|
||||
QString PremiumAuth::request(const QString& email, const QString& password)
|
||||
{
|
||||
QString program(QCoreApplication::applicationDirPath() + "/syntool");
|
||||
QStringList args("--premium-auth");
|
||||
|
||||
QProcess process;
|
||||
process.setReadChannel(QProcess::StandardOutput);
|
||||
process.start(program, args);
|
||||
bool success = process.waitForStarted();
|
||||
|
||||
QString out, error;
|
||||
if (success)
|
||||
{
|
||||
// hash password in case it contains interesting chars.
|
||||
QString credentials(email + ":" + hash(password) + "\n");
|
||||
process.write(credentials.toStdString().c_str());
|
||||
|
||||
if (process.waitForFinished()) {
|
||||
out = process.readAllStandardOutput();
|
||||
error = process.readAllStandardError();
|
||||
}
|
||||
}
|
||||
|
||||
out = out.trimmed();
|
||||
error = error.trimmed();
|
||||
|
||||
if (out.isEmpty() ||
|
||||
!error.isEmpty() ||
|
||||
!success ||
|
||||
process.exitCode() != 0)
|
||||
{
|
||||
throw std::runtime_error(
|
||||
QString("Code: %1\nError: %2")
|
||||
.arg(process.exitCode())
|
||||
.arg(error.isEmpty() ? "Unknown" : error)
|
||||
.toStdString());
|
||||
}
|
||||
|
||||
return out;
|
||||
}
|
||||
|
||||
@@ -1,26 +0,0 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Bolton Software Ltd.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include <QString>
|
||||
|
||||
class PremiumAuth
|
||||
{
|
||||
public:
|
||||
QString request(const QString& email, const QString& password);
|
||||
};
|
||||
|
||||
@@ -30,7 +30,8 @@
|
||||
SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
|
||||
QDialog(parent, Qt::WindowTitleHint | Qt::WindowSystemMenuHint),
|
||||
Ui::SettingsDialogBase(),
|
||||
m_AppConfig(config)
|
||||
m_AppConfig(config),
|
||||
m_SuppressElevateWarning(false)
|
||||
{
|
||||
setupUi(this);
|
||||
|
||||
@@ -48,6 +49,15 @@ SettingsDialog::SettingsDialog(QWidget* parent, AppConfig& config) :
|
||||
{
|
||||
m_pLineEditCryptoPass->setText(appConfig().cryptoPass());
|
||||
}
|
||||
|
||||
#if defined(Q_OS_WIN)
|
||||
m_SuppressElevateWarning = true;
|
||||
m_pCheckBoxElevateMode->setChecked(appConfig().elevateMode());
|
||||
m_SuppressElevateWarning = false;
|
||||
#else
|
||||
// elevate checkbox is only useful on ms windows.
|
||||
m_pCheckBoxElevateMode->hide();
|
||||
#endif
|
||||
}
|
||||
|
||||
void SettingsDialog::accept()
|
||||
@@ -73,6 +83,7 @@ void SettingsDialog::accept()
|
||||
appConfig().setCryptoEnabled(cryptoEnabled);
|
||||
appConfig().setCryptoPass(cryptoPass);
|
||||
appConfig().setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
|
||||
appConfig().setElevateMode(m_pCheckBoxElevateMode->isChecked());
|
||||
appConfig().saveSettings();
|
||||
QDialog::accept();
|
||||
}
|
||||
@@ -144,3 +155,21 @@ void SettingsDialog::on_m_pComboLanguage_currentIndexChanged(int index)
|
||||
QString ietfCode = m_pComboLanguage->itemData(index).toString();
|
||||
QSynergyApplication::getInstance()->switchTranslator(ietfCode);
|
||||
}
|
||||
|
||||
void SettingsDialog::on_m_pCheckBoxElevateMode_toggled(bool checked)
|
||||
{
|
||||
if (checked && !m_SuppressElevateWarning) {
|
||||
int r = QMessageBox::warning(
|
||||
this, tr("Elevate Synergy"),
|
||||
tr("Are you sure you want to elevate Synergy?\n\n"
|
||||
"This allows Synergy to interact with elevated processes "
|
||||
"and the UAC dialog, but can cause problems with non-elevated "
|
||||
"processes. Elevate Synergy only if you really need to."),
|
||||
QMessageBox::Yes | QMessageBox::No);
|
||||
|
||||
if (r != QMessageBox::Yes) {
|
||||
m_pCheckBoxElevateMode->setChecked(false);
|
||||
return;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -44,8 +44,10 @@ class SettingsDialog : public QDialog, public Ui::SettingsDialogBase
|
||||
private:
|
||||
AppConfig& m_AppConfig;
|
||||
SynergyLocale m_Locale;
|
||||
bool m_SuppressElevateWarning;
|
||||
|
||||
private slots:
|
||||
void on_m_pCheckBoxElevateMode_toggled(bool checked);
|
||||
void on_m_pCheckBoxEnableCrypto_stateChanged(int );
|
||||
void on_m_pComboLanguage_currentIndexChanged(int index);
|
||||
void on_m_pCheckBoxLogToFile_stateChanged(int );
|
||||
|
||||
@@ -19,15 +19,8 @@
|
||||
#include "MainWindow.h"
|
||||
#include "QSynergyApplication.h"
|
||||
#include "QUtility.h"
|
||||
#include "PremiumAuth.h"
|
||||
|
||||
#include <QMessageBox>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QNetworkRequest>
|
||||
#include <QNetworkReply>
|
||||
|
||||
#define PREMIUM_REGISTER_URL "http://synergy-project.org/donate/?source=gui-wizard"
|
||||
|
||||
SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
|
||||
m_MainWindow(mainWindow),
|
||||
@@ -58,13 +51,7 @@ SetupWizard::SetupWizard(MainWindow& mainWindow, bool startMain) :
|
||||
|
||||
m_Locale.fillLanguageComboBox(m_pComboLanguage);
|
||||
setIndexFromItemData(m_pComboLanguage, m_MainWindow.appConfig().language());
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
QString premiumEmail = appConfig.premiumEmail();
|
||||
if (!premiumEmail.isEmpty())
|
||||
{
|
||||
m_pRadioButtonPremiumLogin->setChecked(true);
|
||||
m_pLineEditPremiumEmail->setText(premiumEmail);
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
SetupWizard::~SetupWizard()
|
||||
@@ -89,32 +76,6 @@ bool SetupWizard::validateCurrentPage()
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (currentPage() == m_pPremiumUserPage)
|
||||
{
|
||||
if (m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
if (m_pLineEditPremiumEmail->text().isEmpty() ||
|
||||
m_pLineEditPremiumPassword->text().isEmpty())
|
||||
{
|
||||
message.setText(tr("Please enter your email address and password."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
else if (!isPremiumLoginValid(message))
|
||||
{
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else if (m_pRadioButtonPremiumLater->isChecked())
|
||||
{
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
message.setText(tr("Please select an option."));
|
||||
message.exec();
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
@@ -144,19 +105,6 @@ void SetupWizard::accept()
|
||||
AppConfig& appConfig = m_MainWindow.appConfig();
|
||||
|
||||
appConfig.setLanguage(m_pComboLanguage->itemData(m_pComboLanguage->currentIndex()).toString());
|
||||
appConfig.setPremiumEmail(m_pLineEditPremiumEmail->text());
|
||||
|
||||
if (!m_pRadioButtonPremiumLogin->isChecked())
|
||||
{
|
||||
appConfig.setPremiumToken("");
|
||||
}
|
||||
else
|
||||
{
|
||||
QString mac = getFirstMacAddress();
|
||||
QString hashSrc = m_pLineEditPremiumEmail->text() + mac;
|
||||
QString hashResult = hash(hashSrc);
|
||||
appConfig.setPremiumToken(hashResult);
|
||||
}
|
||||
|
||||
appConfig.setWizardHasRun();
|
||||
appConfig.saveSettings();
|
||||
@@ -205,65 +153,3 @@ void SetupWizard::on_m_pComboLanguage_currentIndexChanged(int index)
|
||||
QString ietfCode = m_pComboLanguage->itemData(index).toString();
|
||||
QSynergyApplication::getInstance()->switchTranslator(ietfCode);
|
||||
}
|
||||
|
||||
void SetupWizard::on_m_pRadioButtonPremiumLogin_toggled(bool checked)
|
||||
{
|
||||
m_pLineEditPremiumEmail->setEnabled(checked);
|
||||
m_pLineEditPremiumPassword->setEnabled(checked);
|
||||
}
|
||||
|
||||
bool SetupWizard::isPremiumLoginValid(QMessageBox& message)
|
||||
{
|
||||
QString email = m_pLineEditPremiumEmail->text();
|
||||
QString password = m_pLineEditPremiumPassword->text();
|
||||
|
||||
QString responseJson;
|
||||
try
|
||||
{
|
||||
PremiumAuth auth;
|
||||
responseJson = auth.request(email, password);
|
||||
}
|
||||
catch (std::exception& e)
|
||||
{
|
||||
message.critical(
|
||||
this, "Error",
|
||||
tr("Sorry, an error occured while trying to sign in. "
|
||||
"Please contact the help desk, and provide the "
|
||||
"following details.\n\n%1")
|
||||
.arg(e.what()));
|
||||
return false;
|
||||
}
|
||||
|
||||
QRegExp resultRegex(".*\"result\".*:.*(true|false).*");
|
||||
if (resultRegex.exactMatch(responseJson)) {
|
||||
QString boolString = resultRegex.cap(1);
|
||||
if (boolString == "true") {
|
||||
return true;
|
||||
}
|
||||
else if (boolString == "false") {
|
||||
message.critical(
|
||||
this, "Error",
|
||||
tr("Login failed, invalid email or password."));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
else {
|
||||
QRegExp errorRegex(".*\"error\".*:.*\"(.+)\".*");
|
||||
if (errorRegex.exactMatch(responseJson)) {
|
||||
|
||||
// replace "\n" with real new lines.
|
||||
QString error = errorRegex.cap(1).replace("\\n", "\n");
|
||||
|
||||
message.critical(
|
||||
this, "Error",
|
||||
tr("Login failed, an error occurred.\n\n%1").arg(error));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
message.critical(
|
||||
this, "Error",
|
||||
tr("Login failed, an error occurred.\n\nServer response:\n\n%1")
|
||||
.arg(responseJson));
|
||||
return false;
|
||||
}
|
||||
|
||||
@@ -39,9 +39,6 @@ protected:
|
||||
void accept();
|
||||
void reject();
|
||||
|
||||
private:
|
||||
bool isPremiumLoginValid(QMessageBox& message);
|
||||
|
||||
private:
|
||||
MainWindow& m_MainWindow;
|
||||
bool m_StartMain;
|
||||
@@ -50,5 +47,4 @@ private:
|
||||
private slots:
|
||||
void on_m_pCheckBoxEnableCrypto_stateChanged(int );
|
||||
void on_m_pComboLanguage_currentIndexChanged(int index);
|
||||
void on_m_pRadioButtonPremiumLogin_toggled(bool checked);
|
||||
};
|
||||
|
||||
@@ -130,81 +130,26 @@ int waitForTray()
|
||||
}
|
||||
|
||||
#if defined(Q_OS_MAC)
|
||||
bool settingsExist()
|
||||
{
|
||||
QSettings settings;
|
||||
|
||||
//FIXME: check settings existance properly
|
||||
int port = settings.value("port", -1).toInt();
|
||||
|
||||
return port == -1 ? false : true;
|
||||
}
|
||||
|
||||
bool checkMacAssistiveDevices()
|
||||
{
|
||||
#if __MAC_OS_X_VERSION_MIN_REQUIRED >= 1090 // mavericks
|
||||
|
||||
// new in mavericks, applications are trusted individually
|
||||
// with use of the accessibility api. this call will show a
|
||||
// prompt which can show the security/privacy/accessibility
|
||||
// tab, with a list of allowed applications. synergy should
|
||||
// show up there automatically, but will be unchecked.
|
||||
|
||||
const void* keys[] = { kAXTrustedCheckOptionPrompt };
|
||||
const void* trueValue[] = { kCFBooleanTrue };
|
||||
const void* falseValue[] = { kCFBooleanFalse };
|
||||
CFDictionaryRef optionsWithPrompt = CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL);
|
||||
CFDictionaryRef optionsWithoutPrompt = CFDictionaryCreate(NULL, keys, falseValue, 1, NULL, NULL);
|
||||
bool result;
|
||||
|
||||
result = AXIsProcessTrustedWithOptions(optionsWithoutPrompt);
|
||||
|
||||
// Synergy is not checked in accessibility
|
||||
if (!result) {
|
||||
// if setting doesn't exist, just skip helper tool
|
||||
if (!settingsExist()) {
|
||||
result = AXIsProcessTrustedWithOptions(optionsWithPrompt);
|
||||
}
|
||||
else {
|
||||
int reply;
|
||||
reply = QMessageBox::question(
|
||||
NULL,
|
||||
"Synergy",
|
||||
"Synergy requires access to Assistive Devices, but was not allowed.\n\nShould Synergy attempt to fix this?",
|
||||
QMessageBox::Yes|QMessageBox::Default,
|
||||
QMessageBox::No|QMessageBox::Escape);
|
||||
|
||||
if (reply == QMessageBox::Yes) {
|
||||
// call privilege help tool
|
||||
AXDatabaseCleaner axdc;
|
||||
result = axdc.loadPrivilegeHelper();
|
||||
result = axdc.xpcConnect();
|
||||
|
||||
QMessageBox box;
|
||||
box.setModal(false);
|
||||
box.setStandardButtons(0);
|
||||
box.setText("Please wait.");
|
||||
box.resize(150, 10);
|
||||
box.show();
|
||||
|
||||
const char* command = "sudo sqlite3 /Library/Application\\ Support/com.apple.TCC/TCC.db 'delete from access where client like \"%Synergy.app%\"'";
|
||||
result = axdc.privilegeCommand(command);
|
||||
|
||||
box.hide();
|
||||
|
||||
if (result) {
|
||||
QMessageBox::information(
|
||||
NULL, "Synergy",
|
||||
"Synergy helper tool is complete. Please tick the checkbox in Accessibility.");
|
||||
}
|
||||
}
|
||||
|
||||
result = AXIsProcessTrustedWithOptions(optionsWithPrompt);
|
||||
}
|
||||
if (AXIsProcessTrusted()) {
|
||||
return true;
|
||||
}
|
||||
|
||||
CFRelease(optionsWithoutPrompt);
|
||||
CFRelease(optionsWithPrompt);
|
||||
const void* keys[] = { kAXTrustedCheckOptionPrompt };
|
||||
const void* trueValue[] = { kCFBooleanTrue };
|
||||
CFDictionaryRef options = CFDictionaryCreate(NULL, keys, trueValue, 1, NULL, NULL);
|
||||
|
||||
bool result = AXIsProcessTrustedWithOptions(options);
|
||||
CFRelease(options);
|
||||
return result;
|
||||
|
||||
#else
|
||||
|
||||
@@ -50,6 +50,18 @@ public:
|
||||
*/
|
||||
virtual std::string getSystemDirectory() = 0;
|
||||
|
||||
//! Get installed directory
|
||||
/*!
|
||||
Returns the directory in which Synergy is installed.
|
||||
*/
|
||||
virtual std::string getInstalledDirectory() = 0;
|
||||
|
||||
//! Get log directory
|
||||
/*!
|
||||
Returns the log file directory.
|
||||
*/
|
||||
virtual std::string getLogDirectory() = 0;
|
||||
|
||||
//! Concatenate path components
|
||||
/*!
|
||||
Concatenate pathname components with a directory separator
|
||||
|
||||
@@ -88,6 +88,22 @@ CArchFileUnix::getSystemDirectory()
|
||||
return "/etc";
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileUnix::getInstalledDirectory()
|
||||
{
|
||||
#if WINAPI_XWINDOWS
|
||||
return "/bin";
|
||||
#else
|
||||
return "";
|
||||
#endif
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileUnix::getLogDirectory()
|
||||
{
|
||||
return "/var/log";
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileUnix::concatPath(const std::string& prefix,
|
||||
const std::string& suffix)
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
virtual const char* getBasename(const char* pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string concatPath(const std::string& prefix,
|
||||
const std::string& suffix);
|
||||
};
|
||||
|
||||
@@ -121,6 +121,24 @@ CArchFileWindows::getSystemDirectory()
|
||||
}
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileWindows::getInstalledDirectory()
|
||||
{
|
||||
char fileNameBuffer[MAX_PATH];
|
||||
GetModuleFileName(NULL, fileNameBuffer, MAX_PATH);
|
||||
std::string fileName(fileNameBuffer);
|
||||
size_t lastSlash = fileName.find_last_of("\\");
|
||||
fileName = fileName.substr(0, lastSlash);
|
||||
|
||||
return fileName;
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileWindows::getLogDirectory()
|
||||
{
|
||||
return getInstalledDirectory();
|
||||
}
|
||||
|
||||
std::string
|
||||
CArchFileWindows::concatPath(const std::string& prefix,
|
||||
const std::string& suffix)
|
||||
|
||||
@@ -32,6 +32,8 @@ public:
|
||||
virtual const char* getBasename(const char* pathname);
|
||||
virtual std::string getUserDirectory();
|
||||
virtual std::string getSystemDirectory();
|
||||
virtual std::string getInstalledDirectory();
|
||||
virtual std::string getLogDirectory();
|
||||
virtual std::string concatPath(const std::string& prefix,
|
||||
const std::string& suffix);
|
||||
};
|
||||
|
||||
@@ -26,6 +26,7 @@
|
||||
#include <stdarg.h>
|
||||
|
||||
#define CLOG (CLog::getInstance())
|
||||
#define BYE "\nTry `%s --help' for more information."
|
||||
|
||||
class ILogOutputter;
|
||||
class CThread;
|
||||
|
||||
@@ -235,14 +235,20 @@ CBufferedLogOutputter::write(ELevel, const char* message)
|
||||
|
||||
CFileLogOutputter::CFileLogOutputter(const char* logFile)
|
||||
{
|
||||
assert(logFile != NULL);
|
||||
m_fileName = logFile;
|
||||
setLogFilename(logFile);
|
||||
}
|
||||
|
||||
CFileLogOutputter::~CFileLogOutputter()
|
||||
{
|
||||
}
|
||||
|
||||
void
|
||||
CFileLogOutputter::setLogFilename(const char* logFile)
|
||||
{
|
||||
assert(logFile != NULL);
|
||||
m_fileName = logFile;
|
||||
}
|
||||
|
||||
bool
|
||||
CFileLogOutputter::write(ELevel level, const char *message)
|
||||
{
|
||||
|
||||
@@ -79,8 +79,11 @@ public:
|
||||
virtual void close();
|
||||
virtual void show(bool showIfEmpty);
|
||||
virtual bool write(ELevel level, const char* message);
|
||||
|
||||
void setLogFilename(const char* title);
|
||||
|
||||
private:
|
||||
std::string m_fileName;
|
||||
std::string m_fileName;
|
||||
};
|
||||
|
||||
//! Write log to system log
|
||||
|
||||
@@ -72,6 +72,9 @@
|
||||
|
||||
// Added this because it doesn't compile on OS X 10.6 because they are already defined in Carbon
|
||||
#if !defined(__MACTYPES__)
|
||||
#if defined(__APPLE__)
|
||||
#include <CoreServices/CoreServices.h>
|
||||
#else
|
||||
typedef signed TYPE_OF_SIZE_1 SInt8;
|
||||
typedef signed TYPE_OF_SIZE_2 SInt16;
|
||||
typedef signed TYPE_OF_SIZE_4 SInt32;
|
||||
@@ -79,6 +82,7 @@ typedef unsigned TYPE_OF_SIZE_1 UInt8;
|
||||
typedef unsigned TYPE_OF_SIZE_2 UInt16;
|
||||
typedef unsigned TYPE_OF_SIZE_4 UInt32;
|
||||
#endif
|
||||
#endif
|
||||
//
|
||||
// clean up
|
||||
//
|
||||
|
||||
@@ -141,7 +141,7 @@ CIpcClientProxy::send(const CIpcMessage& message)
|
||||
// also, don't allow the dtor to destroy the stream while we're using it.
|
||||
CArchMutexLock lock(m_writeMutex);
|
||||
|
||||
LOG((CLOG_DEBUG "ipc write: %d", message.type()));
|
||||
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
||||
|
||||
switch (message.type()) {
|
||||
case kIpcLogLine: {
|
||||
|
||||
@@ -83,7 +83,7 @@ CIpcServerProxy::handleData(const CEvent&, void*)
|
||||
void
|
||||
CIpcServerProxy::send(const CIpcMessage& message)
|
||||
{
|
||||
LOG((CLOG_DEBUG "ipc write: %d", message.type()));
|
||||
LOG((CLOG_DEBUG4 "ipc write: %d", message.type()));
|
||||
|
||||
switch (message.type()) {
|
||||
case kIpcHello: {
|
||||
|
||||
@@ -21,7 +21,6 @@
|
||||
#include "synergy/XSynergy.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
#include <Tlhelp32.h>
|
||||
#include <Wtsapi32.h>
|
||||
|
||||
CMSWindowsSession::CMSWindowsSession() :
|
||||
@@ -69,34 +68,29 @@ CMSWindowsSession::isProcessInSession(const char* name, PHANDLE process = NULL)
|
||||
entry.th32ProcessID, &processSessionId);
|
||||
|
||||
if (!pidToSidRet) {
|
||||
// if we can not acquire session associated with a specified process,
|
||||
// simply ignore it
|
||||
LOG((CLOG_ERR "could not get session id for process id %i", entry.th32ProcessID));
|
||||
throw XArch(new XArchEvalWindows());
|
||||
gotEntry = nextProcessEntry(snapshot, &entry);
|
||||
continue;
|
||||
}
|
||||
else {
|
||||
// only pay attention to processes in the active session
|
||||
if (processSessionId == m_activeSessionId) {
|
||||
|
||||
// only pay attention to processes in the active session
|
||||
if (processSessionId == m_activeSessionId) {
|
||||
// store the names so we can record them for debug
|
||||
nameList.push_back(entry.szExeFile);
|
||||
|
||||
// store the names so we can record them for debug
|
||||
nameList.push_back(entry.szExeFile);
|
||||
|
||||
if (_stricmp(entry.szExeFile, name) == 0) {
|
||||
pid = entry.th32ProcessID;
|
||||
if (_stricmp(entry.szExeFile, name) == 0) {
|
||||
pid = entry.th32ProcessID;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
|
||||
// now move on to the next entry (if we're not at the end)
|
||||
gotEntry = Process32Next(snapshot, &entry);
|
||||
if (!gotEntry) {
|
||||
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_NO_MORE_FILES) {
|
||||
|
||||
// only worry about error if it's not the end of the snapshot
|
||||
LOG((CLOG_ERR "could not get next process entry"));
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
}
|
||||
gotEntry = nextProcessEntry(snapshot, &entry);
|
||||
}
|
||||
|
||||
std::string nameListJoin;
|
||||
@@ -158,3 +152,40 @@ CMSWindowsSession::updateActiveSession()
|
||||
{
|
||||
m_activeSessionId = WTSGetActiveConsoleSessionId();
|
||||
}
|
||||
|
||||
|
||||
BOOL
|
||||
CMSWindowsSession::nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry)
|
||||
{
|
||||
BOOL gotEntry = Process32Next(snapshot, entry);
|
||||
if (!gotEntry) {
|
||||
|
||||
DWORD err = GetLastError();
|
||||
if (err != ERROR_NO_MORE_FILES) {
|
||||
|
||||
// only worry about error if it's not the end of the snapshot
|
||||
LOG((CLOG_ERR "could not get next process entry"));
|
||||
throw XArch(new XArchEvalWindows());
|
||||
}
|
||||
}
|
||||
|
||||
return gotEntry;
|
||||
}
|
||||
|
||||
CString
|
||||
CMSWindowsSession::getActiveDesktopName()
|
||||
{
|
||||
CString result;
|
||||
|
||||
HDESK hd = OpenInputDesktop(0, TRUE, GENERIC_READ);
|
||||
if (hd != NULL) {
|
||||
DWORD size;
|
||||
GetUserObjectInformation(hd, UOI_NAME, NULL, 0, &size);
|
||||
TCHAR* name = (TCHAR*)alloca(size + sizeof(TCHAR));
|
||||
GetUserObjectInformation(hd, UOI_NAME, name, size, &size);
|
||||
result = name;
|
||||
CloseDesktop(hd);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
@@ -17,8 +17,11 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/String.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
#include <Tlhelp32.h>
|
||||
|
||||
class CMSWindowsSession {
|
||||
public:
|
||||
@@ -39,6 +42,11 @@ public:
|
||||
|
||||
void updateActiveSession();
|
||||
|
||||
CString getActiveDesktopName();
|
||||
|
||||
private:
|
||||
BOOL nextProcessEntry(HANDLE snapshot, LPPROCESSENTRY32 entry);
|
||||
|
||||
private:
|
||||
DWORD m_activeSessionId;
|
||||
};
|
||||
|
||||
@@ -28,6 +28,7 @@
|
||||
#include "arch/win32/ArchDaemonWindows.h"
|
||||
#include "arch/win32/XArchWindows.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "base/log_outputters.h"
|
||||
#include "base/TMethodJob.h"
|
||||
#include "base/Log.h"
|
||||
#include "common/Version.h"
|
||||
@@ -42,6 +43,8 @@ enum {
|
||||
|
||||
typedef VOID (WINAPI *SendSas)(BOOL asUser);
|
||||
|
||||
const char g_activeDesktop[] = {"activeDesktop:"};
|
||||
|
||||
CMSWindowsWatchdog::CMSWindowsWatchdog(
|
||||
bool autoDetectCommand,
|
||||
CIpcServer& ipcServer,
|
||||
@@ -56,12 +59,24 @@ CMSWindowsWatchdog::CMSWindowsWatchdog(
|
||||
m_ipcLogOutputter(ipcLogOutputter),
|
||||
m_elevateProcess(false),
|
||||
m_processFailures(0),
|
||||
m_processRunning(false)
|
||||
m_processRunning(false),
|
||||
m_fileLogOutputter(NULL),
|
||||
m_autoElevated(false),
|
||||
m_ready(false)
|
||||
{
|
||||
m_mutex = ARCH->newMutex();
|
||||
m_condVar = ARCH->newCondVar();
|
||||
}
|
||||
|
||||
CMSWindowsWatchdog::~CMSWindowsWatchdog()
|
||||
{
|
||||
if (m_condVar != NULL) {
|
||||
ARCH->closeCondVar(m_condVar);
|
||||
}
|
||||
|
||||
if (m_mutex != NULL) {
|
||||
ARCH->closeMutex(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
@@ -124,7 +139,9 @@ CMSWindowsWatchdog::getUserToken(LPSECURITY_ATTRIBUTES security)
|
||||
// elevate for the uac dialog (consent.exe) but this would be pointless,
|
||||
// since synergy would re-launch as non-elevated after the desk switch,
|
||||
// and so would be unusable with the new elevated process taking focus.
|
||||
if (m_elevateProcess || m_session.isProcessInSession("logonui.exe", NULL)) {
|
||||
if (m_elevateProcess
|
||||
|| m_autoElevated
|
||||
|| m_session.isProcessInSession("logonui.exe", NULL)) {
|
||||
|
||||
LOG((CLOG_DEBUG "getting elevated token, %s",
|
||||
(m_elevateProcess ? "elevation required" : "at login screen")));
|
||||
@@ -245,6 +262,12 @@ CMSWindowsWatchdog::isProcessActive()
|
||||
return exitCode == STILL_ACTIVE;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsWatchdog::setFileLogOutputter(CFileLogOutputter* outputter)
|
||||
{
|
||||
m_fileLogOutputter = outputter;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsWatchdog::startProcess()
|
||||
{
|
||||
@@ -265,7 +288,11 @@ CMSWindowsWatchdog::startProcess()
|
||||
SECURITY_ATTRIBUTES sa;
|
||||
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
||||
|
||||
getActiveDesktop(&sa);
|
||||
|
||||
ZeroMemory(&sa, sizeof(SECURITY_ATTRIBUTES));
|
||||
HANDLE userToken = getUserToken(&sa);
|
||||
m_autoElevated = false;
|
||||
|
||||
// patch by Jack Zhou and Henry Tung
|
||||
// set UIAccess to fix Windows 8 GUI interaction
|
||||
@@ -273,6 +300,33 @@ CMSWindowsWatchdog::startProcess()
|
||||
DWORD uiAccess = 1;
|
||||
SetTokenInformation(userToken, TokenUIAccess, &uiAccess, sizeof(DWORD));
|
||||
|
||||
BOOL createRet = doStartProcess(m_command, userToken, &sa);
|
||||
|
||||
if (!createRet) {
|
||||
LOG((CLOG_ERR "could not launch"));
|
||||
DWORD exitCode = 0;
|
||||
GetExitCodeProcess(m_processInfo.hProcess, &exitCode);
|
||||
LOG((CLOG_ERR "exit code: %d", exitCode));
|
||||
throw XArch(new XArchEvalWindows);
|
||||
}
|
||||
else {
|
||||
// wait for program to fail.
|
||||
ARCH->sleep(1);
|
||||
if (!isProcessActive()) {
|
||||
throw XMSWindowsWatchdogError("process immediately stopped");
|
||||
}
|
||||
|
||||
m_processRunning = true;
|
||||
m_processFailures = 0;
|
||||
|
||||
LOG((CLOG_DEBUG "started process, session=%i, command=%s",
|
||||
m_session.getActiveSessionId(), m_command.c_str()));
|
||||
}
|
||||
}
|
||||
|
||||
BOOL
|
||||
CMSWindowsWatchdog::doStartProcess(CString& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa)
|
||||
{
|
||||
// clear, as we're reusing process info struct
|
||||
ZeroMemory(&m_processInfo, sizeof(PROCESS_INFORMATION));
|
||||
|
||||
@@ -299,30 +353,14 @@ CMSWindowsWatchdog::startProcess()
|
||||
// re-launch in current active user session
|
||||
LOG((CLOG_INFO "starting new process"));
|
||||
BOOL createRet = CreateProcessAsUser(
|
||||
userToken, NULL, LPSTR(m_command.c_str()),
|
||||
&sa, NULL, TRUE, creationFlags,
|
||||
userToken, NULL, LPSTR(command.c_str()),
|
||||
sa, NULL, TRUE, creationFlags,
|
||||
environment, NULL, &si, &m_processInfo);
|
||||
|
||||
DestroyEnvironmentBlock(environment);
|
||||
CloseHandle(userToken);
|
||||
|
||||
if (!createRet) {
|
||||
LOG((CLOG_ERR "could not launch"));
|
||||
throw XArch(new XArchEvalWindows);
|
||||
}
|
||||
else {
|
||||
// wait for program to fail.
|
||||
ARCH->sleep(1);
|
||||
if (!isProcessActive()) {
|
||||
throw XMSWindowsWatchdogError("process immediately stopped");
|
||||
}
|
||||
|
||||
m_processRunning = true;
|
||||
m_processFailures = 0;
|
||||
|
||||
LOG((CLOG_DEBUG "started process, session=%i, command=%s",
|
||||
m_session.getActiveSessionId(), m_command.c_str()));
|
||||
}
|
||||
return createRet;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -380,11 +418,16 @@ CMSWindowsWatchdog::outputLoop(void*)
|
||||
else {
|
||||
buffer[bytesRead] = '\0';
|
||||
|
||||
testOutput(buffer);
|
||||
|
||||
// send process output over IPC to GUI, and force it to be sent
|
||||
// which bypasses the ipc logging anti-recursion mechanism.
|
||||
m_ipcLogOutputter.write(kINFO, buffer, true);
|
||||
}
|
||||
|
||||
|
||||
if (m_fileLogOutputter != NULL) {
|
||||
m_fileLogOutputter->write(kINFO, buffer);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
@@ -481,3 +524,57 @@ CMSWindowsWatchdog::shutdownExistingProcesses()
|
||||
CloseHandle(snapshot);
|
||||
m_processRunning = false;
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsWatchdog::getActiveDesktop(LPSECURITY_ATTRIBUTES security)
|
||||
{
|
||||
CString installedDir = ARCH->getInstalledDirectory();
|
||||
if (!installedDir.empty()) {
|
||||
CString syntoolCommand;
|
||||
syntoolCommand.append("\"").append(installedDir).append("\\").append("syntool").append("\"");
|
||||
syntoolCommand.append(" --get-active-desktop");
|
||||
|
||||
m_session.updateActiveSession();
|
||||
bool elevateProcess = m_elevateProcess;
|
||||
m_elevateProcess = true;
|
||||
HANDLE userToken = getUserToken(security);
|
||||
m_elevateProcess = elevateProcess;
|
||||
|
||||
BOOL createRet = doStartProcess(syntoolCommand, userToken, security);
|
||||
|
||||
if (!createRet) {
|
||||
DWORD rc = GetLastError();
|
||||
RevertToSelf();
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_DEBUG "launched syntool to check active desktop"));
|
||||
}
|
||||
|
||||
ARCH->lockMutex(m_mutex);
|
||||
while (!m_ready) {
|
||||
ARCH->waitCondVar(m_condVar, m_mutex, 1.0);
|
||||
}
|
||||
m_ready = false;
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
CMSWindowsWatchdog::testOutput(CString buffer)
|
||||
{
|
||||
// HACK: check standard output seems hacky.
|
||||
size_t i = buffer.find(g_activeDesktop);
|
||||
if (i != CString::npos) {
|
||||
size_t s = sizeof(g_activeDesktop);
|
||||
CString defaultDesktop("Default");
|
||||
CString sub = buffer.substr(s - 1, defaultDesktop.size());
|
||||
if (sub != defaultDesktop) {
|
||||
m_autoElevated = true;
|
||||
}
|
||||
|
||||
ARCH->lockMutex(m_mutex);
|
||||
m_ready = true;
|
||||
ARCH->broadcastCondVar(m_condVar);
|
||||
ARCH->unlockMutex(m_mutex);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -20,6 +20,7 @@
|
||||
|
||||
#include "platform/MSWindowsSession.h"
|
||||
#include "synergy/XSynergy.h"
|
||||
#include "arch/IArchMultithread.h"
|
||||
|
||||
#define WIN32_LEAN_AND_MEAN
|
||||
#include <Windows.h>
|
||||
@@ -29,6 +30,7 @@
|
||||
class CThread;
|
||||
class CIpcLogOutputter;
|
||||
class CIpcServer;
|
||||
class CFileLogOutputter;
|
||||
|
||||
class CMSWindowsWatchdog {
|
||||
public:
|
||||
@@ -43,6 +45,7 @@ public:
|
||||
void setCommand(const std::string& command, bool elevate);
|
||||
void stop();
|
||||
bool isProcessActive();
|
||||
void setFileLogOutputter(CFileLogOutputter* outputter);
|
||||
|
||||
private:
|
||||
void mainLoop(void*);
|
||||
@@ -52,7 +55,10 @@ private:
|
||||
HANDLE duplicateProcessToken(HANDLE process, LPSECURITY_ATTRIBUTES security);
|
||||
HANDLE getUserToken(LPSECURITY_ATTRIBUTES security);
|
||||
void startProcess();
|
||||
BOOL doStartProcess(CString& command, HANDLE userToken, LPSECURITY_ATTRIBUTES sa);
|
||||
void sendSas();
|
||||
void getActiveDesktop(LPSECURITY_ATTRIBUTES security);
|
||||
void testOutput(CString buffer);
|
||||
|
||||
private:
|
||||
CThread* m_thread;
|
||||
@@ -70,6 +76,11 @@ private:
|
||||
PROCESS_INFORMATION m_processInfo;
|
||||
int m_processFailures;
|
||||
bool m_processRunning;
|
||||
CFileLogOutputter* m_fileLogOutputter;
|
||||
bool m_autoElevated;
|
||||
CArchMutex m_mutex;
|
||||
CArchCond m_condVar;
|
||||
bool m_ready;
|
||||
};
|
||||
|
||||
//! Relauncher error
|
||||
|
||||
@@ -62,6 +62,10 @@ enum {
|
||||
kSynergyMouseScrollAxisY = 'saxy'
|
||||
};
|
||||
|
||||
enum {
|
||||
kCarbonLoopWaitTimeout = 10
|
||||
};
|
||||
|
||||
// TODO: upgrade deprecated function usage in these functions.
|
||||
void setZeroSuppressionInterval();
|
||||
void avoidSupression();
|
||||
@@ -292,13 +296,14 @@ COSXScreen::getShape(SInt32& x, SInt32& y, SInt32& w, SInt32& h) const
|
||||
void
|
||||
COSXScreen::getCursorPos(SInt32& x, SInt32& y) const
|
||||
{
|
||||
Point mouse;
|
||||
GetGlobalMouse(&mouse);
|
||||
x = mouse.h;
|
||||
y = mouse.v;
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint mouse = CGEventGetLocation(event);
|
||||
x = mouse.x;
|
||||
y = mouse.y;
|
||||
m_cursorPosValid = true;
|
||||
m_xCursor = x;
|
||||
m_yCursor = y;
|
||||
CFRelease(event);
|
||||
}
|
||||
|
||||
void
|
||||
@@ -696,15 +701,16 @@ COSXScreen::fakeMouseRelativeMove(SInt32 dx, SInt32 dy) const
|
||||
// we can do.
|
||||
|
||||
// get current position
|
||||
Point oldPos;
|
||||
GetGlobalMouse(&oldPos);
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint oldPos = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
|
||||
// synthesize event
|
||||
CGPoint pos;
|
||||
m_xCursor = static_cast<SInt32>(oldPos.h);
|
||||
m_yCursor = static_cast<SInt32>(oldPos.v);
|
||||
pos.x = oldPos.h + dx;
|
||||
pos.y = oldPos.v + dy;
|
||||
m_xCursor = static_cast<SInt32>(oldPos.x);
|
||||
m_yCursor = static_cast<SInt32>(oldPos.y);
|
||||
pos.x = oldPos.x + dx;
|
||||
pos.y = oldPos.y + dy;
|
||||
postMouseEvent(pos);
|
||||
|
||||
// we now assume we don't know the current cursor position
|
||||
@@ -1052,7 +1058,7 @@ COSXScreen::handleSystemEvent(const CEvent& event, void*)
|
||||
// get scroll amount
|
||||
r = GetEventParameter(*carbonEvent,
|
||||
kSynergyMouseScrollAxisX,
|
||||
typeLongInteger,
|
||||
typeSInt32,
|
||||
NULL,
|
||||
sizeof(xScroll),
|
||||
NULL,
|
||||
@@ -1062,7 +1068,7 @@ COSXScreen::handleSystemEvent(const CEvent& event, void*)
|
||||
}
|
||||
r = GetEventParameter(*carbonEvent,
|
||||
kSynergyMouseScrollAxisY,
|
||||
typeLongInteger,
|
||||
typeSInt32,
|
||||
NULL,
|
||||
sizeof(yScroll),
|
||||
NULL,
|
||||
@@ -1090,7 +1096,10 @@ COSXScreen::handleSystemEvent(const CEvent& event, void*)
|
||||
break;
|
||||
|
||||
case kEventClassWindow:
|
||||
SendEventToWindow(*carbonEvent, m_userInputWindow);
|
||||
// 2nd param was formerly GetWindowEventTarget(m_userInputWindow) which is 32-bit only,
|
||||
// however as m_userInputWindow is never initialized to anything we can take advantage of
|
||||
// the fact that GetWindowEventTarget(NULL) == NULL
|
||||
SendEventToEventTarget(*carbonEvent, NULL);
|
||||
switch (GetEventKind(*carbonEvent)) {
|
||||
case kEventWindowActivated:
|
||||
LOG((CLOG_DEBUG1 "window activated"));
|
||||
@@ -1514,15 +1523,16 @@ COSXScreen::getScrollSpeedFactor() const
|
||||
void
|
||||
COSXScreen::enableDragTimer(bool enable)
|
||||
{
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
|
||||
if (enable && m_dragTimer == NULL) {
|
||||
m_dragTimer = m_events->newTimer(0.01, NULL);
|
||||
m_events->adoptHandler(CEvent::kTimer, m_dragTimer,
|
||||
new TMethodEventJob<COSXScreen>(this,
|
||||
&COSXScreen::handleDrag));
|
||||
TrackMouseLocationWithOptions(NULL, 0, 0, &m_dragLastPoint, &modifiers, &res);
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint mouse = CGEventGetLocation(event);
|
||||
m_dragLastPoint.h = (short)mouse.x;
|
||||
m_dragLastPoint.v = (short)mouse.y;
|
||||
CFRelease(event);
|
||||
}
|
||||
else if (!enable && m_dragTimer != NULL) {
|
||||
m_events->removeHandler(CEvent::kTimer, m_dragTimer);
|
||||
@@ -1534,15 +1544,14 @@ COSXScreen::enableDragTimer(bool enable)
|
||||
void
|
||||
COSXScreen::handleDrag(const CEvent&, void*)
|
||||
{
|
||||
Point p;
|
||||
UInt32 modifiers;
|
||||
MouseTrackingResult res;
|
||||
CGEventRef event = CGEventCreate(NULL);
|
||||
CGPoint p = CGEventGetLocation(event);
|
||||
CFRelease(event);
|
||||
|
||||
TrackMouseLocationWithOptions(NULL, 0, 0, &p, &modifiers, &res);
|
||||
|
||||
if (res != kMouseTrackingTimedOut && (p.h != m_dragLastPoint.h || p.v != m_dragLastPoint.v)) {
|
||||
m_dragLastPoint = p;
|
||||
onMouseMove((SInt32)p.h, (SInt32)p.v);
|
||||
if ((short)p.x != m_dragLastPoint.h || (short)p.y != m_dragLastPoint.v) {
|
||||
m_dragLastPoint.h = (short)p.x;
|
||||
m_dragLastPoint.v = (short)p.y;
|
||||
onMouseMove((SInt32)p.x, (SInt32)p.y);
|
||||
}
|
||||
}
|
||||
|
||||
@@ -1693,17 +1702,24 @@ COSXScreen::watchSystemPowerThread(void*)
|
||||
// setting m_pmThreadReady to true otherwise the parent thread will
|
||||
// block waiting for it.
|
||||
if (m_pmRootPort == 0) {
|
||||
LOG((CLOG_WARN "failed to init watchSystemPowerThread"));
|
||||
return;
|
||||
}
|
||||
|
||||
LOG((CLOG_DEBUG "started watchSystemPowerThread"));
|
||||
|
||||
|
||||
LOG((CLOG_DEBUG "waiting for event loop"));
|
||||
m_events->waitForReady();
|
||||
|
||||
#if defined(MAC_OS_X_VERSION_10_7)
|
||||
{
|
||||
CLock lockCarbon(m_carbonLoopMutex);
|
||||
if (*m_carbonLoopReady == false) {
|
||||
|
||||
// we signalling carbon loop ready before starting
|
||||
// unless we know how to do it within the loop
|
||||
LOG((CLOG_DEBUG "signalling carbon loop ready"));
|
||||
|
||||
*m_carbonLoopReady = true;
|
||||
m_carbonLoopReady->signal();
|
||||
}
|
||||
@@ -1713,6 +1729,7 @@ COSXScreen::watchSystemPowerThread(void*)
|
||||
// start the run loop
|
||||
LOG((CLOG_DEBUG "starting carbon loop"));
|
||||
CFRunLoopRun();
|
||||
LOG((CLOG_DEBUG "carbon loop has stopped"));
|
||||
|
||||
// cleanup
|
||||
if (notificationPortRef) {
|
||||
@@ -2126,14 +2143,26 @@ void
|
||||
COSXScreen::waitForCarbonLoop() const
|
||||
{
|
||||
#if defined(MAC_OS_X_VERSION_10_7)
|
||||
double timeout = ARCH->time() + 10;
|
||||
if (*m_carbonLoopReady) {
|
||||
LOG((CLOG_DEBUG "carbon loop already ready"));
|
||||
return;
|
||||
}
|
||||
|
||||
CLock lock(m_carbonLoopMutex);
|
||||
|
||||
LOG((CLOG_DEBUG "waiting for carbon loop"));
|
||||
|
||||
double timeout = ARCH->time() + kCarbonLoopWaitTimeout;
|
||||
while (!m_carbonLoopReady->wait()) {
|
||||
if(ARCH->time() > timeout) {
|
||||
throw std::runtime_error("carbon loop is not ready within 5 sec");
|
||||
LOG((CLOG_DEBUG "carbon loop not ready, waiting again"));
|
||||
timeout = ARCH->time() + kCarbonLoopWaitTimeout;
|
||||
}
|
||||
}
|
||||
|
||||
LOG((CLOG_DEBUG "carbon loop ready"));
|
||||
#endif
|
||||
|
||||
}
|
||||
|
||||
#pragma GCC diagnostic ignored "-Wdeprecated-declarations"
|
||||
|
||||
@@ -142,7 +142,7 @@ COSXScreenSaver::launchTerminationCallback(
|
||||
OSStatus result;
|
||||
ProcessSerialNumber psn;
|
||||
EventParamType actualType;
|
||||
UInt32 actualSize;
|
||||
ByteCount actualSize;
|
||||
|
||||
result = GetEventParameter(theEvent, kEventParamProcessID,
|
||||
typeProcessSerialNumber, &actualType,
|
||||
|
||||
@@ -937,8 +937,14 @@ CXWindowsClipboard::pushReplies()
|
||||
for (CReplyMap::iterator index = m_replies.begin();
|
||||
index != m_replies.end(); ) {
|
||||
assert(!index->second.empty());
|
||||
if (!index->second.front()->m_replied) {
|
||||
pushReplies(index, index->second, index->second.begin());
|
||||
CReplyList::iterator listit = index->second.begin();
|
||||
while (listit != index->second.end()) {
|
||||
if (!(*listit)->m_replied)
|
||||
break;
|
||||
++listit;
|
||||
}
|
||||
if (listit != index->second.end() && !(*listit)->m_replied) {
|
||||
pushReplies(index, index->second, listit);
|
||||
}
|
||||
else {
|
||||
++index;
|
||||
|
||||
@@ -1782,29 +1782,32 @@ CXWindowsScreen::doSelectEvents(Window w) const
|
||||
// that we select PointerMotionMask on every window. we also select
|
||||
// SubstructureNotifyMask in order to get CreateNotify events so we
|
||||
// select events on new windows too.
|
||||
//
|
||||
// note that this can break certain clients due a design flaw of X.
|
||||
// X will deliver a PointerMotion event to the deepest window in the
|
||||
// hierarchy that contains the pointer and has PointerMotionMask
|
||||
// selected by *any* client. if another client doesn't select
|
||||
// motion events in a subwindow so the parent window will get them
|
||||
// then by selecting for motion events on the subwindow we break
|
||||
// that client because the parent will no longer get the events.
|
||||
|
||||
// FIXME -- should provide some workaround for event selection
|
||||
// design flaw. perhaps only select for motion events on windows
|
||||
// that already do or are top-level windows or don't propagate
|
||||
// pointer events. or maybe an option to simply poll the mouse.
|
||||
|
||||
// we don't want to adjust our grab window
|
||||
if (w == m_window) {
|
||||
return;
|
||||
}
|
||||
|
||||
// X11 has a design flaw. If *no* client selected PointerMotionMask for
|
||||
// a window, motion events will be delivered to that window's parent.
|
||||
// If *any* client, not necessarily the owner, selects PointerMotionMask
|
||||
// on such a window, X will stop propagating motion events to its
|
||||
// parent. This breaks applications that rely on event propagation
|
||||
// behavior.
|
||||
//
|
||||
// Avoid selecting PointerMotionMask unless some other client selected
|
||||
// it already.
|
||||
long mask = SubstructureNotifyMask;
|
||||
XWindowAttributes attr;
|
||||
XGetWindowAttributes(m_display, w, &attr);
|
||||
if ((attr.all_event_masks & PointerMotionMask) == PointerMotionMask) {
|
||||
mask |= PointerMotionMask;
|
||||
}
|
||||
|
||||
// select events of interest. do this before querying the tree so
|
||||
// we'll get notifications of children created after the XQueryTree()
|
||||
// so we won't miss them.
|
||||
XSelectInput(m_display, w, PointerMotionMask | SubstructureNotifyMask);
|
||||
XSelectInput(m_display, w, mask);
|
||||
|
||||
// recurse on child windows
|
||||
Window rw, pw, *cw;
|
||||
|
||||
@@ -17,6 +17,7 @@
|
||||
*/
|
||||
|
||||
#include "synergy/App.h"
|
||||
|
||||
#include "base/Log.h"
|
||||
#include "common/Version.h"
|
||||
#include "synergy/protocol_types.h"
|
||||
@@ -51,6 +52,10 @@
|
||||
|
||||
CApp* CApp::s_instance = nullptr;
|
||||
|
||||
//
|
||||
// CApp
|
||||
//
|
||||
|
||||
CApp::CApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver, CArgsBase* args) :
|
||||
m_bye(&exit),
|
||||
m_taskBarReceiver(NULL),
|
||||
@@ -67,205 +72,10 @@ CApp::CApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver,
|
||||
|
||||
CApp::~CApp()
|
||||
{
|
||||
s_instance = nullptr;
|
||||
delete m_args;
|
||||
}
|
||||
|
||||
bool
|
||||
CApp::isArg(
|
||||
int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters)
|
||||
{
|
||||
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
||||
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
||||
// match. check args left.
|
||||
if (argi + minRequiredParameters >= argc) {
|
||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||
argsBase().m_pname, argv[argi], argsBase().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
if (appUtil().parseArg(argc, argv, i)) {
|
||||
// handled by platform util
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||
// change logging level
|
||||
argsBase().m_logFilter = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
|
||||
argsBase().m_logFile = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||
// not a daemon
|
||||
argsBase().m_daemon = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||
// daemonize
|
||||
argsBase().m_daemon = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||
// save screen name
|
||||
argsBase().m_name = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||
// don't try to restart
|
||||
argsBase().m_restartable = false;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||
// try to restart
|
||||
argsBase().m_restartable = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||
argsBase().m_backend = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--no-hooks")) {
|
||||
argsBase().m_noHooks = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||
help();
|
||||
m_bye(kExitSuccess);
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--version")) {
|
||||
version();
|
||||
m_bye(kExitSuccess);
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--no-tray")) {
|
||||
argsBase().m_disableTray = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--ipc")) {
|
||||
argsBase().m_enableIpc = true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--server")) {
|
||||
// HACK: stop error happening when using portable (synergyp)
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--client")) {
|
||||
// HACK: stop error happening when using portable (synergyp)
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--crypto-pass")) {
|
||||
argsBase().m_crypto.m_pass = argv[++i];
|
||||
argsBase().m_crypto.setMode("cfb");
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) {
|
||||
bool useDragDrop = true;
|
||||
|
||||
#ifdef WINAPI_XWINDOWS
|
||||
|
||||
useDragDrop = false;
|
||||
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux."));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WINAPI_MSWINDOWS
|
||||
|
||||
OSVERSIONINFO osvi;
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
if (osvi.dwMajorVersion < 6) {
|
||||
useDragDrop = false;
|
||||
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista."));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (useDragDrop) {
|
||||
argsBase().m_enableDragDrop = true;
|
||||
}
|
||||
}
|
||||
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CApp::parseArgs(int argc, const char* const* argv, int& i)
|
||||
{
|
||||
// about these use of assert() here:
|
||||
// previously an /analyze warning was displayed if we only used assert and
|
||||
// did not return on failure. however, this warning does not appear to show
|
||||
// any more (could be because new compiler args have been added).
|
||||
// the asserts are programmer benefit only; the os should never pass 0 args,
|
||||
// because the first is always the binary name. the only way assert would
|
||||
// evaluate to true, is if this parse function were implemented incorrectly,
|
||||
// which is unlikely because it's old code and has a specific use.
|
||||
// we should avoid using anything other than assert here, because it will
|
||||
// look like important code, which it's not really.
|
||||
assert(argsBase().m_pname != NULL);
|
||||
assert(argv != NULL);
|
||||
assert(argc >= 1);
|
||||
|
||||
// set defaults
|
||||
argsBase().m_name = ARCH->getHostName();
|
||||
|
||||
// parse options
|
||||
for (i = 1; i < argc; ++i) {
|
||||
|
||||
if (parseArg(argc, argv, i)) {
|
||||
continue;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "--", NULL)) {
|
||||
// remaining arguments are not options
|
||||
++i;
|
||||
break;
|
||||
}
|
||||
|
||||
else if (argv[i][0] == '-') {
|
||||
std::cerr << "Unrecognized option: " << argv[i] << std::endl;
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
|
||||
else {
|
||||
// this and remaining arguments are not options
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
// suggest that user installs as a windows service. when launched as
|
||||
// service, process should automatically detect that it should run in
|
||||
// daemon mode.
|
||||
if (argsBase().m_daemon) {
|
||||
LOG((CLOG_ERR
|
||||
"the --daemon argument is not supported on windows. "
|
||||
"instead, install %s as a service (--service install)",
|
||||
argsBase().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
#endif
|
||||
}
|
||||
|
||||
void
|
||||
CApp::version()
|
||||
{
|
||||
@@ -363,6 +173,18 @@ CApp::initApp(int argc, const char** argv)
|
||||
// parse command line
|
||||
parseArgs(argc, argv);
|
||||
|
||||
// set log filter
|
||||
if (!CLOG->setFilter(argsBase().m_logFilter)) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||
argsBase().m_pname, argsBase().m_logFilter, argsBase().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
loggingFilterWarning();
|
||||
|
||||
if (argsBase().m_enableDragDrop) {
|
||||
LOG((CLOG_INFO "drag and drop enabled"));
|
||||
}
|
||||
|
||||
// setup file logging after parsing args
|
||||
setupFileLogging();
|
||||
|
||||
@@ -422,3 +244,80 @@ CApp::runEventsLoop(void*)
|
||||
|
||||
#endif
|
||||
}
|
||||
|
||||
//
|
||||
// CMinimalApp
|
||||
//
|
||||
|
||||
CMinimalApp::CMinimalApp() :
|
||||
CApp(NULL, NULL, new CArgsBase())
|
||||
{
|
||||
setEvents(m_events);
|
||||
}
|
||||
|
||||
CMinimalApp::~CMinimalApp()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
CMinimalApp::standardStartup(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
CMinimalApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
void
|
||||
CMinimalApp::startNode()
|
||||
{
|
||||
}
|
||||
|
||||
int
|
||||
CMinimalApp::mainLoop()
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
int
|
||||
CMinimalApp::foregroundStartup(int argc, char** argv)
|
||||
{
|
||||
return 0;
|
||||
}
|
||||
|
||||
CScreen*
|
||||
CMinimalApp::createScreen()
|
||||
{
|
||||
return NULL;
|
||||
}
|
||||
|
||||
void
|
||||
CMinimalApp::loadConfig()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CMinimalApp::loadConfig(const CString& pathname)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
const char*
|
||||
CMinimalApp::daemonInfo() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
const char*
|
||||
CMinimalApp::daemonName() const
|
||||
{
|
||||
return "";
|
||||
}
|
||||
|
||||
void
|
||||
CMinimalApp::parseArgs(int argc, const char* const* argv)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -18,10 +18,12 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "common/common.h"
|
||||
#include "base/String.h"
|
||||
#include "synergy/IApp.h"
|
||||
#include "ipc/IpcClient.h"
|
||||
#include "synergy/IApp.h"
|
||||
#include "base/String.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/EventQueue.h"
|
||||
#include "common/common.h"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "synergy/win32/AppUtilWindows.h"
|
||||
@@ -70,11 +72,6 @@ public:
|
||||
// TODO: this is old C code - use inheritance to normalize
|
||||
void (*m_bye)(int);
|
||||
|
||||
// Returns true if argv[argi] is equal to name1 or name2.
|
||||
bool isArg(int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters = 0);
|
||||
|
||||
static CApp& instance() { assert(s_instance != nullptr); return *s_instance; }
|
||||
|
||||
// If --log was specified in args, then add a file logger.
|
||||
@@ -101,12 +98,12 @@ public:
|
||||
void setSocketMultiplexer(CSocketMultiplexer* sm) { m_socketMultiplexer = sm; }
|
||||
CSocketMultiplexer* getSocketMultiplexer() const { return m_socketMultiplexer; }
|
||||
|
||||
void setEvents(CEventQueue& events) { m_events = &events; }
|
||||
|
||||
private:
|
||||
void handleIpcMessage(const CEvent&, void*);
|
||||
|
||||
protected:
|
||||
virtual void parseArgs(int argc, const char* const* argv, int &i);
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
void initIpcClient();
|
||||
void cleanupIpcClient();
|
||||
void runEventsLoop(void*);
|
||||
@@ -125,7 +122,29 @@ private:
|
||||
CSocketMultiplexer* m_socketMultiplexer;
|
||||
};
|
||||
|
||||
#define BYE "\nTry `%s --help' for more information."
|
||||
class CMinimalApp : public CApp {
|
||||
public:
|
||||
CMinimalApp();
|
||||
virtual ~CMinimalApp();
|
||||
|
||||
// IApp overrides
|
||||
virtual int standardStartup(int argc, char** argv);
|
||||
virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup);
|
||||
virtual void startNode();
|
||||
virtual int mainLoop();
|
||||
virtual int foregroundStartup(int argc, char** argv);
|
||||
virtual CScreen* createScreen();
|
||||
virtual void loadConfig();
|
||||
virtual bool loadConfig(const CString& pathname);
|
||||
virtual const char* daemonInfo() const;
|
||||
virtual const char* daemonName() const;
|
||||
virtual void parseArgs(int argc, const char* const* argv);
|
||||
|
||||
private:
|
||||
CArch m_arch;
|
||||
CLog m_log;
|
||||
CEventQueue m_events;
|
||||
};
|
||||
|
||||
#if WINAPI_MSWINDOWS
|
||||
#define DAEMON_RUNNING(running_) CArchMiscWindows::daemonRunning(running_)
|
||||
|
||||
@@ -30,13 +30,6 @@ CAppUtil::~CAppUtil()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CAppUtil::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
// no common platform args (yet)
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CAppUtil::adoptApp(IApp* app)
|
||||
{
|
||||
|
||||
@@ -25,8 +25,7 @@ class CAppUtil : public IAppUtil {
|
||||
public:
|
||||
CAppUtil();
|
||||
virtual ~CAppUtil();
|
||||
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
|
||||
virtual void adoptApp(IApp* app);
|
||||
IApp& app() const;
|
||||
virtual void exitApp(int code) { throw XExitApp(code); }
|
||||
|
||||
449
src/lib/synergy/ArgParser.cpp
Normal file
449
src/lib/synergy/ArgParser.cpp
Normal file
@@ -0,0 +1,449 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
|
||||
#include "synergy/App.h"
|
||||
#include "synergy/ServerArgs.h"
|
||||
#include "synergy/ClientArgs.h"
|
||||
#include "synergy/ToolArgs.h"
|
||||
#include "synergy/ArgsBase.h"
|
||||
#include "base/Log.h"
|
||||
|
||||
CArgsBase* CArgParser::m_argsBase = NULL;
|
||||
|
||||
CArgParser::CArgParser(CApp* app) :
|
||||
m_app(app)
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::parseServerArgs(CServerArgs& args, int argc, const char* const* argv)
|
||||
{
|
||||
setArgsBase(args);
|
||||
updateCommonArgs(argv);
|
||||
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (parsePlatformArg(args, argc, argv, i)) {
|
||||
continue;
|
||||
}
|
||||
else if (parseGenericArgs(argc, argv, i)) {
|
||||
continue;
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||
// save listen address
|
||||
args.m_synergyAddress = argv[++i];
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||
// save configuration file path
|
||||
args.m_configFile = argv[++i];
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
if (checkUnexpectedArgs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::parseClientArgs(CClientArgs& args, int argc, const char* const* argv)
|
||||
{
|
||||
setArgsBase(args);
|
||||
updateCommonArgs(argv);
|
||||
|
||||
int i;
|
||||
for (i = 1; i < argc; ++i) {
|
||||
if (parsePlatformArg(args, argc, argv, i)) {
|
||||
continue;
|
||||
}
|
||||
else if (parseGenericArgs(argc, argv, i)) {
|
||||
continue;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
||||
// ignore -- included for backwards compatibility
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
||||
// ignore -- included for backwards compatibility
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) {
|
||||
// define scroll
|
||||
args.m_yscroll = atoi(argv[++i]);
|
||||
}
|
||||
else {
|
||||
if (i + 1 == argc) {
|
||||
args.m_synergyAddress = argv[i];
|
||||
return true;
|
||||
}
|
||||
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE, args.m_pname, argv[i], args.m_pname));
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
// exactly one non-option argument (server-address)
|
||||
if (i == argc) {
|
||||
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
||||
args.m_pname, args.m_pname));
|
||||
return false;
|
||||
}
|
||||
|
||||
if (checkUnexpectedArgs()) {
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
#if WINAPI_MSWINDOWS
|
||||
if (isArg(i, argc, argv, NULL, "--service")) {
|
||||
LOG((CLOG_WARN "obsolete argument --service, use synergyd instead."));
|
||||
argsBase.m_shouldExit = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--exit-pause")) {
|
||||
argsBase.m_pauseOnExit = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) {
|
||||
argsBase.m_stopOnDeskSwitch = true;
|
||||
}
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif WINAPI_XWINDOWS
|
||||
if (isArg(i, argc, argv, "-display", "--display", 1)) {
|
||||
// use alternative display
|
||||
argsBase.m_display = argv[++i];
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--no-xinitthreads")) {
|
||||
argsBase.m_disableXInitThreads = true;
|
||||
}
|
||||
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#elif WINAPI_CARBON
|
||||
// no options for carbon
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
|
||||
bool
|
||||
CArgParser::parseToolArgs(CToolArgs& args, int argc, const char* const* argv)
|
||||
{
|
||||
for (int i = 1; i < argc; ++i) {
|
||||
if (isArg(i, argc, argv, NULL, "--get-active-desktop", 0)) {
|
||||
args.m_printActiveDesktopName = true;
|
||||
return true;
|
||||
}
|
||||
else {
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::parseGenericArgs(int argc, const char* const* argv, int& i)
|
||||
{
|
||||
if (isArg(i, argc, argv, "-d", "--debug", 1)) {
|
||||
// change logging level
|
||||
argsBase().m_logFilter = argv[++i];
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-l", "--log", 1)) {
|
||||
argsBase().m_logFile = argv[++i];
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-f", "--no-daemon")) {
|
||||
// not a daemon
|
||||
argsBase().m_daemon = false;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--daemon")) {
|
||||
// daemonize
|
||||
argsBase().m_daemon = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-n", "--name", 1)) {
|
||||
// save screen name
|
||||
argsBase().m_name = argv[++i];
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-1", "--no-restart")) {
|
||||
// don't try to restart
|
||||
argsBase().m_restartable = false;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--restart")) {
|
||||
// try to restart
|
||||
argsBase().m_restartable = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-z", NULL)) {
|
||||
argsBase().m_backend = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--no-hooks")) {
|
||||
argsBase().m_noHooks = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, "-h", "--help")) {
|
||||
if (m_app) {
|
||||
m_app->help();
|
||||
}
|
||||
argsBase().m_shouldExit = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--version")) {
|
||||
if (m_app) {
|
||||
m_app->version();
|
||||
}
|
||||
argsBase().m_shouldExit = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--no-tray")) {
|
||||
argsBase().m_disableTray = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--ipc")) {
|
||||
argsBase().m_enableIpc = true;
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--server")) {
|
||||
// HACK: stop error happening when using portable (synergyp)
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--client")) {
|
||||
// HACK: stop error happening when using portable (synergyp)
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--crypto-pass")) {
|
||||
argsBase().m_crypto.m_pass = argv[++i];
|
||||
argsBase().m_crypto.setMode("cfb");
|
||||
}
|
||||
else if (isArg(i, argc, argv, NULL, "--enable-drag-drop")) {
|
||||
bool useDragDrop = true;
|
||||
|
||||
#ifdef WINAPI_XWINDOWS
|
||||
|
||||
useDragDrop = false;
|
||||
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported on linux."));
|
||||
|
||||
#endif
|
||||
|
||||
#ifdef WINAPI_MSWINDOWS
|
||||
|
||||
OSVERSIONINFO osvi;
|
||||
ZeroMemory(&osvi, sizeof(OSVERSIONINFO));
|
||||
osvi.dwOSVersionInfoSize = sizeof(OSVERSIONINFO);
|
||||
GetVersionEx(&osvi);
|
||||
|
||||
if (osvi.dwMajorVersion < 6) {
|
||||
useDragDrop = false;
|
||||
LOG((CLOG_INFO "ignoring --enable-drag-drop, not supported below vista."));
|
||||
}
|
||||
#endif
|
||||
|
||||
if (useDragDrop) {
|
||||
argsBase().m_enableDragDrop = true;
|
||||
}
|
||||
}
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::isArg(
|
||||
int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters)
|
||||
{
|
||||
if ((name1 != NULL && strcmp(argv[argi], name1) == 0) ||
|
||||
(name2 != NULL && strcmp(argv[argi], name2) == 0)) {
|
||||
// match. check args left.
|
||||
if (argi + minRequiredParameters >= argc) {
|
||||
LOG((CLOG_PRINT "%s: missing arguments for `%s'" BYE,
|
||||
argsBase().m_pname, argv[argi], argsBase().m_pname));
|
||||
argsBase().m_shouldExit = true;
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
// no match
|
||||
return false;
|
||||
}
|
||||
|
||||
void
|
||||
CArgParser::splitCommandString(CString& command, std::vector<CString>& argv)
|
||||
{
|
||||
if (command.empty()) {
|
||||
return ;
|
||||
}
|
||||
|
||||
size_t leftDoubleQuote = 0;
|
||||
size_t rightDoubleQuote = 0;
|
||||
searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote);
|
||||
|
||||
size_t startPos = 0;
|
||||
size_t space = command.find(" ", startPos);
|
||||
|
||||
while (space != CString::npos) {
|
||||
bool ignoreThisSpace = false;
|
||||
|
||||
// check if the space is between two double quotes
|
||||
if (space > leftDoubleQuote && space < rightDoubleQuote) {
|
||||
ignoreThisSpace = true;
|
||||
}
|
||||
else if (space > rightDoubleQuote){
|
||||
searchDoubleQuotes(command, leftDoubleQuote, rightDoubleQuote, rightDoubleQuote + 1);
|
||||
}
|
||||
|
||||
if (!ignoreThisSpace) {
|
||||
CString subString = command.substr(startPos, space - startPos);
|
||||
|
||||
removeDoubleQuotes(subString);
|
||||
argv.push_back(subString);
|
||||
}
|
||||
|
||||
// find next space
|
||||
if (ignoreThisSpace) {
|
||||
space = command.find(" ", rightDoubleQuote + 1);
|
||||
}
|
||||
else {
|
||||
startPos = space + 1;
|
||||
space = command.find(" ", startPos);
|
||||
}
|
||||
}
|
||||
|
||||
CString subString = command.substr(startPos, command.size());
|
||||
removeDoubleQuotes(subString);
|
||||
argv.push_back(subString);
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::searchDoubleQuotes(CString& command, size_t& left, size_t& right, size_t startPos)
|
||||
{
|
||||
bool result = false;
|
||||
left = CString::npos;
|
||||
right = CString::npos;
|
||||
|
||||
left = command.find("\"", startPos);
|
||||
if (left != CString::npos) {
|
||||
right = command.find("\"", left + 1);
|
||||
if (right != CString::npos) {
|
||||
result = true;
|
||||
}
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
left = 0;
|
||||
right = 0;
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
CArgParser::removeDoubleQuotes(CString& arg)
|
||||
{
|
||||
// if string is surrounded by double quotes, remove them
|
||||
if (arg[0] == '\"' &&
|
||||
arg[arg.size() - 1] == '\"') {
|
||||
arg = arg.substr(1, arg.size() - 2);
|
||||
}
|
||||
}
|
||||
|
||||
const char**
|
||||
CArgParser::getArgv(std::vector<CString>& argsArray)
|
||||
{
|
||||
size_t argc = argsArray.size();
|
||||
|
||||
// caller is responsible for deleting the outer array only
|
||||
// we use the c string pointers from argsArray and assign
|
||||
// them to the inner array. So caller only need to use
|
||||
// delete[] to delete the outer array
|
||||
const char** argv = new const char*[argc];
|
||||
|
||||
for (size_t i = 0; i < argc; i++) {
|
||||
argv[i] = argsArray[i].c_str();
|
||||
}
|
||||
|
||||
return argv;
|
||||
}
|
||||
|
||||
CString
|
||||
CArgParser::assembleCommand(std::vector<CString>& argsArray, CString ignoreArg, int parametersRequired)
|
||||
{
|
||||
CString result;
|
||||
|
||||
for (std::vector<CString>::iterator it = argsArray.begin(); it != argsArray.end(); ++it) {
|
||||
if (it->compare(ignoreArg) == 0) {
|
||||
it = it + parametersRequired;
|
||||
continue;
|
||||
}
|
||||
|
||||
// if there is a space in this arg, use double quotes surround it
|
||||
if ((*it).find(" ") != CString::npos) {
|
||||
(*it).insert(0, "\"");
|
||||
(*it).push_back('\"');
|
||||
}
|
||||
|
||||
result.append(*it);
|
||||
// add space to saperate args
|
||||
result.append(" ");
|
||||
}
|
||||
|
||||
if (!result.empty()) {
|
||||
// remove the tail space
|
||||
result = result.substr(0, result.size() - 1);
|
||||
}
|
||||
|
||||
return result;
|
||||
}
|
||||
|
||||
void
|
||||
CArgParser::updateCommonArgs(const char* const* argv)
|
||||
{
|
||||
argsBase().m_name = ARCH->getHostName();
|
||||
argsBase().m_pname = ARCH->getBasename(argv[0]);
|
||||
}
|
||||
|
||||
bool
|
||||
CArgParser::checkUnexpectedArgs()
|
||||
{
|
||||
#if SYSAPI_WIN32
|
||||
// suggest that user installs as a windows service. when launched as
|
||||
// service, process should automatically detect that it should run in
|
||||
// daemon mode.
|
||||
if (argsBase().m_daemon) {
|
||||
LOG((CLOG_ERR
|
||||
"the --daemon argument is not supported on windows. "
|
||||
"instead, install %s as a service (--service install)",
|
||||
argsBase().m_pname));
|
||||
return true;
|
||||
}
|
||||
#endif
|
||||
|
||||
return false;
|
||||
}
|
||||
62
src/lib/synergy/ArgParser.h
Normal file
62
src/lib/synergy/ArgParser.h
Normal file
@@ -0,0 +1,62 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/String.h"
|
||||
#include "common/stdvector.h"
|
||||
|
||||
class CServerArgs;
|
||||
class CClientArgs;
|
||||
class CToolArgs;
|
||||
class CArgsBase;
|
||||
class CApp;
|
||||
|
||||
class CArgParser {
|
||||
|
||||
public:
|
||||
CArgParser(CApp* app);
|
||||
|
||||
bool parseServerArgs(CServerArgs& args, int argc, const char* const* argv);
|
||||
bool parseClientArgs(CClientArgs& args, int argc, const char* const* argv);
|
||||
bool parsePlatformArg(CArgsBase& argsBase, const int& argc, const char* const* argv, int& i);
|
||||
bool parseToolArgs(CToolArgs& args, int argc, const char* const* argv);
|
||||
bool parseGenericArgs(int argc, const char* const* argv, int& i);
|
||||
void setArgsBase(CArgsBase& argsBase) { m_argsBase = &argsBase; }
|
||||
|
||||
static bool isArg(int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters = 0);
|
||||
static void splitCommandString(CString& command, std::vector<CString>& argv);
|
||||
static bool searchDoubleQuotes(CString& command, size_t& left,
|
||||
size_t& right, size_t startPos = 0);
|
||||
static void removeDoubleQuotes(CString& arg);
|
||||
static const char** getArgv(std::vector<CString>& argsArray);
|
||||
static CString assembleCommand(std::vector<CString>& argsArray,
|
||||
CString ignoreArg = "", int parametersRequired = 0);
|
||||
|
||||
private:
|
||||
void updateCommonArgs(const char* const* argv);
|
||||
bool checkUnexpectedArgs();
|
||||
|
||||
static CArgsBase& argsBase() { return *m_argsBase; }
|
||||
|
||||
private:
|
||||
CApp* m_app;
|
||||
|
||||
static CArgsBase* m_argsBase;
|
||||
};
|
||||
@@ -39,7 +39,9 @@ m_logFile(NULL),
|
||||
m_display(NULL),
|
||||
m_disableTray(false),
|
||||
m_enableIpc(false),
|
||||
m_enableDragDrop(false)
|
||||
m_enableDragDrop(false),
|
||||
m_shouldExit(false),
|
||||
m_synergyAddress()
|
||||
{
|
||||
}
|
||||
|
||||
|
||||
@@ -46,4 +46,6 @@ public:
|
||||
#if WINAPI_XWINDOWS
|
||||
bool m_disableXInitThreads;
|
||||
#endif
|
||||
bool m_shouldExit;
|
||||
CString m_synergyAddress;
|
||||
};
|
||||
|
||||
@@ -19,9 +19,11 @@
|
||||
#include "synergy/ClientApp.h"
|
||||
|
||||
#include "client/Client.h"
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/protocol_types.h"
|
||||
#include "synergy/Screen.h"
|
||||
#include "synergy/XScreen.h"
|
||||
#include "synergy/ClientArgs.h"
|
||||
#include "net/NetworkAddress.h"
|
||||
#include "net/TCPSocketFactory.h"
|
||||
#include "net/SocketMultiplexer.h"
|
||||
@@ -61,9 +63,10 @@
|
||||
#define RETRY_TIME 1.0
|
||||
|
||||
CClientApp::CClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) :
|
||||
CApp(events, createTaskBarReceiver, new CArgs()),
|
||||
CApp(events, createTaskBarReceiver, new CClientArgs()),
|
||||
m_client(NULL),
|
||||
m_clientScreen(NULL)
|
||||
m_clientScreen(NULL),
|
||||
m_serverAddress(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -71,97 +74,35 @@ CClientApp::~CClientApp()
|
||||
{
|
||||
}
|
||||
|
||||
CClientApp::CArgs::CArgs() :
|
||||
m_yscroll(0),
|
||||
m_serverAddress(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CClientApp::CArgs::~CArgs()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CClientApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
if (CApp::parseArg(argc, argv, i)) {
|
||||
// found common arg
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--camp")) {
|
||||
// ignore -- included for backwards compatibility
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--no-camp")) {
|
||||
// ignore -- included for backwards compatibility
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, NULL, "--yscroll", 1)) {
|
||||
// define scroll
|
||||
args().m_yscroll = atoi(argv[++i]);
|
||||
}
|
||||
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
// argument was valid
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CClientApp::parseArgs(int argc, const char* const* argv)
|
||||
{
|
||||
// asserts values, sets defaults, and parses args
|
||||
int i;
|
||||
CApp::parseArgs(argc, argv, i);
|
||||
CArgParser argParser(this);
|
||||
bool result = argParser.parseClientArgs(args(), argc, argv);
|
||||
|
||||
// exactly one non-option argument (server-address)
|
||||
if (i == argc) {
|
||||
LOG((CLOG_PRINT "%s: a server address or name is required" BYE,
|
||||
args().m_pname, args().m_pname));
|
||||
if (!result || args().m_shouldExit) {
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
if (i + 1 != argc) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
args().m_pname, argv[i], args().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
|
||||
// save server address
|
||||
try {
|
||||
*args().m_serverAddress = CNetworkAddress(argv[i], kDefaultPort);
|
||||
args().m_serverAddress->resolve();
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
// allow an address that we can't look up if we're restartable.
|
||||
// we'll try to resolve the address each time we connect to the
|
||||
// server. a bad port will never get better. patch by Brent
|
||||
// Priddy.
|
||||
if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
args().m_pname, e.what(), args().m_pname));
|
||||
m_bye(kExitFailed);
|
||||
else {
|
||||
// save server address
|
||||
if (!args().m_synergyAddress.empty()) {
|
||||
try {
|
||||
*m_serverAddress = CNetworkAddress(args().m_synergyAddress, kDefaultPort);
|
||||
m_serverAddress->resolve();
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
// allow an address that we can't look up if we're restartable.
|
||||
// we'll try to resolve the address each time we connect to the
|
||||
// server. a bad port will never get better. patch by Brent
|
||||
// Priddy.
|
||||
if (!args().m_restartable || e.getError() == XSocketAddress::kBadPort) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
args().m_pname, e.what(), args().m_pname));
|
||||
m_bye(kExitFailed);
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// set log filter
|
||||
if (!CLOG->setFilter(args().m_logFilter)) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||
args().m_pname, args().m_logFilter, args().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
|
||||
// identify system
|
||||
LOG((CLOG_INFO "%s Client on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
|
||||
|
||||
if (args().m_enableDragDrop) {
|
||||
LOG((CLOG_INFO "drag and drop enabled"));
|
||||
}
|
||||
|
||||
loggingFilterWarning();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -460,7 +401,7 @@ CClientApp::startClient()
|
||||
if (m_clientScreen == NULL) {
|
||||
clientScreen = openClientScreen();
|
||||
m_client = openClient(args().m_name,
|
||||
*args().m_serverAddress, clientScreen, args().m_crypto);
|
||||
*m_serverAddress, clientScreen, args().m_crypto);
|
||||
m_clientScreen = clientScreen;
|
||||
LOG((CLOG_NOTE "started client"));
|
||||
}
|
||||
@@ -590,7 +531,7 @@ int
|
||||
CClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||
{
|
||||
// general initialization
|
||||
args().m_serverAddress = new CNetworkAddress;
|
||||
m_serverAddress = new CNetworkAddress;
|
||||
args().m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
// install caller's output filter
|
||||
@@ -612,7 +553,7 @@ CClientApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFun
|
||||
delete m_taskBarReceiver;
|
||||
}
|
||||
|
||||
delete args().m_serverAddress;
|
||||
delete m_serverAddress;
|
||||
|
||||
throw;
|
||||
}
|
||||
|
||||
@@ -19,26 +19,17 @@
|
||||
#pragma once
|
||||
|
||||
#include "synergy/App.h"
|
||||
#include "synergy/ArgsBase.h"
|
||||
|
||||
class CScreen;
|
||||
class CEvent;
|
||||
class CClient;
|
||||
class CNetworkAddress;
|
||||
class CThread;
|
||||
class CClientArgs;
|
||||
class CCryptoOptions;
|
||||
|
||||
class CClientApp : public CApp {
|
||||
public:
|
||||
class CArgs : public CArgsBase {
|
||||
public:
|
||||
CArgs();
|
||||
~CArgs();
|
||||
|
||||
public:
|
||||
int m_yscroll;
|
||||
CNetworkAddress* m_serverAddress;
|
||||
};
|
||||
|
||||
CClientApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||
virtual ~CClientApp();
|
||||
|
||||
@@ -49,7 +40,7 @@ public:
|
||||
void help();
|
||||
|
||||
// Returns arguments that are common and for client.
|
||||
CArgs& args() const { return (CArgs&)argsBase(); }
|
||||
CClientArgs& args() const { return (CClientArgs&)argsBase(); }
|
||||
|
||||
const char* daemonName() const;
|
||||
const char* daemonInfo() const;
|
||||
@@ -84,11 +75,9 @@ public:
|
||||
static CClientApp& instance() { return (CClientApp&)CApp::instance(); }
|
||||
|
||||
CClient* getClientPtr() { return m_client; }
|
||||
|
||||
private:
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
|
||||
private:
|
||||
CClient* m_client;
|
||||
CScreen* m_clientScreen;
|
||||
CNetworkAddress* m_serverAddress;
|
||||
};
|
||||
|
||||
23
src/lib/synergy/ClientArgs.cpp
Normal file
23
src/lib/synergy/ClientArgs.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ClientArgs.h"
|
||||
|
||||
CClientArgs::CClientArgs() :
|
||||
m_yscroll(0)
|
||||
{
|
||||
}
|
||||
30
src/lib/synergy/ClientArgs.h
Normal file
30
src/lib/synergy/ClientArgs.h
Normal file
@@ -0,0 +1,30 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "synergy/ArgsBase.h"
|
||||
|
||||
class CNetworkAddress;
|
||||
|
||||
class CClientArgs : public CArgsBase {
|
||||
public:
|
||||
CClientArgs();
|
||||
|
||||
public:
|
||||
int m_yscroll;
|
||||
};
|
||||
@@ -22,6 +22,9 @@
|
||||
#include "synergy/DaemonApp.h"
|
||||
|
||||
#include "synergy/App.h"
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/ServerArgs.h"
|
||||
#include "synergy/ClientArgs.h"
|
||||
#include "ipc/IpcClientProxy.h"
|
||||
#include "ipc/IpcMessage.h"
|
||||
#include "ipc/IpcLogOutputter.h"
|
||||
@@ -84,7 +87,8 @@ CDaemonApp::CDaemonApp() :
|
||||
#if SYSAPI_WIN32
|
||||
m_watchdog(nullptr),
|
||||
#endif
|
||||
m_events(nullptr)
|
||||
m_events(nullptr),
|
||||
m_fileLogOutputter(nullptr)
|
||||
{
|
||||
s_instance = this;
|
||||
}
|
||||
@@ -194,8 +198,10 @@ CDaemonApp::mainLoop(bool logToFile)
|
||||
{
|
||||
DAEMON_RUNNING(true);
|
||||
|
||||
if (logToFile)
|
||||
CLOG->insert(new CFileLogOutputter(logPath().c_str()));
|
||||
if (logToFile) {
|
||||
m_fileLogOutputter = new CFileLogOutputter(logFilename().c_str());
|
||||
CLOG->insert(m_fileLogOutputter);
|
||||
}
|
||||
|
||||
// create socket multiplexer. this must happen after daemonization
|
||||
// on unix because threads evaporate across a fork().
|
||||
@@ -210,6 +216,7 @@ CDaemonApp::mainLoop(bool logToFile)
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
m_watchdog = new CMSWindowsWatchdog(false, *m_ipcServer, *m_ipcLogOutputter);
|
||||
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
||||
#endif
|
||||
|
||||
m_events->adoptHandler(
|
||||
@@ -267,21 +274,17 @@ CDaemonApp::foregroundError(const char* message)
|
||||
}
|
||||
|
||||
std::string
|
||||
CDaemonApp::logPath()
|
||||
CDaemonApp::logFilename()
|
||||
{
|
||||
#ifdef SYSAPI_WIN32
|
||||
// TODO: move to CArchMiscWindows
|
||||
// on windows, log to the same dir as the binary.
|
||||
char fileNameBuffer[MAX_PATH];
|
||||
GetModuleFileName(NULL, fileNameBuffer, MAX_PATH);
|
||||
string fileName(fileNameBuffer);
|
||||
size_t lastSlash = fileName.find_last_of("\\");
|
||||
string path(fileName.substr(0, lastSlash));
|
||||
path.append("\\").append(LOG_FILENAME);
|
||||
return path;
|
||||
#elif SYSAPI_UNIX
|
||||
return "/var/log/" LOG_FILENAME;
|
||||
#endif
|
||||
string logFilename;
|
||||
logFilename = ARCH->setting("LogFilename");
|
||||
if (logFilename.empty()) {
|
||||
logFilename = ARCH->getLogDirectory();
|
||||
logFilename.append("/");
|
||||
logFilename.append(LOG_FILENAME);
|
||||
}
|
||||
|
||||
return logFilename;
|
||||
}
|
||||
|
||||
void
|
||||
@@ -301,13 +304,29 @@ CDaemonApp::handleIpcMessage(const CEvent& e, void*)
|
||||
if (!command.empty()) {
|
||||
LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str()));
|
||||
|
||||
CString debugArg("--debug");
|
||||
UInt32 debugArgPos = static_cast<UInt32>(command.find(debugArg));
|
||||
if (debugArgPos != CString::npos) {
|
||||
UInt32 from = debugArgPos + static_cast<UInt32>(debugArg.size()) + 1;
|
||||
UInt32 nextSpace = static_cast<UInt32>(command.find(" ", from));
|
||||
CString logLevel(command.substr(from, nextSpace - from));
|
||||
std::vector<CString> argsArray;
|
||||
CArgParser::splitCommandString(command, argsArray);
|
||||
CArgParser argParser(NULL);
|
||||
const char** argv = argParser.getArgv(argsArray);
|
||||
CServerArgs serverArgs;
|
||||
CClientArgs clientArgs;
|
||||
int argc = static_cast<int>(argsArray.size());
|
||||
bool server = argsArray[0].find("synergys") != CString::npos ? true : false;
|
||||
CArgsBase* argBase = NULL;
|
||||
|
||||
if (server) {
|
||||
argParser.parseServerArgs(serverArgs, argc, argv);
|
||||
argBase = &serverArgs;
|
||||
}
|
||||
else {
|
||||
argParser.parseClientArgs(clientArgs, argc, argv);
|
||||
argBase = &clientArgs;
|
||||
}
|
||||
|
||||
delete[] argv;
|
||||
|
||||
CString logLevel(argBase->m_logFilter);
|
||||
if (!logLevel.empty()) {
|
||||
try {
|
||||
// change log level based on that in the command string
|
||||
// and change to that log level now.
|
||||
@@ -318,6 +337,23 @@ CDaemonApp::handleIpcMessage(const CEvent& e, void*)
|
||||
LOG((CLOG_ERR "failed to save LogLevel setting, %s", e.what()));
|
||||
}
|
||||
}
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
CString logFilename;
|
||||
if (argBase->m_logFile != NULL) {
|
||||
logFilename = CString(argBase->m_logFile);
|
||||
ARCH->setting("LogFilename", logFilename);
|
||||
m_watchdog->setFileLogOutputter(m_fileLogOutputter);
|
||||
command = CArgParser::assembleCommand(argsArray, "--log", 1);
|
||||
LOG((CLOG_DEBUG "removed log file argument and filename %s from command ", logFilename.c_str()));
|
||||
LOG((CLOG_DEBUG "new command, elevate=%d command=%s", cm->elevate(), command.c_str()));
|
||||
}
|
||||
else {
|
||||
m_watchdog->setFileLogOutputter(NULL);
|
||||
}
|
||||
|
||||
m_fileLogOutputter->setLogFilename(logFilename.c_str());
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
LOG((CLOG_DEBUG "empty command, elevate=%d", cm->elevate()));
|
||||
|
||||
@@ -25,6 +25,7 @@
|
||||
|
||||
class CEvent;
|
||||
class CIpcLogOutputter;
|
||||
class CFileLogOutputter;
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
class CMSWindowsWatchdog;
|
||||
@@ -41,7 +42,7 @@ public:
|
||||
private:
|
||||
void daemonize();
|
||||
void foregroundError(const char* message);
|
||||
std::string logPath();
|
||||
std::string logFilename();
|
||||
void handleIpcMessage(const CEvent&, void*);
|
||||
|
||||
public:
|
||||
@@ -55,6 +56,7 @@ private:
|
||||
CIpcServer* m_ipcServer;
|
||||
CIpcLogOutputter* m_ipcLogOutputter;
|
||||
IEventQueue* m_events;
|
||||
CFileLogOutputter* m_fileLogOutputter;
|
||||
};
|
||||
|
||||
#define LOG_FILENAME "synergyd.log"
|
||||
|
||||
@@ -32,9 +32,6 @@ class IApp : public IInterface
|
||||
{
|
||||
public:
|
||||
virtual void setByeFunc(void(*bye)(int)) = 0;
|
||||
virtual bool isArg(int argi, int argc, const char* const* argv,
|
||||
const char* name1, const char* name2,
|
||||
int minRequiredParameters = 0) = 0;
|
||||
virtual CArgsBase& argsBase() const = 0;
|
||||
virtual int standardStartup(int argc, char** argv) = 0;
|
||||
virtual int runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup) = 0;
|
||||
|
||||
@@ -23,7 +23,6 @@
|
||||
|
||||
class IAppUtil : public IInterface {
|
||||
public:
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i) = 0;
|
||||
virtual void adoptApp(IApp* app) = 0;
|
||||
virtual IApp& app() const = 0;
|
||||
virtual int run(int argc, char** argv) = 0;
|
||||
|
||||
@@ -22,9 +22,11 @@
|
||||
#include "server/ClientListener.h"
|
||||
#include "server/ClientProxy.h"
|
||||
#include "server/PrimaryClient.h"
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/Screen.h"
|
||||
#include "synergy/XScreen.h"
|
||||
#include "synergy/ServerTaskBarReceiver.h"
|
||||
#include "synergy/ServerArgs.h"
|
||||
#include "net/SocketMultiplexer.h"
|
||||
#include "net/TCPSocketFactory.h"
|
||||
#include "net/XSocket.h"
|
||||
@@ -63,13 +65,14 @@
|
||||
//
|
||||
|
||||
CServerApp::CServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver) :
|
||||
CApp(events, createTaskBarReceiver, new CArgs()),
|
||||
CApp(events, createTaskBarReceiver, new CServerArgs()),
|
||||
m_server(NULL),
|
||||
m_serverState(kUninitialized),
|
||||
m_serverScreen(NULL),
|
||||
m_primaryClient(NULL),
|
||||
m_listener(NULL),
|
||||
m_timer(NULL)
|
||||
m_timer(NULL),
|
||||
m_synergyAddress(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
@@ -77,82 +80,29 @@ CServerApp::~CServerApp()
|
||||
{
|
||||
}
|
||||
|
||||
CServerApp::CArgs::CArgs() :
|
||||
m_synergyAddress(NULL),
|
||||
m_config(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
CServerApp::CArgs::~CArgs()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CServerApp::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
if (CApp::parseArg(argc, argv, i)) {
|
||||
// found common arg
|
||||
return true;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-a", "--address", 1)) {
|
||||
// save listen address
|
||||
try {
|
||||
*args().m_synergyAddress = CNetworkAddress(argv[i + 1],
|
||||
kDefaultPort);
|
||||
args().m_synergyAddress->resolve();
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
args().m_pname, e.what(), args().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
++i;
|
||||
}
|
||||
|
||||
else if (isArg(i, argc, argv, "-c", "--config", 1)) {
|
||||
// save configuration file path
|
||||
args().m_configFile = argv[++i];
|
||||
}
|
||||
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
// argument was valid
|
||||
return true;
|
||||
}
|
||||
|
||||
void
|
||||
CServerApp::parseArgs(int argc, const char* const* argv)
|
||||
{
|
||||
// asserts values, sets defaults, and parses args
|
||||
int i;
|
||||
CApp::parseArgs(argc, argv, i);
|
||||
CArgParser argParser(this);
|
||||
bool result = argParser.parseServerArgs(args(), argc, argv);
|
||||
|
||||
// no non-option arguments are allowed
|
||||
if (i != argc) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized option `%s'" BYE,
|
||||
args().m_pname, argv[i], args().m_pname));
|
||||
if (!result || args().m_shouldExit) {
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
|
||||
// set log filter
|
||||
if (!CLOG->setFilter(args().m_logFilter)) {
|
||||
LOG((CLOG_PRINT "%s: unrecognized log level `%s'" BYE,
|
||||
args().m_pname, args().m_logFilter, args().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
else {
|
||||
if (!args().m_synergyAddress.empty()) {
|
||||
try {
|
||||
*m_synergyAddress = CNetworkAddress(args().m_synergyAddress,
|
||||
kDefaultPort);
|
||||
m_synergyAddress->resolve();
|
||||
}
|
||||
catch (XSocketAddress& e) {
|
||||
LOG((CLOG_PRINT "%s: %s" BYE,
|
||||
args().m_pname, e.what(), args().m_pname));
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// identify system
|
||||
LOG((CLOG_INFO "%s Server on %s %s", kAppVersion, ARCH->getOSName().c_str(), ARCH->getPlatformName().c_str()));
|
||||
|
||||
if (args().m_enableDragDrop) {
|
||||
LOG((CLOG_INFO "drag and drop enabled"));
|
||||
}
|
||||
|
||||
loggingFilterWarning();
|
||||
}
|
||||
|
||||
void
|
||||
@@ -742,8 +692,8 @@ CServerApp::mainLoop()
|
||||
// set the contact address, if provided, in the config.
|
||||
// otherwise, if the config doesn't have an address, use
|
||||
// the default.
|
||||
if (args().m_synergyAddress->isValid()) {
|
||||
args().m_config->setSynergyAddress(*args().m_synergyAddress);
|
||||
if (m_synergyAddress->isValid()) {
|
||||
args().m_config->setSynergyAddress(*m_synergyAddress);
|
||||
}
|
||||
else if (!args().m_config->getSynergyAddress().isValid()) {
|
||||
args().m_config->setSynergyAddress(CNetworkAddress(kDefaultPort));
|
||||
@@ -839,7 +789,7 @@ int
|
||||
CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFunc startup)
|
||||
{
|
||||
// general initialization
|
||||
args().m_synergyAddress = new CNetworkAddress;
|
||||
m_synergyAddress = new CNetworkAddress;
|
||||
args().m_config = new CConfig(m_events);
|
||||
args().m_pname = ARCH->getBasename(argv[0]);
|
||||
|
||||
@@ -858,7 +808,7 @@ CServerApp::runInner(int argc, char** argv, ILogOutputter* outputter, StartupFun
|
||||
}
|
||||
|
||||
delete args().m_config;
|
||||
delete args().m_synergyAddress;
|
||||
delete m_synergyAddress;
|
||||
return result;
|
||||
}
|
||||
|
||||
|
||||
@@ -18,6 +18,7 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "synergy/ArgsBase.h"
|
||||
#include "synergy/App.h"
|
||||
#include "base/String.h"
|
||||
#include "server/Config.h"
|
||||
@@ -44,20 +45,10 @@ class CClientListener;
|
||||
class CEventQueueTimer;
|
||||
class ILogOutputter;
|
||||
class IEventQueue;
|
||||
class CServerArgs;
|
||||
|
||||
class CServerApp : public CApp {
|
||||
public:
|
||||
class CArgs : public CArgsBase {
|
||||
public:
|
||||
CArgs();
|
||||
~CArgs();
|
||||
|
||||
public:
|
||||
CString m_configFile;
|
||||
CNetworkAddress* m_synergyAddress;
|
||||
CConfig* m_config;
|
||||
};
|
||||
|
||||
CServerApp(IEventQueue* events, CreateTaskBarReceiverFunc createTaskBarReceiver);
|
||||
virtual ~CServerApp();
|
||||
|
||||
@@ -68,7 +59,7 @@ public:
|
||||
void help();
|
||||
|
||||
// Returns arguments that are common and for server.
|
||||
CArgs& args() const { return (CArgs&)argsBase(); }
|
||||
CServerArgs& args() const { return (CServerArgs&)argsBase(); }
|
||||
|
||||
const char* daemonName() const;
|
||||
const char* daemonInfo() const;
|
||||
@@ -120,9 +111,9 @@ public:
|
||||
CPrimaryClient* m_primaryClient;
|
||||
CClientListener* m_listener;
|
||||
CEventQueueTimer* m_timer;
|
||||
CNetworkAddress* m_synergyAddress;
|
||||
|
||||
private:
|
||||
virtual bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
void handleScreenSwitched(const CEvent&, void* data);
|
||||
};
|
||||
|
||||
|
||||
25
src/lib/synergy/ServerArgs.cpp
Normal file
25
src/lib/synergy/ServerArgs.cpp
Normal file
@@ -0,0 +1,25 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ServerArgs.h"
|
||||
|
||||
CServerArgs::CServerArgs() :
|
||||
m_configFile(),
|
||||
m_config(NULL)
|
||||
{
|
||||
}
|
||||
|
||||
32
src/lib/synergy/ServerArgs.h
Normal file
32
src/lib/synergy/ServerArgs.h
Normal file
@@ -0,0 +1,32 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "synergy/ArgsBase.h"
|
||||
|
||||
class CNetworkAddress;
|
||||
class CConfig;
|
||||
|
||||
class CServerArgs : public CArgsBase {
|
||||
public:
|
||||
CServerArgs();
|
||||
|
||||
public:
|
||||
CString m_configFile;
|
||||
CConfig* m_config;
|
||||
};
|
||||
@@ -16,14 +16,18 @@
|
||||
*/
|
||||
|
||||
#include "synergy/ToolApp.h"
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "arch/Arch.h"
|
||||
#include "base/Log.h"
|
||||
#include "base/String.h"
|
||||
|
||||
#include <iostream>
|
||||
#include <sstream>
|
||||
|
||||
//#define PREMIUM_AUTH_URL "http://localhost/synergy/premium/json/auth/"
|
||||
#define PREMIUM_AUTH_URL "https://synergy-project.org/premium/json/auth/"
|
||||
|
||||
#if SYSAPI_WIN32
|
||||
#include "platform/MSWindowsSession.h"
|
||||
#endif
|
||||
|
||||
enum {
|
||||
kErrorOk,
|
||||
@@ -41,43 +45,43 @@ CToolApp::run(int argc, char** argv)
|
||||
}
|
||||
|
||||
try {
|
||||
for (int i = 1; i < argc; i++) {
|
||||
if (strcmp(argv[i], "--premium-auth") == 0) {
|
||||
premiumAuth();
|
||||
return kErrorOk;
|
||||
CArgParser argParser(this);
|
||||
bool result = argParser.parseToolArgs(m_args, argc, argv);
|
||||
|
||||
if (!result) {
|
||||
m_bye(kExitArgs);
|
||||
}
|
||||
|
||||
if (m_args.m_printActiveDesktopName) {
|
||||
#if SYSAPI_WIN32
|
||||
CMSWindowsSession session;
|
||||
CString name = session.getActiveDesktopName();
|
||||
if (name.empty()) {
|
||||
LOG((CLOG_CRIT "failed to get active desktop name"));
|
||||
return kExitFailed;
|
||||
}
|
||||
else {
|
||||
std::cerr << "unknown arg: " << argv[i] << std::endl;
|
||||
return kErrorArgs;
|
||||
std::cout << "activeDesktop:" << name.c_str() << std::endl;
|
||||
}
|
||||
#endif
|
||||
}
|
||||
else {
|
||||
throw XSynergy("Nothing to do");
|
||||
}
|
||||
}
|
||||
catch (std::exception& e) {
|
||||
std::cerr << e.what() << std::endl;
|
||||
return kErrorException;
|
||||
LOG((CLOG_CRIT "An error occurred: %s\n", e.what()));
|
||||
return kExitFailed;
|
||||
}
|
||||
catch (...) {
|
||||
std::cerr << "unknown error" << std::endl;
|
||||
return kErrorUnknown;
|
||||
LOG((CLOG_CRIT "An unknown error occurred.\n"));
|
||||
return kExitFailed;
|
||||
}
|
||||
|
||||
return kErrorOk;
|
||||
}
|
||||
|
||||
void
|
||||
CToolApp::premiumAuth()
|
||||
CToolApp::help()
|
||||
{
|
||||
CString credentials;
|
||||
std::cin >> credentials;
|
||||
|
||||
size_t separator = credentials.find(':');
|
||||
CString email = credentials.substr(0, separator);
|
||||
CString password = credentials.substr(separator + 1, credentials.length());
|
||||
|
||||
std::stringstream ss;
|
||||
ss << PREMIUM_AUTH_URL;
|
||||
ss << "?email=" << ARCH->internet().urlEncode(email);
|
||||
ss << "&password=" << password;
|
||||
|
||||
std::cout << ARCH->internet().get(ss.str()) << std::endl;
|
||||
}
|
||||
|
||||
@@ -17,12 +17,15 @@
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "synergy/App.h"
|
||||
#include "synergy/ToolArgs.h"
|
||||
#include "common/basic_types.h"
|
||||
|
||||
class CToolApp {
|
||||
class CToolApp : public CMinimalApp
|
||||
{
|
||||
public:
|
||||
UInt32 run(int argc, char** argv);
|
||||
|
||||
void help();
|
||||
private:
|
||||
void premiumAuth();
|
||||
CToolArgs m_args;
|
||||
};
|
||||
|
||||
23
src/lib/synergy/ToolArgs.cpp
Normal file
23
src/lib/synergy/ToolArgs.cpp
Normal file
@@ -0,0 +1,23 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ToolArgs.h"
|
||||
|
||||
CToolArgs::CToolArgs() :
|
||||
m_printActiveDesktopName(false)
|
||||
{
|
||||
}
|
||||
28
src/lib/synergy/ToolArgs.h
Normal file
28
src/lib/synergy/ToolArgs.h
Normal file
@@ -0,0 +1,28 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#include "base/String.h"
|
||||
|
||||
class CToolArgs {
|
||||
public:
|
||||
CToolArgs();
|
||||
|
||||
public:
|
||||
bool m_printActiveDesktopName;
|
||||
};
|
||||
@@ -27,31 +27,6 @@ CAppUtilUnix::~CAppUtilUnix()
|
||||
{
|
||||
}
|
||||
|
||||
bool
|
||||
CAppUtilUnix::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
#if WINAPI_XWINDOWS
|
||||
if (app().isArg(i, argc, argv, "-display", "--display", 1)) {
|
||||
// use alternative display
|
||||
app().argsBase().m_display = argv[++i];
|
||||
}
|
||||
|
||||
else if (app().isArg(i, argc, argv, NULL, "--no-xinitthreads")) {
|
||||
app().argsBase().m_disableXInitThreads = true;
|
||||
}
|
||||
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
#else
|
||||
// no options for carbon
|
||||
return false;
|
||||
#endif
|
||||
}
|
||||
|
||||
int
|
||||
standardStartupStatic(int argc, char** argv)
|
||||
{
|
||||
|
||||
@@ -29,7 +29,6 @@ public:
|
||||
CAppUtilUnix(IEventQueue* events);
|
||||
virtual ~CAppUtilUnix();
|
||||
|
||||
bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
int run(int argc, char** argv);
|
||||
void startNode();
|
||||
};
|
||||
|
||||
@@ -58,29 +58,6 @@ BOOL WINAPI CAppUtilWindows::consoleHandler(DWORD)
|
||||
return TRUE;
|
||||
}
|
||||
|
||||
bool
|
||||
CAppUtilWindows::parseArg(const int& argc, const char* const* argv, int& i)
|
||||
{
|
||||
if (app().isArg(i, argc, argv, NULL, "--service")) {
|
||||
|
||||
LOG((CLOG_WARN "obsolete argument --service, use synergyd instead."));
|
||||
app().bye(kExitFailed);
|
||||
}
|
||||
else if (app().isArg(i, argc, argv, NULL, "--exit-pause")) {
|
||||
|
||||
app().argsBase().m_pauseOnExit = true;
|
||||
}
|
||||
else if (app().isArg(i, argc, argv, NULL, "--stop-on-desk-switch")) {
|
||||
app().argsBase().m_stopOnDeskSwitch = true;
|
||||
}
|
||||
else {
|
||||
// option not supported here
|
||||
return false;
|
||||
}
|
||||
|
||||
return true;
|
||||
}
|
||||
|
||||
static
|
||||
int
|
||||
mainLoopStatic()
|
||||
|
||||
@@ -38,8 +38,6 @@ public:
|
||||
CAppUtilWindows(IEventQueue* events);
|
||||
virtual ~CAppUtilWindows();
|
||||
|
||||
bool parseArg(const int& argc, const char* const* argv, int& i);
|
||||
|
||||
int daemonNTStartup(int, char**);
|
||||
|
||||
int daemonNTMainLoop(int argc, const char** argv);
|
||||
|
||||
@@ -118,6 +118,7 @@ static WPARAM g_deadVirtKey = 0;
|
||||
static WPARAM g_deadRelease = 0;
|
||||
static LPARAM g_deadLParam = 0;
|
||||
static BYTE g_deadKeyState[256] = { 0 };
|
||||
static BYTE g_keyState[256] = { 0 };
|
||||
static DWORD g_hookThread = 0;
|
||||
static DWORD g_attachedThread = 0;
|
||||
static bool g_fakeInput = false;
|
||||
@@ -192,17 +193,41 @@ makeKeyMsg(UINT virtKey, char c, bool noAltGr)
|
||||
|
||||
static
|
||||
void
|
||||
keyboardGetState(BYTE keys[256])
|
||||
keyboardGetState(BYTE keys[256], DWORD vkCode, bool kf_up)
|
||||
{
|
||||
// we have to use GetAsyncKeyState() rather than GetKeyState() because
|
||||
// we don't pass through most keys so the event synchronous state
|
||||
// doesn't get updated. we do that because certain modifier keys have
|
||||
// side effects, like alt and the windows key.
|
||||
SHORT key;
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
key = GetAsyncKeyState(i);
|
||||
keys[i] = (BYTE)((key < 0) ? 0x80u : 0);
|
||||
if (vkCode < 0 || vkCode >= 256) {
|
||||
return;
|
||||
}
|
||||
|
||||
// Keep track of key state on our own in case GetAsyncKeyState() fails
|
||||
g_keyState[vkCode] = kf_up ? 0 : 0x80;
|
||||
g_keyState[VK_SHIFT] = g_keyState[VK_LSHIFT] | g_keyState[VK_RSHIFT];
|
||||
|
||||
SHORT key;
|
||||
// Test whether GetAsyncKeyState() is being honest with us
|
||||
key = GetAsyncKeyState(vkCode);
|
||||
|
||||
if (key & 0x80) {
|
||||
// The only time we know for sure that GetAsyncKeyState() is working
|
||||
// is when it tells us that the current key is down.
|
||||
// In this case, update g_keyState to reflect what GetAsyncKeyState()
|
||||
// is telling us, just in case we have gotten out of sync
|
||||
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
key = GetAsyncKeyState(i);
|
||||
g_keyState[i] = (BYTE)((key < 0) ? 0x80u : 0);
|
||||
}
|
||||
}
|
||||
|
||||
// copy g_keyState to keys
|
||||
for (int i = 0; i < 256; ++i) {
|
||||
keys[i] = g_keyState[i];
|
||||
}
|
||||
|
||||
key = GetKeyState(VK_CAPITAL);
|
||||
keys[VK_CAPITAL] = (BYTE)(((key < 0) ? 0x80 : 0) | (key & 1));
|
||||
}
|
||||
@@ -211,6 +236,9 @@ static
|
||||
bool
|
||||
doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||
{
|
||||
DWORD vkCode = wParam;
|
||||
bool kf_up = (lParam & (KF_UP << 16)) != 0;
|
||||
|
||||
// check for special events indicating if we should start or stop
|
||||
// passing events through and not report them to the server. this
|
||||
// is used to allow the server to synthesize events locally but
|
||||
@@ -254,7 +282,7 @@ doKeyboardHookHandler(WPARAM wParam, LPARAM lParam)
|
||||
|
||||
// we need the keyboard state for ToAscii()
|
||||
BYTE keys[256];
|
||||
keyboardGetState(keys);
|
||||
keyboardGetState(keys, vkCode, kf_up);
|
||||
|
||||
// ToAscii() maps ctrl+letter to the corresponding control code
|
||||
// and ctrl+backspace to delete. we don't want those translations
|
||||
|
||||
44
src/test/mock/synergy/MockApp.h
Normal file
44
src/test/mock/synergy/MockApp.h
Normal file
@@ -0,0 +1,44 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TEST_ENV
|
||||
|
||||
#include "synergy/App.h"
|
||||
|
||||
#include "test/global/gmock.h"
|
||||
|
||||
class CMockApp : public CApp
|
||||
{
|
||||
public:
|
||||
CMockApp() : CApp(NULL, NULL, NULL) { }
|
||||
|
||||
MOCK_METHOD0(help, void());
|
||||
MOCK_METHOD0(loadConfig, void());
|
||||
MOCK_METHOD1(loadConfig, bool(const CString&));
|
||||
MOCK_CONST_METHOD0(daemonInfo, const char*());
|
||||
MOCK_CONST_METHOD0(daemonName, const char*());
|
||||
MOCK_METHOD2(parseArgs, void(int, const char* const*));
|
||||
MOCK_METHOD0(version, void());
|
||||
MOCK_METHOD2(standardStartup, int(int, char**));
|
||||
MOCK_METHOD4(runInner, int(int, char**, ILogOutputter*, StartupFunc));
|
||||
MOCK_METHOD0(startNode, void());
|
||||
MOCK_METHOD0(mainLoop, int());
|
||||
MOCK_METHOD2(foregroundStartup, int(int, char**));
|
||||
MOCK_METHOD0(createScreen, CScreen*());
|
||||
};
|
||||
33
src/test/mock/synergy/MockArgParser.h
Normal file
33
src/test/mock/synergy/MockArgParser.h
Normal file
@@ -0,0 +1,33 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#pragma once
|
||||
|
||||
#define TEST_ENV
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
|
||||
#include "test/global/gmock.h"
|
||||
|
||||
class CMockArgParser : public CArgParser
|
||||
{
|
||||
public:
|
||||
CMockArgParser() : CArgParser(NULL) { }
|
||||
|
||||
MOCK_METHOD3(parseGenericArgs, bool(int, const char* const*, int&));
|
||||
MOCK_METHOD0(checkUnexpectedArgs, bool());
|
||||
};
|
||||
@@ -49,4 +49,4 @@ endif()
|
||||
|
||||
add_executable(unittests ${sources})
|
||||
target_link_libraries(unittests
|
||||
arch base client server common io net platform server synergy mt gtest gmock cryptopp ${libs})
|
||||
arch base client server common io net platform server synergy mt ipc gtest gmock cryptopp ${libs})
|
||||
|
||||
207
src/test/unittests/synergy/ArgParserTests.cpp
Normal file
207
src/test/unittests/synergy/ArgParserTests.cpp
Normal file
@@ -0,0 +1,207 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/ArgsBase.h"
|
||||
|
||||
#include "test/global/gtest.h"
|
||||
|
||||
TEST(CArgParserTests, isArg_abbreviationsArg_returnTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* argv[argc] = { "stub", "-t" };
|
||||
bool result = CArgParser::isArg(i, argc, argv, "-t", NULL);
|
||||
|
||||
EXPECT_EQ(true, result);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, isArg_fullArg_returnTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* argv[argc] = { "stub", "--test" };
|
||||
bool result = CArgParser::isArg(i, argc, argv, NULL, "--test");
|
||||
|
||||
EXPECT_EQ(true, result);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, isArg_missingArgs_returnFalse)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* argv[argc] = { "stub", "-t" };
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
bool result = CArgParser::isArg(i, argc, argv, "-t", NULL, 1);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(true, argsBase.m_shouldExit);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, searchDoubleQuotes_doubleQuotedArg_returnTrue)
|
||||
{
|
||||
CString command("\"stub\"");
|
||||
size_t left = 0;
|
||||
size_t right = 0;
|
||||
|
||||
bool result = CArgParser::searchDoubleQuotes(command, left, right);
|
||||
|
||||
EXPECT_EQ(true, result);
|
||||
EXPECT_EQ(0, left);
|
||||
EXPECT_EQ(5, right);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, searchDoubleQuotes_noDoubleQuotedArg_returnfalse)
|
||||
{
|
||||
CString command("stub");
|
||||
size_t left = 0;
|
||||
size_t right = 0;
|
||||
|
||||
bool result = CArgParser::searchDoubleQuotes(command, left, right);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(0, left);
|
||||
EXPECT_EQ(0, right);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, searchDoubleQuotes_oneDoubleQuoteArg_returnfalse)
|
||||
{
|
||||
CString command("\"stub");
|
||||
size_t left = 0;
|
||||
size_t right = 0;
|
||||
|
||||
bool result = CArgParser::searchDoubleQuotes(command, left, right);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
EXPECT_EQ(0, left);
|
||||
EXPECT_EQ(0, right);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, splitCommandString_oneArg_returnArgv)
|
||||
{
|
||||
CString command("stub");
|
||||
std::vector<CString> argv;
|
||||
|
||||
CArgParser::splitCommandString(command, argv);
|
||||
|
||||
EXPECT_EQ(1, argv.size());
|
||||
EXPECT_EQ("stub", argv.at(0));
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, splitCommandString_twoArgs_returnArgv)
|
||||
{
|
||||
CString command("stub1 stub2");
|
||||
std::vector<CString> argv;
|
||||
|
||||
CArgParser::splitCommandString(command, argv);
|
||||
|
||||
EXPECT_EQ(2, argv.size());
|
||||
EXPECT_EQ("stub1", argv.at(0));
|
||||
EXPECT_EQ("stub2", argv.at(1));
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, splitCommandString_doubleQuotedArgs_returnArgv)
|
||||
{
|
||||
CString command("\"stub1\" stub2 \"stub3\"");
|
||||
std::vector<CString> argv;
|
||||
|
||||
CArgParser::splitCommandString(command, argv);
|
||||
|
||||
EXPECT_EQ(3, argv.size());
|
||||
EXPECT_EQ("stub1", argv.at(0));
|
||||
EXPECT_EQ("stub2", argv.at(1));
|
||||
EXPECT_EQ("stub3", argv.at(2));
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, splitCommandString_spaceDoubleQuotedArgs_returnArgv)
|
||||
{
|
||||
CString command("\"stub1\" stub2 \"stub3 space\"");
|
||||
std::vector<CString> argv;
|
||||
|
||||
CArgParser::splitCommandString(command, argv);
|
||||
|
||||
EXPECT_EQ(3, argv.size());
|
||||
EXPECT_EQ("stub1", argv.at(0));
|
||||
EXPECT_EQ("stub2", argv.at(1));
|
||||
EXPECT_EQ("stub3 space", argv.at(2));
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, getArgv_stringArray_return2DArray)
|
||||
{
|
||||
std::vector<CString> argArray;
|
||||
argArray.push_back("stub1");
|
||||
argArray.push_back("stub2");
|
||||
argArray.push_back("stub3 space");
|
||||
const char** argv = CArgParser::getArgv(argArray);
|
||||
|
||||
CString row1(argv[0]);
|
||||
CString row2(argv[1]);
|
||||
CString row3(argv[2]);
|
||||
|
||||
EXPECT_EQ("stub1", row1);
|
||||
EXPECT_EQ("stub2", row2);
|
||||
EXPECT_EQ("stub3 space", row3);
|
||||
|
||||
delete[] argv;
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, assembleCommand_stringArray_returnCommand)
|
||||
{
|
||||
std::vector<CString> argArray;
|
||||
argArray.push_back("stub1");
|
||||
argArray.push_back("stub2");
|
||||
CString command = CArgParser::assembleCommand(argArray);
|
||||
|
||||
EXPECT_EQ("stub1 stub2", command);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, assembleCommand_ignoreSecondArg_returnCommand)
|
||||
{
|
||||
std::vector<CString> argArray;
|
||||
argArray.push_back("stub1");
|
||||
argArray.push_back("stub2");
|
||||
CString command = CArgParser::assembleCommand(argArray, "stub2");
|
||||
|
||||
EXPECT_EQ("stub1", command);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, assembleCommand_ignoreSecondArgWithOneParameter_returnCommand)
|
||||
{
|
||||
std::vector<CString> argArray;
|
||||
argArray.push_back("stub1");
|
||||
argArray.push_back("stub2");
|
||||
argArray.push_back("stub3");
|
||||
argArray.push_back("stub4");
|
||||
CString command = CArgParser::assembleCommand(argArray, "stub2", 1);
|
||||
|
||||
EXPECT_EQ("stub1 stub4", command);
|
||||
}
|
||||
|
||||
TEST(CArgParserTests, assembleCommand_stringArrayWithSpace_returnCommand)
|
||||
{
|
||||
std::vector<CString> argArray;
|
||||
argArray.push_back("stub1 space");
|
||||
argArray.push_back("stub2");
|
||||
argArray.push_back("stub3 space");
|
||||
CString command = CArgParser::assembleCommand(argArray);
|
||||
|
||||
EXPECT_EQ("\"stub1 space\" stub2 \"stub3 space\"", command);
|
||||
}
|
||||
|
||||
95
src/test/unittests/synergy/ClientArgsParsingTests.cpp
Normal file
95
src/test/unittests/synergy/ClientArgsParsingTests.cpp
Normal file
@@ -0,0 +1,95 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/ClientArgs.h"
|
||||
#include "test/mock/synergy/MockArgParser.h"
|
||||
|
||||
#include "test/global/gtest.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
bool
|
||||
client_stubParseGenericArgs(int, const char* const*, int&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
client_stubCheckUnexpectedArgs()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(CClientArgsParsingTests, parseClientArgs_yScrollArg_setYScroll)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs));
|
||||
CClientArgs clientArgs;
|
||||
const int argc = 3;
|
||||
const char* kYScrollCmd[argc] = { "stub", "--yscroll", "1" };
|
||||
|
||||
argParser.parseClientArgs(clientArgs, argc, kYScrollCmd);
|
||||
|
||||
EXPECT_EQ(1, clientArgs.m_yscroll);
|
||||
}
|
||||
|
||||
TEST(CClientArgsParsingTests, parseClientArgs_addressArg_setSynergyAddress)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs));
|
||||
CClientArgs clientArgs;
|
||||
const int argc = 2;
|
||||
const char* kAddressCmd[argc] = { "stub", "mock_address" };
|
||||
|
||||
bool result = argParser.parseClientArgs(clientArgs, argc, kAddressCmd);
|
||||
|
||||
EXPECT_EQ("mock_address", clientArgs.m_synergyAddress);
|
||||
EXPECT_EQ(true, result);
|
||||
}
|
||||
|
||||
TEST(CClientArgsParsingTests, parseClientArgs_noAddressArg_returnFalse)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs));
|
||||
CClientArgs clientArgs;
|
||||
const int argc = 1;
|
||||
const char* kNoAddressCmd[argc] = { "stub" };
|
||||
|
||||
bool result = argParser.parseClientArgs(clientArgs, argc, kNoAddressCmd);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
|
||||
TEST(CClientArgsParsingTests, parseClientArgs_unrecognizedArg_returnFalse)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(client_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(client_stubCheckUnexpectedArgs));
|
||||
CClientArgs clientArgs;
|
||||
const int argc = 3;
|
||||
const char* kUnrecognizedCmd[argc] = { "stub", "mock_arg", "mock_address"};
|
||||
|
||||
bool result = argParser.parseClientArgs(clientArgs, argc, kUnrecognizedCmd);
|
||||
|
||||
EXPECT_FALSE(result);
|
||||
}
|
||||
332
src/test/unittests/synergy/GenericArgsParsingTests.cpp
Normal file
332
src/test/unittests/synergy/GenericArgsParsingTests.cpp
Normal file
@@ -0,0 +1,332 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/ArgsBase.h"
|
||||
#include "test/mock/synergy/MockApp.h"
|
||||
|
||||
#include "test/global/gtest.h"
|
||||
|
||||
using namespace synergy;
|
||||
using ::testing::_;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
bool g_helpShowed = false;
|
||||
bool g_versionShowed = false;
|
||||
|
||||
void
|
||||
showMockHelp()
|
||||
{
|
||||
g_helpShowed = true;
|
||||
}
|
||||
|
||||
void
|
||||
showMockVersion()
|
||||
{
|
||||
g_versionShowed = true;
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_logLevelCmd_setLogLevel)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 3;
|
||||
const char* kLogLevelCmd[argc] = { "stub", "--debug", "DEBUG" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kLogLevelCmd, i);
|
||||
|
||||
CString logFilter(argsBase.m_logFilter);
|
||||
|
||||
EXPECT_EQ("DEBUG", logFilter);
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_logFileCmd_saveLogFilename)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 3;
|
||||
const char* kLogFileCmd[argc] = { "stub", "--log", "mock_filename" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kLogFileCmd, i);
|
||||
|
||||
CString logFile(argsBase.m_logFile);
|
||||
|
||||
EXPECT_EQ("mock_filename", logFile);
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_logFileCmdWithSpace_saveLogFilename)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 3;
|
||||
const char* kLogFileCmdWithSpace[argc] = { "stub", "--log", "mo ck_filename" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kLogFileCmdWithSpace, i);
|
||||
|
||||
CString logFile(argsBase.m_logFile);
|
||||
|
||||
EXPECT_EQ("mo ck_filename", logFile);
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_noDeamonCmd_daemonFalse)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kNoDeamonCmd[argc] = { "stub", "-f" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kNoDeamonCmd, i);
|
||||
|
||||
EXPECT_FALSE(argsBase.m_daemon);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_deamonCmd_daemonTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kDeamonCmd[argc] = { "stub", "--daemon" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kDeamonCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_daemon);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_nameCmd_saveName)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 3;
|
||||
const char* kNameCmd[argc] = { "stub", "--name", "mock" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kNameCmd, i);
|
||||
|
||||
EXPECT_EQ("mock", argsBase.m_name);
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_noRestartCmd_restartFalse)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kNoRestartCmd[argc] = { "stub", "--no-restart" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kNoRestartCmd, i);
|
||||
|
||||
EXPECT_FALSE(argsBase.m_restartable);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_restartCmd_restartTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kRestartCmd[argc] = { "stub", "--restart" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kRestartCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_restartable);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_backendCmd_backendTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kBackendCmd[argc] = { "stub", "-z" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kBackendCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_backend);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_noHookCmd_noHookTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kNoHookCmd[argc] = { "stub", "--no-hooks" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kNoHookCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_noHooks);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_helpCmd_showHelp)
|
||||
{
|
||||
g_helpShowed = false;
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kHelpCmd[argc] = { "stub", "--help" };
|
||||
|
||||
NiceMock<CMockApp> app;
|
||||
CArgParser argParser(&app);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
ON_CALL(app, help()).WillByDefault(Invoke(showMockHelp));
|
||||
|
||||
argParser.parseGenericArgs(argc, kHelpCmd, i);
|
||||
|
||||
EXPECT_EQ(true, g_helpShowed);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_versionCmd_showVersion)
|
||||
{
|
||||
g_versionShowed = false;
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kVersionCmd[argc] = { "stub", "--version" };
|
||||
|
||||
NiceMock<CMockApp> app;
|
||||
CArgParser argParser(&app);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
ON_CALL(app, version()).WillByDefault(Invoke(showMockVersion));
|
||||
|
||||
argParser.parseGenericArgs(argc, kVersionCmd, i);
|
||||
|
||||
EXPECT_EQ(true, g_versionShowed);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_noTrayCmd_disableTrayTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kNoTrayCmd[argc] = { "stub", "--no-tray" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kNoTrayCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_disableTray);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_ipcCmd_enableIpcTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kIpcCmd[argc] = { "stub", "--ipc" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kIpcCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_enableIpc);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_cryptoPassCmd_savePassword)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 3;
|
||||
const char* kCryptoPassCmd[argc] = { "stub", "--crypto-pass", "mock_password" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kCryptoPassCmd, i);
|
||||
|
||||
EXPECT_EQ("mock_password", argsBase.m_crypto.m_pass);
|
||||
EXPECT_EQ(1, argsBase.m_crypto.m_mode); // 1 == kCfb
|
||||
EXPECT_EQ(2, i);
|
||||
}
|
||||
|
||||
#ifndef WINAPI_XWINDOWS
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_dragDropCmdOnNonLinux_enableDragDropTrue)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kDragDropCmd, i);
|
||||
|
||||
EXPECT_EQ(true, argsBase.m_enableDragDrop);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
#endif
|
||||
|
||||
#ifdef WINAPI_XWINDOWS
|
||||
TEST(CGenericArgsParsingTests, parseGenericArgs_dragDropCmdOnLinux_enableDragDropFalse)
|
||||
{
|
||||
int i = 1;
|
||||
const int argc = 2;
|
||||
const char* kDragDropCmd[argc] = { "stub", "--enable-drag-drop" };
|
||||
|
||||
CArgParser argParser(NULL);
|
||||
CArgsBase argsBase;
|
||||
argParser.setArgsBase(argsBase);
|
||||
|
||||
argParser.parseGenericArgs(argc, kDragDropCmd, i);
|
||||
|
||||
EXPECT_FALSE(argsBase.m_enableDragDrop);
|
||||
EXPECT_EQ(1, i);
|
||||
}
|
||||
#endif
|
||||
66
src/test/unittests/synergy/ServerArgsParsingTests.cpp
Normal file
66
src/test/unittests/synergy/ServerArgsParsingTests.cpp
Normal file
@@ -0,0 +1,66 @@
|
||||
/*
|
||||
* synergy -- mouse and keyboard sharing utility
|
||||
* Copyright (C) 2014 Synergy Si, Inc.
|
||||
*
|
||||
* 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.
|
||||
*
|
||||
* You should have received a copy of the GNU General Public License
|
||||
* along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
|
||||
#include "synergy/ArgParser.h"
|
||||
#include "synergy/ServerArgs.h"
|
||||
#include "test/mock/synergy/MockArgParser.h"
|
||||
|
||||
#include "test/global/gtest.h"
|
||||
|
||||
using ::testing::_;
|
||||
using ::testing::Invoke;
|
||||
using ::testing::NiceMock;
|
||||
|
||||
bool
|
||||
server_stubParseGenericArgs(int, const char* const*, int&)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
bool
|
||||
server_stubCheckUnexpectedArgs()
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
TEST(CServerArgsParsingTests, parseServerArgs_addressArg_setSynergyAddress)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs));
|
||||
CServerArgs serverArgs;
|
||||
const int argc = 3;
|
||||
const char* kAddressCmd[argc] = { "stub", "--address", "mock_address" };
|
||||
|
||||
argParser.parseServerArgs(serverArgs, argc, kAddressCmd);
|
||||
|
||||
EXPECT_EQ("mock_address", serverArgs.m_synergyAddress);
|
||||
}
|
||||
|
||||
TEST(CServerArgsParsingTests, parseServerArgs_configArg_setConfigFile)
|
||||
{
|
||||
NiceMock<CMockArgParser> argParser;
|
||||
ON_CALL(argParser, parseGenericArgs(_, _, _)).WillByDefault(Invoke(server_stubParseGenericArgs));
|
||||
ON_CALL(argParser, checkUnexpectedArgs()).WillByDefault(Invoke(server_stubCheckUnexpectedArgs));
|
||||
CServerArgs serverArgs;
|
||||
const int argc = 3;
|
||||
const char* kConfigCmd[argc] = { "stub", "--config", "mock_configFile" };
|
||||
|
||||
argParser.parseServerArgs(serverArgs, argc, kConfigCmd);
|
||||
|
||||
EXPECT_EQ("mock_configFile", serverArgs.m_configFile);
|
||||
}
|
||||
Reference in New Issue
Block a user