<commit_before>import path from 'path';

import {
  app,
  BrowserWindow,
  nativeImage,
  screen,
  Rectangle,
  NativeImage,
  WebPreferences,
} from 'electron';
import i18next from 'i18next';
import { createStructuredSelector } from 'reselect';

import { setupRootWindowReload } from '../../app/main/dev';
import { Server } from '../../servers/common';
import { select, watch, listen, dispatchLocal } from '../../store';
import { RootState } from '../../store/rootReducer';
import { ROOT_WINDOW_STATE_CHANGED, WEBVIEW_FOCUS_REQUESTED } from '../actions';
import { RootWindowIcon, WindowState } from '../common';
import { selectGlobalBadge, selectGlobalBadgeCount } from '../selectors';
import { debounce } from './debounce';
import { getTrayIconPath } from './icons';

const webPreferences: WebPreferences = {
  nodeIntegration: true,
  nodeIntegrationInSubFrames: true,
  contextIsolation: false,
  webviewTag: true,
  worldSafeExecuteJavaScript: true,
};

const selectRootWindowState = ({ rootWindowState }: RootState): WindowState =>
  rootWindowState ?? {
    bounds: {
      x: 0,
      y: 0,
      width: 0,
      height: 0,
    },
    focused: false,
    fullscreen: false,
    maximized: false,
    minimized: false,
    normal: false,
    visible: false,
  };

let _rootWindow: BrowserWindow;

export const getRootWindow = (): Promise<BrowserWindow> =>
  new Promise((resolve, reject) => {
    setImmediate(() => {
      _rootWindow ? resolve(_rootWindow) : reject(new Error());
    });
  });

export const createRootWindow = (): void => {
  _rootWindow = new BrowserWindow({
    width: 1000,
    height: 600,
    minWidth: 400,
    minHeight: 400,
    titleBarStyle: 'hidden',
    backgroundColor: '#2f343d',
    show: false,
    webPreferences,
  });

  _rootWindow.addListener('close', (event) => {
    event.preventDefault();
  });
};

const isInsideSomeScreen = ({ x, y, width, height }: Rectangle): boolean =>
  screen
    .getAllDisplays()
    .some(
      ({ bounds }) =>
        x >= bounds.x &&
        y >= bounds.y &&
        x + width <= bounds.x + bounds.width &&
        y + height <= bounds.y + bounds.height
    );

export const applyRootWindowState = (browserWindow: BrowserWindow): void => {
  const rootWindowState = select(selectRootWindowState);
  const isTrayIconEnabled = select(
    ({ isTrayIconEnabled }) => isTrayIconEnabled
  );

  let { x, y } = rootWindowState.bounds;
  const { width, height } = rootWindowState.bounds;
  if (
    x === null ||
    x === undefined ||
    y === null ||
    y === undefined ||
    !isInsideSomeScreen({ x, y, width, height })
  ) {
    const {
      bounds: { width: primaryDisplayWidth, height: primaryDisplayHeight },
    } = screen.getPrimaryDisplay();
    x = Math.round((primaryDisplayWidth - width) / 2);
    y = Math.round((primaryDisplayHeight - height) / 2);
  }

  if (browserWindow.isVisible()) {
    return;
  }

  if (x === null || x === undefined || y === null || y === undefined) {
    browserWindow.setBounds({ width, height });
  } else {
    browserWindow.setBounds({ x, y, width, height });
  }

  if (rootWindowState.maximized) {
    browserWindow.maximize();
  }

  if (rootWindowState.minimized) {
    browserWindow.minimize();
  }

  if (rootWindowState.fullscreen) {
    browserWindow.setFullScreen(true);
  }

  if (rootWindowState.visible || !isTrayIconEnabled) {
    browserWindow.show();
  }

  if (rootWindowState.focused) {
    browserWindow.focus();
  }
};

const fetchRootWindowState = async (): Promise<
  ReturnType<typeof selectRootWindowState>
> => {
  const browserWindow = await getRootWindow();
  return {
    focused: browserWindow.isFocused(),
    visible: browserWindow.isVisible(),
    maximized: browserWindow.isMaximized(),
    minimized: browserWindow.isMinimized(),
    fullscreen: browserWindow.isFullScreen(),
    normal: browserWindow.isNormal(),
    bounds: browserWindow.getNormalBounds(),
  };
};

