Merge branch 'master' into as-ns-startup-snapshot

This commit is contained in:
Antonio Scandurra
2017-03-10 15:04:26 +01:00
9 changed files with 133 additions and 151 deletions

View File

@@ -1,5 +1,5 @@
_ = require 'underscore-plus'
{screen, ipcRenderer, remote, shell, webFrame} = require 'electron'
{ipcRenderer, remote, shell} = require 'electron'
ipcHelpers = require './ipc-helpers'
{Disposable} = require 'event-kit'
getWindowLoadSettings = require './get-window-load-settings'
@@ -80,6 +80,12 @@ class ApplicationDelegate
setWindowFullScreen: (fullScreen=false) ->
ipcHelpers.call('window-method', 'setFullScreen', fullScreen)
onDidEnterFullScreen: (callback) ->
ipcHelpers.on(ipcRenderer, 'did-enter-full-screen', callback)
onDidLeaveFullScreen: (callback) ->
ipcHelpers.on(ipcRenderer, 'did-leave-full-screen', callback)
openWindowDevTools: ->
# Defer DevTools interaction to the next tick, because using them during
# event handling causes some wrong input events to be triggered on
@@ -254,20 +260,6 @@ class ApplicationDelegate
openExternal: (url) ->
shell.openExternal(url)
disableZoom: ->
outerCallback = ->
webFrame.setZoomLevelLimits(1, 1)
outerCallback()
# Set the limits every time a display is added or removed, otherwise the
# configuration gets reset to the default, which allows zooming the
# webframe.
screen.on('display-added', outerCallback)
screen.on('display-removed', outerCallback)
new Disposable ->
screen.removeListener('display-added', outerCallback)
screen.removeListener('display-removed', outerCallback)
checkForUpdate: ->
ipcRenderer.send('command', 'application:check-for-update')

View File

