@ -3,6 +3,7 @@
/ *
Copyright 2016 Aviral Dasgupta
Copyright 2016 OpenMarket Ltd
Copyright 2018 New Vector Ltd
Licensed under the Apache License , Version 2.0 ( the "License" ) ;
you may not use this file except in compliance with the License .
@ -21,44 +22,24 @@ import VectorBasePlatform, {updateCheckStatusEnum} from './VectorBasePlatform';
import dis from 'matrix-react-sdk/lib/dispatcher' ;
import { _t } from 'matrix-react-sdk/lib/languageHandler' ;
import Promise from 'bluebird' ;
import { remote , ipcRenderer , desktopCapturer } from 'electron' ;
import rageshake from 'matrix-react-sdk/lib/rageshake/rageshake' ;
remote . autoUpdater . on ( 'update-downloaded' , onUpdateDownloaded ) ;
// try to flush the rageshake logs to indexeddb before quit.
ipcRenderer . on ( 'before-quit' , function ( ) {
console . log ( 'riot-desktop closing' ) ;
rageshake . flush ( ) ;
} ) ;
function onUpdateDownloaded ( ev : Event , releaseNotes : string , ver : string , date : Date , updateURL : string ) {
dis . dispatch ( {
action : 'new_version' ,
currentVersion : remote . app . getVersion ( ) ,
newVersion : ver ,
releaseNotes : releaseNotes ,
} ) ;
}
function platformFriendlyName ( ) : string {
console . log ( window . process ) ;
switch ( window . process . platform ) {
case 'darwin' :
return 'macOS' ;
case 'freebsd' :
return 'FreeBSD' ;
case 'openbsd' :
return 'OpenBSD' ;
case 'sunos' :
return 'SunOS' ;
case 'win32' :
return 'Windows' ;
default :
// Sorry, Linux users: you get lumped into here,
// but only because Linux's capitalisation is
// normal. We do care about you.
return window . process . platform [ 0 ] . toUpperCase ( ) + window . process . platform . slice ( 1 ) ;
// used to use window.process but the same info is available here
if ( navigator . userAgent . indexOf ( 'Macintosh' ) ) {
return 'macOS' ;
} else if ( navigator . userAgent . indexOf ( 'FreeBSD' ) ) {
return 'FreeBSD' ;
} else if ( navigator . userAgent . indexOf ( 'OpenBSD' ) ) {
return 'OpenBSD' ;
} else if ( navigator . userAgent . indexOf ( 'SunOS' ) ) {
return 'SunOS' ;
} else if ( navigator . userAgent . indexOf ( 'Windows' ) ) {
return 'Windows' ;
} else if ( navigator . userAgent . indexOf ( 'Linux' ) ) {
return 'Linux' ;
} else {
return 'Unknown' ;
}
}
@ -85,9 +66,11 @@ function getUpdateCheckStatus(status) {
export default class ElectronPlatform extends VectorBasePlatform {
constructor ( ) {
super ( ) ;
dis . register ( _onAction ) ;
this . updatable = Boolean ( remote . autoUpdater . getFeedURL ( ) ) ;
this . _pendingIpcCalls = { } ;
this . _nextIpcCallId = 0 ;
dis . register ( _onAction ) ;
/ *
IPC Call ` check_updates ` returns :
true if there is an update available
@ -103,10 +86,28 @@ export default class ElectronPlatform extends VectorBasePlatform {
this . showUpdateCheck = false ;
} ) ;
// try to flush the rageshake logs to indexeddb before quit.
ipcRenderer . on ( 'before-quit' , function ( ) {
console . log ( 'riot-desktop closing' ) ;
rageshake . flush ( ) ;
} ) ;
ipcRenderer . on ( 'ipcReply' , this . _onIpcReply . bind ( this ) ) ;
ipcRenderer . on ( 'update-downloaded' , this . onUpdateDownloaded . bind ( this ) ) ;
this . startUpdateCheck = this . startUpdateCheck . bind ( this ) ;
this . stopUpdateCheck = this . stopUpdateCheck . bind ( this ) ;
}
async onUpdateDownloaded ( ev , updateInfo ) {
dis . dispatch ( {
action : 'new_version' ,
currentVersion : await this . getAppVersion ( ) ,
newVersion : updateInfo ,
releaseNotes : updateInfo . releaseNotes ,
} ) ;
}
getHumanReadableName ( ) : string {
return 'Electron Platform' ; // no translation required: only used for analytics
}
@ -133,7 +134,7 @@ export default class ElectronPlatform extends VectorBasePlatform {
// maybe we should pass basic styling (italics, bold, underline) through from MD
// we only have to strip out < and > as the spec doesn't include anything about things like &
// so we shouldn't assume that all implementations will treat those properly. Very basic tag parsing is done.
if ( window . process . platform === 'linux' ) {
if ( navigator . userAgent . indexOf ( 'Linux' ) ) {
msg = msg . replace ( /</g , '<' ) . replace ( />/g , '>' ) ;
}
@ -147,17 +148,13 @@ export default class ElectronPlatform extends VectorBasePlatform {
} ,
) ;
notification . onclick = function ( ) {
notification . onclick = ( ) => {
dis . dispatch ( {
action : 'view_room' ,
room _id : room . roomId ,
} ) ;
global . focus ( ) ;
const win = remote . getCurrentWindow ( ) ;
if ( win . isMinimized ( ) ) win . restore ( ) ;
else if ( ! win . isVisible ( ) ) win . show ( ) ;
else win . focus ( ) ;
this . _ipcCall ( 'focusWindow' ) ;
} ;
return notification ;
@ -171,8 +168,25 @@ export default class ElectronPlatform extends VectorBasePlatform {
notif . close ( ) ;
}
getAppVersion ( ) : Promise < string > {
return Promise . resolve ( remote . app . getVersion ( ) ) ;
async getAppVersion ( ) : Promise < string > {
return await this . _ipcCall ( 'getAppVersion' ) ;
}
supportsAutoLaunch ( ) {
return true ;
}
async getAutoLaunchEnabled ( ) {
return await this . _ipcCall ( 'getAutoLaunchEnabled' ) ;
}
async setAutoLaunchEnabled ( enabled ) {
return await this . _ipcCall ( 'setAutoLaunchEnabled' , enabled ) ;
}
async canSelfUpdate ( ) : boolean {
const feedUrl = await this . _ipcCall ( 'getUpdateFeedUrl' ) ;
return Boolean ( feedUrl ) ;
}
startUpdateCheck ( ) {
@ -197,52 +211,43 @@ export default class ElectronPlatform extends VectorBasePlatform {
return null ;
}
isElectron ( ) : boolean { return true ; }
requestNotificationPermission ( ) : Promise < string > {
return Promise . resolve ( 'granted' ) ;
}
reload ( ) {
remote . getCurrentWebContents ( ) . reload ( ) ;
}
/ * B E G I N c o p i e d a n d s l i g h t l y - m o d i f i e d c o d e
* setupScreenSharingForIframe function from :
* https : //github.com/jitsi/jitsi-meet-electron-utils
* Copied directly here to avoid the need for a native electron module for
* 'just a bit of JavaScript'
* NOTE : Apache v2 . 0 licensed
* /
setupScreenSharingForIframe ( iframe : Object ) {
iframe . contentWindow . JitsiMeetElectron = {
/ * *
* Get sources available for screensharing . The callback is invoked
* with an array of DesktopCapturerSources .
*
* @ param { Function } callback - The success callback .
* @ param { Function } errorCallback - The callback for errors .
* @ param { Object } options - Configuration for getting sources .
* @ param { Array } options . types - Specify the desktop source types
* to get , with valid sources being "window" and "screen" .
* @ param { Object } options . thumbnailSize - Specify how big the
* preview images for the sources should be . The valid keys are
* height and width , e . g . { height : number , width : number } . By
* default electron will return images with height and width of
* 150 px .
* /
obtainDesktopStreams ( callback , errorCallback , options = { } ) {
desktopCapturer . getSources ( options ,
( error , sources ) => {
if ( error ) {
errorCallback ( error ) ;
return ;
}
callback ( sources ) ;
} ) ;
} ,
} ;
// we used to remote to the main process to get it to
// reload the webcontents, but in practice this is unnecessary:
// the normal way works fine.
window . location . reload ( false ) ;
}
async _ipcCall ( name , ... args ) {
const ipcCallId = ++ this . _nextIpcCallId ;
return new Promise ( ( resolve , reject ) => {
this . _pendingIpcCalls [ ipcCallId ] = { resolve , reject } ;
window . ipcRenderer . send ( 'ipcCall' , { id : ipcCallId , name , args } ) ;
// Maybe add a timeout to these? Probably not necessary.
} ) ;
}
_onIpcReply ( ev , payload ) {
if ( payload . id === undefined ) {
console . warn ( "Ignoring IPC reply with no ID" ) ;
return ;
}
if ( this . _pendingIpcCalls [ payload . id ] === undefined ) {
console . warn ( "Unknown IPC payload ID: " + payload . id ) ;
return ;
}
const callbacks = this . _pendingIpcCalls [ payload . id ] ;
delete this . _pendingIpcCalls [ payload . id ] ;
if ( payload . error ) {
callbacks . reject ( payload . error ) ;
} else {
callbacks . resolve ( payload . reply ) ;
}
}
/* END of copied and slightly-modified code */
}