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