Merge branch 'master' into mkt-use-apm-with-npm3-and-node-4

This commit is contained in:
Antonio Scandurra
2016-07-21 12:34:21 +02:00
7 changed files with 95 additions and 85 deletions

View File

@@ -18,6 +18,10 @@ module.exports =
Disposable: Disposable
CompositeDisposable: CompositeDisposable
# Shell integration is required by both Squirrel and Settings-View
if process.platform is 'win32'
module.exports.WinShell = require '../src/main-process/win-shell'
# The following classes can't be used from a Task handler and should therefore
# only be exported when not running as a child node process
unless process.env.ATOM_SHELL_INTERNAL_RUN_AS_NODE

View File

@@ -60,6 +60,7 @@
"text-buffer": "9.2.2",
"typescript-simple": "1.0.0",
"underscore-plus": "^1.6.6",
"winreg": "^1.2.1",
"yargs": "^3.23.0"
},
"packageDependencies": {
@@ -113,12 +114,12 @@
"status-bar": "1.4.0",
"styleguide": "0.47.0",
"symbols-view": "0.113.0",
"tabs": "0.99.0",
"timecop": "0.33.1",
"tabs": "0.100.0",
"timecop": "0.33.2",
"tree-view": "0.208.1",
"update-package-dependencies": "0.10.0",
"welcome": "0.34.0",
"whitespace": "0.32.2",
"whitespace": "0.33.0",
"wrap-guide": "0.38.1",
"language-c": "0.52.1",
"language-clojure": "0.21.0",

View File

@@ -5,7 +5,7 @@ temp = require 'temp'
SquirrelUpdate = require '../src/main-process/squirrel-update'
Spawner = require '../src/main-process/spawner'
WinPowerShell = require '../src/main-process/win-powershell'
WinRegistry = require '../src/main-process/win-registry'
WinShell = require '../src/main-process/win-shell'
# Run passed callback as Spawner.spawn() would do
invokeCallback = (callback) ->
@@ -26,12 +26,16 @@ describe "Windows Squirrel Update", ->
# do nothing on command, just run passed callback
invokeCallback callback
# Prevent any actual change to Windows registry
for own method of WinRegistry
# all WinRegistry APIs share the same signature
spyOn(WinRegistry, method).andCallFake (callback) ->
# do nothing on registry, just run passed callback
invokeCallback callback
# Prevent any actual change to Windows Shell
class FakeShellOption
isRegistered: (callback) -> callback true
register: (callback) -> callback null
deregister: (callback) -> callback null, true
update: (callback) -> callback null
WinShell.fileHandler = new FakeShellOption()
WinShell.fileContextMenu = new FakeShellOption()
WinShell.folderContextMenu = new FakeShellOption()
WinShell.folderBackgroundContextMenu = new FakeShellOption()
it "quits the app on all squirrel events", ->
app = quit: jasmine.createSpy('quit')

View File

@@ -1,8 +1,4 @@
module.exports = (extra) ->
# Breakpad on Mac OS X must be running on UI and non-UI processes
# Crashpad on Windows and Linux should only be running on non-UI process
return if process.type is 'renderer' and process.platform isnt 'darwin'
{crashReporter} = require 'electron'
crashReporter.start({

View File

@@ -1,7 +1,7 @@
fs = require 'fs-plus'
path = require 'path'
Spawner = require './spawner'
WinRegistry = require './win-registry'
WinShell = require './win-shell'
WinPowerShell = require './win-powershell'
appFolder = path.resolve(process.execPath, '..')
@@ -125,26 +125,36 @@ exports.restartAtom = (app) ->
app.once 'will-quit', -> Spawner.spawn(path.join(binFolder, 'atom.cmd'), args)
app.quit()
updateContextMenus = (callback) ->
WinShell.fileContextMenu.update ->
WinShell.folderContextMenu.update ->
WinShell.folderBackgroundContextMenu.update ->
callback()
# Handle squirrel events denoted by --squirrel-* command line arguments.
exports.handleStartupEvent = (app, squirrelCommand) ->
switch squirrelCommand
when '--squirrel-install'
createShortcuts ->
WinRegistry.installContextMenu ->
addCommandsToPath ->
app.quit()
addCommandsToPath ->
WinShell.fileHandler.register ->
updateContextMenus ->
app.quit()
true
when '--squirrel-updated'
updateShortcuts ->
WinRegistry.installContextMenu ->
addCommandsToPath ->
addCommandsToPath ->
updateContextMenus ->
app.quit()
true
when '--squirrel-uninstall'
removeShortcuts ->
WinRegistry.uninstallContextMenu ->
removeCommandsFromPath ->
app.quit()
removeCommandsFromPath ->
WinShell.fileHandler.deregister ->
WinShell.fileContextMenu.deregister ->
WinShell.folderContextMenu.deregister ->
WinShell.folderBackgroundContextMenu.deregister ->
app.quit()
true
when '--squirrel-obsolete'
app.quit()

View File

@@ -1,62 +0,0 @@
path = require 'path'
Spawner = require './spawner'
if process.env.SystemRoot
system32Path = path.join(process.env.SystemRoot, 'System32')
regPath = path.join(system32Path, 'reg.exe')
else
regPath = 'reg.exe'
# Registry keys used for context menu
fileKeyPath = 'HKCU\\Software\\Classes\\*\\shell\\Atom'
directoryKeyPath = 'HKCU\\Software\\Classes\\directory\\shell\\Atom'
backgroundKeyPath = 'HKCU\\Software\\Classes\\directory\\background\\shell\\Atom'
applicationsKeyPath = 'HKCU\\Software\\Classes\\Applications\\atom.exe'
# Spawn reg.exe and callback when it completes
spawnReg = (args, callback) ->
Spawner.spawn(regPath, args, callback)
# Install the Open with Atom explorer context menu items via the registry.
#
# * `callback` The {Function} to call after registry operation is done.
# It will be invoked with the same arguments provided by {Spawner.spawn}.
#
# Returns `undefined`.
exports.installContextMenu = (callback) ->
addToRegistry = (args, callback) ->
args.unshift('add')
args.push('/f')
spawnReg(args, callback)
installFileHandler = (callback) ->
args = ["#{applicationsKeyPath}\\shell\\open\\command", '/ve', '/d', "\"#{process.execPath}\" \"%1\""]
addToRegistry(args, callback)
installMenu = (keyPath, arg, callback) ->
args = [keyPath, '/ve', '/d', 'Open with Atom']
addToRegistry args, ->
args = [keyPath, '/v', 'Icon', '/d', "\"#{process.execPath}\""]
addToRegistry args, ->
args = ["#{keyPath}\\command", '/ve', '/d', "\"#{process.execPath}\" \"#{arg}\""]
addToRegistry(args, callback)
installMenu fileKeyPath, '%1', ->
installMenu directoryKeyPath, '%1', ->
installMenu backgroundKeyPath, '%V', ->
installFileHandler(callback)
# Uninstall the Open with Atom explorer context menu items via the registry.
#
# * `callback` The {Function} to call after registry operation is done.
# It will be invoked with the same arguments provided by {Spawner.spawn}.
#
# Returns `undefined`.
exports.uninstallContextMenu = (callback) ->
deleteFromRegistry = (keyPath, callback) ->
spawnReg(['delete', keyPath, '/f'], callback)
deleteFromRegistry fileKeyPath, ->
deleteFromRegistry directoryKeyPath, ->
deleteFromRegistry backgroundKeyPath, ->
deleteFromRegistry(applicationsKeyPath, callback)

View File

@@ -0,0 +1,57 @@
Registry = require 'winreg'
Path = require 'path'
exeName = Path.basename(process.execPath)
appPath = "\"#{process.execPath}\""
appName = exeName.replace('atom', 'Atom').replace('beta', 'Beta').replace('.exe', '')
class ShellOption
constructor: (key, parts) ->
@key = key
@parts = parts
isRegistered: (callback) =>
new Registry({hive: 'HKCU', key: "#{@key}\\#{@parts[0].key}"})
.get @parts[0].name, (err, val) =>
callback(not err? and val.value is @parts[0].value)
register: (callback) =>
doneCount = @parts.length
for part in @parts
reg = new Registry({hive: 'HKCU', key: if part.key? then "#{@key}\\#{part.key}" else @key})
reg.create( -> reg.set part.name, Registry.REG_SZ, part.value, -> callback() if --doneCount is 0)
deregister: (callback) =>
@isRegistered (isRegistered) =>
if isRegistered
new Registry({hive: 'HKCU', key: @key}).destroy -> callback null, true
else
callback null, false
update: (callback) =>
new Registry({hive: 'HKCU', key: "#{@key}\\#{@parts[0].key}"})
.get @parts[0].name, (err, val) =>
if err? or not val.value.includes '\\' + exeName
callback(err)
else
@register callback
exports.appName = appName
exports.fileHandler = new ShellOption("\\Software\\Classes\\Applications\\#{exeName}",
[{key: 'shell\\open\\command', name: '', value: "#{appPath} \"%1\""}]
)
contextParts = [
{key: 'command', name: '', value: "#{appPath} \"%1\""},
{name: '', value: "Open with #{appName}"},
{name: 'Icon', value: "#{appPath}"}
]
exports.fileContextMenu = new ShellOption("\\Software\\Classes\\*\\shell\\#{appName}", contextParts)
exports.folderContextMenu = new ShellOption("\\Software\\Classes\\Directory\\shell\\#{appName}", contextParts)
exports.folderBackgroundContextMenu = new ShellOption("\\Software\\Classes\\Directory\\background\\shell\\#{appName}",
JSON.parse(JSON.stringify(contextParts).replace('%1', '%V'))
)