@@ -101,7 +101,7 @@ export class Ext extends Ecs.System<ExtEvent> {
101101 row_size : number = 32 ;
102102
103103 /** The known display configuration, for tracking monitor removals and changes */
104- displays : Map < number , Display > = new Map ( ) ;
104+ displays : [ number , Map < number , Display > ] = [ global . display . get_primary_monitor ( ) , new Map ( ) ] ;
105105
106106 /** The current scaling factor in GNOME Shell */
107107 dpi : number = St . ThemeContext . get_for_stage ( global . stage ) . scale_factor ;
@@ -145,6 +145,8 @@ export class Ext extends Ecs.System<ExtEvent> {
145145
146146 was_locked : boolean = false ;
147147
148+ private workareas_update : null | SignalID = null
149+
148150 /** Record of misc. global objects and their attached signals */
149151 private signals : Map < GObject . Object , Array < SignalID > > = new Map ( ) ;
150152
@@ -542,30 +544,48 @@ export class Ext extends Ecs.System<ExtEvent> {
542544
543545 find_monitor_to_retach ( width : number , height : number ) : [ number , Display ] {
544546 if ( ! this . settings . workspaces_only_on_primary ( ) ) {
545- for ( const [ index , display ] of this . displays ) {
547+ for ( const [ index , display ] of this . displays [ 1 ] ) {
546548 if ( display . area . width == width && display . area . height == height ) {
547549 return [ index , display ] ;
548550 }
549551 }
550552 }
551553
552554 const primary = display . get_primary_monitor ( ) ;
553- return [ primary , this . displays . get ( primary ) as Display ] ;
555+ return [ primary , this . displays [ 1 ] . get ( primary ) as Display ] ;
554556 }
555557
556558 find_unused_workspace ( monitor : number ) : [ number , any ] {
557559 if ( ! this . auto_tiler ) return [ 0 , wom . get_workspace_by_index ( 0 ) ]
558560
559561 let id = 0
560562
561- for ( const fork of this . auto_tiler . forest . forks . values ( ) ) {
562- if ( fork . monitor === monitor && id < fork . workspace ) id = fork . workspace
563+ const tiled_windows = new Array < Window . ShellWindow > ( )
564+
565+ for ( const [ window ] of this . auto_tiler . attached . iter ( ) ) {
566+ if ( ! this . auto_tiler . attached . contains ( window ) ) continue
567+
568+ const win = this . windows . get ( window )
569+
570+ if ( win && ! win . reassignment && win . meta . get_monitor ( ) === monitor ) tiled_windows . push ( win )
571+ }
572+
573+ cancel:
574+ while ( true ) {
575+ for ( const window of tiled_windows ) {
576+ if ( window . workspace_id ( ) === id ) {
577+ id += 1
578+ continue cancel
579+ }
580+ }
581+
582+ break
563583 }
564584
565- id += 1
566585 let new_work
567586
568- if ( id === wom . get_n_workspaces ( ) ) {
587+ if ( id + 1 === wom . get_n_workspaces ( ) ) {
588+ id += 1
569589 new_work = wom . append_new_workspace ( true , global . get_current_time ( ) )
570590 } else {
571591 new_work = wom . get_workspace_by_index ( id )
@@ -599,7 +619,7 @@ export class Ext extends Ecs.System<ExtEvent> {
599619 }
600620
601621 monitor_work_area ( monitor : number ) : Rectangle {
602- const meta = display . get_workspace_manager ( )
622+ const meta = wom
603623 . get_active_workspace ( )
604624 . get_work_area_for_monitor ( monitor ) ;
605625
@@ -1458,7 +1478,7 @@ export class Ext extends Ecs.System<ExtEvent> {
14581478 return true ;
14591479 } ) ;
14601480
1461- const workspace_manager = display . get_workspace_manager ( ) ;
1481+ const workspace_manager = wom ;
14621482
14631483 for ( const [ , ws ] of iter_workspaces ( workspace_manager ) ) {
14641484 let index = ws . index ( ) ;
@@ -1794,7 +1814,7 @@ export class Ext extends Ecs.System<ExtEvent> {
17941814 }
17951815 }
17961816
1797- update_display_configuration ( _workareas_only : boolean ) {
1817+ update_display_configuration ( workareas_only : boolean ) {
17981818 if ( ! this . auto_tiler || sessionMode . isLocked ) return
17991819
18001820 if ( this . ignore_display_update ) {
@@ -1805,7 +1825,49 @@ export class Ext extends Ecs.System<ExtEvent> {
18051825 // Ignore the update if there are no monitors to assign to
18061826 if ( layoutManager . monitors . length === 0 ) return
18071827
1808- if ( this . displays_updating !== null ) GLib . source_remove ( this . displays_updating )
1828+ const primary_display = global . display . get_primary_monitor ( )
1829+
1830+ const primary_display_ready = ( ext : Ext ) : boolean => {
1831+ const area = global . display . get_monitor_geometry ( primary_display )
1832+ const work_area = ext . monitor_work_area ( primary_display )
1833+
1834+ if ( ! area || ! work_area ) return false
1835+
1836+ return ! ( area . width === work_area . width && area . height === work_area . height )
1837+ }
1838+
1839+ function displays_ready ( ) : boolean {
1840+ const monitors = global . display . get_n_monitors ( )
1841+
1842+ if ( monitors === 0 ) return false
1843+
1844+ for ( let i = 0 ; i < monitors ; i += 1 ) {
1845+ const display = global . display . get_monitor_geometry ( i )
1846+
1847+ if ( ! display ) return false
1848+
1849+ if ( display . width < 1 || display . height < 1 ) return false
1850+ }
1851+
1852+ return true
1853+ }
1854+
1855+ if ( ! displays_ready ( ) || ! primary_display_ready ( this ) ) {
1856+ if ( this . displays_updating !== null ) return
1857+ if ( this . workareas_update !== null ) GLib . source_remove ( this . workareas_update )
1858+
1859+ this . workareas_update = GLib . timeout_add ( GLib . PRIORITY_DEFAULT , 500 , ( ) => {
1860+ this . register_fn ( ( ) => {
1861+ this . update_display_configuration ( workareas_only )
1862+ } )
1863+
1864+ this . workareas_update = null
1865+
1866+ return false
1867+ } )
1868+
1869+ return
1870+ }
18091871
18101872 // Update every tree on each display with the new dimensions
18111873 const update_tiling = ( ) => {
@@ -1814,28 +1876,82 @@ export class Ext extends Ecs.System<ExtEvent> {
18141876 for ( const f of this . auto_tiler . forest . forks . values ( ) ) {
18151877 if ( ! f . is_toplevel ) continue
18161878
1817- const display = this . displays . get ( f . monitor ) ;
1879+ const display = this . monitor_work_area ( f . monitor )
18181880
18191881 if ( display ) {
1820- f . set_area ( display . ws )
1882+ const area = new Rect . Rectangle ( [ display . x , display . y , display . width , display . height ] )
1883+
1884+ f . smart_gapped = false
1885+ f . set_area ( area . clone ( ) ) ;
18211886 this . auto_tiler . update_toplevel ( this , f , f . monitor , this . settings . smart_gaps ( ) ) ;
18221887 }
18231888 }
18241889 }
18251890
1826- let updated = new Map ( )
1827- let changes = new Map ( )
1891+ let migrations : Array < [ Fork , number , Rectangle , boolean ] > = new Array ( )
1892+
1893+ const apply_migrations = ( assigned_monitors : Set < number > ) => {
1894+ if ( ! migrations ) return
1895+
1896+ const iterator = migrations [ Symbol . iterator ] ( )
1897+
1898+ GLib . timeout_add ( GLib . PRIORITY_LOW , 500 , ( ) => {
1899+ let next : null | [ Fork , number , Rectangle , boolean ] = iterator . next ( ) . value ;
1900+
1901+ if ( next ) {
1902+ const [ fork , new_monitor , workspace , find_workspace ] = next
1903+ let new_workspace
1904+
1905+ if ( find_workspace ) {
1906+ if ( assigned_monitors . has ( new_monitor ) ) {
1907+ [ new_workspace ] = this . find_unused_workspace ( new_monitor )
1908+ } else {
1909+ assigned_monitors . add ( new_monitor )
1910+ new_workspace = 0
1911+ }
1912+ } else {
1913+ new_workspace = fork . workspace
1914+ }
1915+
1916+ fork . migrate ( this , forest , workspace , new_monitor , new_workspace ) ;
1917+ fork . set_ratio ( fork . length ( ) / 2 )
1918+
1919+ return true
1920+ }
1921+
1922+ update_tiling ( )
1923+
1924+ return false
1925+ } )
1926+ }
1927+
1928+ function mark_for_reassignment ( ext : Ext , fork : Ecs . Entity ) {
1929+ for ( const win of forest . iter ( fork , node . NodeKind . WINDOW ) ) {
1930+ if ( win . inner . kind === 2 ) {
1931+ const entity = win . inner . entity
1932+ const window = ext . windows . get ( entity )
1933+ if ( window ) window . reassignment = true
1934+ }
1935+ }
1936+ }
1937+
1938+ const [ old_primary , old_displays ] = this . displays
1939+
1940+ const changes = new Map < number , number > ( )
18281941
18291942 // Records which display's windows were moved to what new display's ID
18301943 for ( const [ entity , w ] of this . windows . iter ( ) ) {
18311944 if ( ! w . actor_exists ( ) ) continue
18321945
18331946 this . monitors . with ( entity , ( [ mon , ] ) => {
1834- changes . set ( mon , w . meta . get_monitor ( ) )
1947+ const assignment = mon === old_primary ? primary_display : w . meta . get_monitor ( )
1948+ changes . set ( mon , assignment )
18351949 } )
18361950 }
18371951
18381952 // Fetch a new list of monitors
1953+ const updated = new Map ( )
1954+
18391955 for ( const monitor of layoutManager . monitors ) {
18401956 const mon = monitor as Monitor
18411957
@@ -1845,44 +1961,39 @@ export class Ext extends Ecs.System<ExtEvent> {
18451961 updated . set ( mon . index , { area, ws } )
18461962 }
18471963
1848- function compare_maps < K , V > ( map1 : Map < K , V > , map2 : Map < K , V > ) {
1849- if ( map1 . size !== map2 . size ) {
1850- return false
1851- }
1964+ const forest = this . auto_tiler . forest
18521965
1853- let cmp
1966+ if ( old_displays . size === updated . size ) {
1967+ update_tiling ( )
18541968
1855- for ( let [ key , val ] of map1 ) {
1856- cmp = map2 . get ( key )
1857- if ( cmp !== val || ( cmp === undefined && ! map2 . has ( key ) ) ) {
1858- return false
1859- }
1860- }
1969+ this . displays = [ primary_display , updated ]
1970+
1971+ return
1972+ }
18611973
1862- return true
1974+ this . displays = [ primary_display , updated ]
1975+
1976+ if ( utils . map_eq ( old_displays , updated ) ) {
1977+ return
1978+ }
1979+
1980+ if ( this . displays_updating !== null ) GLib . source_remove ( this . displays_updating )
1981+
1982+ if ( this . workareas_update !== null ) {
1983+ GLib . source_remove ( this . workareas_update )
1984+ this . workareas_update = null
18631985 }
18641986
1865- // Delay actions until 3 seconds later, in case of temporary connection loss
1987+ // Delay actions in case of temporary connection loss
18661988 this . displays_updating = GLib . timeout_add ( GLib . PRIORITY_DEFAULT , 2000 , ( ) => {
18671989 ( ( ) => {
18681990 if ( ! this . auto_tiler ) return
18691991
1870- if ( compare_maps ( this . displays , updated ) ) {
1871- return
1872- }
1873-
1874- this . displays = updated
1875-
1876- const forest = this . auto_tiler . forest
1877-
1878- let migrations : Array < [ Fork , number , Rectangle , boolean ] > = new Array ( )
1879- let toplevels = new Array ( )
1880- let assigned_monitors = new Set ( )
1992+ const toplevels = new Array ( )
1993+ const assigned_monitors = new Set < number > ( )
18811994
18821995 for ( const [ old_mon , new_mon ] of changes ) {
1883- if ( old_mon === new_mon ) {
1884- assigned_monitors . add ( new_mon )
1885- }
1996+ if ( old_mon === new_mon ) assigned_monitors . add ( new_mon )
18861997 }
18871998
18881999 for ( const f of forest . forks . values ( ) ) {
@@ -1891,61 +2002,35 @@ export class Ext extends Ecs.System<ExtEvent> {
18912002
18922003 let migration : null | [ Fork , number , Rectangle , boolean ] = null ;
18932004
1894- for ( const [ old_monitor , new_monitor ] of changes ) {
1895- if ( old_monitor === new_monitor ) continue
2005+ const displays = this . displays [ 1 ]
18962006
1897- if ( f . monitor === old_monitor ) {
1898- const display = this . displays . get ( new_monitor )
2007+ for ( const [ old_monitor , new_monitor ] of changes ) {
2008+ const display = displays . get ( new_monitor )
18992009
1900- if ( display ) {
1901- f . monitor = new_monitor
1902- f . workspace = 0
1903- migration = [ f , new_monitor , display . ws , true ]
1904- }
2010+ if ( ! display ) continue
19052011
1906- break
2012+ if ( f . monitor === old_monitor ) {
2013+ f . monitor = new_monitor
2014+ f . workspace = 0
2015+ migration = [ f , new_monitor , display . ws , true ]
19072016 }
19082017 }
19092018
19102019 if ( ! migration ) {
1911- const display = this . displays . get ( f . monitor )
2020+ const display = displays . get ( f . monitor )
19122021 if ( display ) {
19132022 migration = [ f , f . monitor , display . ws , false ]
19142023 }
19152024 }
19162025
1917- if ( migration ) migrations . push ( migration )
1918- }
1919- }
1920-
1921- let iterator = migrations [ Symbol . iterator ] ( )
1922-
1923- GLib . timeout_add ( GLib . PRIORITY_LOW , 500 , ( ) => {
1924- let next : null | [ Fork , number , Rectangle , boolean ] = iterator . next ( ) . value ;
1925-
1926- if ( next ) {
1927- const [ fork , new_monitor , workspace , find_workspace ] = next
1928- let new_workspace
1929-
1930- if ( find_workspace ) {
1931- if ( assigned_monitors . has ( new_monitor ) ) {
1932- [ new_workspace ] = this . find_unused_workspace ( new_monitor )
1933- } else {
1934- assigned_monitors . add ( new_monitor )
1935- new_workspace = 0
1936- }
1937- } else {
1938- new_workspace = fork . workspace
2026+ if ( migration ) {
2027+ mark_for_reassignment ( this , migration [ 0 ] . entity )
2028+ migrations . push ( migration )
19392029 }
1940-
1941- fork . migrate ( this , forest , workspace , new_monitor , new_workspace ) ;
1942- return true
19432030 }
2031+ }
19442032
1945- update_tiling ( )
1946-
1947- return false
1948- } )
2033+ apply_migrations ( assigned_monitors )
19492034
19502035 return
19512036 } ) ( )
@@ -2053,7 +2138,7 @@ export class Ext extends Ecs.System<ExtEvent> {
20532138
20542139 /** Fetch a workspace by its index */
20552140 workspace_by_id ( id : number ) : Meta . Workspace | null {
2056- return display . get_workspace_manager ( ) . get_workspace_by_index ( id ) ;
2141+ return wom . get_workspace_by_index ( id ) ;
20572142 }
20582143
20592144 workspace_id ( window : Window . ShellWindow | null = null ) : [ number , number ] {
0 commit comments