@@ -33,7 +33,7 @@ import { ITelemetryService } from 'vs/platform/telemetry/common/telemetry';
33
33
import { ThemeIcon } from 'vs/base/common/themables' ;
34
34
import { IThemeMainService } from 'vs/platform/theme/electron-main/themeMainService' ;
35
35
import { getMenuBarVisibility , IFolderToOpen , INativeWindowConfiguration , IWindowSettings , IWorkspaceToOpen , MenuBarVisibility , hasNativeTitlebar , useNativeFullScreen , useWindowControlsOverlay } from 'vs/platform/window/common/window' ;
36
- import { defaultBrowserWindowOptions , IWindowsMainService , OpenContext } from 'vs/platform/windows/electron-main/windows' ;
36
+ import { defaultBrowserWindowOptions , IWindowsMainService , OpenContext , WindowStateValidator } from 'vs/platform/windows/electron-main/windows' ;
37
37
import { ISingleFolderWorkspaceIdentifier , IWorkspaceIdentifier , isSingleFolderWorkspaceIdentifier , isWorkspaceIdentifier , toWorkspaceIdentifier } from 'vs/platform/workspace/common/workspace' ;
38
38
import { IWorkspacesManagementMainService } from 'vs/platform/workspaces/electron-main/workspacesManagementMainService' ;
39
39
import { IWindowState , ICodeWindow , ILoadEvent , WindowMode , WindowError , LoadReason , defaultWindowState , IBaseWindow } from 'vs/platform/window/electron-main/window' ;
@@ -1259,7 +1259,7 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
1259
1259
const displays = screen . getAllDisplays ( ) ;
1260
1260
hasMultipleDisplays = displays . length > 1 ;
1261
1261
1262
- state = this . validateWindowState ( state , displays ) ;
1262
+ state = WindowStateValidator . validateWindowState ( this . logService , state , displays ) ;
1263
1263
} catch ( err ) {
1264
1264
this . logService . warn ( `Unexpected error validating window state: ${ err } \n${ err . stack } ` ) ; // somehow display API can be picky about the state to validate
1265
1265
}
@@ -1270,148 +1270,6 @@ export class CodeWindow extends BaseWindow implements ICodeWindow {
1270
1270
return [ state || defaultWindowState ( ) , hasMultipleDisplays ] ;
1271
1271
}
1272
1272
1273
- private validateWindowState ( state : IWindowState , displays : Display [ ] ) : IWindowState | undefined {
1274
- this . logService . trace ( `window#validateWindowState: validating window state on ${ displays . length } display(s)` , state ) ;
1275
-
1276
- if (
1277
- typeof state . x !== 'number' ||
1278
- typeof state . y !== 'number' ||
1279
- typeof state . width !== 'number' ||
1280
- typeof state . height !== 'number'
1281
- ) {
1282
- this . logService . trace ( 'window#validateWindowState: unexpected type of state values' ) ;
1283
-
1284
- return undefined ;
1285
- }
1286
-
1287
- if ( state . width <= 0 || state . height <= 0 ) {
1288
- this . logService . trace ( 'window#validateWindowState: unexpected negative values' ) ;
1289
-
1290
- return undefined ;
1291
- }
1292
-
1293
- // Single Monitor: be strict about x/y positioning
1294
- // macOS & Linux: these OS seem to be pretty good in ensuring that a window is never outside of it's bounds.
1295
- // Windows: it is possible to have a window with a size that makes it fall out of the window. our strategy
1296
- // is to try as much as possible to keep the window in the monitor bounds. we are not as strict as
1297
- // macOS and Linux and allow the window to exceed the monitor bounds as long as the window is still
1298
- // some pixels (128) visible on the screen for the user to drag it back.
1299
- if ( displays . length === 1 ) {
1300
- const displayWorkingArea = this . getWorkingArea ( displays [ 0 ] ) ;
1301
- if ( displayWorkingArea ) {
1302
- this . logService . trace ( 'window#validateWindowState: 1 monitor working area' , displayWorkingArea ) ;
1303
-
1304
- function ensureStateInDisplayWorkingArea ( ) : void {
1305
- if ( ! state || typeof state . x !== 'number' || typeof state . y !== 'number' || ! displayWorkingArea ) {
1306
- return ;
1307
- }
1308
-
1309
- if ( state . x < displayWorkingArea . x ) {
1310
- // prevent window from falling out of the screen to the left
1311
- state . x = displayWorkingArea . x ;
1312
- }
1313
-
1314
- if ( state . y < displayWorkingArea . y ) {
1315
- // prevent window from falling out of the screen to the top
1316
- state . y = displayWorkingArea . y ;
1317
- }
1318
- }
1319
-
1320
- // ensure state is not outside display working area (top, left)
1321
- ensureStateInDisplayWorkingArea ( ) ;
1322
-
1323
- if ( state . width > displayWorkingArea . width ) {
1324
- // prevent window from exceeding display bounds width
1325
- state . width = displayWorkingArea . width ;
1326
- }
1327
-
1328
- if ( state . height > displayWorkingArea . height ) {
1329
- // prevent window from exceeding display bounds height
1330
- state . height = displayWorkingArea . height ;
1331
- }
1332
-
1333
- if ( state . x > ( displayWorkingArea . x + displayWorkingArea . width - 128 ) ) {
1334
- // prevent window from falling out of the screen to the right with
1335
- // 128px margin by positioning the window to the far right edge of
1336
- // the screen
1337
- state . x = displayWorkingArea . x + displayWorkingArea . width - state . width ;
1338
- }
1339
-
1340
- if ( state . y > ( displayWorkingArea . y + displayWorkingArea . height - 128 ) ) {
1341
- // prevent window from falling out of the screen to the bottom with
1342
- // 128px margin by positioning the window to the far bottom edge of
1343
- // the screen
1344
- state . y = displayWorkingArea . y + displayWorkingArea . height - state . height ;
1345
- }
1346
-
1347
- // again ensure state is not outside display working area
1348
- // (it may have changed from the previous validation step)
1349
- ensureStateInDisplayWorkingArea ( ) ;
1350
- }
1351
-
1352
- return state ;
1353
- }
1354
-
1355
- // Multi Montior (fullscreen): try to find the previously used display
1356
- if ( state . display && state . mode === WindowMode . Fullscreen ) {
1357
- const display = displays . find ( d => d . id === state . display ) ;
1358
- if ( display && typeof display . bounds ?. x === 'number' && typeof display . bounds ?. y === 'number' ) {
1359
- this . logService . trace ( 'window#validateWindowState: restoring fullscreen to previous display' ) ;
1360
-
1361
- const defaults = defaultWindowState ( WindowMode . Fullscreen ) ; // make sure we have good values when the user restores the window
1362
- defaults . x = display . bounds . x ; // carefull to use displays x/y position so that the window ends up on the correct monitor
1363
- defaults . y = display . bounds . y ;
1364
-
1365
- return defaults ;
1366
- }
1367
- }
1368
-
1369
- // Multi Monitor (non-fullscreen): ensure window is within display bounds
1370
- let display : Display | undefined ;
1371
- let displayWorkingArea : Rectangle | undefined ;
1372
- try {
1373
- display = screen . getDisplayMatching ( { x : state . x , y : state . y , width : state . width , height : state . height } ) ;
1374
- displayWorkingArea = this . getWorkingArea ( display ) ;
1375
- } catch ( error ) {
1376
- // Electron has weird conditions under which it throws errors
1377
- // e.g. https://github.com/microsoft/vscode/issues/100334 when
1378
- // large numbers are passed in
1379
- }
1380
-
1381
- if (
1382
- display && // we have a display matching the desired bounds
1383
- displayWorkingArea && // we have valid working area bounds
1384
- state . x + state . width > displayWorkingArea . x && // prevent window from falling out of the screen to the left
1385
- state . y + state . height > displayWorkingArea . y && // prevent window from falling out of the screen to the top
1386
- state . x < displayWorkingArea . x + displayWorkingArea . width && // prevent window from falling out of the screen to the right
1387
- state . y < displayWorkingArea . y + displayWorkingArea . height // prevent window from falling out of the screen to the bottom
1388
- ) {
1389
- this . logService . trace ( 'window#validateWindowState: multi-monitor working area' , displayWorkingArea ) ;
1390
-
1391
- return state ;
1392
- }
1393
-
1394
- return undefined ;
1395
- }
1396
-
1397
- private getWorkingArea ( display : Display ) : Rectangle | undefined {
1398
-
1399
- // Prefer the working area of the display to account for taskbars on the
1400
- // desktop being positioned somewhere (https://github.com/microsoft/vscode/issues/50830).
1401
- //
1402
- // Linux X11 sessions sometimes report wrong display bounds, so we validate
1403
- // the reported sizes are positive.
1404
- if ( display . workArea . width > 0 && display . workArea . height > 0 ) {
1405
- return display . workArea ;
1406
- }
1407
-
1408
- if ( display . bounds . width > 0 && display . bounds . height > 0 ) {
1409
- return display . bounds ;
1410
- }
1411
-
1412
- return undefined ;
1413
- }
1414
-
1415
1273
getBounds ( ) : Rectangle {
1416
1274
const [ x , y ] = this . _win . getPosition ( ) ;
1417
1275
const [ width , height ] = this . _win . getSize ( ) ;
0 commit comments