<commit_before>import { BrowserWindow, ipcMain, app } from 'electron'
import { Emitter, Disposable } from 'event-kit'
import { logInfo, logError } from '../lib/logging/main'
import { ICrashDetails, ErrorType } from '../crash/shared'
import { registerWindowStateChangedEvents } from '../lib/window-state'

const minWidth = 600
const minHeight = 500

export class CrashWindow {
  private readonly window: Electron.BrowserWindow
  private readonly emitter = new Emitter()
  private readonly errorType: ErrorType
  private readonly error: Error

  private _loadTime: number | null = null
  private _rendererReadyTime: number | null = null

  public constructor(errorType: ErrorType, error: Error) {
    const windowOptions: Electron.BrowserWindowOptions = {
      width: minWidth,
      height: minHeight,
      minWidth: minWidth,
      minHeight: minHeight,
      show: false,
      // This fixes subpixel aliasing on Windows
      // See https://github.com/atom/atom/commit/683bef5b9d133cb194b476938c77cc07fd05b972
      backgroundColor: '#fff',
      webPreferences: {
        // Disable auxclick event
        // See https://developers.google.com/web/updates/2016/10/auxclick
        disableBlinkFeatures: 'Auxclick',
        // Enable, among other things, the ResizeObserver
        experimentalFeatures: true,
      },
    }

    if (__DARWIN__) {
        windowOptions.titleBarStyle = 'hidden'
    } else if (__WIN32__) {
        windowOptions.frame = false
    }

    this.window = new BrowserWindow(windowOptions)
    this.error = error
    this.errorType = errorType
  }

  public load() {
    logInfo('Starting crash process')
    let startLoad = 0
    // We only listen for the first of the loading events to avoid a bug in
    // Electron/Chromium where they can sometimes fire more than once. See
    // See
    // https://github.com/desktop/desktop/pull/513#issuecomment-253028277. This
    // shouldn't really matter as in production builds loading _should_ only
    // happen once.
    this.window.webContents.once('did-start-loading', () => {
      logInfo('Crash process in startup')
      this._rendererReadyTime = null
      this._loadTime = null

      startLoad = Date.now()
    })

    this.window.webContents.once('did-finish-load', () => {
      logInfo('Crash process started')
      if (process.env.NODE_ENV === 'development') {
        this.window.webContents.openDevTools()
      }

      const now = Date.now()
      this._loadTime = now - startLoad

      this.maybeEmitDidLoad()
    })

    this.window.webContents.on('did-finish-load', () => {
      this.window.webContents.setVisualZoomLevelLimits(1, 1)
    })

    this.window.webContents.on('did-fail-load', () => {
      logError('Crash process failed to load')
      if (__DEV__) {
        this.window.webContents.openDevTools()
        this.window.show()
      } else {
        this.emitter.emit('did-fail-load', null)
      }
    })

    ipcMain.on('crash-ready', (event: Electron.IpcMainEvent, readyTime: number) => {
      logInfo(`Crash process is ready after ${readyTime}ms`)
      this._rendererReadyTime = readyTime
      this.sendError()
      this.maybeEmitDidLoad()
    })

    ipcMain.on('crash-quit', (event: Electron.IpcMainEvent) => {
      if (!__DEV__) {
        app.relaunch()
      }

      app.quit()
    })

    registerWindowStateChangedEvents(this.window)

    this.window.loadURL(`file://${__dirname}/crash.html`)
  }

  /**
   * Emit the `onDidLoad` event if the page has loaded and the renderer has
   * signalled that it's ready.
   */
  private maybeEmitDidLoad() {
    if (!this.rendererLoaded) { return }

    this.emitter.emit('did-load', null)
  }

  /** Is the page loaded and has the renderer signalled it's ready? */
  private get rendererLoaded(): boolean {
    return this.loadTime !== null && this.rendererReadyTime !== null
  }

  public onClose(fn: () => void) {
    this.window.on('closed', fn)
  }

  public onFailedToLoad(fn: () => void) {
    this.emitter.on('did-fail-load', fn)
  }

  /**
   * Register a function to call when the window is done loading. At that point
   * the page has loaded and the renderer has signalled that it is ready.
   */
  public onDidLoad(fn: () => void): Disposable {
    return this.emitter.on('did-load', fn)
  }

  public focus() {
    this.window.focus()
  }

  /** Show the window. */
  public show() {
    logError('Showing crash process window')
    this.window.show()
  }

  /** Report the error to the renderer. */
  private sendError() {
    // `Error` can't be JSONified so it doesn't transport nicely over IPC. So
    // we'll just manually copy the properties we care about.
    const friendlyError = {
      stack: this.error.stack,
      message: this.error.message,
      name: this.error.name,
    }

    const details: ICrashDetails = {
      type: this.errorType,
      error: friendlyError,
    }

    this.window.webContents.send('error', details)
  }

