Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
Loading
Sorry, something went wrong. Reload?
Sorry, we cannot display this file.
Sorry, this file is invalid so it cannot be displayed.
6 changes: 6 additions & 0 deletions web/packages/teleterm/electron-builder-config.js
Original file line number Diff line number Diff line change
Expand Up @@ -144,6 +144,8 @@ module.exports = {
},
].filter(Boolean),
},
// Copy the tray icon to resources.
extraResources: ['build_resources/icon-macTemplate@2x.png'],
dmg: {
artifactName: '${productName}-${version}-${arch}.${ext}',
// Turn off blockmaps since we don't support automatic updates.
Expand Down Expand Up @@ -202,6 +204,8 @@ module.exports = {
from: env.CONNECT_WINTUN_DLL_PATH,
to: './bin/wintun.dll',
},
// Copy the tray icon to resources.
'build_resources/icon-win.ico',
].filter(Boolean),
},
nsis: {
Expand Down Expand Up @@ -241,6 +245,8 @@ module.exports = {
from: 'build_resources/linux/apparmor-profile',
to: './apparmor-profile',
},
// Copy the tray icon to resources.
'build_resources/icon-linux/tray.png',
].filter(Boolean),
},
directories: {
Expand Down
22 changes: 21 additions & 1 deletion web/packages/teleterm/src/main.ts
Original file line number Diff line number Diff line change
Expand Up @@ -41,6 +41,8 @@ import { createFileLoggerService, LoggerColor } from 'teleterm/services/logger';
import * as types from 'teleterm/types';
import { assertUnreachable } from 'teleterm/ui/utils';

import { setTray } from './tray';

if (!app.isPackaged) {
// Sets app name and data directories to Electron.
// Allows running packaged and non-packaged Connect at the same time.
Expand Down Expand Up @@ -85,7 +87,11 @@ async function initializeApp(): Promise<void> {
});

nativeTheme.themeSource = configService.get('theme').value;
const windowsManager = new WindowsManager(appStateFileStorage, settings);
const windowsManager = new WindowsManager(
appStateFileStorage,
settings,
configService
);

process.on('uncaughtException', (error, origin) => {
logger.error('Uncaught exception', origin, error);
Expand Down Expand Up @@ -159,9 +165,19 @@ async function initializeApp(): Promise<void> {
}
});

// On Windows/Linux: Re-launching the app while it's already running
// triggers 'second-instance' (because of app.requestSingleInstanceLock()).
//
// On macOS: Re-launching the app (from places like Finder, Spotlight, or Dock)
// does not trigger 'second-instance'. Instead, the system emits 'activate'.
// However, launching the app outside the desktop manager (e.g., from the command
// line) does trigger 'second-instance'.
app.on('second-instance', () => {
windowsManager.focusWindow();
});
app.on('activate', () => {
windowsManager.focusWindow();
});

// Since setUpDeepLinks adds another listener for second-instance, it's important to call it after
// the listener which calls windowsManager.focusWindow. This way the focus will be brought to the
Expand Down Expand Up @@ -199,6 +215,10 @@ async function initializeApp(): Promise<void> {
enableWebHandlersProtection();

windowsManager.createWindow();

if (configService.get('runInBackground').value) {
setTray(settings, { show: () => windowsManager.showWindow() });
}
})
.catch(error => {
const message = 'Could not create the main app window';
Expand Down
5 changes: 5 additions & 0 deletions web/packages/teleterm/src/mainProcess/fixtures/mocks.ts
Original file line number Diff line number Diff line change
Expand Up @@ -197,6 +197,11 @@ export class MockMainProcessClient implements MainProcessClient {
} {
return { cleanup: () => undefined };
}
subscribeToIsInBackgroundMode(): {
cleanup: () => void;
} {
return { cleanup: () => undefined };
}
}

export const makeRuntimeSettings = (
Expand Down
14 changes: 14 additions & 0 deletions web/packages/teleterm/src/mainProcess/mainProcessClient.ts
Original file line number Diff line number Diff line change
Expand Up @@ -249,5 +249,19 @@ export default function createMainProcessClient(): MainProcessClient {
ipcRenderer.removeListener(RendererIpc.OpenAppUpdateDialog, listener),
};
},
subscribeToIsInBackgroundMode: listener => {
const ipcListener = (_, { isInBackgroundMode }) => {
listener({ isInBackgroundMode });
};

ipcRenderer.addListener(RendererIpc.IsInBackgroundMode, ipcListener);
return {
cleanup: () =>
ipcRenderer.removeListener(
RendererIpc.IsInBackgroundMode,
ipcListener
),
};
},
};
}
4 changes: 2 additions & 2 deletions web/packages/teleterm/src/mainProcess/runtimeSettings.ts
Original file line number Diff line number Diff line change
Expand Up @@ -30,7 +30,7 @@ const { argv, env } = process;

