mirror of
https://github.com/lubosz/overte.git
synced 2025-04-07 16:42:08 +02:00
First steps towards a screenshare app
This commit is contained in:
parent
faa192a337
commit
ea373ac14c
22 changed files with 3073 additions and 364 deletions
|
@ -256,6 +256,7 @@ endif()
|
|||
|
||||
if (BUILD_CLIENT)
|
||||
add_subdirectory(interface)
|
||||
add_subdirectory(screenshare)
|
||||
set_target_properties(interface PROPERTIES FOLDER "Apps")
|
||||
|
||||
option(USE_SIXENSE "Build Interface with sixense library/plugin" OFF)
|
||||
|
|
|
@ -146,23 +146,27 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
|
||||
set(DMG_SUBFOLDER_ICON "${HF_CMAKE_DIR}/installer/install-folder.rsrc")
|
||||
|
||||
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(NITPICK_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(CONSOLE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(INTERFACE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(SCREENSHARE_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
set(NITPICK_INSTALL_DIR ${DMG_SUBFOLDER_NAME})
|
||||
|
||||
if (CLIENT_ONLY)
|
||||
set(CONSOLE_EXEC_NAME "Console.app")
|
||||
else ()
|
||||
set(CONSOLE_EXEC_NAME "Sandbox.app")
|
||||
endif()
|
||||
|
||||
set(CONSOLE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${CONSOLE_EXEC_NAME}")
|
||||
|
||||
set(SCREENSHARE_EXEC_NAME "HiFiScreenshare.app")
|
||||
set(SCREENSHARE_INSTALL_APP_PATH "${SCREENSHARE_INSTALL_DIR}/${SCREENSHARE_EXEC_NAME}")
|
||||
|
||||
set(CONSOLE_APP_CONTENTS "${CONSOLE_INSTALL_APP_PATH}/Contents")
|
||||
set(COMPONENT_APP_PATH "${CONSOLE_APP_CONTENTS}/MacOS/Components.app")
|
||||
set(COMPONENT_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/MacOS")
|
||||
set(CONSOLE_PLUGIN_INSTALL_DIR "${COMPONENT_APP_PATH}/Contents/PlugIns")
|
||||
|
||||
|
||||
set(SCREENSHARE_APP_CONTENTS "${SCREENSHARE_INSTALL_APP_PATH}/Contents")
|
||||
|
||||
set(INTERFACE_INSTALL_APP_PATH "${CONSOLE_INSTALL_DIR}/${INTERFACE_BUNDLE_NAME}.app")
|
||||
set(INTERFACE_ICON_FILENAME "${INTERFACE_ICON_PREFIX}.icns")
|
||||
|
@ -170,9 +174,11 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
else ()
|
||||
if (WIN32)
|
||||
set(CONSOLE_INSTALL_DIR "server-console")
|
||||
set(SCREENSHARE_INSTALL_DIR "screenshare")
|
||||
set(NITPICK_INSTALL_DIR "nitpick")
|
||||
else ()
|
||||
set(CONSOLE_INSTALL_DIR ".")
|
||||
set(SCREENSHARE_INSTALL_DIR ".")
|
||||
set(NITPICK_INSTALL_DIR ".")
|
||||
endif ()
|
||||
|
||||
|
@ -186,6 +192,7 @@ macro(SET_PACKAGING_PARAMETERS)
|
|||
set(NITPICK_ICON_FILENAME "${NITPICK_ICON_PREFIX}.ico")
|
||||
|
||||
set(CONSOLE_EXEC_NAME "server-console.exe")
|
||||
set(SCREENSHARE_EXEC_NAME "hifi-screenshare.exe")
|
||||
|
||||
set(DS_EXEC_NAME "domain-server.exe")
|
||||
set(AC_EXEC_NAME "assignment-client.exe")
|
||||
|
|
1
cmake/templates/.gitignore
vendored
Normal file
1
cmake/templates/.gitignore
vendored
Normal file
|
@ -0,0 +1 @@
|
|||
screenshare*
|
357
hifi_android.py
357
hifi_android.py
|
@ -1,357 +0,0 @@
|
|||
import hifi_utils
|
||||
import json
|
||||
import os
|
||||
import platform
|
||||
import re
|
||||
import shutil
|
||||
import xml.etree.ElementTree as ET
|
||||
import functools
|
||||
import zipfile
|
||||
|
||||
print = functools.partial(print, flush=True)
|
||||
|
||||
ANDROID_PACKAGE_URL = 'https://hifi-public.s3.amazonaws.com/dependencies/android/'
|
||||
|
||||
ANDROID_PACKAGES = {
|
||||
'qt' : {
|
||||
'file': 'qt-5.11.1_linux_armv8-libcpp_openssl_patched.tgz',
|
||||
'versionId': '3S97HBM5G5Xw9EfE52sikmgdN3t6C2MN',
|
||||
'checksum': 'aa449d4bfa963f3bc9a9dfe558ba29df',
|
||||
},
|
||||
'bullet': {
|
||||
'file': 'bullet-2.88_armv8-libcpp.tgz',
|
||||
'versionId': 'S8YaoED0Cl8sSb8fSV7Q2G1lQJSNDxqg',
|
||||
'checksum': '81642779ccb110f8c7338e8739ac38a0',
|
||||
},
|
||||
'draco': {
|
||||
'file': 'draco_armv8-libcpp.tgz',
|
||||
'versionId': '3.B.uBj31kWlgND3_R2xwQzT_TP6Dz_8',
|
||||
'checksum': '617a80d213a5ec69fbfa21a1f2f738cd',
|
||||
},
|
||||
'glad': {
|
||||
'file': 'glad_armv8-libcpp.zip',
|
||||
'versionId': 'r5Zran.JSCtvrrB6Q4KaqfIoALPw3lYY',
|
||||
'checksum': 'a8ee8584cf1ccd34766c7ddd9d5e5449',
|
||||
},
|
||||
'gvr': {
|
||||
'file': 'gvrsdk_v1.101.0.tgz',
|
||||
'versionId': 'nqBV_j81Uc31rC7bKIrlya_Hah4v3y5r',
|
||||
'checksum': '57fd02baa069176ba18597a29b6b4fc7',
|
||||
},
|
||||
'nvtt': {
|
||||
'file': 'nvtt_armv8-libcpp.zip',
|
||||
'versionId': 'lmkBVR5t4UF1UUwMwEirnk9H_8Nt90IO',
|
||||
'checksum': 'eb46d0b683e66987190ed124aabf8910',
|
||||
'sharedLibFolder': 'lib',
|
||||
'includeLibs': ['libnvtt.so', 'libnvmath.so', 'libnvimage.so', 'libnvcore.so']
|
||||
},
|
||||
'oculus_1.22': {
|
||||
'file': 'ovr_sdk_mobile_1.22.zip',
|
||||
'versionId': 'InhomR5gwkzyiLAelH3X9k4nvV3iIpA_',
|
||||
'checksum': '1ac3c5b0521e5406f287f351015daff8',
|
||||
'sharedLibFolder': 'VrApi/Libs/Android/arm64-v8a/Release',
|
||||
'includeLibs': ['libvrapi.so']
|
||||
},
|
||||
'oculusPlatform': {
|
||||
'file': 'OVRPlatformSDK_v1.34.0.zip',
|
||||
'versionId': 'vbRUkkyzUAXfTGSEtuiUr_7.Fm5h5BZk',
|
||||
'checksum': '16e4c5f39520f122bc49cb6d5bb88289',
|
||||
'sharedLibFolder': 'Android/libs/arm64-v8a',
|
||||
'includeLibs': ['libovrplatformloader.so']
|
||||
},
|
||||
'openssl': {
|
||||
'file': 'openssl-1.1.0g_armv8.tgz',
|
||||
'versionId': 'AiiPjmgUZTgNj7YV1EEx2lL47aDvvvAW',
|
||||
'checksum': 'cabb681fbccd79594f65fcc266e02f32'
|
||||
},
|
||||
'polyvox': {
|
||||
'file': 'polyvox_armv8-libcpp.tgz',
|
||||
'versionId': 'A2kbKiNhpIenGq23bKRRzg7IMAI5BI92',
|
||||
'checksum': 'dba88b3a098747af4bb169e9eb9af57e',
|
||||
'sharedLibFolder': 'lib',
|
||||
'includeLibs': ['Release/libPolyVoxCore.so', 'libPolyVoxUtil.so'],
|
||||
},
|
||||
'tbb': {
|
||||
'file': 'tbb-2018_U1_armv8_libcpp.tgz',
|
||||
'versionId': 'mrRbWnv4O4evcM1quRH43RJqimlRtaKB',
|
||||
'checksum': '20768f298f53b195e71b414b0ae240c4',
|
||||
'sharedLibFolder': 'lib/release',
|
||||
'includeLibs': ['libtbb.so', 'libtbbmalloc.so'],
|
||||
},
|
||||
'hifiAC': {
|
||||
'baseUrl': 'http://s3.amazonaws.com/hifi-public/dependencies/',
|
||||
'file': 'codecSDK-android_armv8-2.0.zip',
|
||||
'checksum': '1cbef929675818fc64c4101b72f84a6a'
|
||||
},
|
||||
'etc2comp': {
|
||||
'file': 'etc2comp-patched-armv8-libcpp.tgz',
|
||||
'versionId': 'bHhGECRAQR1vkpshBcK6ByNc1BQIM8gU',
|
||||
'checksum': '14b02795d774457a33bbc60e00a786bc'
|
||||
},
|
||||
'breakpad': {
|
||||
'file': 'breakpad.tgz',
|
||||
'versionId': '8VrYXz7oyc.QBxNia0BVJOUBvrFO61jI',
|
||||
'checksum': 'ddcb23df336b08017042ba4786db1d9e',
|
||||
'sharedLibFolder': 'lib',
|
||||
'includeLibs': {'libbreakpad_client.a'}
|
||||
},
|
||||
'webrtc': {
|
||||
'file': 'webrtc-20190626-android.tar.gz',
|
||||
'checksum': 'e2dccd3d8efdcba6d428c87ba7fb2a53'
|
||||
}
|
||||
}
|
||||
|
||||
ANDROID_PLATFORM_PACKAGES = {
|
||||
'Darwin' : {
|
||||
'qt': {
|
||||
'file': 'qt-5.11.1_osx_armv8-libcpp_openssl_patched.tgz',
|
||||
'versionId': 'OxBD7iKINv1HbyOXmAmDrBb8AF3N.Kup',
|
||||
'checksum': 'c83cc477c08a892e00c71764dca051a0'
|
||||
},
|
||||
},
|
||||
'Windows' : {
|
||||
'qt': {
|
||||
'file': 'qt-5.11.1_win_armv8-libcpp_openssl_patched.tgz',
|
||||
'versionId': 'JfWM0P_Mz5Qp0LwpzhrsRwN3fqlLSFeT',
|
||||
'checksum': '0582191cc55431aa4f660848a542883e'
|
||||
},
|
||||
}
|
||||
}
|
||||
|
||||
QT5_DEPS = [
|
||||
'Qt5Concurrent',
|
||||
'Qt5Core',
|
||||
'Qt5Gui',
|
||||
'Qt5Multimedia',
|
||||
'Qt5Network',
|
||||
'Qt5OpenGL',
|
||||
'Qt5Qml',
|
||||
'Qt5Quick',
|
||||
'Qt5QuickControls2',
|
||||
'Qt5QuickTemplates2',
|
||||
'Qt5Script',
|
||||
'Qt5ScriptTools',
|
||||
'Qt5Svg',
|
||||
'Qt5WebChannel',
|
||||
'Qt5WebSockets',
|
||||
'Qt5Widgets',
|
||||
'Qt5XmlPatterns',
|
||||
# Android specific
|
||||
'Qt5AndroidExtras',
|
||||
'Qt5WebView',
|
||||
]
|
||||
|
||||
def getPlatformPackages():
|
||||
result = ANDROID_PACKAGES.copy()
|
||||
system = platform.system()
|
||||
if system in ANDROID_PLATFORM_PACKAGES:
|
||||
platformPackages = ANDROID_PLATFORM_PACKAGES[system]
|
||||
result = { **result, **platformPackages }
|
||||
return result
|
||||
|
||||
def getPackageUrl(package):
|
||||
url = ANDROID_PACKAGE_URL
|
||||
if 'baseUrl' in package:
|
||||
url = package['baseUrl']
|
||||
url += package['file']
|
||||
if 'versionId' in package:
|
||||
url += '?versionId=' + package['versionId']
|
||||
return url
|
||||
|
||||
def copyAndroidLibs(packagePath, appPath):
|
||||
androidPackages = getPlatformPackages()
|
||||
jniPath = os.path.join(appPath, 'src/main/jniLibs/arm64-v8a')
|
||||
if not os.path.isdir(jniPath):
|
||||
os.makedirs(jniPath)
|
||||
for packageName in androidPackages:
|
||||
package = androidPackages[packageName]
|
||||
if 'sharedLibFolder' in package:
|
||||
sharedLibFolder = os.path.join(packagePath, packageName, package['sharedLibFolder'])
|
||||
if 'includeLibs' in package:
|
||||
for lib in package['includeLibs']:
|
||||
sourceFile = os.path.join(sharedLibFolder, lib)
|
||||
destFile = os.path.join(jniPath, os.path.split(lib)[1])
|
||||
if not os.path.isfile(destFile):
|
||||
print("Copying {}".format(lib))
|
||||
shutil.copy(sourceFile, destFile)
|
||||
|
||||
gvrLibFolder = os.path.join(packagePath, 'gvr/gvr-android-sdk-1.101.0/libraries')
|
||||
audioSoOut = os.path.join(gvrLibFolder, 'libgvr_audio.so')
|
||||
if not os.path.isfile(audioSoOut):
|
||||
audioAar = os.path.join(gvrLibFolder, 'sdk-audio-1.101.0.aar')
|
||||
with zipfile.ZipFile(audioAar) as z:
|
||||
with z.open('jni/arm64-v8a/libgvr_audio.so') as f:
|
||||
with open(audioSoOut, 'wb') as of:
|
||||
shutil.copyfileobj(f, of)
|
||||
|
||||
audioSoOut2 = os.path.join(jniPath, 'libgvr_audio.so')
|
||||
if not os.path.isfile(audioSoOut2):
|
||||
shutil.copy(audioSoOut, audioSoOut2)
|
||||
|
||||
baseSoOut = os.path.join(gvrLibFolder, 'libgvr.so')
|
||||
if not os.path.isfile(baseSoOut):
|
||||
baseAar = os.path.join(gvrLibFolder, 'sdk-base-1.101.0.aar')
|
||||
with zipfile.ZipFile(baseAar) as z:
|
||||
with z.open('jni/arm64-v8a/libgvr.so') as f:
|
||||
with open(baseSoOut, 'wb') as of:
|
||||
shutil.copyfileobj(f, of)
|
||||
|
||||
baseSoOut2 = os.path.join(jniPath, 'libgvr.so')
|
||||
if not os.path.isfile(baseSoOut2):
|
||||
shutil.copy(baseSoOut, baseSoOut2)
|
||||
|
||||
class QtPackager:
|
||||
def __init__(self, appPath, qtRootPath):
|
||||
self.appPath = appPath
|
||||
self.qtRootPath = qtRootPath
|
||||
self.jniPath = os.path.join(self.appPath, 'src/main/jniLibs/arm64-v8a')
|
||||
self.assetPath = os.path.join(self.appPath, 'src/main/assets')
|
||||
self.qtAssetPath = os.path.join(self.assetPath, '--Added-by-androiddeployqt--')
|
||||
self.qtAssetCacheList = os.path.join(self.qtAssetPath, 'qt_cache_pregenerated_file_list')
|
||||
# Jars go into the qt library
|
||||
self.jarPath = os.path.realpath(os.path.join(self.appPath, '../../libraries/qt/libs'))
|
||||
self.xmlFile = os.path.join(self.appPath, 'src/main/res/values/libs.xml')
|
||||
self.files = []
|
||||
self.features = []
|
||||
self.permissions = []
|
||||
|
||||
def copyQtDeps(self):
|
||||
for lib in QT5_DEPS:
|
||||
libfile = os.path.join(self.qtRootPath, "lib/lib{}.so".format(lib))
|
||||
if not os.path.exists(libfile):
|
||||
continue
|
||||
self.files.append(libfile)
|
||||
androidDeps = os.path.join(self.qtRootPath, "lib/{}-android-dependencies.xml".format(lib))
|
||||
if not os.path.exists(androidDeps):
|
||||
continue
|
||||
|
||||
tree = ET.parse(androidDeps)
|
||||
root = tree.getroot()
|
||||
for item in root.findall('./dependencies/lib/depends/*'):
|
||||
if (item.tag == 'lib') or (item.tag == 'bundled'):
|
||||
relativeFilename = item.attrib['file']
|
||||
if (relativeFilename.startswith('qml')):
|
||||
continue
|
||||
filename = os.path.join(self.qtRootPath, relativeFilename)
|
||||
self.files.extend(hifi_utils.recursiveFileList(filename, excludeNamePattern=r"^\."))
|
||||
elif item.tag == 'jar' and 'bundling' in item.attrib and item.attrib['bundling'] == "1":
|
||||
self.files.append(os.path.join(self.qtRootPath, item.attrib['file']))
|
||||
elif item.tag == 'permission':
|
||||
self.permissions.append(item.attrib['name'])
|
||||
elif item.tag == 'feature':
|
||||
self.features.append(item.attrib['name'])
|
||||
|
||||
def scanQmlImports(self):
|
||||
qmlImportCommandFile = os.path.join(self.qtRootPath, 'bin/qmlimportscanner')
|
||||
system = platform.system()
|
||||
if 'Windows' == system:
|
||||
qmlImportCommandFile += ".exe"
|
||||
if not os.path.isfile(qmlImportCommandFile):
|
||||
raise RuntimeError("Couldn't find qml import scanner")
|
||||
qmlRootPath = hifi_utils.scriptRelative('interface/resources/qml')
|
||||
qmlImportPath = os.path.join(self.qtRootPath, 'qml')
|
||||
commandResult = hifi_utils.executeSubprocessCapture([
|
||||
qmlImportCommandFile,
|
||||
'-rootPath', qmlRootPath,
|
||||
'-importPath', qmlImportPath
|
||||
])
|
||||
qmlImportResults = json.loads(commandResult)
|
||||
for item in qmlImportResults:
|
||||
if 'path' not in item:
|
||||
continue
|
||||
path = os.path.realpath(item['path'])
|
||||
if not os.path.exists(path):
|
||||
continue
|
||||
basePath = path
|
||||
if os.path.isfile(basePath):
|
||||
basePath = os.path.dirname(basePath)
|
||||
basePath = os.path.normcase(basePath)
|
||||
if basePath.startswith(qmlRootPath):
|
||||
continue
|
||||
self.files.extend(hifi_utils.recursiveFileList(path, excludeNamePattern=r"^\."))
|
||||
|
||||
def processFiles(self):
|
||||
self.files = list(set(self.files))
|
||||
self.files.sort()
|
||||
libsXmlRoot = ET.Element('resources')
|
||||
qtLibsNode = ET.SubElement(libsXmlRoot, 'array', {'name':'qt_libs'})
|
||||
bundledLibsNode = ET.SubElement(libsXmlRoot, 'array', {'name':'bundled_in_lib'})
|
||||
bundledAssetsNode = ET.SubElement(libsXmlRoot, 'array', {'name':'bundled_in_assets'})
|
||||
libPrefix = 'lib'
|
||||
for sourceFile in self.files:
|
||||
if not os.path.isfile(sourceFile):
|
||||
raise RuntimeError("Unable to find dependency file " + sourceFile)
|
||||
relativePath = os.path.relpath(sourceFile, self.qtRootPath).replace('\\', '/')
|
||||
destinationFile = None
|
||||
if relativePath.endswith('.so'):
|
||||
garbledFileName = None
|
||||
if relativePath.startswith(libPrefix):
|
||||
garbledFileName = relativePath[4:]
|
||||
p = re.compile(r'lib(Qt5.*).so')
|
||||
m = p.search(garbledFileName)
|
||||
if not m:
|
||||
raise RuntimeError("Huh?")
|
||||
libName = m.group(1)
|
||||
ET.SubElement(qtLibsNode, 'item').text = libName
|
||||
else:
|
||||
garbledFileName = 'lib' + relativePath.replace('/', '_'[0])
|
||||
value = "{}:{}".format(garbledFileName, relativePath).replace('\\', '/')
|
||||
ET.SubElement(bundledLibsNode, 'item').text = value
|
||||
destinationFile = os.path.join(self.jniPath, garbledFileName)
|
||||
elif relativePath.startswith('jar'):
|
||||
destinationFile = os.path.join(self.jarPath, relativePath[4:])
|
||||
else:
|
||||
value = "--Added-by-androiddeployqt--/{}:{}".format(relativePath,relativePath).replace('\\', '/')
|
||||
ET.SubElement(bundledAssetsNode, 'item').text = value
|
||||
destinationFile = os.path.join(self.qtAssetPath, relativePath)
|
||||
|
||||
destinationParent = os.path.realpath(os.path.dirname(destinationFile))
|
||||
if not os.path.isdir(destinationParent):
|
||||
os.makedirs(destinationParent)
|
||||
if not os.path.isfile(destinationFile):
|
||||
shutil.copy(sourceFile, destinationFile)
|
||||
|
||||
tree = ET.ElementTree(libsXmlRoot)
|
||||
tree.write(self.xmlFile, 'UTF-8', True)
|
||||
|
||||
def generateAssetsFileList(self):
|
||||
print("Implement asset file list")
|
||||
# outputFilename = os.path.join(self.qtAssetPath, "qt_cache_pregenerated_file_list")
|
||||
# fileList = hifi_utils.recursiveFileList(self.qtAssetPath)
|
||||
# fileMap = {}
|
||||
# for fileName in fileList:
|
||||
# relativeFileName = os.path.relpath(fileName, self.assetPath)
|
||||
# dirName, localFileName = os.path.split(relativeFileName)
|
||||
# if not dirName in fileMap:
|
||||
# fileMap[dirName] = []
|
||||
# fileMap[dirName].append(localFileName)
|
||||
|
||||
# for dirName in fileMap:
|
||||
# for localFileName in fileMap[dirName]:
|
||||
# ????
|
||||
|
||||
#
|
||||
# Gradle version
|
||||
#
|
||||
# DataOutputStream fos = new DataOutputStream(new FileOutputStream(outputFile));
|
||||
# for (Map.Entry<String, List<String>> e: directoryContents.entrySet()) {
|
||||
# def entryList = e.getValue()
|
||||
# fos.writeInt(e.key.length()*2); // 2 bytes per char
|
||||
# fos.writeChars(e.key);
|
||||
# fos.writeInt(entryList.size());
|
||||
# for (String entry: entryList) {
|
||||
# fos.writeInt(entry.length()*2);
|
||||
# fos.writeChars(entry);
|
||||
# }
|
||||
# }
|
||||
|
||||
def bundle(self):
|
||||
if not os.path.isfile(self.xmlFile):
|
||||
print("Bundling Qt info into {}".format(self.xmlFile))
|
||||
self.copyQtDeps()
|
||||
self.scanQmlImports()
|
||||
self.processFiles()
|
||||
# if not os.path.isfile(self.qtAssetCacheList):
|
||||
# self.generateAssetsFileList()
|
||||
|
||||
|
|
@ -184,6 +184,7 @@
|
|||
#include "scripting/AssetMappingsScriptingInterface.h"
|
||||
#include "scripting/ClipboardScriptingInterface.h"
|
||||
#include "scripting/DesktopScriptingInterface.h"
|
||||
#include "scripting/ScreenshareScriptingInterface.h"
|
||||
#include "scripting/AccountServicesScriptingInterface.h"
|
||||
#include "scripting/HMDScriptingInterface.h"
|
||||
#include "scripting/MenuScriptingInterface.h"
|
||||
|
@ -892,7 +893,7 @@ bool setupEssentials(int& argc, char** argv, bool runningMarkerExisted) {
|
|||
#ifdef HAVE_DDE
|
||||
DependencyManager::set<DdeFaceTracker>();
|
||||
#endif
|
||||
|
||||
DependencyManager::set<ScreenshareScriptingInterface>();
|
||||
DependencyManager::set<AudioClient>();
|
||||
DependencyManager::set<AudioScope>();
|
||||
DependencyManager::set<DeferredLightingEffect>();
|
||||
|
@ -3448,7 +3449,7 @@ void Application::onDesktopRootContextCreated(QQmlContext* surfaceContext) {
|
|||
surfaceContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
|
||||
surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
|
||||
surfaceContext->setContextProperty("Screenshare", DependencyManager::get<ScreenshareScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Camera", &_myCamera);
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
|
@ -3557,6 +3558,7 @@ void Application::userKickConfirmation(const QUuid& nodeID) {
|
|||
}
|
||||
|
||||
void Application::setupQmlSurface(QQmlContext* surfaceContext, bool setAdditionalContextProperties) {
|
||||
surfaceContext->setContextProperty("Screenshare", DependencyManager::get<ScreenshareScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("Users", DependencyManager::get<UsersScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("HMD", DependencyManager::get<HMDScriptingInterface>().data());
|
||||
surfaceContext->setContextProperty("UserActivityLogger", DependencyManager::get<UserActivityLoggerScriptingInterface>().data());
|
||||
|
@ -7422,6 +7424,7 @@ void Application::registerScriptEngineWithApplicationServices(const ScriptEngine
|
|||
scriptEngine->registerGlobalObject("AvatarList", DependencyManager::get<AvatarManager>().data());
|
||||
|
||||
scriptEngine->registerGlobalObject("Camera", &_myCamera);
|
||||
scriptEngine->registerGlobalObject("Screenshare", DependencyManager::get<ScreenshareScriptingInterface>().data());
|
||||
|
||||
#if defined(Q_OS_MAC) || defined(Q_OS_WIN)
|
||||
scriptEngine->registerGlobalObject("SpeechRecognizer", DependencyManager::get<SpeechRecognizer>().data());
|
||||
|
|
70
interface/src/scripting/ScreenshareScriptingInterface.cpp
Normal file
70
interface/src/scripting/ScreenshareScriptingInterface.cpp
Normal file
|
@ -0,0 +1,70 @@
|
|||
//
|
||||
// ScreenshareScriptingInterface.cpp
|
||||
// interface/src/scripting/
|
||||
//
|
||||
// Created by Milad Nazeri on 2019-10-23.
|
||||
// Copyright 2019 High Fidelity, Inc.
|
||||
//
|
||||
// Distributed under the Apache License, Version 2.0.
|
||||
// See the accompanying file LICENSE or http://www.apache.org/licenses/LICENSE-2.0.html
|
||||
//
|
||||
|
||||
#include "ScreenshareScriptingInterface.h"
|
||||
#include <QProcess>
|
||||
#include <QThread>
|
||||
#include <QDesktopServices>
|
||||
#include <QUrl>
|
||||
#include <QCoreApplication>
|
||||
|
||||
|
||||
ScreenshareScriptingInterface::ScreenshareScriptingInterface() {
|
||||
|
||||
};
|
||||
|
||||
void ScreenshareScriptingInterface::startScreenshare(QString displayName, QString userName, QString token, QString sessionID, QString apiKey, QString fileLocation) {
|
||||
if (QThread::currentThread() != thread()) {
|
||||
// We must start a new QProcess from the main thread.
|
||||
QMetaObject::invokeMethod(
|
||||
this, "startScreenshare",
|
||||
Q_ARG(QString, displayName),
|
||||
Q_ARG(QString, userName),
|
||||
Q_ARG(QString, token),
|
||||
Q_ARG(QString, sessionID),
|
||||
Q_ARG(QString, apiKey),
|
||||
Q_ARG(QString, fileLocation)
|
||||
);
|
||||
return;
|
||||
}
|
||||
|
||||
qDebug() << "ZRF: Inside startScreenshare(). `SCREENSHARE_EXE_PATH`:" << SCREENSHARE_EXE_PATH;
|
||||
|
||||
if (displayName.isEmpty() || userName.isEmpty() || token.isEmpty() || sessionID.isEmpty() || apiKey.isEmpty()) {
|
||||
qDebug() << "Screenshare executable can't launch without connection info.";
|
||||
return;
|
||||
}
|
||||
|
||||
QStringList arguments;
|
||||
arguments << "--userName=" + userName;
|
||||
arguments << "--displayName=" + displayName;
|
||||
arguments << "--token=" + token;
|
||||
arguments << "--apiKey=" + apiKey;
|
||||
arguments << "--sessionID=" + sessionID;
|
||||
|
||||
QProcess* electronProcess = new QProcess(this);
|
||||
|
||||
connect(electronProcess, &QProcess::errorOccurred,
|
||||
[=](QProcess::ProcessError error) { qDebug() << "ZRF QProcess::errorOccurred. `error`:" << error; });
|
||||
connect(electronProcess, &QProcess::started, [=]() { qDebug() << "ZRF QProcess::started"; });
|
||||
connect(electronProcess, &QProcess::stateChanged,
|
||||
[=](QProcess::ProcessState newState) { qDebug() << "ZRF QProcess::stateChanged. `newState`:" << newState; });
|
||||
connect(electronProcess, QOverload<int, QProcess::ExitStatus>::of(&QProcess::finished),
|
||||
[=](int exitCode, QProcess::ExitStatus exitStatus) {
|
||||
qDebug() << "ZRF QProcess::finished. `exitCode`:" << exitCode << "`exitStatus`:" << exitStatus;
|
||||
});
|
||||
|
||||
// Note for Milad:
|
||||
// We'll have to have equivalent lines of code for MacOS.
|
||||
#ifdef Q_OS_WIN
|
||||
electronProcess->start(fileLocation, arguments);
|
||||
#endif
|
||||
};
|
19
interface/src/scripting/ScreenshareScriptingInterface.h
Normal file
19
interface/src/scripting/ScreenshareScriptingInterface.h
Normal file
|
@ -0,0 +1,19 @@
|
|||
#ifndef hifi_ScreenshareScriptingInterface_h
|
||||
#define hifi_ScreenshareScriptingInterface_h
|
||||
|
||||
#include <QObject>
|
||||
#include <DependencyManager.h>
|
||||
|
||||
class ScreenshareScriptingInterface : public QObject, public Dependency {
|
||||
Q_OBJECT
|
||||
public:
|
||||
ScreenshareScriptingInterface();
|
||||
// This is a note for Milad:
|
||||
// The value of this `SCREENSHARE_EXE_PATH` string will have to be changed based on the operating system we're using.
|
||||
// The binary should probably be stored in a path like this one.
|
||||
const QString SCREENSHARE_EXE_PATH{ "C:\\hifi\\hiFi\\screenshare\\screenshare-win32-x64\\screenshare.exe" };
|
||||
|
||||
Q_INVOKABLE void startScreenshare(QString displayName, QString userName, QString token, QString sessionID, QString apiKey, QString fileLocation);
|
||||
};
|
||||
|
||||
#endif // hifi_ScreenshareScriptingInterface_h
|
2
screenshare/.gitignore
vendored
Normal file
2
screenshare/.gitignore
vendored
Normal file
|
@ -0,0 +1,2 @@
|
|||
screenshare-*/
|
||||
screenshare*.zip
|
34
screenshare/CMakeLists.txt
Normal file
34
screenshare/CMakeLists.txt
Normal file
|
@ -0,0 +1,34 @@
|
|||
set(TARGET_NAME screenshare)
|
||||
add_custom_target(${TARGET_NAME}-npm-install
|
||||
COMMAND npm install
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
)
|
||||
add_custom_target(${TARGET_NAME}
|
||||
COMMAND npm run packager
|
||||
WORKING_DIRECTORY ${CMAKE_CURRENT_SOURCE_DIR}
|
||||
DEPENDS ${TARGET_NAME}-npm-install
|
||||
)
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES FOLDER "screenshare")
|
||||
set_target_properties(${TARGET_NAME}-npm-install PROPERTIES FOLDER "hidden/screenshare")
|
||||
|
||||
if (WIN32)
|
||||
set(PACKAGED_SCREENSHARE_FOLDER "screenshare-win32-x64")
|
||||
set(SCREENSHARE_DESTINATION "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_SCREENSHARE_FOLDER}")
|
||||
install(
|
||||
DIRECTORY "${SCREENSHARE_DESTINATION}/"
|
||||
DESTINATION ${SCREENSHARE_INSTALL_DIR}
|
||||
)
|
||||
|
||||
set(EXECUTABLE_PATH "${SCREENSHARE_DESTINATION}/${SCREENSHARE_EXEC_NAME}")
|
||||
optional_win_executable_signing()
|
||||
elseif (APPLE)
|
||||
set(PACKAGED_SCREENSHARE_FOLDER "screenshare-darwin-x64/${SCREENSHARE_EXEC_NAME}")
|
||||
install(
|
||||
DIRECTORY "${CMAKE_CURRENT_BINARY_DIR}/${PACKAGED_SCREENSHARE_FOLDER}"
|
||||
USE_SOURCE_PERMISSIONS
|
||||
DESTINATION ${SCREENSHARE_INSTALL_DIR}
|
||||
)
|
||||
endif()
|
||||
|
||||
set_target_properties(${TARGET_NAME} PROPERTIES EXCLUDE_FROM_ALL FALSE EXCLUDE_FROM_DEFAULT_BUILD FALSE)
|
2289
screenshare/package-lock.json
generated
Normal file
2289
screenshare/package-lock.json
generated
Normal file
File diff suppressed because it is too large
Load diff
26
screenshare/package.json
Normal file
26
screenshare/package.json
Normal file
|
@ -0,0 +1,26 @@
|
|||
{
|
||||
"name": "highfidelity_screenshare",
|
||||
"version": "1.0.0",
|
||||
"description": "High Fidelity Screenshare",
|
||||
"main": "src/main.js",
|
||||
"scripts": {
|
||||
"test": "echo \"Error: no test specified\" && exit 1"
|
||||
},
|
||||
"repository": {
|
||||
"type": "git",
|
||||
"url": "git+https://github.com/highfidelity/hifi.git"
|
||||
},
|
||||
"author": "High Fidelity",
|
||||
"license": "Apache-2.0",
|
||||
"bugs": {
|
||||
"url": "https://github.com/highfidelity/hifi/issues"
|
||||
},
|
||||
"homepage": "https://github.com/highfidelity/hifi#readme",
|
||||
"devDependencies": {
|
||||
"electron": "^6.0.12",
|
||||
"electron-packager": "^14.0.6"
|
||||
},
|
||||
"dependencies": {
|
||||
"yargs": "^14.2.0"
|
||||
}
|
||||
}
|
25
screenshare/packager.js
Normal file
25
screenshare/packager.js
Normal file
|
@ -0,0 +1,25 @@
|
|||
var packager = require('electron-packager');
|
||||
var options = {
|
||||
dir: __dirname,
|
||||
name: "screenshare",
|
||||
version: "0.1.0",
|
||||
overwrite: true,
|
||||
prune: true,
|
||||
arch: "x64",
|
||||
platform: "win32",
|
||||
CompanyName: "High Fidelity, Inc.",
|
||||
FileDescription: "High Fidelity Screenshare",
|
||||
OriginalFilename: "hifi-screenshare.exe",
|
||||
ignore: "electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore"
|
||||
};
|
||||
|
||||
|
||||
// call the packager to produce the executable
|
||||
packager(options, function(error, appPath) {
|
||||
if (error) {
|
||||
console.error("There was an error writing the packaged console: " + error.message);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log("Wrote new app to " + appPath);
|
||||
}
|
||||
});
|
26
screenshare/packager_mac.js
Normal file
26
screenshare/packager_mac.js
Normal file
|
@ -0,0 +1,26 @@
|
|||
var packager = require('electron-packager');
|
||||
var options = {
|
||||
dir: __dirname,
|
||||
name: "screenshare",
|
||||
version: "0.1.0",
|
||||
overwrite: true,
|
||||
prune: true,
|
||||
arch: "x64",
|
||||
platform: "darwin",
|
||||
CompanyName: "High Fidelity, Inc.",
|
||||
FileDescription: "High Fidelity Screenshare",
|
||||
OriginalFilename: "screenshare.exe",
|
||||
ignore: "electron-packager|README.md|CMakeLists.txt|packager.js|.gitignore"
|
||||
};
|
||||
|
||||
options["app-bundle-id"] = "com.highfidelity.screenshare";
|
||||
|
||||
// call the packager to produce the executable
|
||||
packager(options, function(error, appPath) {
|
||||
if (error) {
|
||||
console.error("There was an error writing the packaged console: " + error.message);
|
||||
process.exit(1);
|
||||
} else {
|
||||
console.log("Wrote new app to " + appPath);
|
||||
}
|
||||
});
|
271
screenshare/src/app.js
Normal file
271
screenshare/src/app.js
Normal file
|
@ -0,0 +1,271 @@
|
|||
// Helpers
|
||||
function handleError(error) {
|
||||
if (error) {
|
||||
console.error(error);
|
||||
}
|
||||
}
|
||||
|
||||
/* SOURCE EXAMPLE
|
||||
[23584:1028/110448.237:INFO:CONSOLE(67)] "{
|
||||
"id": "screen:0:0",
|
||||
"name": "Screen 1",
|
||||
"thumbnail": {},
|
||||
"display_id": "2528732444",
|
||||
"appIcon": null
|
||||
}"
|
||||
*/
|
||||
|
||||
var isBrowser = false;
|
||||
const imageWidth = 265;
|
||||
const imageHeight = 165;
|
||||
|
||||
var images = 10;
|
||||
var testImage = "resources/test.jpg";
|
||||
function MakeSource(name, thumbnail, id, newWidth, newHeight){
|
||||
this.name = name;
|
||||
this.thumbnail = thumbnail;
|
||||
this.id = id;
|
||||
this.width = newWidth;
|
||||
this.height = newHeight;
|
||||
}
|
||||
|
||||
let testSources = [];
|
||||
|
||||
for (let index = 0; index < images; index++) {
|
||||
let test = new MakeSource("REALLY LONG LONG title" + index, testImage, index, imageWidth, imageHeight);
|
||||
testSources.push(test);
|
||||
}
|
||||
|
||||
// if (!isBrowser) {
|
||||
const electron = require('electron');
|
||||
// }
|
||||
|
||||
let currentScreensharePickID = "";
|
||||
function screensharePicked(id){
|
||||
currentScreensharePickID = id;
|
||||
// console.log(currentScreensharePickID);
|
||||
document.getElementById("share_pick").innerHTML = "";
|
||||
addSource(sourceMap[id], "share_pick");
|
||||
togglePage();
|
||||
}
|
||||
|
||||
|
||||
|
||||
function screenConfirmed(isConfirmed){
|
||||
if (isConfirmed === true){
|
||||
onAccessApproved(currentScreensharePickID);
|
||||
}
|
||||
togglePage();
|
||||
}
|
||||
|
||||
|
||||
let currentPage = "mainPage";
|
||||
function togglePage(){
|
||||
if (currentPage === "mainPage") {
|
||||
currentPage = "confirmationPage";
|
||||
document.getElementById("select_screen").style.display = "none";
|
||||
document.getElementById("confirmation_screen").style.display = "block";
|
||||
} else {
|
||||
currentPage = "mainPage";
|
||||
document.getElementById("select_screen").style.display = "block";
|
||||
document.getElementById("confirmation_screen").style.display = "none";
|
||||
}
|
||||
}
|
||||
|
||||
// UI
|
||||
function addSource(source, type) {
|
||||
let sourceBody = document.createElement('div')
|
||||
let thumbnail = isBrowser ? source.thumbnail : source.thumbnail.toDataURL();
|
||||
sourceBody.classList.add("box")
|
||||
let circle = `<div class="circle" onclick="screensharePicked('${source.id}')"}></div>`
|
||||
sourceBody.innerHTML = `
|
||||
<div class="heading">
|
||||
${type === "selects" ? circle : ""}
|
||||
<span class="screen_label">${source.name}</span>
|
||||
</div>
|
||||
<div class="image">
|
||||
<img src="${thumbnail}"></img>
|
||||
</div>
|
||||
`
|
||||
// console.log(sourceBody.innerHTML);
|
||||
if (type === "selects") {
|
||||
document.getElementById("selects").appendChild(sourceBody);
|
||||
} else {
|
||||
document.getElementById("share_pick").appendChild(sourceBody);
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let sourceMap = {};
|
||||
function showSources() {
|
||||
document.getElementById("selects").innerHTML="";
|
||||
if (isBrowser) {
|
||||
for (let source of testSources) {
|
||||
sourceMap[source.id] = source;
|
||||
addSource(source, "selects");
|
||||
}
|
||||
} else {
|
||||
electron.desktopCapturer.getSources({
|
||||
types:['window', 'screen'],
|
||||
thumbnailSize: {
|
||||
width: imageWidth,
|
||||
height: imageHeight
|
||||
}
|
||||
}, (error, sources) => {
|
||||
if (error) {
|
||||
console.log("Error getting sources", error);
|
||||
}
|
||||
|
||||
for (let source of sources) {
|
||||
sourceMap[source.id] = source;
|
||||
addSource(source, "selects");
|
||||
}
|
||||
});
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
let localStream;
|
||||
function stopSharing(){
|
||||
desktopSharing = false;
|
||||
|
||||
if (localStream) {
|
||||
localStream.getTracks()[0].stop();
|
||||
localStream = null;
|
||||
}
|
||||
|
||||
document.getElementById('screenshare').style.display = "none";
|
||||
stopTokBoxPublisher();
|
||||
}
|
||||
|
||||
function gotStream(stream) {
|
||||
localStream = stream;
|
||||
startTokboxPublisher(localStream);
|
||||
|
||||
stream.onended = () => {
|
||||
if (desktopSharing) {
|
||||
toggle();
|
||||
}
|
||||
};
|
||||
}
|
||||
|
||||
|
||||
function onAccessApproved(desktop_id) {
|
||||
if (!desktop_id) {
|
||||
console.log('Desktop Capture access rejected.');
|
||||
return;
|
||||
}
|
||||
showSources();
|
||||
document.getElementById('screenshare').style.visibility = "block";
|
||||
desktopSharing = true;
|
||||
console.log("Desktop sharing started.. desktop_id:" + desktop_id);
|
||||
navigator.webkitGetUserMedia({
|
||||
audio: false,
|
||||
video: {
|
||||
mandatory: {
|
||||
chromeMediaSource: 'desktop',
|
||||
chromeMediaSourceId: desktop_id,
|
||||
minWidth: 1280,
|
||||
maxWidth: 1280,
|
||||
minHeight: 720,
|
||||
maxHeight: 720
|
||||
}
|
||||
}
|
||||
}, gotStream, handleError);
|
||||
}
|
||||
|
||||
// Tokbox
|
||||
|
||||
function initializeTokboxSession() {
|
||||
console.log("\n\n\n\n #$######\n TRYING TO START SESSION")
|
||||
session = OT.initSession(apiKey, sessionId);
|
||||
|
||||
session.on('sessionDisconnected', (event) => {
|
||||
console.log('You were disconnected from the session.', event.reason);
|
||||
});
|
||||
|
||||
// Connect to the session
|
||||
session.connect(token, (error) => {
|
||||
if (error) {
|
||||
handleError(error);
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
var publisher;
|
||||
function startTokboxPublisher(stream){
|
||||
publisher = document.createElement("div");
|
||||
console.log("publisher pushed")
|
||||
|
||||
var publisherOptions = {
|
||||
videoSource: stream.getVideoTracks()[0],
|
||||
audioSource: stream.getAudioTracks()[0],
|
||||
insertMode: 'append',
|
||||
width: 1280,
|
||||
height: 720
|
||||
};
|
||||
|
||||
publisher = OT.initPublisher(publisher, publisherOptions, function(error){
|
||||
if (error) {
|
||||
console.log("ERROR: " + error);
|
||||
} else {
|
||||
session.publish(publisher, function(error) {
|
||||
if (error) {
|
||||
console.log("ERROR FROM Session.publish: " + error);
|
||||
return;
|
||||
}
|
||||
console.log("MADE IT TO PUBLISH")
|
||||
})
|
||||
}
|
||||
});
|
||||
}
|
||||
|
||||
|
||||
function stopTokBoxPublisher(){
|
||||
console.log("TOK BOX STOPPED!")
|
||||
publisher.destroy();
|
||||
}
|
||||
|
||||
|
||||
// main TODO:
|
||||
// const {ipcRenderer} = ipcRenderer;
|
||||
// let apiKey;
|
||||
// let sessionId;
|
||||
// let token;
|
||||
// let session;
|
||||
// ipcRenderer.on('connectionInfo', function(event, message){
|
||||
// console.log("event", event);
|
||||
// console.log("MESSAGE FROM MAIN", message);
|
||||
// const connectionInfo = JSON.parse(message);
|
||||
// apiKey = connectionInfo.apiKey;
|
||||
// sessionId = connectionInfo.sessionId;
|
||||
// token = connectionInfo.token;
|
||||
// initializeTokboxSession();
|
||||
// })
|
||||
|
||||
function startup(){
|
||||
console.log("\n\n IN STARTUP \n\n")
|
||||
// Make an Ajax request to get the OpenTok API key, session ID, and token from the server
|
||||
// TODO:
|
||||
fetch(process.env.hifiScreenshareURL)
|
||||
.then(function(res) {
|
||||
return res.json();
|
||||
})
|
||||
.then(function fetchJson(json) {
|
||||
apiKey = json.apiKey;
|
||||
sessionId = json.sessionId;
|
||||
token = json.token;
|
||||
|
||||
initializeTokboxSession();
|
||||
})
|
||||
.catch(function catchErr(error) {
|
||||
handleError(error);
|
||||
alert('Failed to get opentok sessionId and token. Make sure you have updated the config.js file.');
|
||||
});
|
||||
}
|
||||
|
||||
document.addEventListener("DOMContentLoaded", () => {
|
||||
startup();
|
||||
showSources();
|
||||
})
|
55
screenshare/src/index.html
Normal file
55
screenshare/src/index.html
Normal file
|
@ -0,0 +1,55 @@
|
|||
<html>
|
||||
<head>
|
||||
<link href="styles.css" rel="stylesheet">
|
||||
</head>
|
||||
<body id="main">
|
||||
<div id="title" class="text_title">
|
||||
<h1>Share your screen</h1>
|
||||
<h3>Please select the content you'd like to share.</h3>
|
||||
</div>
|
||||
<button id="screenshare" onclick="stopSharing()" style="display: none;">Stop Screenshare</button>
|
||||
<div id="select_screen">
|
||||
<div class="scrollbar" id="style-1">
|
||||
<div class="force-overflow">
|
||||
|
||||
<div id="selects">
|
||||
|
||||
<!-- <div class="box"> -->
|
||||
<!-- <div class="heading"> -->
|
||||
<!-- <div class="circle"></div> -->
|
||||
<!-- <span class="screen_label">Screen 1</span> -->
|
||||
<!-- </div> heading -->
|
||||
<!-- <div class="image"> -->
|
||||
<!-- </div> -->
|
||||
<!-- </div> box -->
|
||||
|
||||
</div>
|
||||
|
||||
</div>
|
||||
</div>
|
||||
</div>
|
||||
<div id="confirmation_screen" style="display: none;">
|
||||
<div id="share_pick">
|
||||
|
||||
</div> <!-- share_pick -->
|
||||
<div id="confirmation_text" style="color: white;">
|
||||
<p>
|
||||
Are you sure you'd like to share <span id="content_name">Content Name</span>?
|
||||
</p>
|
||||
<p>
|
||||
Others will be able to everything contained within this view.
|
||||
</p>
|
||||
</div>
|
||||
<div id="button_selection" >
|
||||
<div id="yes" class="button_confirmation" style="color: #ffffff" onClick="screenConfirmed(true)">
|
||||
Yes, share this content
|
||||
</div>
|
||||
<div id="no" class="button_confirmation" style="color: #009ee0" onClick="screenConfirmed(false)">
|
||||
No, don't share this content
|
||||
</div>
|
||||
</div> <!-- button_selection -->
|
||||
</div> <!-- confirmation screen -->
|
||||
<script src="app.js"></script>
|
||||
<script src="https://static.opentok.com/v2/js/opentok.min.js"></script>
|
||||
</body>
|
||||
</html>
|
57
screenshare/src/main.js
Normal file
57
screenshare/src/main.js
Normal file
|
@ -0,0 +1,57 @@
|
|||
'use strict';
|
||||
|
||||
var userName, displayName, token, apiKey, sessionID;
|
||||
|
||||
const {app, BrowserWindow, ipcMain} = require('electron');
|
||||
const gotTheLock = app.requestSingleInstanceLock()
|
||||
const argv = require('yargs').argv;
|
||||
// ./screenshare.exe --userName=miladN ...
|
||||
|
||||
const connectionInfo = {
|
||||
userName: argv.userName || "testName",
|
||||
displayName: argv.displayName || "displayName",
|
||||
token: argv.token || "token",
|
||||
apiKey: argv.apiKey || "apiKey",
|
||||
sessionID: argv.sessionID || "sessionID"
|
||||
}
|
||||
|
||||
if (!gotTheLock) {
|
||||
// log.warn("Another instance of the screenshare is already running - this instance will quit.");
|
||||
app.exit(0);
|
||||
return;
|
||||
}
|
||||
|
||||
var window;
|
||||
function createWindow(){
|
||||
const zoomFactor = 1.0;
|
||||
window = new BrowserWindow({
|
||||
backgroundColor: "#000000",
|
||||
width: 1280 * zoomFactor,
|
||||
height: 720 * zoomFactor,
|
||||
center: true,
|
||||
frame: true,
|
||||
useContentSize: true,
|
||||
zoomFactor: zoomFactor,
|
||||
resizable: false,
|
||||
alwaysOnTop: true, // TRY
|
||||
webPreferences: {
|
||||
nodeIntegration: true
|
||||
},
|
||||
devTools: true
|
||||
});
|
||||
window.loadURL('file://' + __dirname + '/index.html');
|
||||
window.setMenu(null);
|
||||
|
||||
window.once('ready-to-show', () => {
|
||||
window.show();
|
||||
window.webContents.openDevTools()
|
||||
})
|
||||
}
|
||||
|
||||
// This method will be called when Electron has finished
|
||||
// initialization and is ready to create browser windows.
|
||||
app.on('ready', function() {
|
||||
createWindow();
|
||||
console.log("sending info");
|
||||
window.webContents.send('connectionInfo', JSON.stringify(connectionInfo))
|
||||
});
|
BIN
screenshare/src/resources/Graphik-Medium.ttf
Normal file
BIN
screenshare/src/resources/Graphik-Medium.ttf
Normal file
Binary file not shown.
BIN
screenshare/src/resources/Graphik-Regular.ttf
Normal file
BIN
screenshare/src/resources/Graphik-Regular.ttf
Normal file
Binary file not shown.
BIN
screenshare/src/resources/Graphik-Semibold.ttf
Normal file
BIN
screenshare/src/resources/Graphik-Semibold.ttf
Normal file
Binary file not shown.
BIN
screenshare/src/resources/Graphikbold.ttf
Normal file
BIN
screenshare/src/resources/Graphikbold.ttf
Normal file
Binary file not shown.
BIN
screenshare/src/resources/test.jpg
Normal file
BIN
screenshare/src/resources/test.jpg
Normal file
Binary file not shown.
After Width: | Height: | Size: 58 KiB |
180
screenshare/src/styles.css
Normal file
180
screenshare/src/styles.css
Normal file
|
@ -0,0 +1,180 @@
|
|||
body {
|
||||
background: black;
|
||||
box-sizing: 0px;
|
||||
/* display: -webkit-flex; */
|
||||
/* -webkit-justify-content: center; */
|
||||
/* -webkit-align-items: center; */
|
||||
/* -webkit-flex-direction: column; */
|
||||
font-family: "Graphik";
|
||||
margin: 0px;
|
||||
}
|
||||
|
||||
|
||||
.text_title {
|
||||
color: white;
|
||||
}
|
||||
|
||||
@font-face {
|
||||
font-family: "Graphik";
|
||||
src: url("./resources/Graphik-Regular.ttf");
|
||||
}
|
||||
|
||||
#title {
|
||||
margin-left: 21px;
|
||||
margin-top: 21px;
|
||||
}
|
||||
|
||||
#selects {
|
||||
margin-left: 21px;
|
||||
margin-top: 70px;
|
||||
}
|
||||
|
||||
h1 {
|
||||
line-height: 48px;
|
||||
font-size: 48px;
|
||||
margin: 0px 0px 0px 0px;
|
||||
}
|
||||
|
||||
h3 {
|
||||
line-height: 24px;
|
||||
font-size: 24px;
|
||||
margin: 9px 0px 0px 0px;
|
||||
}
|
||||
|
||||
#publisher {
|
||||
visibility: hidden;
|
||||
width: 0px;
|
||||
height: 0px;
|
||||
bottom: 10px;
|
||||
left: 10px;
|
||||
z-index: 100;
|
||||
border: 3px solid white;
|
||||
border-radius: 3px;
|
||||
}
|
||||
|
||||
.screen_label {
|
||||
max-width: 220px;
|
||||
font-size: 18px;
|
||||
line-height: 24px;
|
||||
margin-left: 15px;
|
||||
color: white;
|
||||
white-space: nowrap;
|
||||
overflow: hidden;
|
||||
text-overflow: ellipsis;
|
||||
}
|
||||
|
||||
.circle {
|
||||
display: inline-block;
|
||||
background: #C4C4C4;
|
||||
width: 30px;
|
||||
height: 30px;
|
||||
border-radius: 50%;
|
||||
}
|
||||
|
||||
.circle:hover{
|
||||
background-color: yellow;
|
||||
cursor: pointer;
|
||||
}
|
||||
|
||||
.button_confirmation {
|
||||
margin: 4px;
|
||||
cursor: pointer;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.button_confirmation:hover {
|
||||
border: 2px solid white;
|
||||
width: 250px;
|
||||
}
|
||||
|
||||
.box {
|
||||
background-color: orange;
|
||||
height: 165px;
|
||||
width: 265px;
|
||||
display: inline-block;
|
||||
margin-left: 20px;
|
||||
margin-bottom: 40px;
|
||||
margin-top: 20px;
|
||||
}
|
||||
|
||||
.heading {
|
||||
background-color: red;
|
||||
height: 35px;
|
||||
display: flex;
|
||||
align-items: center;
|
||||
}
|
||||
|
||||
.image {
|
||||
background-color: blue;
|
||||
width: 265px;
|
||||
height: 165px;
|
||||
max-height: 165px;
|
||||
max-width: 265px;
|
||||
}
|
||||
|
||||
img {
|
||||
width: 265px;
|
||||
height: 165px;
|
||||
}
|
||||
|
||||
.scrollbar {
|
||||
/* background-color: #F5F5F5; */
|
||||
float: right;
|
||||
height: 100%;
|
||||
/* margin-bottom: 25px; */
|
||||
/* margin-left: 22px; */
|
||||
/* margin-top: 40px; */
|
||||
margin-right: 20px;
|
||||
width: 100%;
|
||||
overflow-y: scroll;
|
||||
}
|
||||
|
||||
#style-1::-webkit-scrollbar {
|
||||
width: 15px;
|
||||
background-color: red;
|
||||
}
|
||||
|
||||
#style-1::-webkit-scrollbar-thumb {
|
||||
background-color: #0198CB;
|
||||
|
||||
}
|
||||
|
||||
#style-1::-webkit-scrollbar-track {
|
||||
-webkit-box-shadow: inset 0 0 6px rgba(0,0,0,0.3);
|
||||
background-color: #848484;
|
||||
margin-right: 22px;
|
||||
}
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
|
||||
/*
|
||||
button {
|
||||
display: inline-block;
|
||||
background: -webkit-linear-gradient(#F9F9F9 40%, #E3E3E3 70%);
|
||||
background: linear-gradient(#F9F9F9 40%, #E3E3E3 70%);
|
||||
border: 1px solid #999;
|
||||
-webkit-border-radius: 3px;
|
||||
border-radius: 3px;
|
||||
padding: 5px 8px;
|
||||
outline: none;
|
||||
white-space: nowrap;
|
||||
-webkit-user-select: none;
|
||||
user-select: none;
|
||||
cursor: pointer;
|
||||
text-shadow: 1px 1px #fff;
|
||||
font-weight: 700;
|
||||
font-size: 10pt;
|
||||
}
|
||||
|
||||
button:hover,
|
||||
button.active {
|
||||
border-color: black;
|
||||
}
|
||||
button:active,
|
||||
button.active {
|
||||
background: -webkit-linear-gradient(#E3E3E3 40%, #F9F9F9 70%);
|
||||
background: linear-gradient(#E3E3E3 40%, #F9F9F9 70%);
|
||||
} */
|
Loading…
Reference in a new issue