export const setupRootWindow = (): void => {
  const unsubscribers = [
    watch(selectGlobalBadgeCount, async (globalBadgeCount) => {
      const browserWindow = await getRootWindow();

      if (browserWindow.isFocused() || globalBadgeCount === 0) {
        return;
      }

      const { isShowWindowOnUnreadChangedEnabled, isFlashFrameEnabled } =
        select(
          ({ isShowWindowOnUnreadChangedEnabled, isFlashFrameEnabled }) => ({
            isShowWindowOnUnreadChangedEnabled,
            isFlashFrameEnabled,
          })
        );

      if (isShowWindowOnUnreadChangedEnabled && !browserWindow.isVisible()) {
        const isMinimized = browserWindow.isMinimized();
        const isMaximized = browserWindow.isMaximized();

        browserWindow.showInactive();

        if (isMinimized) {
          browserWindow.minimize();
        }

        if (isMaximized) {
          browserWindow.maximize();
        }
        return;
      }

      if (isFlashFrameEnabled) {
        browserWindow.flashFrame(true);
      }
    }),
    watch(
      ({ currentView, servers }) => {
        const currentServer =
          typeof currentView === 'object'
            ? servers.find(({ url }) => url === currentView.url)
            : null;
        return (currentServer && currentServer.title) || app.name;
      },
      async (windowTitle) => {
        const browserWindow = await getRootWindow();
        browserWindow.setTitle(windowTitle);
      }
    ),

    listen(WEBVIEW_FOCUS_REQUESTED, async () => {
      const browserWindow = await getRootWindow();
      browserWindow.focus();
    }),
  ];

  const fetchAndDispatchWindowState = debounce(async (): Promise<void> => {
    dispatchLocal({
      type: ROOT_WINDOW_STATE_CHANGED,
      payload: await fetchRootWindowState(),
    });
  }, 1000);

  getRootWindow().then((rootWindow) => {
    rootWindow.addListener('show', fetchAndDispatchWindowState);
    rootWindow.addListener('hide', fetchAndDispatchWindowState);
    rootWindow.addListener('focus', fetchAndDispatchWindowState);
    rootWindow.addListener('blur', fetchAndDispatchWindowState);
    rootWindow.addListener('maximize', fetchAndDispatchWindowState);
    rootWindow.addListener('unmaximize', fetchAndDispatchWindowState);
    rootWindow.addListener('minimize', fetchAndDispatchWindowState);
    rootWindow.addListener('restore', fetchAndDispatchWindowState);
    rootWindow.addListener('resize', fetchAndDispatchWindowState);
    rootWindow.addListener('move', fetchAndDispatchWindowState);

    fetchAndDispatchWindowState();

    rootWindow.addListener('focus', async () => {
      rootWindow.flashFrame(false);
    });

    rootWindow.addListener('close', async () => {<commit_msg>fix: Restore window on focus request<commit_after>import path from 'path';

import {
  app,
  BrowserWindow,
  nativeImage,
  screen,
  Rectangle,
  NativeImage,
  WebPreferences,
} from 'electron';
import i18next from 'i18next';
import { createStructuredSelector } from 'reselect';

import { setupRootWindowReload } from '../../app/main/dev';
import { Server } from '../../servers/common';
import { select, watch, listen, dispatchLocal } from '../../store';
import { RootState } from '../../store/rootReducer';
import { ROOT_WINDOW_STATE_CHANGED, WEBVIEW_FOCUS_REQUESTED } from '../actions';
import { RootWindowIcon, WindowState } from '../common';
import { selectGlobalBadge, selectGlobalBadgeCount } from '../selectors';
import { debounce } from './debounce';
import { getTrayIconPath } from './icons';

const webPreferences: WebPreferences = {
  nodeIntegration: true,
  nodeIntegrationInSubFrames: true,
  contextIsolation: false,
  webviewTag: true,
  worldSafeExecuteJavaScript: true,
};

const selectRootWindowState = ({ rootWindowState }: RootState): WindowState =>
  rootWindowState ?? {
    bounds: {
      x: 0,
      y: 0,
      width: 0,
      height: 0,
    },
    focused: false,
    fullscreen: false,
    maximized: false,
    minimized: false,
    normal: false,
    visible: false,
  };

let _rootWindow: BrowserWindow;

export const getRootWindow = (): Promise<BrowserWindow> =>
  new Promise((resolve, reject) => {
    setImmediate(() => {
      _rootWindow ? resolve(_rootWindow) : reject(new Error());
    });
  });

export const createRootWindow = (): void => {
  _rootWindow = new BrowserWindow({
    width: 1000,
    height: 600,
    minWidth: 400,
    minHeight: 400,
    titleBarStyle: 'hidden',
    backgroundColor: '#2f343d',
    show: false,
    webPreferences,
  });

  _rootWindow.addListener('close', (event) => {
    event.preventDefault();
  });
};

const isInsideSomeScreen = ({ x, y, width, height }: Rectangle): boolean =>
  screen
    .getAllDisplays()
    .some(
      ({ bounds }) =>
        x >= bounds.x &&
        y >= bounds.y &&
        x + width <= bounds.x + bounds.width &&
        y + height <= bounds.y + bounds.height
    );

export const applyRootWindowState = (browserWindow: BrowserWindow): void => {
  const rootWindowState = select(selectRootWindowState);
  const isTrayIconEnabled = select(
    ({ isTrayIconEnabled }) => isTrayIconEnabled
  );

  let { x, y } = rootWindowState.bounds;
  const { width, height } = rootWindowState.bounds;
  if (
    x === null ||
    x === undefined ||
    y === null ||
    y === undefined ||
    !isInsideSomeScreen({ x, y, width, height })
  ) {
    const {
      bounds: { width: primaryDisplayWidth, height: primaryDisplayHeight },
    } = screen.getPrimaryDisplay();
    x = Math.round((primaryDisplayWidth - width) / 2);
    y = Math.round((primaryDisplayHeight - height) / 2);
  }

  if (browserWindow.isVisible()) {
    return;
  }

  if (x === null || x === undefined || y === null || y === undefined) {
    browserWindow.setBounds({ width, height });
  } else {
    browserWindow.setBounds({ x, y, width, height });
  }

  if (rootWindowState.maximized) {
    browserWindow.maximize();
  }

  if (rootWindowState.minimized) {
    browserWindow.minimize();
  }

  if (rootWindowState.fullscreen) {
    browserWindow.setFullScreen(true);
  }

  if (rootWindowState.visible || !isTrayIconEnabled) {
    browserWindow.show();
  }

  if (rootWindowState.focused) {
    browserWindow.focus();
  }
};

const fetchRootWindowState = async (): Promise<
  ReturnType<typeof selectRootWindowState>
> => {
  const browserWindow = await getRootWindow();
  return {
    focused: browserWindow.isFocused(),
    visible: browserWindow.isVisible(),
    maximized: browserWindow.isMaximized(),
    minimized: browserWindow.isMinimized(),
    fullscreen: browserWindow.isFullScreen(),
    normal: browserWindow.isNormal(),
    bounds: browserWindow.getNormalBounds(),
  };
};

export const setupRootWindow = (): void => {
  const unsubscribers = [
    watch(selectGlobalBadgeCount, async (globalBadgeCount) => {
      const browserWindow = await getRootWindow();

      if (browserWindow.isFocused() || globalBadgeCount === 0) {
        return;
      }

      const { isShowWindowOnUnreadChangedEnabled, isFlashFrameEnabled } =
        select(
          ({ isShowWindowOnUnreadChangedEnabled, isFlashFrameEnabled }) => ({
            isShowWindowOnUnreadChangedEnabled,
            isFlashFrameEnabled,
          })
        );

      if (isShowWindowOnUnreadChangedEnabled && !browserWindow.isVisible()) {
        const isMinimized = browserWindow.isMinimized();
        const isMaximized = browserWindow.isMaximized();

        browserWindow.showInactive();

        if (isMinimized) {
          browserWindow.minimize();
        }

        if (isMaximized) {
          browserWindow.maximize();
        }
        return;
      }

      if (isFlashFrameEnabled) {
        browserWindow.flashFrame(true);
      }
    }),
    watch(
      ({ currentView, servers }) => {
        const currentServer =
          typeof currentView === 'object'
            ? servers.find(({ url }) => url === currentView.url)
            : null;
        return (currentServer && currentServer.title) || app.name;
      },
      async (windowTitle) => {
        const browserWindow = await getRootWindow();
        browserWindow.setTitle(windowTitle);
      }
    ),
    listen(WEBVIEW_FOCUS_REQUESTED, async () => {
      const rootWindow = await getRootWindow();
      rootWindow.restore();
      rootWindow.show();
    }),
  ];

  const fetchAndDispatchWindowState = debounce(async (): Promise<void> => {
    dispatchLocal({
      type: ROOT_WINDOW_STATE_CHANGED,
      payload: await fetchRootWindowState(),
    });
  }, 1000);

  getRootWindow().then((rootWindow) => {
    rootWindow.addListener('show', fetchAndDispatchWindowState);
    rootWindow.addListener('hide', fetchAndDispatchWindowState);
    rootWindow.addListener('focus', fetchAndDispatchWindowState);
    rootWindow.addListener('blur', fetchAndDispatchWindowState);
    rootWindow.addListener('maximize', fetchAndDispatchWindowState);
    rootWindow.addListener('unmaximize', fetchAndDispatchWindowState);
    rootWindow.addListener('minimize', fetchAndDispatchWindowState);
    rootWindow.addListener('restore', fetchAndDispatchWindowState);
    rootWindow.addListener('resize', fetchAndDispatchWindowState);
    rootWindow.addListener('move', fetchAndDispatchWindowState);

    fetchAndDispatchWindowState();

    rootWindow.addListener('focus', async () => {
      rootWindow.flashFrame(false);
    });

    rootWindow.addListener('close', async () => {
{'fraction_non_alphanumeric': 0.13203868936042587, 'fraction_numerical': 0.0047986803629002026, 'mean_word_length': 3.303969022265247, 'pattern_counts': {'":': 0, '<': 15, '<?xml version=': 0, '>': 59, 'https://': 0, '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': '7288451', 'n_tokens_mistral': 3982, 'n_tokens_neox': 3860, 'n_words': 798}