const RESOURCES_PATH = app.isPackaged
? process.resourcesPath
: path.join(__dirname, '../../../../');
: path.join(__dirname, '../../..');

const TSH_BIN_ENV_VAR = 'CONNECT_TSH_BIN_PATH';
// __dirname of this file in dev mode is teleport/web/packages/teleterm/build/app/main
Expand Down Expand Up @@ -201,7 +201,7 @@ function getBinaryPaths(): { binDir?: string; tshBinPath: string } {
}

export function getAssetPath(...paths: string[]): string {
return path.join(RESOURCES_PATH, 'assets', ...paths);
return path.join(RESOURCES_PATH, 'build_resources', ...paths);
}

/**
Expand Down
6 changes: 6 additions & 0 deletions web/packages/teleterm/src/mainProcess/types.ts
Original file line number Diff line number Diff line change
Expand Up @@ -224,6 +224,11 @@ export type MainProcessClient = {
subscribeToOpenAppUpdateDialog(listener: () => void): {
cleanup: () => void;
};
subscribeToIsInBackgroundMode(
listener: (opts: { isInBackgroundMode: boolean }) => void
): {
cleanup: () => void;
};
};

export type ChildProcessAddresses = {
Expand Down Expand Up @@ -331,6 +336,7 @@ export enum RendererIpc {
DeepLinkLaunch = 'renderer-deep-link-launch',
OpenAppUpdateDialog = 'renderer-open-app-update-dialog',
AppUpdateEvent = 'renderer-app-update-event',
IsInBackgroundMode = 'renderer-is-in-background-mode',
}

export enum MainProcessIpc {
Expand Down
6 changes: 5 additions & 1 deletion web/packages/teleterm/src/mainProcess/windowsManager.test.ts
Original file line number Diff line number Diff line change
Expand Up @@ -21,6 +21,7 @@

import { BrowserWindow } from 'electron';

import { createMockConfigService } from 'teleterm/services/config/fixtures/mocks';
import { createMockFileStorage } from 'teleterm/services/fileStorage/fixtures/mocks';

import { makeRuntimeSettings } from './fixtures/mocks';
Expand Down Expand Up @@ -73,7 +74,8 @@ describe('waitForWindowFocus', () => {
const makeWindowsManager = () => {
const windowsManager = new WindowsManager(
createMockFileStorage(),
makeRuntimeSettings()
makeRuntimeSettings(),
createMockConfigService({})
);

let isFocused = false;
Expand All @@ -84,6 +86,8 @@ const makeWindowsManager = () => {
}),
isFocused: jest.fn().mockImplementation(() => isFocused),
isMinimized: jest.fn().mockReturnValue(false),
isVisible: jest.fn().mockReturnValue(true),
isDestroyed: jest.fn().mockReturnValue(false),
} as Partial<BrowserWindow>;

windowsManager['window'] = mockWindow as BrowserWindow;
Expand Down
Loading
Loading