diff --git a/src/vs/base/browser/ui/dialog/dialog.ts b/src/vs/base/browser/ui/dialog/dialog.ts index 6c972e7866b..fceb9c852cc 100644 --- a/src/vs/base/browser/ui/dialog/dialog.ts +++ b/src/vs/base/browser/ui/dialog/dialog.ts @@ -58,6 +58,7 @@ export interface IDialogOptions { readonly disableCloseAction?: boolean; readonly disableCloseButton?: boolean; readonly disableDefaultAction?: boolean; + readonly onVisibilityChange?: (window: Window, visible: boolean) => void; readonly buttonStyles: IButtonStyles; readonly checkboxStyles: ICheckboxStyles; readonly inputBoxStyles: IInputBoxStyles; @@ -536,6 +537,10 @@ export class Dialog extends Disposable { this.element.setAttribute('aria-describedby', 'monaco-dialog-icon monaco-dialog-message-text monaco-dialog-message-detail monaco-dialog-message-body monaco-dialog-footer'); show(this.element); + // Notify visibility change + this.options.onVisibilityChange?.(window, true); + this._register(toDisposable(() => this.options.onVisibilityChange?.(window, false))); + // Focus first element (input or button) if (this.inputs.length > 0) { this.inputs[0].focus(); diff --git a/src/vs/platform/native/common/native.ts b/src/vs/platform/native/common/native.ts index 585585003d3..7369736706c 100644 --- a/src/vs/platform/native/common/native.ts +++ b/src/vs/platform/native/common/native.ts @@ -145,12 +145,7 @@ export interface ICommonNativeHostService { toggleWindowAlwaysOnTop(options?: INativeHostOptions): Promise; setWindowAlwaysOnTop(alwaysOnTop: boolean, options?: INativeHostOptions): Promise; - /** - * Only supported on Windows and macOS. Updates the window controls to match the title bar size. - * - * @param options `backgroundColor` and `foregroundColor` are only supported on Windows - */ - updateWindowControls(options: INativeHostOptions & { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise; + updateWindowControls(options: INativeHostOptions & { height?: number; backgroundColor?: string; foregroundColor?: string; dimmed?: boolean }): Promise; updateWindowAccentColor(color: 'default' | 'off' | string, inactiveColor: string | undefined): Promise; diff --git a/src/vs/platform/native/electron-main/nativeHostMainService.ts b/src/vs/platform/native/electron-main/nativeHostMainService.ts index 22ad671ed56..93d000872d6 100644 --- a/src/vs/platform/native/electron-main/nativeHostMainService.ts +++ b/src/vs/platform/native/electron-main/nativeHostMainService.ts @@ -374,7 +374,7 @@ export class NativeHostMainService extends Disposable implements INativeHostMain } } - async updateWindowControls(windowId: number | undefined, options: INativeHostOptions & { height?: number; backgroundColor?: string; foregroundColor?: string }): Promise { + async updateWindowControls(windowId: number | undefined, options: INativeHostOptions & { height?: number; backgroundColor?: string; foregroundColor?: string; dimmed?: boolean }): Promise { const window = this.windowById(options?.targetWindowId, windowId); window?.updateWindowControls(options); } diff --git a/src/vs/platform/window/electron-main/window.ts b/src/vs/platform/window/electron-main/window.ts index 13268e716ef..748e90019de 100644 --- a/src/vs/platform/window/electron-main/window.ts +++ b/src/vs/platform/window/electron-main/window.ts @@ -38,7 +38,7 @@ export interface IBaseWindow extends IDisposable { readonly isFullScreen: boolean; toggleFullScreen(): void; - updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string }): void; + updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string; dimmed?: boolean }): void; matches(webContents: electron.WebContents): boolean; } diff --git a/src/vs/platform/windows/electron-main/windowImpl.ts b/src/vs/platform/windows/electron-main/windowImpl.ts index 3841cfa34a7..4faede85f4c 100644 --- a/src/vs/platform/windows/electron-main/windowImpl.ts +++ b/src/vs/platform/windows/electron-main/windowImpl.ts @@ -46,6 +46,7 @@ import { IInstantiationService } from '../../instantiation/common/instantiation. import { VSBuffer } from '../../../base/common/buffer.js'; import { errorHandler } from '../../../base/common/errors.js'; import { FocusMode } from '../../native/common/native.js'; +import { Color } from '../../../base/common/color.js'; export interface IWindowCreationOptions { readonly state: IWindowState; @@ -404,7 +405,10 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { private static readonly windowControlHeightStateStorageKey = 'windowControlHeight'; - updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string }): void { + private windowControlsDimmed = false; + private lastWindowControlColors: { backgroundColor?: string; foregroundColor?: string } | undefined; + + updateWindowControls(options: { height?: number; backgroundColor?: string; foregroundColor?: string; dimmed?: boolean }): void { const win = this.win; if (!win) { return; @@ -417,9 +421,25 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { // Windows/Linux: update window controls via setTitleBarOverlay() if (!isMacintosh && useWindowControlsOverlay(this.configurationService)) { + + // Update dimmed state if explicitly provided + if (options.dimmed !== undefined) { + this.windowControlsDimmed = options.dimmed; + } + + const backgroundColor = options.backgroundColor ?? this.lastWindowControlColors?.backgroundColor; + const foregroundColor = options.foregroundColor ?? this.lastWindowControlColors?.foregroundColor; + + if (options.backgroundColor !== undefined || options.foregroundColor !== undefined) { + this.lastWindowControlColors = { backgroundColor, foregroundColor }; + } + + const effectiveBackgroundColor = this.windowControlsDimmed && backgroundColor ? this.dimColor(backgroundColor) : backgroundColor; + const effectiveForegroundColor = this.windowControlsDimmed && foregroundColor ? this.dimColor(foregroundColor) : foregroundColor; + win.setTitleBarOverlay({ - color: options.backgroundColor?.trim() === '' ? undefined : options.backgroundColor, - symbolColor: options.foregroundColor?.trim() === '' ? undefined : options.foregroundColor, + color: effectiveBackgroundColor?.trim() === '' ? undefined : effectiveBackgroundColor, + symbolColor: effectiveForegroundColor?.trim() === '' ? undefined : effectiveForegroundColor, height: options.height ? options.height - 1 : undefined // account for window border }); } @@ -439,6 +459,24 @@ export abstract class BaseWindow extends Disposable implements IBaseWindow { } } + private dimColor(color: string): string { + + // Blend a CSS color with black at 30% opacity to match the + // dimming overlay of `rgba(0, 0, 0, 0.3)` used by modals. + + const parsed = Color.Format.CSS.parse(color); + if (!parsed) { + return color; + } + + const dimFactor = 0.7; // 1 - 0.3 opacity of black overlay + const r = Math.round(parsed.rgba.r * dimFactor); + const g = Math.round(parsed.rgba.g * dimFactor); + const b = Math.round(parsed.rgba.b * dimFactor); + + return `rgb(${r}, ${g}, ${b})`; + } + //#endregion //#region Fullscreen diff --git a/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts index 2a95195c06b..eb3bad9ad55 100644 --- a/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts +++ b/src/vs/platform/windows/test/electron-main/windowsFinder.test.ts @@ -73,7 +73,7 @@ suite('WindowsFinder', () => { isDocumentEdited(): boolean { throw new Error('Method not implemented.'); } updateTouchBar(items: UriDto[][]): void { throw new Error('Method not implemented.'); } serializeWindowState(): IWindowState { throw new Error('Method not implemented'); } - updateWindowControls(options: { height?: number | undefined; backgroundColor?: string | undefined; foregroundColor?: string | undefined }): void { throw new Error('Method not implemented.'); } + updateWindowControls(options: { height?: number | undefined; backgroundColor?: string | undefined; foregroundColor?: string | undefined; dimmed?: boolean | undefined }): void { throw new Error('Method not implemented.'); } notifyZoomLevel(level: number): void { throw new Error('Method not implemented.'); } matches(webContents: Electron.WebContents): boolean { throw new Error('Method not implemented.'); } dispose(): void { } diff --git a/src/vs/platform/dialogs/browser/dialog.ts b/src/vs/workbench/browser/parts/dialogs/dialog.ts similarity index 65% rename from src/vs/platform/dialogs/browser/dialog.ts rename to src/vs/workbench/browser/parts/dialogs/dialog.ts index 01d12f126da..d2f18acdb50 100644 --- a/src/vs/platform/dialogs/browser/dialog.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialog.ts @@ -3,16 +3,17 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { EventHelper } from '../../../base/browser/dom.js'; -import { StandardKeyboardEvent } from '../../../base/browser/keyboardEvent.js'; -import { IDialogOptions } from '../../../base/browser/ui/dialog/dialog.js'; -import { fromNow } from '../../../base/common/date.js'; -import { localize } from '../../../nls.js'; -import { IKeybindingService } from '../../keybinding/common/keybinding.js'; -import { ResultKind } from '../../keybinding/common/keybindingResolver.js'; -import { ILayoutService } from '../../layout/browser/layoutService.js'; -import { IProductService } from '../../product/common/productService.js'; -import { defaultButtonStyles, defaultCheckboxStyles, defaultInputBoxStyles, defaultDialogStyles } from '../../theme/browser/defaultStyles.js'; +import { EventHelper } from '../../../../base/browser/dom.js'; +import { StandardKeyboardEvent } from '../../../../base/browser/keyboardEvent.js'; +import { IDialogOptions } from '../../../../base/browser/ui/dialog/dialog.js'; +import { fromNow } from '../../../../base/common/date.js'; +import { localize } from '../../../../nls.js'; +import { IHostService } from '../../../services/host/browser/host.js'; +import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; +import { ResultKind } from '../../../../platform/keybinding/common/keybindingResolver.js'; +import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js'; +import { IProductService } from '../../../../platform/product/common/productService.js'; +import { defaultButtonStyles, defaultCheckboxStyles, defaultInputBoxStyles, defaultDialogStyles } from '../../../../platform/theme/browser/defaultStyles.js'; const defaultDialogAllowableCommands = new Set([ 'workbench.action.quit', @@ -25,7 +26,7 @@ const defaultDialogAllowableCommands = new Set([ 'editor.action.clipboardPasteAction' ]); -export function createWorkbenchDialogOptions(options: Partial, keybindingService: IKeybindingService, layoutService: ILayoutService, allowableCommands = defaultDialogAllowableCommands): IDialogOptions { +export function createWorkbenchDialogOptions(options: Partial, keybindingService: IKeybindingService, layoutService: ILayoutService, hostService: IHostService, allowableCommands = defaultDialogAllowableCommands): IDialogOptions { return { keyEventProcessor: (event: StandardKeyboardEvent) => { const resolved = keybindingService.softDispatch(event, layoutService.activeContainer); @@ -39,6 +40,7 @@ export function createWorkbenchDialogOptions(options: Partial, k checkboxStyles: defaultCheckboxStyles, inputBoxStyles: defaultInputBoxStyles, dialogStyles: defaultDialogStyles, + onVisibilityChange: (window, visible) => hostService.setWindowDimmed(window, visible), ...options }; } diff --git a/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts b/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts index bba15b35fbb..7e0e5ce8e9d 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialog.web.contribution.ts @@ -3,11 +3,7 @@ * Licensed under the MIT License. See License.txt in the project root for license information. *--------------------------------------------------------------------------------------------*/ -import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js'; import { IDialogHandler, IDialogResult, IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; -import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js'; -import { ILogService } from '../../../../platform/log/common/log.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; import { IWorkbenchContribution, WorkbenchPhase, registerWorkbenchContribution2 } from '../../../common/contributions.js'; import { IDialogsModel, IDialogViewItem } from '../../../common/dialogs.js'; @@ -16,9 +12,7 @@ import { DialogService } from '../../../services/dialogs/common/dialogService.js import { Disposable } from '../../../../base/common/lifecycle.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { Lazy } from '../../../../base/common/lazy.js'; -import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { createBrowserAboutDialogDetails } from '../../../../platform/dialogs/browser/dialog.js'; -import { IMarkdownRendererService } from '../../../../platform/markdown/browser/markdownRenderer.js'; +import { createBrowserAboutDialogDetails } from './dialog.js'; export class DialogHandlerContribution extends Disposable implements IWorkbenchContribution { @@ -31,18 +25,12 @@ export class DialogHandlerContribution extends Disposable implements IWorkbenchC constructor( @IDialogService private dialogService: IDialogService, - @ILogService logService: ILogService, - @ILayoutService layoutService: ILayoutService, - @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService instantiationService: IInstantiationService, @IProductService private productService: IProductService, - @IClipboardService clipboardService: IClipboardService, - @IOpenerService openerService: IOpenerService, - @IMarkdownRendererService markdownRendererService: IMarkdownRendererService, ) { super(); - this.impl = new Lazy(() => new BrowserDialogHandler(logService, layoutService, keybindingService, instantiationService, clipboardService, openerService, markdownRendererService)); + this.impl = new Lazy(() => instantiationService.createInstance(BrowserDialogHandler)); this.model = (this.dialogService as DialogService).model; this._register(this.model.onWillShowDialog(() => { diff --git a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts index 7664074eced..16e11df3630 100644 --- a/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts +++ b/src/vs/workbench/browser/parts/dialogs/dialogHandler.ts @@ -15,7 +15,8 @@ import { IClipboardService } from '../../../../platform/clipboard/common/clipboa import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { IMarkdownRendererService, openLinkFromMarkdown } from '../../../../platform/markdown/browser/markdownRenderer.js'; import { IOpenerService } from '../../../../platform/opener/common/opener.js'; -import { createWorkbenchDialogOptions } from '../../../../platform/dialogs/browser/dialog.js'; +import { createWorkbenchDialogOptions } from './dialog.js'; +import { IHostService } from '../../../services/host/browser/host.js'; export class BrowserDialogHandler extends AbstractDialogHandler { @@ -36,6 +37,7 @@ export class BrowserDialogHandler extends AbstractDialogHandler { @IClipboardService private readonly clipboardService: IClipboardService, @IOpenerService private readonly openerService: IOpenerService, @IMarkdownRendererService private readonly markdownRendererService: IMarkdownRendererService, + @IHostService private readonly hostService: IHostService, ) { super(); } @@ -119,7 +121,7 @@ export class BrowserDialogHandler extends AbstractDialogHandler { checkboxLabel: checkbox?.label, checkboxChecked: checkbox?.checked, inputs - }, this.keybindingService, this.layoutService, BrowserDialogHandler.ALLOWABLE_COMMANDS) + }, this.keybindingService, this.layoutService, this.hostService, BrowserDialogHandler.ALLOWABLE_COMMANDS) ); dialogDisposables.add(dialog); diff --git a/src/vs/workbench/browser/parts/editor/modalEditorPart.ts b/src/vs/workbench/browser/parts/editor/modalEditorPart.ts index 9964e55f840..580732318a4 100644 --- a/src/vs/workbench/browser/parts/editor/modalEditorPart.ts +++ b/src/vs/workbench/browser/parts/editor/modalEditorPart.ts @@ -57,6 +57,7 @@ export class ModalEditorPart { @IEditorService private readonly editorService: IEditorService, @IWorkbenchLayoutService private readonly layoutService: IWorkbenchLayoutService, @IKeybindingService private readonly keybindingService: IKeybindingService, + @IHostService private readonly hostService: IHostService, ) { } @@ -203,6 +204,10 @@ export class ModalEditorPart { disposables.add(Event.runAndSubscribe(this.layoutService.onDidLayoutMainContainer, layoutModal)); disposables.add(editorPart.onDidChangeMaximized(() => layoutModal())); + // Dim window controls to match the modal overlay + this.hostService.setWindowDimmed(mainWindow, true); + disposables.add(toDisposable(() => this.hostService.setWindowDimmed(mainWindow, false))); + // Focus the modal editorPartContainer.focus(); diff --git a/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupRunner.ts b/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupRunner.ts index 4c51c01f5ad..9929aa7064e 100644 --- a/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupRunner.ts +++ b/src/vs/workbench/contrib/chat/browser/chatSetup/chatSetupRunner.ts @@ -16,7 +16,7 @@ import { DisposableStore } from '../../../../../base/common/lifecycle.js'; import { IMarkdownRendererService } from '../../../../../platform/markdown/browser/markdownRenderer.js'; import { localize } from '../../../../../nls.js'; import { ICommandService } from '../../../../../platform/commands/common/commands.js'; -import { createWorkbenchDialogOptions } from '../../../../../platform/dialogs/browser/dialog.js'; +import { createWorkbenchDialogOptions } from '../../../../browser/parts/dialogs/dialog.js'; import { IInstantiationService } from '../../../../../platform/instantiation/common/instantiation.js'; import { IKeybindingService } from '../../../../../platform/keybinding/common/keybinding.js'; import { ILayoutService } from '../../../../../platform/layout/browser/layoutService.js'; @@ -30,6 +30,7 @@ import { IChatWidgetService } from '../chat.js'; import { ChatSetupController } from './chatSetupController.js'; import { IChatSetupResult, ChatSetupAnonymous, InstallChatEvent, InstallChatClassification, ChatSetupStrategy, ChatSetupResultValue } from './chatSetup.js'; import { IDefaultAccountService } from '../../../../../platform/defaultAccount/common/defaultAccount.js'; +import { IHostService } from '../../../../services/host/browser/host.js'; const defaultChat = { publicCodeMatchesUrl: product.defaultChatAgent?.publicCodeMatchesUrl ?? '', @@ -48,7 +49,7 @@ export class ChatSetup { let instance = ChatSetup.instance; if (!instance) { instance = ChatSetup.instance = instantiationService.invokeFunction(accessor => { - return new ChatSetup(context, controller, accessor.get(ITelemetryService), accessor.get(IWorkbenchLayoutService), accessor.get(IKeybindingService), accessor.get(IChatEntitlementService) as ChatEntitlementService, accessor.get(ILogService), accessor.get(IChatWidgetService), accessor.get(IWorkspaceTrustRequestService), accessor.get(IMarkdownRendererService), accessor.get(IDefaultAccountService)); + return new ChatSetup(context, controller, accessor.get(ITelemetryService), accessor.get(IWorkbenchLayoutService), accessor.get(IKeybindingService), accessor.get(IChatEntitlementService) as ChatEntitlementService, accessor.get(ILogService), accessor.get(IChatWidgetService), accessor.get(IWorkspaceTrustRequestService), accessor.get(IMarkdownRendererService), accessor.get(IDefaultAccountService), accessor.get(IHostService)); }); } @@ -71,6 +72,7 @@ export class ChatSetup { @IWorkspaceTrustRequestService private readonly workspaceTrustRequestService: IWorkspaceTrustRequestService, @IMarkdownRendererService private readonly markdownRendererService: IMarkdownRendererService, @IDefaultAccountService private readonly defaultAccountService: IDefaultAccountService, + @IHostService private readonly hostService: IHostService ) { } skipDialog(): void { @@ -176,7 +178,7 @@ export class ChatSetup { disableCloseButton: true, renderFooter: footer => footer.appendChild(this.createDialogFooter(disposables, options)), buttonOptions: buttons.map(button => button[2]) - }, this.keybindingService, this.layoutService) + }, this.keybindingService, this.layoutService, this.hostService) )); const { button } = await dialog.show(); diff --git a/src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts b/src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts index 729fc617379..e21db81253e 100644 --- a/src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts +++ b/src/vs/workbench/electron-browser/parts/dialogs/dialog.contribution.ts @@ -6,8 +6,6 @@ import { IClipboardService } from '../../../../platform/clipboard/common/clipboardService.js'; import { IConfigurationService } from '../../../../platform/configuration/common/configuration.js'; import { IDialogHandler, IDialogResult, IDialogService } from '../../../../platform/dialogs/common/dialogs.js'; -import { IKeybindingService } from '../../../../platform/keybinding/common/keybinding.js'; -import { ILayoutService } from '../../../../platform/layout/browser/layoutService.js'; import { ILogService } from '../../../../platform/log/common/log.js'; import { INativeHostService } from '../../../../platform/native/common/native.js'; import { IProductService } from '../../../../platform/product/common/productService.js'; @@ -19,10 +17,8 @@ import { DialogService } from '../../../services/dialogs/common/dialogService.js import { Disposable } from '../../../../base/common/lifecycle.js'; import { IInstantiationService } from '../../../../platform/instantiation/common/instantiation.js'; import { Lazy } from '../../../../base/common/lazy.js'; -import { IOpenerService } from '../../../../platform/opener/common/opener.js'; import { createNativeAboutDialogDetails } from '../../../../platform/dialogs/electron-browser/dialog.js'; import { IWorkbenchEnvironmentService } from '../../../services/environment/common/environmentService.js'; -import { IMarkdownRendererService } from '../../../../platform/markdown/browser/markdownRenderer.js'; export class DialogHandlerContribution extends Disposable implements IWorkbenchContribution { @@ -38,19 +34,15 @@ export class DialogHandlerContribution extends Disposable implements IWorkbenchC @IConfigurationService private configurationService: IConfigurationService, @IDialogService private dialogService: IDialogService, @ILogService logService: ILogService, - @ILayoutService layoutService: ILayoutService, - @IKeybindingService keybindingService: IKeybindingService, @IInstantiationService instantiationService: IInstantiationService, @IProductService private productService: IProductService, @IClipboardService clipboardService: IClipboardService, @INativeHostService private nativeHostService: INativeHostService, @IWorkbenchEnvironmentService private environmentService: IWorkbenchEnvironmentService, - @IOpenerService openerService: IOpenerService, - @IMarkdownRendererService markdownRendererService: IMarkdownRendererService, ) { super(); - this.browserImpl = new Lazy(() => new BrowserDialogHandler(logService, layoutService, keybindingService, instantiationService, clipboardService, openerService, markdownRendererService)); + this.browserImpl = new Lazy(() => instantiationService.createInstance(BrowserDialogHandler)); this.nativeImpl = new Lazy(() => new NativeDialogHandler(logService, nativeHostService, clipboardService)); this.model = (this.dialogService as DialogService).model; diff --git a/src/vs/workbench/services/host/browser/browserHostService.ts b/src/vs/workbench/services/host/browser/browserHostService.ts index de8fda44c33..6038ad8ac94 100644 --- a/src/vs/workbench/services/host/browser/browserHostService.ts +++ b/src/vs/workbench/services/host/browser/browserHostService.ts @@ -577,6 +577,10 @@ export class BrowserHostService extends Disposable implements IHostService { // There seems to be no API to bring a window to front in browsers } + async setWindowDimmed(_targetWindow: Window, _dimmed: boolean): Promise { + // not supported in browser + } + async getCursorScreenPoint(): Promise { return undefined; } diff --git a/src/vs/workbench/services/host/browser/host.ts b/src/vs/workbench/services/host/browser/host.ts index 402d97d4634..c7d300bf3c7 100644 --- a/src/vs/workbench/services/host/browser/host.ts +++ b/src/vs/workbench/services/host/browser/host.ts @@ -105,6 +105,12 @@ export interface IHostService { */ moveTop(targetWindow: Window): Promise; + /** + * Toggle dimming of window control overlays (e.g. when showing + * a modal dialog or modal editor part). + */ + setWindowDimmed(targetWindow: Window, dimmed: boolean): Promise; + /** * Get the location of the mouse cursor and its display bounds or `undefined` if unavailable. */ diff --git a/src/vs/workbench/services/host/electron-browser/nativeHostService.ts b/src/vs/workbench/services/host/electron-browser/nativeHostService.ts index 16defe36aff..3838e3bb4e5 100644 --- a/src/vs/workbench/services/host/electron-browser/nativeHostService.ts +++ b/src/vs/workbench/services/host/electron-browser/nativeHostService.ts @@ -173,6 +173,10 @@ class WorkbenchHostService extends Disposable implements IHostService { return this.nativeHostService.moveWindowTop(isAuxiliaryWindow(targetWindow) ? { targetWindowId: targetWindow.vscodeWindowId } : undefined); } + async setWindowDimmed(targetWindow: Window, dimmed: boolean): Promise { + return this.nativeHostService.updateWindowControls({ dimmed, targetWindowId: getWindowId(targetWindow) }); + } + getCursorScreenPoint(): Promise<{ readonly point: IPoint; readonly display: IRectangle }> { return this.nativeHostService.getCursorScreenPoint(); } diff --git a/src/vs/workbench/services/progress/browser/progressService.ts b/src/vs/workbench/services/progress/browser/progressService.ts index daf34ce8ee1..a03c869f958 100644 --- a/src/vs/workbench/services/progress/browser/progressService.ts +++ b/src/vs/workbench/services/progress/browser/progressService.ts @@ -23,7 +23,8 @@ import { IViewsService } from '../../views/common/viewsService.js'; import { IPaneCompositePartService } from '../../panecomposite/browser/panecomposite.js'; import { stripIcons } from '../../../../base/common/iconLabels.js'; import { IUserActivityService } from '../../userActivity/common/userActivityService.js'; -import { createWorkbenchDialogOptions } from '../../../../platform/dialogs/browser/dialog.js'; +import { createWorkbenchDialogOptions } from '../../../browser/parts/dialogs/dialog.js'; +import { IHostService } from '../../host/browser/host.js'; export class ProgressService extends Disposable implements IProgressService { @@ -39,6 +40,7 @@ export class ProgressService extends Disposable implements IProgressService { @ILayoutService private readonly layoutService: ILayoutService, @IKeybindingService private readonly keybindingService: IKeybindingService, @IUserActivityService private readonly userActivityService: IUserActivityService, + @IHostService private readonly hostService: IHostService, ) { super(); } @@ -567,7 +569,7 @@ export class ProgressService extends Disposable implements IProgressService { cancelId: buttons.length - 1, disableCloseAction: options.sticky, disableDefaultAction: options.sticky - }, this.keybindingService, this.layoutService) + }, this.keybindingService, this.layoutService, this.hostService) ); disposables.add(dialog); diff --git a/src/vs/workbench/test/browser/workbenchTestServices.ts b/src/vs/workbench/test/browser/workbenchTestServices.ts index 0684952209a..a911112cb4a 100644 --- a/src/vs/workbench/test/browser/workbenchTestServices.ts +++ b/src/vs/workbench/test/browser/workbenchTestServices.ts @@ -1379,6 +1379,8 @@ export class TestHostService implements IHostService { async showToast(_options: IToastOptions, token: CancellationToken): Promise { return { supported: false, clicked: false }; } + async setWindowDimmed(_targetWindow: Window, _dimmed: boolean): Promise { } + readonly colorScheme = ColorScheme.DARK; onDidChangeColorScheme = Event.None; }