@@ -215,8 +215,6 @@ class AtomEnvironment extends Model
@stylesElement = @styles.buildStylesElement()
@document.head.appendChild(@stylesElement)
@disposables.add(@applicationDelegate.disableZoom())
@keymaps.subscribeToFileReadFailure()
@keymaps.loadBundledKeymaps()
@@ -231,14 +229,12 @@ class AtomEnvironment extends Model
@observeAutoHideMenuBar()
@history = new HistoryManager({@project, @commands, localStorage})
@history = new HistoryManager({@project, @commands, @stateStore, localStorage: window.localStorage})
# Keep instances of HistoryManager in sync
@history.onDidChangeProjects (e) =>
@disposables.add @history.onDidChangeProjects (e) =>
@applicationDelegate.didChangeHistoryManager() unless e.reloaded
@disposables.add @applicationDelegate.onDidChangeHistoryManager(=> @history.loadState())
(new ReopenProjectMenuManager({@menu, @commands, @history, @config, open: (paths) => @open(pathsToOpen: paths)})).update()
attachSaveStateListeners: ->
saveState = _.debounce((=>
window.requestIdleCallback => @saveState({isUnloading: false}) unless @unloaded
@@ -716,7 +712,14 @@ class AtomEnvironment extends Model
@openInitialEmptyEditorIfNecessary()
Promise.all([loadStatePromise, updateProcessEnvPromise])
loadHistoryPromise = @history.loadState().then =>
@reopenProjectMenuManager = new ReopenProjectMenuManager({
@menu, @commands, @history, @config,
open: (paths) => @open(pathsToOpen: paths)
})
@reopenProjectMenuManager.update()
Promise.all([loadStatePromise, loadHistoryPromise, updateProcessEnvPromise])
serialize: (options) ->
version: @constructor.version

View File

@@ -4,7 +4,7 @@ let windowLoadSettings = null
module.exports = () => {
if (!windowLoadSettings) {
windowLoadSettings = remote.getCurrentWindow().loadSettings
windowLoadSettings = JSON.parse(remote.getCurrentWindow().loadSettingsJSON)
}
return windowLoadSettings
}

View File

@@ -1,6 +1,6 @@
/** @babel */
import {Emitter} from 'event-kit'
import {Emitter, CompositeDisposable} from 'event-kit'
// Extended: History manager for remembering which projects have been opened.
//
@@ -8,12 +8,18 @@ import {Emitter} from 'event-kit'
//
// The project history is used to enable the 'Reopen Project' menu.
export class HistoryManager {
constructor ({project, commands, localStorage}) {
constructor ({stateStore, localStorage, project, commands}) {
this.stateStore = stateStore
this.localStorage = localStorage
commands.add('atom-workspace', {'application:clear-project-history': this.clearProjects.bind(this)})
this.emitter = new Emitter()
this.loadState()
project.onDidChangePaths((projectPaths) => this.addProject(projectPaths))
this.projects = []
this.disposables = new CompositeDisposable()
this.disposables.add(commands.add('atom-workspace', {'application:clear-project-history': this.clearProjects.bind(this)}))
this.disposables.add(project.onDidChangePaths((projectPaths) => this.addProject(projectPaths)))
}
destroy () {
this.disposables.dispose()
}
// Public: Obtain a list of previously opened projects.
@@ -27,9 +33,12 @@ export class HistoryManager {
//
// Note: This is not a privacy function - other traces will still exist,
// e.g. window state.
clearProjects () {
//
// Return a {Promise} that resolves when the history has been successfully
// cleared.
async clearProjects () {
this.projects = []
this.saveState()
await this.saveState()
this.didChangeProjects()
}
@@ -46,7 +55,7 @@ export class HistoryManager {
this.emitter.emit('did-change-projects', args || { reloaded: false })
}
addProject (paths, lastOpened) {
async addProject (paths, lastOpened) {
if (paths.length === 0) return
let project = this.getProject(paths)
@@ -57,11 +66,11 @@ export class HistoryManager {
project.lastOpened = lastOpened || new Date()
this.projects.sort((a, b) => b.lastOpened - a.lastOpened)
this.saveState()
await this.saveState()
this.didChangeProjects()
}
removeProject (paths) {
async removeProject (paths) {
if (paths.length === 0) return
let project = this.getProject(paths)
@@ -70,7 +79,7 @@ export class HistoryManager {
let index = this.projects.indexOf(project)
this.projects.splice(index, 1)
this.saveState()
await this.saveState()
this.didChangeProjects()
}
@@ -84,31 +93,23 @@ export class HistoryManager {
return null
}
loadState () {
const state = JSON.parse(this.localStorage.getItem('history'))
if (state && state.projects) {
this.projects = state.projects.filter(p => Array.isArray(p.paths) && p.paths.length > 0).map(p => new HistoryProject(p.paths, new Date(p.lastOpened)))
this.didChangeProjects({ reloaded: true })
async loadState () {
let history = await this.stateStore.load('history-manager')
if (!history) {
history = JSON.parse(this.localStorage.getItem('history'))
}
if (history && history.projects) {
this.projects = history.projects.filter(p => Array.isArray(p.paths) && p.paths.length > 0).map(p => new HistoryProject(p.paths, new Date(p.lastOpened)))
this.didChangeProjects({reloaded: true})
} else {
this.projects = []
}
}
saveState () {
const state = JSON.stringify({
projects: this.projects.map(p => ({
paths: p.paths, lastOpened: p.lastOpened
}))
})
this.localStorage.setItem('history', state)
}
async importProjectHistory () {
for (let project of await HistoryImporter.getAllProjects()) {
this.addProject(project.paths, project.lastOpened)
}
this.saveState()
this.didChangeProjects()
async saveState () {
const projects = this.projects.map(p => ({paths: p.paths, lastOpened: p.lastOpened}))
await this.stateStore.save('history-manager', {projects})
}
}
@@ -132,32 +133,3 @@ export class HistoryProject {
set lastOpened (lastOpened) { this._lastOpened = lastOpened }
get lastOpened () { return this._lastOpened }
}
class HistoryImporter {
static async getStateStoreCursor () {
const db = await atom.stateStore.dbPromise
const store = db.transaction(['states']).objectStore('states')
return store.openCursor()
}
static async getAllProjects (stateStore) {
const request = await HistoryImporter.getStateStoreCursor()
return new Promise((resolve, reject) => {
const rows = []
request.onerror = reject
request.onsuccess = event => {
const cursor = event.target.result
if (cursor) {
let project = cursor.value.value.project
let storedAt = cursor.value.storedAt
if (project && project.paths && storedAt) {
rows.push(new HistoryProject(project.paths, new Date(Date.parse(storedAt))))
}
cursor.continue()
} else {
resolve(rows)
}
}
})
}
}

View File

@@ -6,8 +6,8 @@ StorageFolder = require '../storage-folder'
Config = require '../config'
FileRecoveryService = require './file-recovery-service'
ipcHelpers = require '../ipc-helpers'
{BrowserWindow, Menu, app, dialog, ipcMain, shell} = require 'electron'
{CompositeDisposable} = require 'event-kit'
{BrowserWindow, Menu, app, dialog, ipcMain, shell, screen} = require 'electron'
{CompositeDisposable, Disposable} = require 'event-kit'
fs = require 'fs-plus'
path = require 'path'
os = require 'os'
@@ -94,7 +94,7 @@ class AtomApplication
if process.platform is 'darwin' and @config.get('core.useCustomTitleBar')
@config.unset('core.useCustomTitleBar')
@config.set('core.titleBar', 'custom')
@config.onDidChange 'core.titleBar', @promptForRestart.bind(this)
process.nextTick => @autoUpdateManager.initialize()
@@ -397,6 +397,8 @@ class AtomApplication
@disposable.add ipcHelpers.on ipcMain, 'did-change-paths', =>
@saveState(false)
@disposable.add(@disableZoomOnDisplayChange())
setupDockMenu: ->
if process.platform is 'darwin'
dockMenu = Menu.buildFromTemplate [
@@ -815,3 +817,17 @@ class AtomApplication
args.push("--resource-path=#{@resourcePath}")
app.relaunch({args})
app.quit()
disableZoomOnDisplayChange: ->
outerCallback = =>
for window in @windows
window.disableZoom()
# Set the limits every time a display is added or removed, otherwise the
# configuration gets reset to the default, which allows zooming the
# webframe.
screen.on('display-added', outerCallback)
screen.on('display-removed', outerCallback)
new Disposable ->
screen.removeListener('display-added', outerCallback)
screen.removeListener('display-removed', outerCallback)

View File

@@ -83,12 +83,18 @@ class AtomWindow
@representedDirectoryPaths = loadSettings.initialPaths
@env = loadSettings.env if loadSettings.env?
@browserWindow.loadSettings = loadSettings
@browserWindow.loadSettingsJSON = JSON.stringify(loadSettings)
@browserWindow.on 'window:loaded', =>
@emit 'window:loaded'
@resolveLoadedPromise()
@browserWindow.on 'enter-full-screen', =>
@browserWindow.webContents.send('did-enter-full-screen')
@browserWindow.on 'leave-full-screen', =>
@browserWindow.webContents.send('did-leave-full-screen')
@browserWindow.loadURL url.format
protocol: 'file'
pathname: "#{@resourcePath}/static/index.html"
@@ -101,6 +107,7 @@ class AtomWindow
hasPathToOpen = not (locationsToOpen.length is 1 and not locationsToOpen[0].pathToOpen?)
@openLocations(locationsToOpen) if hasPathToOpen and not @isSpecWindow()
@disableZoom()
@atomApplication.addWindow(this)
@@ -303,3 +310,6 @@ class AtomWindow
@atomApplication.saveState()
copy: -> @browserWindow.copy()
disableZoom: ->
@browserWindow.webContents.setZoomLevelLimits(1, 1)

View File

@@ -58,7 +58,7 @@ export default class ReopenProjectMenuManager {
// Windows users can right-click Atom taskbar and remove project from the jump list.
// We have to honor that or the group stops working. As we only get a partial list
// each time we remove them from history entirely.
applyWindowsJumpListRemovals () {
async applyWindowsJumpListRemovals () {
if (process.platform !== 'win32') return
if (this.app === undefined) {
this.app = require('remote').app
@@ -68,7 +68,7 @@ export default class ReopenProjectMenuManager {
if (removed.length === 0) return
for (let project of this.historyManager.getProjects()) {
if (removed.includes(ReopenProjectMenuManager.taskDescription(project.paths))) {
this.historyManager.removeProject(project.paths)
await this.historyManager.removeProject(project.paths)
}
}
}

View File

@@ -20,14 +20,8 @@ class WindowEventHandler
@subscriptions.add listen(@document, 'click', 'a', @handleLinkClick)
@subscriptions.add listen(@document, 'submit', 'form', @handleFormSubmit)
browserWindow = @applicationDelegate.getCurrentWindow()
browserWindow.on 'enter-full-screen', @handleEnterFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('enter-full-screen', @handleEnterFullScreen)
browserWindow.on 'leave-full-screen', @handleLeaveFullScreen
@subscriptions.add new Disposable =>
browserWindow.removeListener('leave-full-screen', @handleLeaveFullScreen)
@subscriptions.add(@applicationDelegate.onDidEnterFullScreen(@handleEnterFullScreen))
@subscriptions.add(@applicationDelegate.onDidLeaveFullScreen(@handleLeaveFullScreen))
@subscriptions.add @atomEnvironment.commands.add @window,
'window:toggle-full-screen': @handleWindowToggleFullScreen