  /** Report an auto updater error to the renderer. */
  public sendAutoUpdaterError(error: Error) {
    // `Error` can't be JSONified so it doesn't transport nicely over IPC. So
    // we'll just manually copy the properties we care about.<commit_msg>Logging tweaks<commit_after>import { BrowserWindow, ipcMain, app } from 'electron'
import { Emitter, Disposable } from 'event-kit'
import { logDebug, logInfo, logError } from '../lib/logging/main'
import { ICrashDetails, ErrorType } from '../crash/shared'
import { registerWindowStateChangedEvents } from '../lib/window-state'

const minWidth = 600
const minHeight = 500

export class CrashWindow {
  private readonly window: Electron.BrowserWindow
  private readonly emitter = new Emitter()
  private readonly errorType: ErrorType
  private readonly error: Error

  private _loadTime: number | null = null
  private _rendererReadyTime: number | null = null

  public constructor(errorType: ErrorType, error: Error) {
    const windowOptions: Electron.BrowserWindowOptions = {
      width: minWidth,
      height: minHeight,
      minWidth: minWidth,
      minHeight: minHeight,
      show: false,
      // This fixes subpixel aliasing on Windows
      // See https://github.com/atom/atom/commit/683bef5b9d133cb194b476938c77cc07fd05b972
      backgroundColor: '#fff',
      webPreferences: {
        // Disable auxclick event
        // See https://developers.google.com/web/updates/2016/10/auxclick
        disableBlinkFeatures: 'Auxclick',
        // Enable, among other things, the ResizeObserver
        experimentalFeatures: true,
      },
    }

    if (__DARWIN__) {
        windowOptions.titleBarStyle = 'hidden'
    } else if (__WIN32__) {
        windowOptions.frame = false
    }

    this.window = new BrowserWindow(windowOptions)
    this.error = error
    this.errorType = errorType
  }

  public load() {
    logDebug('Starting crash process')
    let startLoad = 0
    // We only listen for the first of the loading events to avoid a bug in
    // Electron/Chromium where they can sometimes fire more than once. See
    // See
    // https://github.com/desktop/desktop/pull/513#issuecomment-253028277. This
    // shouldn't really matter as in production builds loading _should_ only
    // happen once.
    this.window.webContents.once('did-start-loading', () => {
      logDebug('Crash process in startup')
      this._rendererReadyTime = null
      this._loadTime = null

      startLoad = Date.now()
    })

    this.window.webContents.once('did-finish-load', () => {
      logDebug('Crash process started')
      if (process.env.NODE_ENV === 'development') {
        this.window.webContents.openDevTools()
      }

      const now = Date.now()
      this._loadTime = now - startLoad

      this.maybeEmitDidLoad()
    })

    this.window.webContents.on('did-finish-load', () => {
      this.window.webContents.setVisualZoomLevelLimits(1, 1)
    })

    this.window.webContents.on('did-fail-load', () => {
      logError('Crash process failed to load')
      if (__DEV__) {
        this.window.webContents.openDevTools()
        this.window.show()
      } else {
        this.emitter.emit('did-fail-load', null)
      }
    })

    ipcMain.on('crash-ready', (event: Electron.IpcMainEvent, readyTime: number) => {
      logInfo(`Crash process is ready after ${readyTime}ms`)
      this._rendererReadyTime = readyTime
      this.sendError()
      this.maybeEmitDidLoad()
    })

    ipcMain.on('crash-quit', (event: Electron.IpcMainEvent) => {
      logDebug('Got quit signal from crash process')

      if (!__DEV__) {
        app.relaunch()
      }

      app.quit()
    })

    registerWindowStateChangedEvents(this.window)

    this.window.loadURL(`file://${__dirname}/crash.html`)
  }

  /**
   * Emit the `onDidLoad` event if the page has loaded and the renderer has
   * signalled that it's ready.
   */
  private maybeEmitDidLoad() {
    if (!this.rendererLoaded) { return }

    this.emitter.emit('did-load', null)
  }

  /** Is the page loaded and has the renderer signalled it's ready? */
  private get rendererLoaded(): boolean {
    return this.loadTime !== null && this.rendererReadyTime !== null
  }

  public onClose(fn: () => void) {
    this.window.on('closed', fn)
  }

  public onFailedToLoad(fn: () => void) {
    this.emitter.on('did-fail-load', fn)
  }

  /**
   * Register a function to call when the window is done loading. At that point
   * the page has loaded and the renderer has signalled that it is ready.
   */
  public onDidLoad(fn: () => void): Disposable {
    return this.emitter.on('did-load', fn)
  }

  public focus() {
    this.window.focus()
  }

  /** Show the window. */
  public show() {
    logInfo('Showing crash process window')
    this.window.show()
  }

  /** Report the error to the renderer. */
  private sendError() {
    // `Error` can't be JSONified so it doesn't transport nicely over IPC. So
    // we'll just manually copy the properties we care about.
    const friendlyError = {
      stack: this.error.stack,
      message: this.error.message,
      name: this.error.name,
    }

    const details: ICrashDetails = {
      type: this.errorType,
      error: friendlyError,
    }

    this.window.webContents.send('error', details)
  }

  /** Report an auto updater error to the renderer. */
  public sendAutoUpdaterError(error: Error) {
    // `Error` can't be JSONified so it doesn't transport nicely over IPC. So
    // we'll just manually copy the properties we care about.
{'fraction_non_alphanumeric': 0.11749497270899167, 'fraction_numerical': 0.010533371636502921, 'mean_word_length': 2.7895500725689404, 'pattern_counts': {'":': 0, '<': 3, '<?xml version=': 0, '>': 21, 'https://': 6, 'lorem ipsum': 0, 'www.': 0, 'xml': 0}, 'pii_count': 0, 'substrings_counts': 0, 'word_list_counts': {'cursed_substrings.json': 0, 'profanity_word_list.json': 0, 'sexual_word_list.json': 0, 'zh_pornsignals.json': 0}}
{'dir': 'git-commits-cleaned', 'id': '2959875', 'n_tokens_mistral': 3264, 'n_tokens_neox': 3091, 'n_words': 835}