mirror of
https://github.com/ckaczor/azuredatastudio.git
synced 2026-02-01 17:23:35 -05:00
461 lines
14 KiB
TypeScript
461 lines
14 KiB
TypeScript
/*---------------------------------------------------------------------------------------------
|
|
* Copyright (c) Microsoft Corporation. All rights reserved.
|
|
* Licensed under the Source EULA. See License.txt in the project root for license information.
|
|
*--------------------------------------------------------------------------------------------*/
|
|
|
|
import { createDecorator } from 'vs/platform/instantiation/common/instantiation';
|
|
import { Event } from 'vs/base/common/event';
|
|
import { ITelemetryData } from 'vs/platform/telemetry/common/telemetry';
|
|
import { IProcessEnvironment, isMacintosh, isLinux } from 'vs/base/common/platform';
|
|
import { ParsedArgs, IEnvironmentService } from 'vs/platform/environment/common/environment';
|
|
import { IWorkspaceIdentifier, ISingleFolderWorkspaceIdentifier } from 'vs/platform/workspaces/common/workspaces';
|
|
import { IRecentlyOpened, IRecent } from 'vs/platform/history/common/history';
|
|
import { ISerializableCommandAction } from 'vs/platform/actions/common/actions';
|
|
import { ExportData } from 'vs/base/common/performance';
|
|
import { LogLevel } from 'vs/platform/log/common/log';
|
|
import { IDisposable, dispose } from 'vs/base/common/lifecycle';
|
|
import { URI, UriComponents } from 'vs/base/common/uri';
|
|
import { IConfigurationService } from 'vs/platform/configuration/common/configuration';
|
|
|
|
export const IWindowsService = createDecorator<IWindowsService>('windowsService');
|
|
|
|
export interface INativeOpenDialogOptions {
|
|
windowId?: number;
|
|
forceNewWindow?: boolean;
|
|
|
|
dialogOptions?: OpenDialogOptions;
|
|
|
|
telemetryEventName?: string;
|
|
telemetryExtraData?: ITelemetryData;
|
|
}
|
|
|
|
export interface IEnterWorkspaceResult {
|
|
workspace: IWorkspaceIdentifier;
|
|
backupPath?: string;
|
|
}
|
|
|
|
export interface CrashReporterStartOptions {
|
|
companyName?: string;
|
|
submitURL: string;
|
|
productName?: string;
|
|
uploadToServer?: boolean;
|
|
ignoreSystemCrashHandler?: boolean;
|
|
extra?: any;
|
|
crashesDirectory?: string;
|
|
}
|
|
|
|
export interface OpenDialogOptions {
|
|
title?: string;
|
|
defaultPath?: string;
|
|
buttonLabel?: string;
|
|
filters?: FileFilter[];
|
|
properties?: Array<'openFile' | 'openDirectory' | 'multiSelections' | 'showHiddenFiles' | 'createDirectory' | 'promptToCreate' | 'noResolveAliases' | 'treatPackageAsDirectory'>;
|
|
message?: string;
|
|
}
|
|
|
|
export interface FileFilter {
|
|
extensions: string[];
|
|
name: string;
|
|
}
|
|
|
|
export interface MessageBoxOptions {
|
|
type?: string;
|
|
buttons?: string[];
|
|
defaultId?: number;
|
|
title?: string;
|
|
message: string;
|
|
detail?: string;
|
|
checkboxLabel?: string;
|
|
checkboxChecked?: boolean;
|
|
cancelId?: number;
|
|
noLink?: boolean;
|
|
normalizeAccessKeys?: boolean;
|
|
}
|
|
|
|
export interface SaveDialogOptions {
|
|
title?: string;
|
|
defaultPath?: string;
|
|
buttonLabel?: string;
|
|
filters?: FileFilter[];
|
|
message?: string;
|
|
nameFieldLabel?: string;
|
|
showsTagField?: boolean;
|
|
}
|
|
|
|
export interface INewWindowOptions {
|
|
remoteAuthority?: string;
|
|
}
|
|
|
|
export interface IDevToolsOptions {
|
|
mode: 'right' | 'bottom' | 'undocked' | 'detach';
|
|
}
|
|
|
|
export interface IWindowsService {
|
|
|
|
_serviceBrand: any;
|
|
|
|
onWindowOpen: Event<number>;
|
|
onWindowFocus: Event<number>;
|
|
onWindowBlur: Event<number>;
|
|
onWindowMaximize: Event<number>;
|
|
onWindowUnmaximize: Event<number>;
|
|
onRecentlyOpenedChange: Event<void>;
|
|
|
|
// Dialogs
|
|
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
showMessageBox(windowId: number, options: MessageBoxOptions): Promise<IMessageBoxResult>;
|
|
showSaveDialog(windowId: number, options: SaveDialogOptions): Promise<string>;
|
|
showOpenDialog(windowId: number, options: OpenDialogOptions): Promise<string[]>;
|
|
|
|
reloadWindow(windowId: number, args?: ParsedArgs): Promise<void>;
|
|
openDevTools(windowId: number, options?: IDevToolsOptions): Promise<void>;
|
|
toggleDevTools(windowId: number): Promise<void>;
|
|
closeWorkspace(windowId: number): Promise<void>;
|
|
enterWorkspace(windowId: number, path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
|
toggleFullScreen(windowId: number): Promise<void>;
|
|
setRepresentedFilename(windowId: number, fileName: string): Promise<void>;
|
|
addRecentlyOpened(recents: IRecent[]): Promise<void>;
|
|
removeFromRecentlyOpened(paths: URI[]): Promise<void>;
|
|
clearRecentlyOpened(): Promise<void>;
|
|
getRecentlyOpened(windowId: number): Promise<IRecentlyOpened>;
|
|
focusWindow(windowId: number): Promise<void>;
|
|
closeWindow(windowId: number): Promise<void>;
|
|
isFocused(windowId: number): Promise<boolean>;
|
|
isMaximized(windowId: number): Promise<boolean>;
|
|
maximizeWindow(windowId: number): Promise<void>;
|
|
unmaximizeWindow(windowId: number): Promise<void>;
|
|
minimizeWindow(windowId: number): Promise<void>;
|
|
onWindowTitleDoubleClick(windowId: number): Promise<void>;
|
|
setDocumentEdited(windowId: number, flag: boolean): Promise<void>;
|
|
quit(): Promise<void>;
|
|
relaunch(options: { addArgs?: string[], removeArgs?: string[] }): Promise<void>;
|
|
|
|
// macOS Native Tabs
|
|
newWindowTab(): Promise<void>;
|
|
showPreviousWindowTab(): Promise<void>;
|
|
showNextWindowTab(): Promise<void>;
|
|
moveWindowTabToNewWindow(): Promise<void>;
|
|
mergeAllWindowTabs(): Promise<void>;
|
|
toggleWindowTabsBar(): Promise<void>;
|
|
|
|
// macOS TouchBar
|
|
updateTouchBar(windowId: number, items: ISerializableCommandAction[][]): Promise<void>;
|
|
|
|
// Shared process
|
|
whenSharedProcessReady(): Promise<void>;
|
|
toggleSharedProcess(): Promise<void>;
|
|
|
|
// Global methods
|
|
openWindow(windowId: number, uris: IURIToOpen[], options?: IOpenSettings): Promise<void>;
|
|
openNewWindow(options?: INewWindowOptions): Promise<void>;
|
|
showWindow(windowId: number): Promise<void>;
|
|
getWindows(): Promise<{ id: number; workspace?: IWorkspaceIdentifier; folderUri?: ISingleFolderWorkspaceIdentifier; title: string; filename?: string; }[]>;
|
|
getWindowCount(): Promise<number>;
|
|
log(severity: string, ...messages: string[]): Promise<void>;
|
|
showItemInFolder(path: URI): Promise<void>;
|
|
getActiveWindowId(): Promise<number | undefined>;
|
|
|
|
// This needs to be handled from browser process to prevent
|
|
// foreground ordering issues on Windows
|
|
openExternal(url: string): Promise<boolean>;
|
|
|
|
// TODO: this is a bit backwards
|
|
startCrashReporter(config: CrashReporterStartOptions): Promise<void>;
|
|
|
|
openAboutDialog(): Promise<void>;
|
|
resolveProxy(windowId: number, url: string): Promise<string | undefined>;
|
|
}
|
|
|
|
export const IWindowService = createDecorator<IWindowService>('windowService');
|
|
|
|
export interface IMessageBoxResult {
|
|
button: number;
|
|
checkboxChecked?: boolean;
|
|
}
|
|
|
|
export interface IOpenSettings {
|
|
forceNewWindow?: boolean;
|
|
forceReuseWindow?: boolean;
|
|
forceOpenWorkspaceAsFile?: boolean;
|
|
diffMode?: boolean;
|
|
addMode?: boolean;
|
|
args?: ParsedArgs;
|
|
}
|
|
|
|
export type URIType = 'file' | 'folder';
|
|
|
|
export interface IURIToOpen {
|
|
uri: URI;
|
|
typeHint?: URIType;
|
|
label?: string;
|
|
}
|
|
|
|
export interface IWindowService {
|
|
|
|
_serviceBrand: any;
|
|
|
|
readonly onDidChangeFocus: Event<boolean>;
|
|
readonly onDidChangeMaximize: Event<boolean>;
|
|
|
|
readonly hasFocus: boolean;
|
|
|
|
getConfiguration(): IWindowConfiguration;
|
|
getCurrentWindowId(): number;
|
|
pickFileFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickFileAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickFolderAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
pickWorkspaceAndOpen(options: INativeOpenDialogOptions): Promise<void>;
|
|
reloadWindow(args?: ParsedArgs): Promise<void>;
|
|
openDevTools(options?: IDevToolsOptions): Promise<void>;
|
|
toggleDevTools(): Promise<void>;
|
|
closeWorkspace(): Promise<void>;
|
|
updateTouchBar(items: ISerializableCommandAction[][]): Promise<void>;
|
|
enterWorkspace(path: URI): Promise<IEnterWorkspaceResult | undefined>;
|
|
toggleFullScreen(): Promise<void>;
|
|
setRepresentedFilename(fileName: string): Promise<void>;
|
|
getRecentlyOpened(): Promise<IRecentlyOpened>;
|
|
focusWindow(): Promise<void>;
|
|
closeWindow(): Promise<void>;
|
|
openWindow(uris: IURIToOpen[], options?: IOpenSettings): Promise<void>;
|
|
isFocused(): Promise<boolean>;
|
|
setDocumentEdited(flag: boolean): Promise<void>;
|
|
isMaximized(): Promise<boolean>;
|
|
maximizeWindow(): Promise<void>;
|
|
unmaximizeWindow(): Promise<void>;
|
|
minimizeWindow(): Promise<void>;
|
|
onWindowTitleDoubleClick(): Promise<void>;
|
|
show(): Promise<void>;
|
|
showMessageBox(options: MessageBoxOptions): Promise<IMessageBoxResult>;
|
|
showSaveDialog(options: SaveDialogOptions): Promise<string>;
|
|
showOpenDialog(options: OpenDialogOptions): Promise<string[]>;
|
|
resolveProxy(url: string): Promise<string | undefined>;
|
|
}
|
|
|
|
export type MenuBarVisibility = 'default' | 'visible' | 'toggle' | 'hidden';
|
|
|
|
export interface IWindowsConfiguration {
|
|
window: IWindowSettings;
|
|
}
|
|
|
|
export interface IWindowSettings {
|
|
openFilesInNewWindow: 'on' | 'off' | 'default';
|
|
openFoldersInNewWindow: 'on' | 'off' | 'default';
|
|
openWithoutArgumentsInNewWindow: 'on' | 'off';
|
|
restoreWindows: 'all' | 'folders' | 'one' | 'none';
|
|
restoreFullscreen: boolean;
|
|
zoomLevel: number;
|
|
titleBarStyle: 'native' | 'custom';
|
|
autoDetectHighContrast: boolean;
|
|
menuBarVisibility: MenuBarVisibility;
|
|
newWindowDimensions: 'default' | 'inherit' | 'maximized' | 'fullscreen';
|
|
nativeTabs: boolean;
|
|
nativeFullScreen: boolean;
|
|
enableMenuBarMnemonics: boolean;
|
|
closeWhenEmpty: boolean;
|
|
clickThroughInactive: boolean;
|
|
}
|
|
|
|
export function getTitleBarStyle(configurationService: IConfigurationService, environment: IEnvironmentService, isExtensionDevelopment = environment.isExtensionDevelopment): 'native' | 'custom' {
|
|
const configuration = configurationService.getValue<IWindowSettings>('window');
|
|
|
|
const isDev = !environment.isBuilt || isExtensionDevelopment;
|
|
if (isMacintosh && isDev) {
|
|
return 'native'; // not enabled when developing due to https://github.com/electron/electron/issues/3647
|
|
}
|
|
|
|
if (configuration) {
|
|
const useNativeTabs = isMacintosh && configuration.nativeTabs === true;
|
|
if (useNativeTabs) {
|
|
return 'native'; // native tabs on sierra do not work with custom title style
|
|
}
|
|
|
|
const useSimpleFullScreen = isMacintosh && configuration.nativeFullScreen === false;
|
|
if (useSimpleFullScreen) {
|
|
return 'native'; // simple fullscreen does not work well with custom title style (https://github.com/Microsoft/vscode/issues/63291)
|
|
}
|
|
|
|
// {{SQL CARBON EDIT}} - Always use native toolbar
|
|
// const style = configuration.titleBarStyle;
|
|
// if (style === 'native' || style === 'custom') {
|
|
// return style;
|
|
// }
|
|
}
|
|
|
|
// {{SQL CARBON EDIT}} - Always use native toolbar
|
|
return 'native';
|
|
// return isLinux ? 'native' : 'custom'; // default to custom on all macOS and Windows
|
|
}
|
|
|
|
export const enum OpenContext {
|
|
|
|
// opening when running from the command line
|
|
CLI,
|
|
|
|
// macOS only: opening from the dock (also when opening files to a running instance from desktop)
|
|
DOCK,
|
|
|
|
// opening from the main application window
|
|
MENU,
|
|
|
|
// opening from a file or folder dialog
|
|
DIALOG,
|
|
|
|
// opening from the OS's UI
|
|
DESKTOP,
|
|
|
|
// opening through the API
|
|
API
|
|
}
|
|
|
|
export const enum ReadyState {
|
|
|
|
/**
|
|
* This window has not loaded any HTML yet
|
|
*/
|
|
NONE,
|
|
|
|
/**
|
|
* This window is loading HTML
|
|
*/
|
|
LOADING,
|
|
|
|
/**
|
|
* This window is navigating to another HTML
|
|
*/
|
|
NAVIGATING,
|
|
|
|
/**
|
|
* This window is done loading HTML
|
|
*/
|
|
READY
|
|
}
|
|
|
|
export interface IPath extends IPathData {
|
|
|
|
// the file path to open within a Code instance
|
|
fileUri?: URI;
|
|
}
|
|
|
|
export interface IPathsToWaitFor extends IPathsToWaitForData {
|
|
paths: IPath[];
|
|
waitMarkerFileUri: URI;
|
|
}
|
|
|
|
export interface IPathsToWaitForData {
|
|
paths: IPathData[];
|
|
waitMarkerFileUri: UriComponents;
|
|
}
|
|
|
|
export interface IPathData {
|
|
|
|
// the file path to open within a Code instance
|
|
fileUri?: UriComponents;
|
|
|
|
// the line number in the file path to open
|
|
lineNumber?: number;
|
|
|
|
// the column number in the file path to open
|
|
columnNumber?: number;
|
|
}
|
|
|
|
export interface IOpenFileRequest {
|
|
filesToOpen?: IPathData[];
|
|
filesToCreate?: IPathData[];
|
|
filesToDiff?: IPathData[];
|
|
filesToWait?: IPathsToWaitForData;
|
|
termProgram?: string;
|
|
}
|
|
|
|
export interface IAddFoldersRequest {
|
|
foldersToAdd: UriComponents[];
|
|
}
|
|
|
|
export interface IWindowConfiguration extends ParsedArgs {
|
|
machineId: string;
|
|
windowId: number;
|
|
logLevel: LogLevel;
|
|
|
|
mainPid: number;
|
|
|
|
appRoot: string;
|
|
execPath: string;
|
|
isInitialStartup?: boolean;
|
|
|
|
userEnv: IProcessEnvironment;
|
|
nodeCachedDataDir?: string;
|
|
|
|
backupPath?: string;
|
|
|
|
workspace?: IWorkspaceIdentifier;
|
|
folderUri?: ISingleFolderWorkspaceIdentifier;
|
|
|
|
remoteAuthority?: string;
|
|
|
|
zoomLevel?: number;
|
|
fullscreen?: boolean;
|
|
maximized?: boolean;
|
|
highContrast?: boolean;
|
|
frameless?: boolean;
|
|
accessibilitySupport?: boolean;
|
|
partsSplashPath?: string;
|
|
|
|
perfStartTime?: number;
|
|
perfAppReady?: number;
|
|
perfWindowLoadTime?: number;
|
|
perfEntries: ExportData;
|
|
|
|
filesToOpen?: IPath[];
|
|
filesToCreate?: IPath[];
|
|
filesToDiff?: IPath[];
|
|
filesToWait?: IPathsToWaitFor;
|
|
termProgram?: string;
|
|
}
|
|
|
|
export interface IRunActionInWindowRequest {
|
|
id: string;
|
|
from: 'menu' | 'touchbar' | 'mouse';
|
|
args?: any[];
|
|
}
|
|
|
|
export interface IRunKeybindingInWindowRequest {
|
|
userSettingsLabel: string;
|
|
}
|
|
|
|
export class ActiveWindowManager implements IDisposable {
|
|
|
|
private disposables: IDisposable[] = [];
|
|
private firstActiveWindowIdPromise: Promise<any> | null;
|
|
private _activeWindowId: number | undefined;
|
|
|
|
constructor(@IWindowsService windowsService: IWindowsService) {
|
|
const onActiveWindowChange = Event.latch(Event.any(windowsService.onWindowOpen, windowsService.onWindowFocus));
|
|
onActiveWindowChange(this.setActiveWindow, this, this.disposables);
|
|
|
|
this.firstActiveWindowIdPromise = windowsService.getActiveWindowId()
|
|
.then(id => (typeof this._activeWindowId === 'undefined') && this.setActiveWindow(id));
|
|
}
|
|
|
|
private setActiveWindow(windowId: number | undefined) {
|
|
if (this.firstActiveWindowIdPromise) {
|
|
this.firstActiveWindowIdPromise = null;
|
|
}
|
|
|
|
this._activeWindowId = windowId;
|
|
}
|
|
|
|
getActiveClientId(): Promise<string> {
|
|
if (this.firstActiveWindowIdPromise) {
|
|
return this.firstActiveWindowIdPromise;
|
|
}
|
|
|
|
return Promise.resolve(`window:${this._activeWindowId}`);
|
|
}
|
|
|
|
dispose() {
|
|
this.disposables = dispose(this.disposables);
|
|
}
|
|
}
|