@@ -109,6 +109,77 @@ pub struct CosmicStackInternal {
109
109
}
110
110
111
111
impl CosmicStackInternal {
112
+ pub fn set_previous_index ( & self , moved_into : Option < & Seat < State > > ) -> Option < usize > {
113
+ let last_mod_serial = moved_into. and_then ( |seat| seat. last_modifier_change ( ) ) ;
114
+ let mut prev_idx = self . previous_index . lock ( ) . unwrap ( ) ;
115
+ if !prev_idx. is_some_and ( |( serial, _) | Some ( serial) == last_mod_serial) {
116
+ * prev_idx = last_mod_serial. map ( |s| ( s, self . active . load ( Ordering :: SeqCst ) ) ) ;
117
+ }
118
+ prev_idx. map ( |( _, idx) | idx)
119
+ }
120
+
121
+ #[ must_use]
122
+ pub fn add_window ( & self , idx : Option < usize > , window : CosmicSurface ) -> Message {
123
+ window. send_configure ( ) ;
124
+ self . scroll_to_focus . store ( true , Ordering :: SeqCst ) ;
125
+ let model = tab:: Model :: from ( & window) ;
126
+ let mut windows = self . windows . lock ( ) . unwrap ( ) ;
127
+ if let Some ( idx) = idx {
128
+ windows. insert ( idx, window) ;
129
+ let prev_active = self . active . swap ( idx, Ordering :: SeqCst ) ;
130
+ if prev_active == idx {
131
+ self . reenter . store ( true , Ordering :: SeqCst ) ;
132
+ self . previous_keyboard . store ( prev_active, Ordering :: SeqCst ) ;
133
+ }
134
+
135
+ Message :: TabInsert ( idx, model)
136
+ } else {
137
+ windows. push ( window) ;
138
+ self . active . store ( windows. len ( ) - 1 , Ordering :: SeqCst ) ;
139
+ Message :: TabAdd ( model)
140
+ }
141
+ }
142
+
143
+ #[ must_use]
144
+ pub fn remove_window ( & self , idx : usize ) -> Option < CosmicSurface > {
145
+ let mut windows = self . windows . lock ( ) . unwrap ( ) ;
146
+
147
+ if windows. len ( ) == 1 {
148
+ self . override_alive . store ( false , Ordering :: SeqCst ) ;
149
+ let window = & windows[ 0 ] ;
150
+ window. try_force_undecorated ( false ) ;
151
+ window. set_tiled ( false ) ;
152
+ return None ;
153
+ }
154
+
155
+ if windows. len ( ) <= idx {
156
+ return None ;
157
+ }
158
+
159
+ if idx == self . active . load ( Ordering :: SeqCst ) {
160
+ self . reenter . store ( true , Ordering :: SeqCst ) ;
161
+ }
162
+
163
+ let window = windows. remove ( idx) ;
164
+ window. try_force_undecorated ( false ) ;
165
+ window. set_tiled ( false ) ;
166
+
167
+ _ = self
168
+ . active
169
+ . fetch_update ( Ordering :: SeqCst , Ordering :: SeqCst , |active| {
170
+ if active == idx {
171
+ self . scroll_to_focus . store ( true , Ordering :: SeqCst ) ;
172
+ Some ( windows. len ( ) - 1 )
173
+ } else if idx < active {
174
+ Some ( active - 1 )
175
+ } else {
176
+ None
177
+ }
178
+ } ) ;
179
+
180
+ Some ( window)
181
+ }
182
+
112
183
pub fn swap_focus ( & self , focus : Option < Focus > ) -> Option < Focus > {
113
184
let value = focus. map_or ( 0 , |x| x as u8 ) ;
114
185
unsafe { Focus :: from_u8 ( self . pointer_entered . swap ( value, Ordering :: SeqCst ) ) }
@@ -180,90 +251,59 @@ impl CosmicStack {
180
251
let window = window. into ( ) ;
181
252
window. try_force_undecorated ( true ) ;
182
253
window. set_tiled ( true ) ;
183
- self . 0 . with_program ( |p| {
184
- let last_mod_serial = moved_into. and_then ( |seat| seat. last_modifier_change ( ) ) ;
185
- let mut prev_idx = p. previous_index . lock ( ) . unwrap ( ) ;
186
- if !prev_idx. is_some_and ( |( serial, _) | Some ( serial) == last_mod_serial) {
187
- * prev_idx = last_mod_serial. map ( |s| ( s, p. active . load ( Ordering :: SeqCst ) ) ) ;
188
- }
254
+ let message = self . 0 . with_program ( |p| {
255
+ p. set_previous_index ( moved_into) ;
189
256
190
257
if let Some ( mut geo) = p. geometry . lock ( ) . unwrap ( ) . clone ( ) {
191
258
geo. loc . y += TAB_HEIGHT ;
192
259
geo. size . h -= TAB_HEIGHT ;
193
260
window. set_geometry ( geo, TAB_HEIGHT as u32 ) ;
194
261
}
195
- window. send_configure ( ) ;
196
- if let Some ( idx) = idx {
197
- p. windows . lock ( ) . unwrap ( ) . insert ( idx, window) ;
198
- let old_idx = p. active . swap ( idx, Ordering :: SeqCst ) ;
199
- if old_idx == idx {
200
- p. reenter . store ( true , Ordering :: SeqCst ) ;
201
- p. previous_keyboard . store ( old_idx, Ordering :: SeqCst ) ;
202
- }
203
- } else {
204
- let mut windows = p. windows . lock ( ) . unwrap ( ) ;
205
- windows. push ( window) ;
206
- p. active . store ( windows. len ( ) - 1 , Ordering :: SeqCst ) ;
207
- }
208
- p. scroll_to_focus . store ( true , Ordering :: SeqCst ) ;
262
+
263
+ p. add_window ( idx, window)
209
264
} ) ;
265
+
266
+ self . 0 . queue_message ( message) ;
210
267
self . 0
211
268
. resize ( Size :: from ( ( self . active ( ) . geometry ( ) . size . w , TAB_HEIGHT ) ) ) ;
212
- self . 0 . force_redraw ( )
213
269
}
214
270
215
271
pub fn remove_window ( & self , window : & CosmicSurface ) {
216
- self . 0 . with_program ( |p| {
217
- let mut windows = p. windows . lock ( ) . unwrap ( ) ;
218
- if windows. len ( ) == 1 {
219
- p. override_alive . store ( false , Ordering :: SeqCst ) ;
220
- let window = windows. get ( 0 ) . unwrap ( ) ;
221
- window. try_force_undecorated ( false ) ;
222
- window. set_tiled ( false ) ;
223
- return ;
224
- }
272
+ let message = self . 0 . with_program ( |p| {
273
+ let windows = p. windows . lock ( ) . unwrap ( ) ;
274
+ let idx = windows. iter ( ) . position ( |w| w == window) ?;
275
+ drop ( windows) ;
276
+ p. remove_window ( idx)
277
+ . is_some ( )
278
+ . then ( || Message :: TabRemove ( idx) )
279
+ } ) ;
225
280
226
- let Some ( idx) = windows. iter ( ) . position ( |w| w == window) else {
227
- return ;
228
- } ;
229
- if idx == p. active . load ( Ordering :: SeqCst ) {
230
- p. reenter . store ( true , Ordering :: SeqCst ) ;
231
- }
232
- let window = windows. remove ( idx) ;
233
- window. try_force_undecorated ( false ) ;
234
- window. set_tiled ( false ) ;
281
+ if let Some ( message) = message {
282
+ self . 0 . queue_message ( message) ;
283
+ }
235
284
236
- p. active . fetch_min ( windows. len ( ) - 1 , Ordering :: SeqCst ) ;
237
- } ) ;
238
285
self . 0
239
286
. resize ( Size :: from ( ( self . active ( ) . geometry ( ) . size . w , TAB_HEIGHT ) ) ) ;
240
287
self . 0 . force_redraw ( )
241
288
}
242
289
243
290
pub fn remove_idx ( & self , idx : usize ) -> Option < CosmicSurface > {
244
- let window = self . 0 . with_program ( |p| {
245
- let mut windows = p. windows . lock ( ) . unwrap ( ) ;
246
- if windows. len ( ) == 1 {
247
- p. override_alive . store ( false , Ordering :: SeqCst ) ;
248
- let window = windows. get ( 0 ) . unwrap ( ) ;
249
- window. try_force_undecorated ( false ) ;
250
- window. set_tiled ( false ) ;
251
- return Some ( window. clone ( ) ) ;
252
- }
253
- if windows. len ( ) <= idx {
254
- return None ;
255
- }
256
- if idx == p. active . load ( Ordering :: SeqCst ) {
257
- p. reenter . store ( true , Ordering :: SeqCst ) ;
291
+ let ( message, window) = self . 0 . with_program ( |p| match p. remove_window ( idx) {
292
+ Some ( window) => ( Some ( Message :: TabRemove ( idx) ) , Some ( window) ) ,
293
+ None => {
294
+ let windows = p. windows . lock ( ) . unwrap ( ) ;
295
+ if windows. len ( ) == 1 {
296
+ ( None , Some ( windows[ 0 ] . clone ( ) ) )
297
+ } else {
298
+ ( None , None )
299
+ }
258
300
}
259
- let window = windows. remove ( idx) ;
260
- window. try_force_undecorated ( false ) ;
261
- window. set_tiled ( false ) ;
301
+ } ) ;
262
302
263
- p. active . fetch_min ( windows. len ( ) - 1 , Ordering :: SeqCst ) ;
303
+ if let Some ( message) = message {
304
+ self . 0 . queue_message ( message) ;
305
+ }
264
306
265
- Some ( window)
266
- } ) ;
267
307
self . 0
268
308
. resize ( Size :: from ( ( self . active ( ) . geometry ( ) . size . w , TAB_HEIGHT ) ) ) ;
269
309
self . 0 . force_redraw ( ) ;
@@ -445,6 +485,7 @@ impl CosmicStack {
445
485
} ) ;
446
486
447
487
if !matches ! ( result, MoveResult :: Default ) {
488
+ self . 0 . queue_message ( Message :: Refresh ) ;
448
489
self . 0
449
490
. resize ( Size :: from ( ( self . active ( ) . geometry ( ) . size . w , TAB_HEIGHT ) ) ) ;
450
491
}
@@ -789,11 +830,15 @@ impl CosmicStack {
789
830
}
790
831
}
791
832
792
- #[ derive( Debug , Clone , Copy ) ]
833
+ #[ derive( Debug , Clone ) ]
793
834
pub enum Message {
794
835
DragStart ,
795
836
Menu ,
837
+ TabAdd ( tab:: Model ) ,
796
838
TabMenu ( usize ) ,
839
+ TabInsert ( usize , tab:: Model ) ,
840
+ TabRemove ( usize ) ,
841
+ TabSwap ( usize , usize ) ,
797
842
PotentialTabDragStart ( usize ) ,
798
843
Activate ( usize ) ,
799
844
Close ( usize ) ,
@@ -964,6 +1009,28 @@ impl Program for CosmicStackInternal {
964
1009
}
965
1010
}
966
1011
}
1012
+ Message :: TabAdd ( model) => {
1013
+ let mut tab_models = Vec :: with_capacity ( self . tab_models . len ( ) + 1 ) ;
1014
+ tab_models. extend_from_slice ( & self . tab_models ) ;
1015
+ tab_models. push ( model) ;
1016
+ self . tab_models = tab_models. into ( )
1017
+ }
1018
+ Message :: TabInsert ( idx, model) => {
1019
+ let mut tab_models = Vec :: with_capacity ( self . tab_models . len ( ) + 1 ) ;
1020
+ tab_models. extend_from_slice ( & self . tab_models ) ;
1021
+ tab_models. insert ( idx, model) ;
1022
+ self . tab_models = tab_models. into ( )
1023
+ }
1024
+ Message :: TabRemove ( idx) => {
1025
+ let mut tab_models = Vec :: from ( self . tab_models . as_ref ( ) ) ;
1026
+ _ = tab_models. remove ( idx) ;
1027
+ self . tab_models = tab_models. into ( ) ;
1028
+ }
1029
+ Message :: TabSwap ( from, to) => {
1030
+ let mut tab_models = Vec :: from ( self . tab_models . as_ref ( ) ) ;
1031
+ tab_models. swap ( from, to) ;
1032
+ self . tab_models = tab_models. into ( ) ;
1033
+ }
967
1034
Message :: TabMenu ( idx) => {
968
1035
if let Some ( ( seat, serial) ) = last_seat. cloned ( ) {
969
1036
if let Some ( surface) = self . windows . lock ( ) . unwrap ( ) [ idx]
0 commit comments