1use alloc::string::String;
58use alloc::vec::Vec;
59
60use super::consts::*;
61use super::keys::*;
62use super::{Sp, Ui};
63
64pub const DWF_NOCLOSE: u32 = 1;
66pub const DWF_NOMIN: u32 = 2;
68pub const DWF_NOMAX: u32 = 4;
70pub const DWF_FIXED: u32 = 8;
72pub const DWF_MAXIMIZED: u32 = 16;
74pub const DWF_NOTASK: u32 = 32;
76pub const DW_MAX: u32 = 1;
78pub const DW_MIN: u32 = 2;
80pub const DW_LEFT: u32 = 4;
83pub const DW_RIGHT: u32 = 8;
84pub const DTB_ICONS: u32 = 1;
86
87const DEF_W: i32 = 400; const DEF_H: i32 = 280;
90const MIN_W: i32 = 160; const MIN_H: i32 = 96;
92const CASCADE: i32 = 28;
93const KEEP: i32 = 64; const MAGNET: i32 = 10; const ZONE: i32 = 4; const GRIP_OUT: i32 = 4; const GRIP_IN: i32 = 2; const SIZE_MAX: i32 = 16384;
99const TASK_H: i32 = 40; const TASK_MIN: i32 = 96; const TASK_MAX: i32 = 200;
102const TASK_GAP: i32 = 2;
103const OVER_W: i32 = 32; const E_LEFT: u32 = 1;
107const E_TOP: u32 = 2;
108const E_RIGHT: u32 = 4;
109const E_BOTTOM: u32 = 8;
110const GRIPS: [(u32, u32); 8] = [
112 (E_TOP, CUR_SIZE_NS),
113 (E_BOTTOM, CUR_SIZE_NS),
114 (E_LEFT, CUR_SIZE_WE),
115 (E_RIGHT, CUR_SIZE_WE),
116 (E_TOP | E_LEFT, CUR_SIZE_NWSE),
117 (E_TOP | E_RIGHT, CUR_SIZE_NESW),
118 (E_BOTTOM | E_LEFT, CUR_SIZE_NESW),
119 (E_BOTTOM | E_RIGHT, CUR_SIZE_NWSE),
120];
121
122const P_AREA: u32 = 1;
124const P_WIN: u32 = 2;
125const P_BOX: u32 = 3;
126const P_TITLE: u32 = 4;
127const P_ICON: u32 = 5;
128const P_MIN: u32 = 6;
129const P_MAX: u32 = 7;
130const P_CLOSE: u32 = 8;
131const P_CONTENT: u32 = 9;
132const P_PANE: u32 = 10;
133const P_MENU: u32 = 11;
134const P_BAR: u32 = 12;
135const P_TASK: u32 = 13;
136const P_TBTN: u32 = 14;
137const P_TMENU: u32 = 15;
138const P_OVER: u32 = 16;
139const P_OITEM: u32 = 17;
140const P_GRIP: u32 = 20; const P_MITEM: u32 = 32; const P_TITEM: u32 = 40; fn pid(desk: u32, part: u32, a: u32) -> u32 {
146 let mut h = desk.wrapping_mul(0x9E37_79B1) ^ part.wrapping_mul(0x85EB_CA6B) ^ a.wrapping_mul(0xC2B2_AE35) ^ 0x5D35_E7A1;
147 h ^= h >> 15;
148 h = h.wrapping_mul(0x2C1B_3C6D);
149 h ^= h >> 12;
150 h | 0x8000_0000
151}
152
153fn inside(r: [i32; 4], p: [i32; 2]) -> bool {
154 p[0] >= r[0] && p[0] < r[0] + r[2] && p[1] >= r[1] && p[1] < r[1] + r[3]
155}
156
157#[derive(Clone, Copy, Debug)]
159pub struct DeskWin<'a> {
160 pub key: u32,
162 pub title: &'a str,
164 pub icon: u32,
166 pub flags: u32,
168 pub min: [i32; 2],
170 pub size: [i32; 2],
172}
173
174impl<'a> DeskWin<'a> {
175 pub const fn new(key: u32, title: &'a str, icon: u32) -> DeskWin<'a> {
177 DeskWin { key, title, icon, flags: 0, min: [0, 0], size: [0, 0] }
178 }
179 pub const fn flags(mut self, f: u32) -> DeskWin<'a> {
181 self.flags |= f;
182 self
183 }
184 pub const fn min(mut self, w: i32, h: i32) -> DeskWin<'a> {
186 self.min = [w, h];
187 self
188 }
189 pub const fn size(mut self, w: i32, h: i32) -> DeskWin<'a> {
191 self.size = [w, h];
192 self
193 }
194}
195
196#[derive(Clone, Copy, Debug, PartialEq, Eq)]
198#[non_exhaustive]
199pub enum DeskEv {
200 Close(u32),
203 Activate(u32),
205 Move(u32),
207 Resize(u32),
209 State(u32),
211}
212
213#[derive(Clone, Copy, Default, Debug, PartialEq, Eq)]
216struct Win {
217 key: u32,
218 rect: [i32; 4],
220 max: bool,
221 min: bool,
222 snap: u8,
224}
225
226impl Win {
227 fn state(&self) -> u32 {
228 let mut s = 0;
229 if self.max {
230 s |= DW_MAX;
231 }
232 if self.min {
233 s |= DW_MIN;
234 }
235 match self.snap {
236 1 => s |= DW_LEFT,
237 2 => s |= DW_RIGHT,
238 _ => {}
239 }
240 s
241 }
242}
243
244#[derive(Clone, Default, Debug, PartialEq, Eq)]
250pub struct DeskState {
251 wins: Vec<Win>,
253 active: u32,
254 cascade: i32,
256 reserve: [i32; 4],
258}
259
260impl DeskState {
261 pub fn new() -> DeskState {
263 DeskState::default()
264 }
265
266 fn find(&self, key: u32) -> Option<usize> {
267 self.wins.iter().position(|w| w.key == key)
268 }
269
270 fn adopt(&mut self, wins: &[DeskWin], area: [i32; 2], tbh: i32) {
272 for d in wins {
273 if d.key == 0 || self.find(d.key).is_some() {
274 continue;
275 }
276 let (mw, mh) = min_size(d, tbh);
277 let w = (if d.size[0] > 0 { d.size[0] } else { DEF_W }).max(mw);
278 let h = (if d.size[1] > 0 { d.size[1] + tbh } else { DEF_H }).max(mh);
279 let mut k = self.cascade;
282 let o = CASCADE / 2 + k * CASCADE;
283 if k > 0 && area[0] > 0 && area[1] > 0 && (o + w > area[0] || o + h > area[1]) {
284 k = 0;
285 self.cascade = 0;
286 }
287 self.cascade += 1;
288 let x = CASCADE / 2 + k * CASCADE;
289 let y = CASCADE / 2 + k * CASCADE;
290 let max = d.flags & DWF_MAXIMIZED != 0 && d.flags & (DWF_NOMAX | DWF_FIXED) == 0;
291 self.wins.push(Win { key: d.key, rect: [x, y, w, h], max, min: false, snap: 0 });
292 self.active = d.key;
293 }
294 }
295
296 pub fn reset(&mut self) {
298 let reserve = self.reserve;
299 *self = DeskState { reserve, ..DeskState::default() };
300 }
301
302 pub fn set_reserve(&mut self, insets: [i32; 4]) {
305 self.reserve = insets.map(|v| v.clamp(0, SIZE_MAX));
306 }
307
308 pub fn reserve(&self) -> [i32; 4] {
310 self.reserve
311 }
312
313 pub fn contains(&self, key: u32) -> bool {
315 self.find(key).is_some()
316 }
317
318 pub fn order(&self) -> Vec<u32> {
320 self.wins.iter().map(|w| w.key).collect()
321 }
322
323 pub fn active(&self) -> u32 {
325 self.active
326 }
327
328 pub fn state(&self, key: u32) -> u32 {
330 self.find(key).map_or(0, |i| self.wins[i].state())
331 }
332
333 pub fn rect(&self, key: u32) -> Option<[i32; 4]> {
336 self.find(key).map(|i| self.wins[i].rect)
337 }
338
339 pub fn set_rect(&mut self, key: u32, r: [i32; 4]) {
342 if let Some(i) = self.find(key) {
343 self.wins[i].rect = [r[0].clamp(-SIZE_MAX, SIZE_MAX), r[1].clamp(-SIZE_MAX, SIZE_MAX), r[2].clamp(1, SIZE_MAX), r[3].clamp(1, SIZE_MAX)];
344 }
345 }
346
347 pub fn activate(&mut self, key: u32) {
349 let Some(i) = self.find(key) else { return };
350 let mut w = self.wins.remove(i);
351 w.min = false;
352 self.wins.push(w);
353 self.active = key;
354 }
355
356 fn activate_top(&mut self) {
358 self.active = self.wins.iter().rev().find(|w| !w.min).map_or(0, |w| w.key);
359 }
360
361 pub fn minimize(&mut self, key: u32) {
364 let Some(i) = self.find(key) else { return };
365 self.wins[i].min = true;
366 if self.active == key || self.active == 0 {
367 self.activate_top();
368 }
369 }
370
371 pub fn maximize(&mut self, key: u32) {
373 if let Some(i) = self.find(key) {
374 self.wins[i].max = true;
375 self.wins[i].snap = 0;
376 self.activate(key);
377 }
378 }
379
380 pub fn restore(&mut self, key: u32) {
383 let Some(i) = self.find(key) else { return };
384 let w = &mut self.wins[i];
385 if w.min {
386 w.min = false;
387 } else {
388 w.max = false;
389 w.snap = 0;
390 }
391 self.activate(key);
392 }
393
394 pub fn toggle_max(&mut self, key: u32) {
396 let Some(i) = self.find(key) else { return };
397 let w = self.wins[i];
398 if w.max || w.snap != 0 {
399 self.wins[i].max = false;
400 self.wins[i].snap = 0;
401 self.activate(key);
402 } else {
403 self.maximize(key);
404 }
405 }
406
407 pub fn snap(&mut self, key: u32, half: u32) {
410 let Some(i) = self.find(key) else { return };
411 let w = &mut self.wins[i];
412 w.max = false;
413 w.min = false;
414 w.snap = match half {
415 DW_LEFT => 1,
416 DW_RIGHT => 2,
417 _ => 0,
418 };
419 self.activate(key);
420 }
421
422 pub fn cycle(&mut self, forward: bool) -> Option<u32> {
426 self.cycle_in(forward, &|_| true)
427 }
428
429 fn cycle_in(&mut self, forward: bool, keep: &dyn Fn(u32) -> bool) -> Option<u32> {
431 let shown: Vec<usize> = (0..self.wins.len()).filter(|&i| !self.wins[i].min && keep(self.wins[i].key)).collect();
432 if shown.is_empty() {
433 return None;
434 }
435 if shown.len() > 1 {
436 if forward {
437 let top = *shown.last()?;
438 let w = self.wins.remove(top);
439 self.wins.insert(shown[0], w);
440 } else {
441 let w = self.wins.remove(shown[0]);
442 self.wins.push(w);
443 }
444 }
445 self.active = self.wins.iter().rev().find(|w| !w.min && keep(w.key)).map_or(0, |w| w.key);
446 Some(self.active)
447 }
448
449 pub fn forget(&mut self, key: u32) {
451 if let Some(i) = self.find(key) {
452 self.wins.remove(i);
453 if self.active == key {
454 self.activate_top();
455 }
456 }
457 }
458
459 pub fn save(&self) -> String {
461 use core::fmt::Write;
462 let mut o = String::from("desk 1\n");
463 for w in &self.wins {
464 let r = w.rect;
465 let _ = writeln!(o, "win {} {} {} {} {} {}", w.key, r[0], r[1], r[2], r[3], w.state());
466 }
467 let _ = writeln!(o, "active {}", self.active);
468 o
469 }
470
471 pub fn load(text: &str) -> Option<DeskState> {
473 let mut lines = text.lines().map(str::trim).filter(|l| !l.is_empty() && !l.starts_with('#'));
474 let mut w = lines.next()?.split_whitespace();
475 if w.next()? != "desk" || w.next()? != "1" {
476 return None;
477 }
478 let mut st = DeskState::default();
479 let mut active = 0;
480 for l in lines {
481 let mut w = l.split_whitespace();
482 let kind = w.next().unwrap_or("");
483 let v: Vec<i64> = w.map(|x| x.parse::<i64>().unwrap_or(i64::MIN)).collect();
484 if v.contains(&i64::MIN) {
485 continue;
486 }
487 let int = |i: usize| v.get(i).copied().unwrap_or(0).clamp(-(SIZE_MAX as i64), SIZE_MAX as i64) as i32;
488 match kind {
489 "win" if v.len() >= 6 => {
490 let key = v[0].clamp(0, u32::MAX as i64) as u32;
491 if key == 0 || st.find(key).is_some() {
492 continue;
493 }
494 let s = v[5].clamp(0, 15) as u32;
495 let snap = if s & DW_LEFT != 0 { 1 } else if s & DW_RIGHT != 0 { 2 } else { 0 };
496 let rect = [int(1), int(2), int(3).max(1), int(4).max(1)];
497 st.wins.push(Win { key, rect, max: s & DW_MAX != 0, min: s & DW_MIN != 0, snap });
498 }
499 "active" if !v.is_empty() => active = v[0].clamp(0, u32::MAX as i64) as u32,
500 _ => {}
501 }
502 }
503 st.cascade = st.wins.len() as i32;
504 if st.find(active).is_some_and(|i| !st.wins[i].min) {
505 st.active = active;
506 } else {
507 st.activate_top();
508 }
509 Some(st)
510 }
511}
512
513fn min_size(d: &DeskWin, tbh: i32) -> (i32, i32) {
515 let w = if d.min[0] > 0 { d.min[0] } else { MIN_W };
516 let h = if d.min[1] > 0 { d.min[1] + tbh } else { MIN_H.max(tbh * 2) };
517 (w.clamp(1, SIZE_MAX), h.clamp(tbh + 1, SIZE_MAX))
518}
519
520struct Info {
524 key: u32,
525 title: String,
526 icon: u32,
527 flags: u32,
528 min: [i32; 2],
530}
531
532#[derive(Clone, Copy)]
534struct Drag {
535 key: u32,
536 edges: u32,
537 ptr0: [i32; 2],
539 rect0: [i32; 4],
541 cur: [i32; 4],
542 zone: u32,
544 was: bool,
546}
547
548#[derive(Clone, Copy)]
549enum Act {
550 Activate(u32),
551 Min(u32),
552 ToggleMax(u32),
553 Restore(u32),
554 Close(u32),
555 Menu(u32),
557 Cycle(bool),
558}
559
560#[derive(Default)]
562pub(crate) struct Rt {
563 id: u32,
564 infos: Vec<Info>,
565 area: [i32; 4],
567 work: [i32; 4],
568 order: Vec<u32>,
571 shown: Vec<(u32, [i32; 4], usize, usize)>,
572 shown_prev: Vec<(u32, [i32; 4], usize, usize)>,
574 next: usize,
575 open: u32,
578 open_notab: bool,
579 hits0: usize,
580 open_rect: [i32; 4],
581 open_place: [i32; 4],
582 open_grips: bool,
583 open_rec: usize,
585 drag: Option<Drag>,
586 acts: Vec<Act>,
587 evs: Vec<DeskEv>,
588 wfocus: Vec<(u32, u32)>,
590 focus_into: u32,
592 focus_kb: bool,
593 focus_here: bool,
596 focus_in: bool,
597 last_focus: u32,
598 last_active: u32,
600 menu_point: u32,
602 tmenu_point: u32,
604}
605
606impl Rt {
607 fn info(&self, key: u32) -> Option<&Info> {
608 self.infos.iter().find(|i| i.key == key)
609 }
610 fn flags(&self, key: u32) -> u32 {
611 self.info(key).map_or(0, |i| i.flags)
612 }
613 fn present(&self, key: u32) -> bool {
614 self.infos.iter().any(|i| i.key == key)
615 }
616}
617
618#[derive(Default)]
620pub(crate) struct S {
621 desks: Vec<Rt>,
622 cur: Vec<u32>,
624}
625
626fn tr(s: &'static str) -> &'static str {
628 super::i18n::tr(s)
629}
630
631fn named(title: &str, state: u32) -> String {
633 if state & DW_MIN != 0 {
634 alloc::format!("{} ({})", title, tr("minimiert"))
635 } else if state & DW_MAX != 0 {
636 alloc::format!("{} ({})", title, tr("maximiert"))
637 } else {
638 String::from(title)
639 }
640}
641
642impl Ui {
643 fn dw_take(&mut self, id: u32) -> Rt {
644 let d = &mut self.m.desk.desks;
645 match d.iter().position(|r| r.id == id) {
646 Some(i) => d.swap_remove(i),
647 None => Rt { id, ..Rt::default() },
648 }
649 }
650
651 fn dw_put(&mut self, rt: Rt) {
652 self.m.desk.desks.push(rt);
653 }
654
655 fn dw_tbh(&self) -> i32 {
657 let v = self.style.metric(SM_WIN_TBH_DIALOG);
658 if v > 0 { v } else { 32 }
659 }
660
661 fn dw_key(&mut self, vk: u32, mods: u32) -> bool {
663 let m3 = MOD_SHIFT | MOD_CTRL | MOD_ALT;
664 let k = self.wp.ctx.keyq.iter().position(|&k| (k as i32) >= 0 && k & 0xFFFF == vk && (k >> 16) & m3 == mods);
665 match self.text_key_filter(k) {
666 Some(i) => {
667 self.wp.ctx.keyq[i] |= 0x8000_0000;
668 true
669 }
670 None => false,
671 }
672 }
673
674 fn dw_dip(&self, px: i32) -> i32 {
676 super::layout::px2dip_at(px, self.wp.rt.dpi)
677 }
678
679 fn dw_px(&self, rt: &Rt, r: [i32; 4]) -> [i32; 4] {
681 [rt.area[0] + self.dp(r[0]), rt.area[1] + self.dp(r[1]), self.dp(r[2]), self.dp(r[3])]
682 }
683
684 fn dw_work(&self, rt: &Rt) -> [i32; 4] {
686 let w = rt.work;
687 [self.dw_dip(w[0] - rt.area[0]), self.dw_dip(w[1] - rt.area[1]), self.dw_dip(w[2]), self.dw_dip(w[3])]
688 }
689
690 fn dw_reach(&self, rt: &Rt, r: [i32; 4]) -> [i32; 4] {
692 let wk = self.dw_work(rt);
693 let tbh = self.dw_tbh();
694 let keep = KEEP.min(r[2]);
695 let x = r[0].min(wk[0] + wk[2] - keep).max(wk[0] + keep - r[2]);
696 let y = r[1].min(wk[1] + wk[3] - tbh).max(wk[1]);
697 [x, y, r[2], r[3]]
698 }
699
700 fn dw_place(&self, rt: &Rt, w: &Win) -> ([i32; 4], bool) {
703 if let Some(d) = rt.drag.filter(|d| d.key == w.key) {
704 return (d.cur, false);
705 }
706 let wk = self.dw_work(rt);
707 if w.max {
708 return (wk, true);
709 }
710 match w.snap {
711 1 => ([wk[0], wk[1], wk[2] / 2, wk[3]], false),
712 2 => ([wk[0] + wk[2] / 2, wk[1], wk[2] - wk[2] / 2, wk[3]], false),
713 _ => (self.dw_reach(rt, w.rect), false),
714 }
715 }
716
717 pub fn desk_begin(&mut self, id: u32, st: &mut DeskState, wins: &[DeskWin]) {
724 let mut rt = self.dw_take(id);
725 let cur = &mut self.m.desk.cur;
726 cur.retain(|&c| c != id); cur.push(id);
728 let tbh = self.dw_tbh();
729 rt.infos = wins
730 .iter()
731 .filter(|d| d.key != 0)
732 .map(|d| {
733 let (mw, mh) = min_size(d, tbh);
734 Info { key: d.key, title: String::from(d.title), icon: d.icon, flags: d.flags, min: [mw, mh] }
735 })
736 .collect();
737 let l = &self.wp.lay;
738 if l.next_w == 0 && l.next_h == 0 && l.next_rect_set == 0 {
739 self.next_size(SIZE_FILL, SIZE_FILL);
740 }
741 self.box_begin(pid(id, P_AREA, 0), BOX_V | BOX_FIXED | BOX_CLIP, 0);
742 rt.area = self.box_rect();
743 let a = rt.area;
744 let rv = st.reserve.map(|v| self.dp(v));
745 rt.work = [a[0] + rv[0], a[1] + rv[1], (a[2] - rv[0] - rv[2]).max(1), (a[3] - rv[1] - rv[3]).max(1)];
746 let wk = rt.work;
748 let dims = if a[2] > 0 && a[3] > 0 { [self.dw_dip(wk[2]), self.dw_dip(wk[3])] } else { [0, 0] };
749 st.adopt(wins, dims, tbh);
750 let sh = self.style.shell();
752 let mut sp = Sp::default();
753 sp.place(a);
754 sh.desk_bg(self, &sp);
755 self.dw_drag_update(&mut rt, st);
757 self.dw_press(&mut rt, st);
759 self.dw_sync_active(&mut rt, st, false);
760 rt.shown_prev = core::mem::take(&mut rt.shown);
761 rt.order = st.wins.iter().filter(|w| !w.min && rt.present(w.key)).map(|w| w.key).collect();
762 let infos = &rt.infos;
764 rt.wfocus.retain(|e| infos.iter().any(|i| i.key == e.0));
765 rt.next = 0;
766 rt.open = 0;
767 rt.focus_here = false;
768 self.dw_put(rt);
769 }
770
771 pub fn desk_next(&mut self, st: &mut DeskState) -> Option<u32> {
774 let id = *self.m.desk.cur.last()?;
775 let mut rt = self.dw_take(id);
776 self.dw_close(&mut rt, st);
777 let mut out = None;
778 if rt.next < rt.order.len() {
779 let key = rt.order[rt.next];
780 rt.next += 1;
781 self.dw_window(&mut rt, st, key);
782 out = Some(key);
783 }
784 self.dw_put(rt);
785 out
786 }
787
788 pub fn desk_end(&mut self, st: &mut DeskState) -> Vec<DeskEv> {
791 let Some(id) = self.m.desk.cur.pop() else { return Vec::new() };
792 let mut rt = self.dw_take(id);
793 self.dw_close(&mut rt, st);
794 let focus = self.wp.ctx.focus;
796 if rt.drag.is_none() && (rt.focus_here || rt.focus_in || focus == 0) {
797 let a = st.active;
798 if self.dw_key(VK_F6, MOD_ALT) {
799 rt.acts.push(Act::Cycle(true));
800 }
801 if self.dw_key(VK_F6, MOD_ALT | MOD_SHIFT) {
802 rt.acts.push(Act::Cycle(false));
803 }
804 if a != 0 && rt.present(a) {
805 let f = rt.flags(a);
806 if f & (DWF_NOMAX | DWF_FIXED) == 0 && self.dw_key(VK_F10, MOD_ALT) {
807 rt.acts.push(Act::ToggleMax(a));
808 }
809 if f & DWF_NOMIN == 0 && self.dw_key(VK_F9, MOD_ALT) {
810 rt.acts.push(Act::Min(a));
811 }
812 if self.dw_key(VK_OEM_MINUS, MOD_ALT) || self.dw_key(VK_SUBTRACT, MOD_ALT) {
813 rt.acts.push(Act::Menu(a));
814 }
815 }
816 }
817 let acts = core::mem::take(&mut rt.acts);
818 let mut by_focus = false;
819 for a in acts {
820 by_focus |= self.dw_apply(&mut rt, st, a);
821 }
822 self.dw_sync_active(&mut rt, st, by_focus);
823 self.box_end(); rt.focus_in = rt.focus_here;
825 rt.last_focus = self.wp.ctx.focus;
826 let evs = core::mem::take(&mut rt.evs);
827 self.dw_put(rt);
828 evs
829 }
830
831 fn dw_sync_active(&mut self, rt: &mut Rt, st: &mut DeskState, by_focus: bool) {
836 if st.active != 0 && (!rt.present(st.active) || st.state(st.active) & DW_MIN != 0) {
839 st.active = st.wins.iter().rev().find(|w| !w.min && rt.present(w.key)).map_or(0, |w| w.key);
840 }
841 if st.active == rt.last_active {
842 return;
843 }
844 rt.last_active = st.active;
845 if st.active == 0 {
846 return;
847 }
848 rt.evs.push(DeskEv::Activate(st.active));
849 if !by_focus {
850 rt.focus_into = st.active;
851 }
852 self.repass = true;
853 }
854
855 fn dw_press(&mut self, rt: &mut Rt, st: &mut DeskState) {
858 let c = &self.wp.ctx;
859 if c.pressed & (1 << BTN_LEFT | 1 << BTN_RIGHT | 1 << BTN_MIDDLE) == 0 || c.modal_prev > L_BASE {
860 return;
861 }
862 let p = if c.pressed & (1 << BTN_LEFT) != 0 { [c.press_x, c.press_y] } else { [c.mx, c.my] };
863 if !inside(rt.area, p) {
864 return;
865 }
866 let hits = &c.hits[c.hit_cur ^ 1];
868 let at = |h: &super::ctx::Hit| p[0] >= h.x0 && p[0] < h.x1 && p[1] >= h.y0 && p[1] < h.y1;
869 if hits.iter().any(|h| h.layer as u32 > L_BASE && at(h)) {
870 return;
871 }
872 let Some(top) = hits.iter().rposition(at) else { return };
873 let Some(&(key, ..)) = rt.shown_prev.iter().find(|e| top >= e.2 && top < e.3) else { return };
874 if st.active != key || st.wins.last().is_some_and(|w| w.key != key) {
875 st.activate(key);
876 self.repass = true;
877 }
878 }
879
880 fn dw_drag_update(&mut self, rt: &mut Rt, st: &mut DeskState) {
882 let Some(mut d) = rt.drag else { return };
883 if !st.contains(d.key) || !rt.present(d.key) {
884 rt.drag = None;
885 return;
886 }
887 if self.kb_chord(VK_ESCAPE, 0) {
889 rt.drag = None;
890 self.wp.ctx.active = 0; self.repass = true;
892 return;
893 }
894 let (mx, my) = self.mouse();
895 let held = self.wp.ctx.mbtn & (1 << BTN_LEFT) != 0;
896 let (dx, dy) = (self.dw_dip(mx - d.ptr0[0]), self.dw_dip(my - d.ptr0[1]));
897 let wk = self.dw_work(rt);
898 let r0 = d.rect0;
899 let min = rt.info(d.key).map_or([MIN_W, MIN_H], |i| i.min);
900 let mut r = r0;
901 d.zone = 0;
902 if d.edges == 0 {
903 r[0] = r0[0] + dx;
904 r[1] = r0[1] + dy;
905 let snap = |v: i32, len: i32, lo: i32, hi: i32| {
907 if (v - lo).abs() <= MAGNET {
908 lo
909 } else if (v + len - hi).abs() <= MAGNET {
910 hi - len
911 } else {
912 v
913 }
914 };
915 r[0] = snap(r[0], r[2], wk[0], wk[0] + wk[2]);
916 r[1] = snap(r[1], r[3], wk[1], wk[1] + wk[3]);
917 r = self.dw_reach(rt, r);
918 let f = rt.flags(d.key);
920 let a = rt.area;
921 let z = self.dp(ZONE);
922 if f & DWF_FIXED == 0 {
923 if mx <= a[0] + z {
924 d.zone = DW_LEFT;
925 } else if mx >= a[0] + a[2] - 1 - z {
926 d.zone = DW_RIGHT;
927 }
928 }
929 if d.zone == 0 && my <= a[1] + z && f & (DWF_NOMAX | DWF_FIXED) == 0 {
930 d.zone = DW_MAX;
931 }
932 } else {
933 let (x1, y1) = (r0[0] + r0[2], r0[1] + r0[3]);
935 if d.edges & E_LEFT != 0 {
936 let x = (r0[0] + dx).max(wk[0].min(r0[0])).min(x1 - min[0]);
937 r[0] = x;
938 r[2] = x1 - x;
939 }
940 if d.edges & E_RIGHT != 0 {
941 r[2] = (r0[2] + dx).min((wk[0] + wk[2]).max(x1) - r0[0]).max(min[0]);
942 }
943 if d.edges & E_TOP != 0 {
944 let y = (r0[1] + dy).max(wk[1].min(r0[1])).min(y1 - min[1]);
945 r[1] = y;
946 r[3] = y1 - y;
947 }
948 if d.edges & E_BOTTOM != 0 {
949 r[3] = (r0[3] + dy).min((wk[1] + wk[3]).max(y1) - r0[1]).max(min[1]);
950 }
951 }
952 if held {
953 if r != d.cur || rt.drag.is_some_and(|o| o.zone != d.zone) {
954 self.repass = true;
955 }
956 d.cur = r;
957 rt.drag = Some(d);
958 return;
959 }
960 rt.drag = None;
962 self.repass = true;
963 let Some(i) = st.find(d.key) else { return };
964 let w = &mut st.wins[i];
965 if d.zone != 0 && d.edges == 0 {
966 w.max = d.zone == DW_MAX;
968 w.snap = match d.zone {
969 DW_LEFT => 1,
970 DW_RIGHT => 2,
971 _ => 0,
972 };
973 rt.evs.push(DeskEv::State(d.key));
974 return;
975 }
976 w.rect = r;
977 w.max = false;
978 w.snap = 0;
979 if d.was {
980 rt.evs.push(DeskEv::State(d.key));
981 }
982 if r != r0 || d.was {
983 rt.evs.push(if d.edges == 0 { DeskEv::Move(d.key) } else { DeskEv::Resize(d.key) });
984 }
985 }
986
987 fn dw_drag_start(&mut self, rt: &mut Rt, st: &DeskState, key: u32, edges: u32, r: [i32; 4]) {
990 let Some(i) = st.find(key) else { return };
991 let w = st.wins[i];
992 let (px, py) = (self.wp.ctx.press_x, self.wp.ctx.press_y);
993 let mut rect0 = r;
994 let was = edges == 0 && (w.max || w.snap != 0);
995 if was {
996 let n = w.rect;
998 let (ax, ay) = (self.dw_dip(px - rt.area[0]), self.dw_dip(py - rt.area[1]));
999 let share = if r[2] > 0 { ((ax - r[0]) as i64 * 1024 / r[2] as i64) as i32 } else { 512 };
1000 let x = ax - (n[2] as i64 * share as i64 / 1024) as i32;
1001 let y = ay - (ay - r[1]).min(self.dw_tbh() / 2);
1002 rect0 = self.dw_reach(rt, [x, y, n[2], n[3]]);
1003 }
1004 rt.drag = Some(Drag { key, edges, ptr0: [px, py], rect0, cur: rect0, zone: 0, was });
1005 self.wp.ctx.last_click_id = 0; self.repass = true;
1007 }
1008
1009 fn dw_window(&mut self, rt: &mut Rt, st: &mut DeskState, key: u32) {
1013 let id = rt.id;
1014 let Some(i) = st.find(key) else { return };
1015 let w = st.wins[i];
1016 let (title, icon, flags) = rt.info(key).map_or((String::new(), 0, 0), |f| (f.title.clone(), f.icon, f.flags));
1017 let active = st.active == key;
1018 let (place, max) = self.dw_place(rt, &w);
1019 let r = self.dw_px(rt, place);
1020 let sh = self.style.shell();
1021 let stl = self.style;
1022 if let Some(d) = rt.drag.filter(|d| d.key == key && d.zone != 0) {
1024 let wk = self.dw_work(rt);
1025 let p = match d.zone {
1026 DW_LEFT => [wk[0], wk[1], wk[2] / 2, wk[3]],
1027 DW_RIGHT => [wk[0] + wk[2] / 2, wk[1], wk[2] - wk[2] / 2, wk[3]],
1028 _ => wk,
1029 };
1030 let mut sp = Sp { value: (d.zone == DW_MAX) as i32, ..Sp::default() };
1031 sp.place(self.dw_px(rt, p));
1032 sh.desk_snap(self, &sp);
1033 }
1034 let state = if max { DW_MAX } else { w.state() & !DW_MIN };
1036 let label = named(&title, state);
1037 self.wp.ctx.last_rect = r;
1038 self.wp.ctx.last_state = if active { SS_SELECTED as u32 } else { 0 };
1039 rt.open_rec = self.sems.len();
1040 let rec = self.sem(K_DIALOG, pid(id, P_WIN, key), Some(&label), state as i32);
1041 rec.min = super::a11y::SEM_SCOPE;
1042 self.next_rect_px(r[0], r[1], r[2], r[3]);
1043 self.box_begin(pid(id, P_BOX, key), BOX_V | BOX_FIXED, 0);
1044 self.wp.ctx.last_rect = r;
1046 let h0 = self.wp.ctx.hits[self.wp.ctx.hit_cur].len();
1047 self.hit(pid(id, P_WIN, key), HB_BLOCK);
1048 rt.shown.push((key, r, h0, usize::MAX));
1049 let mut sp = Sp { value: active as i32, flags: max as u32, ..Sp::default() };
1050 sp.place(r);
1051 sh.desk_window(self, &sp);
1052 let b = if max { 0 } else { self.hair() };
1055 let tbh = self.dp(self.dw_tbh()).min((r[3] - b * 2).max(0));
1056 let bar = [r[0] + b, r[1] + b, (r[2] - b * 2).max(0), tbh];
1057 let capw = {
1058 let v = stl.metric(SM_CAP_W_TOOL);
1059 self.dp(if v > 0 { v } else { 40 })
1060 };
1061 let left = stl.metric(SM_CAP_LEFT) != 0;
1062 let mut btns: Vec<u32> = Vec::new();
1063 if flags & DWF_NOMIN == 0 {
1064 btns.push(P_MIN);
1065 }
1066 if flags & (DWF_NOMAX | DWF_FIXED) == 0 {
1067 btns.push(P_MAX);
1068 }
1069 if flags & DWF_NOCLOSE == 0 {
1070 if left {
1071 btns.insert(0, P_CLOSE);
1072 } else {
1073 btns.push(P_CLOSE);
1074 }
1075 }
1076 let nb = (btns.len() as i32).min(((bar[2] - self.dp(24)) / capw.max(1)).max(0));
1077 let bw = capw * nb;
1078 let bx = if left { bar[0] } else { bar[0] + bar[2] - bw };
1079 let pad = {
1080 let v = stl.metric(SM_WC_TITLE_PAD);
1081 self.dp(if v > 0 { v } else { 12 })
1082 };
1083 let tx = if left { bar[0] + bw + pad } else { bar[0] + pad };
1084 let tw = (bar[2] - bw - pad * 2).max(0);
1085 let mut tsp = Sp { label: Some(&title), icon, value: active as i32, ..Sp::default() };
1086 tsp.place(bar);
1087 tsp.s[0] = tx;
1088 tsp.s[1] = tw;
1089 sh.desk_titlebar(self, &tsp);
1090 let trect = if left { [bar[0] + bw, bar[1], bar[2] - bw, tbh] } else { [bar[0], bar[1], bar[2] - bw, tbh] };
1091 let tid = pid(id, P_TITLE, key);
1092 let ev = self.hit_rect(tid, trect[0], trect[1], trect[2], trect[3], 0);
1093 if ev & EV_HELD != 0 && ev & EV_DRAG != 0 && rt.drag.is_none() {
1094 self.dw_drag_start(rt, st, key, 0, place);
1095 } else if ev & EV_DOUBLE != 0 && flags & (DWF_NOMAX | DWF_FIXED) == 0 {
1096 rt.acts.push(Act::ToggleMax(key));
1097 }
1098 let menu = pid(id, P_MENU, key);
1099 if ev & EV_RCLICK != 0 {
1100 self.popup_open(menu);
1101 rt.menu_point = menu;
1102 }
1103 self.wp.ctx.last_rect = trect;
1104 self.wp.ctx.last_state = 0;
1105 self.sem(K_TITLEBAR, tid, Some(&title), 0);
1106 let isz = self.dp(16);
1108 let irect = [tx - pad / 2, bar[1], isz + pad, tbh];
1109 if icon != 0 && tw > isz {
1110 let iev = self.hit_rect(pid(id, P_ICON, key), irect[0], irect[1], irect[2], irect[3], 0);
1111 if iev & EV_ACT != 0 {
1112 self.popup_open(menu);
1113 rt.menu_point = 0;
1114 }
1115 } else {
1116 self.wp.ctx.last_rect = irect;
1117 }
1118 self.dw_menu(rt, st, key, flags, menu);
1119 for (k, &part) in btns.iter().take(nb as usize).enumerate() {
1121 let x = bx + capw * k as i32;
1122 let bid = pid(id, part, key);
1123 let (hb, ic, lab) = match part {
1124 P_MIN => (HB_MIN, IC_CHROME_MIN, tr("Minimieren")),
1125 P_MAX if state & DW_MAX != 0 || (w.snap != 0 && !max) => (HB_MAX, IC_CHROME_RESTORE, tr("Wiederherstellen")),
1126 P_MAX => (HB_MAX, IC_CHROME_MAX, tr("Maximieren")),
1127 _ => (HB_CLOSE, IC_CHROME_CLOSE, tr("Schließen")),
1128 };
1129 let bev = self.hit_rect(bid, x, bar[1], capw, tbh, 0);
1130 let mut bsp = Sp { ev: bev, flags: hb, icon: ic, value: active as i32, ..Sp::default() };
1131 bsp.place([x, bar[1], capw, tbh]);
1132 sh.desk_button(self, &bsp);
1133 self.sem(K_BUTTON, bid, Some(&alloc::format!("{}: {}", lab, title)), 0);
1135 if bev & EV_ACT != 0 {
1136 rt.acts.push(match part {
1137 P_MIN => Act::Min(key),
1138 P_MAX => Act::ToggleMax(key),
1139 _ => Act::Close(key),
1140 });
1141 }
1142 }
1143 let c = [r[0] + b, r[1] + b + tbh, (r[2] - b * 2).max(0), (r[3] - b * 2 - tbh).max(0)];
1145 self.next_rect_px(c[0], c[1], c[2], c[3]);
1146 self.box_begin(pid(id, P_CONTENT, key), BOX_V | BOX_CLIP | BOX_FIXED, 0);
1147 self.focus_pane_begin(pid(id, P_PANE, key));
1148 rt.open_notab = !active;
1149 if !active {
1150 self.kb_notab(true); }
1152 rt.open = key;
1153 rt.hits0 = self.wp.ctx.hits[self.wp.ctx.hit_cur].len();
1154 rt.open_rect = r;
1155 rt.open_place = place;
1156 rt.open_grips = !max && flags & DWF_FIXED == 0;
1157 }
1158
1159 fn dw_menu(&mut self, rt: &mut Rt, st: &DeskState, key: u32, flags: u32, menu: u32) {
1162 let fl = if rt.menu_point == menu { FL_POINT } else { FL_BELOW };
1163 if self.flyout_begin(menu, fl) {
1164 let s = st.state(key);
1165 let id = rt.id;
1166 let rows: [(&'static str, bool, Act); 3] = [
1167 (tr("Wiederherstellen"), s & (DW_MAX | DW_MIN | DW_LEFT | DW_RIGHT) != 0, Act::Restore(key)),
1168 (tr("Minimieren"), flags & DWF_NOMIN == 0 && s & DW_MIN == 0, Act::Min(key)),
1169 (tr("Maximieren"), flags & (DWF_NOMAX | DWF_FIXED) == 0 && s & DW_MAX == 0, Act::ToggleMax(key)),
1170 ];
1171 for (k, (label, on, act)) in rows.into_iter().enumerate() {
1172 if !on {
1173 self.next_flags(ST_DISABLED);
1174 }
1175 if self.menu_item(pid(id, P_MITEM + k as u32, key), label) & EV_ACT != 0 && on {
1176 rt.acts.push(act);
1177 }
1178 }
1179 self.menu_sep();
1180 if flags & DWF_NOCLOSE != 0 {
1181 self.next_flags(ST_DISABLED);
1182 }
1183 if self.menu_item(pid(id, P_MITEM + 3, key), tr("Schließen")) & EV_ACT != 0 && flags & DWF_NOCLOSE == 0 {
1184 rt.acts.push(Act::Close(key));
1185 }
1186 } else if rt.menu_point == menu {
1187 rt.menu_point = 0;
1188 }
1189 self.flyout_end();
1190 }
1191
1192 fn dw_close(&mut self, rt: &mut Rt, st: &mut DeskState) {
1195 let key = core::mem::take(&mut rt.open);
1196 if key == 0 {
1197 return;
1198 }
1199 let id = rt.id;
1200 if rt.open_notab {
1201 self.kb_notab(false);
1202 }
1203 self.focus_pane_end();
1204 self.box_end(); let focus = self.wp.ctx.focus;
1208 let (here, first, remembered) = {
1209 let c = &self.wp.ctx;
1210 let hits = &c.hits[c.hit_cur];
1211 let from = rt.hits0.min(hits.len());
1212 let mine = &hits[from..];
1213 let here = focus != 0 && mine.iter().any(|h| h.id == focus);
1214 let ok = |h: &&super::ctx::Hit| h.flags as u32 & (HB_FOCUS | HB_DISABLED) == HB_FOCUS && !h.continuation;
1215 let first = mine.iter().find(|h| ok(h) && h.flags as u32 & HB_NOTAB == 0).or_else(|| mine.iter().find(ok)).map(|h| h.id);
1216 let want = rt.wfocus.iter().find(|e| e.0 == key).map_or(0, |e| e.1);
1217 let remembered = if want != 0 && mine.iter().any(|h| h.id == want && ok(&h)) { Some(want) } else { None };
1218 (here, first, remembered)
1219 };
1220 if here {
1221 rt.focus_here = true;
1222 match rt.wfocus.iter_mut().find(|e| e.0 == key) {
1223 Some(e) => e.1 = focus,
1224 None => rt.wfocus.push((key, focus)),
1225 }
1226 if rt.focus_into == key {
1227 rt.focus_into = 0;
1228 }
1229 if st.active != key && focus != rt.last_focus && rt.drag.is_none() {
1230 rt.acts.push(Act::Activate(key));
1231 }
1232 } else if rt.focus_into == key {
1233 rt.focus_into = 0;
1234 match remembered.or(first) {
1235 Some(f) => {
1236 let kb = rt.focus_kb;
1237 self.focus(f);
1238 self.wp.ctx.focus_visible = kb;
1239 rt.focus_here = true;
1240 }
1241 None if rt.focus_in => self.wp.ctx.focus = 0,
1243 None => {}
1244 }
1245 rt.focus_kb = false;
1246 }
1247 if rt.open_grips {
1250 let r = rt.open_rect;
1251 let (o, n) = (self.dp(GRIP_OUT), self.dp(GRIP_IN));
1252 let cs = {
1253 let v = self.style.metric(SM_GRIP_CORNER);
1254 self.dp(if v > 0 { v } else { 12 })
1255 };
1256 let (x0, y0, x1, y1) = (r[0] - o, r[1] - o, r[0] + r[2] + o, r[1] + r[3] + o);
1257 let place = rt.open_place;
1258 for (k, &(edges, cur)) in GRIPS.iter().enumerate() {
1259 let g = match edges {
1260 E_TOP => [x0 + cs, y0, x1 - x0 - cs * 2, o],
1261 E_BOTTOM => [x0 + cs, y1 - o - n, x1 - x0 - cs * 2, o + n],
1262 E_LEFT => [x0, y0 + cs, o + n, y1 - y0 - cs * 2],
1263 E_RIGHT => [x1 - o - n, y0 + cs, o + n, y1 - y0 - cs * 2],
1264 _ => {
1265 let gx = if edges & E_LEFT != 0 { x0 } else { x1 - cs };
1266 let gy = if edges & E_TOP != 0 { y0 } else { y1 - cs };
1267 [gx, gy, cs, cs]
1268 }
1269 };
1270 let cur = match cur {
1272 CUR_SIZE_NWSE if self.rtl => CUR_SIZE_NESW,
1273 CUR_SIZE_NESW if self.rtl => CUR_SIZE_NWSE,
1274 c => c,
1275 };
1276 let gid = pid(id, P_GRIP + k as u32, key);
1277 let ev = self.hit_rect(gid, g[0], g[1], g[2], g[3], cur << HB_CURSOR_SHIFT);
1278 if ev & EV_HELD != 0 && rt.drag.is_none() {
1279 self.dw_drag_start(rt, st, key, edges, place);
1280 }
1281 }
1282 }
1283 self.box_end(); let h1 = self.wp.ctx.hits[self.wp.ctx.hit_cur].len();
1285 if let Some(e) = rt.shown.iter_mut().rev().find(|e| e.0 == key) {
1286 e.3 = h1;
1287 }
1288 let at = rt.open_rec;
1290 if at < self.sems.len() && self.sems[at].id == pid(id, P_WIN, key) {
1291 let win = self.sems[at].win;
1292 let n = self.sems[at + 1..].iter().filter(|s| s.win == win).count();
1293 self.sems[at].max = n as i32;
1294 }
1295 }
1296
1297 fn dw_apply(&mut self, rt: &mut Rt, st: &mut DeskState, a: Act) -> bool {
1301 self.repass = true;
1302 match a {
1303 Act::Activate(k) => {
1304 st.activate(k);
1305 return true;
1306 }
1307 Act::Min(k) => {
1308 if st.state(k) & DW_MIN == 0 {
1309 st.minimize(k);
1310 rt.evs.push(DeskEv::State(k));
1311 }
1312 }
1313 Act::ToggleMax(k) => {
1314 st.toggle_max(k);
1315 rt.evs.push(DeskEv::State(k));
1316 }
1317 Act::Restore(k) => {
1318 st.restore(k);
1319 rt.evs.push(DeskEv::State(k));
1320 }
1321 Act::Close(k) => rt.evs.push(DeskEv::Close(k)),
1322 Act::Menu(k) => {
1323 let menu = pid(rt.id, P_MENU, k);
1324 self.popup_open(menu);
1325 self.pp_flag(menu, super::popup::PPF_FOCUS);
1326 self.wp.ctx.focus_visible = true;
1327 rt.menu_point = 0;
1328 }
1329 Act::Cycle(fwd) => {
1330 let before = st.active;
1332 let infos = &rt.infos;
1333 if st.cycle_in(fwd, &|k| infos.iter().any(|i| i.key == k)).is_some() && st.active != before {
1334 rt.focus_kb = true;
1335 }
1336 }
1337 }
1338 false
1339 }
1340
1341 pub fn desk_taskbar_begin(&mut self, id: u32) {
1349 let l = &self.wp.lay;
1350 let no_size = l.next_w == 0 && l.next_h == 0 && l.next_rect_set == 0;
1351 let open = self.m.desk.cur.contains(&id);
1352 let mut placed = false;
1353 if no_size && open {
1354 if let Some(rt) = self.m.desk.desks.iter().find(|r| r.id == id) {
1355 let (a, w) = (rt.area, rt.work);
1356 let bottom = a[1] + a[3] - (w[1] + w[3]);
1357 let top = w[1] - a[1];
1358 if bottom > 0 {
1359 self.next_rect_px(a[0], w[1] + w[3], a[2], bottom);
1360 placed = true;
1361 } else if top > 0 {
1362 self.next_rect_px(a[0], a[1], a[2], top);
1363 placed = true;
1364 }
1365 }
1366 }
1367 if no_size && !placed {
1368 self.next_size(0, TASK_H);
1369 }
1370 self.box_begin(pid(id, P_BAR, 0), BOX_H | BOX_XCENTER | BOX_BLOCK | pad(4), 4);
1371 let mut sp = Sp::default();
1372 sp.place(self.wp.ctx.last_rect);
1373 self.style.shell().taskbar(self, &sp);
1374 self.wp.ctx.last_state = 0;
1375 self.sem(K_BOX, pid(id, P_BAR, 0), Some(tr("Taskleiste")), 0);
1376 self.focus_pane_begin(pid(id, P_BAR, 0)); }
1378
1379 pub fn desk_taskbar_end(&mut self) {
1381 self.focus_pane_end();
1382 self.box_end();
1383 }
1384
1385 pub fn desk_taskbar(&mut self, id: u32, st: &mut DeskState, flags: u32) {
1389 let l = &self.wp.lay;
1390 if l.next_w == 0 && l.next_h == 0 && l.next_rect_set == 0 {
1391 let h = self.dw_dip(self.box_rect()[3]).max(1);
1393 self.next_size(SIZE_FILL, h);
1394 }
1395 self.box_begin(pid(id, P_TASK, 0), BOX_H | BOX_FIXED | BOX_CLIP, 0);
1396 let area = self.box_rect();
1397 let mut rt = self.dw_take(id);
1398 let sh = self.style.shell();
1399 let wins: Vec<(u32, String, u32, u32)> = rt
1400 .infos
1401 .iter()
1402 .filter(|i| i.flags & DWF_NOTASK == 0 && st.contains(i.key))
1403 .map(|i| (i.key, i.title.clone(), i.icon, i.flags))
1404 .collect();
1405 let icons = flags & DTB_ICONS != 0;
1408 let gap = self.dp(TASK_GAP);
1409 let mut ws: Vec<i32> = Vec::with_capacity(wins.len());
1410 for (_, t, ic, _) in &wins {
1411 let mut tsp = Sp { label: Some(t), icon: *ic, flags, ..Sp::default() };
1412 let (w, _) = sh.taskbar_button_size(self, &mut tsp);
1413 ws.push(if icons { w } else { w.clamp(self.dp(TASK_MIN), self.dp(TASK_MAX)) });
1414 }
1415 let total: i32 = ws.iter().sum::<i32>() + gap * (ws.len() as i32 - 1).max(0);
1416 let mut shown: Vec<usize> = (0..wins.len()).collect();
1417 let mut over: Vec<usize> = Vec::new();
1418 if total > area[2] && !wins.is_empty() {
1419 let minw = if icons { ws.iter().copied().max().unwrap_or(0) } else { self.dp(TASK_MIN) };
1421 let n = wins.len() as i32;
1422 if minw * n + gap * (n - 1) <= area[2] {
1423 let each = ((area[2] - gap * (n - 1)) / n).max(minw);
1424 for w in ws.iter_mut() {
1425 *w = (*w).min(each);
1426 }
1427 } else {
1428 let ow = self.dp(OVER_W);
1429 let k = ((area[2] - ow + gap) / (minw + gap)).max(0) as usize;
1430 for w in ws.iter_mut() {
1431 *w = minw;
1432 }
1433 over = shown.split_off(k.min(shown.len()));
1434 if let Some(p) = over.iter().position(|&i| wins[i].0 == st.active) {
1435 let a = over.remove(p);
1436 if let Some(last) = shown.pop() {
1437 over.insert(0, last);
1438 }
1439 shown.push(a);
1440 }
1441 }
1442 }
1443 self.focus_group_begin(pid(id, P_TASK, 1));
1445 let mut x = area[0];
1446 for &k in &shown {
1447 let (key, ref title, icon, wf) = wins[k];
1448 let s = st.state(key);
1449 let w = ws[k];
1450 let r = [x, area[1], w, area[3]];
1451 x += w + gap;
1452 let bid = pid(id, P_TBTN, key);
1453 let ev = self.hit_rect(bid, r[0], r[1], r[2], r[3], HB_FOCUS);
1454 let state = self.wp.ctx.last_state;
1455 let on = st.active == key && s & DW_MIN == 0;
1456 let mut bsp = Sp { ev, label: Some(title), icon, value: on as i32, value2: (s & DW_MIN != 0) as i32, flags, ..Sp::default() };
1457 bsp.place(r);
1458 sh.taskbar_button(self, &bsp);
1459 if self.focus_ring(ev) {
1460 let stl = self.style;
1461 stl.focus_ring(self, r, 4);
1462 }
1463 self.wp.ctx.last_rect = r;
1464 self.wp.ctx.last_state = state | if on { SS_CHECKED as u32 } else { 0 };
1465 let name = named(title, s & DW_MIN);
1466 self.sem(K_BUTTON, bid, Some(&name), s as i32);
1467 if ev & EV_ACT != 0 {
1468 if on {
1469 if wf & DWF_NOMIN == 0 {
1470 st.minimize(key);
1471 rt.evs.push(DeskEv::State(key));
1472 }
1473 } else {
1474 if s & DW_MIN != 0 {
1475 rt.evs.push(DeskEv::State(key));
1476 }
1477 st.activate(key);
1478 rt.focus_kb = self.wp.ctx.focus_visible;
1479 }
1480 self.repass = true;
1481 }
1482 let menu = pid(id, P_TMENU, key);
1484 if ev & EV_RCLICK != 0 {
1485 self.popup_open(menu);
1486 let kb = self.kb_ctx_rect().is_some();
1487 if kb {
1488 self.pp_flag(menu, super::popup::PPF_FOCUS);
1489 }
1490 rt.tmenu_point = if kb { 0 } else { menu };
1491 }
1492 self.wp.ctx.last_rect = r;
1493 let fl = if rt.tmenu_point == menu { FL_POINT } else { FL_ABOVE };
1494 if self.flyout_begin(menu, fl) {
1495 let rows: [(&'static str, bool); 4] = [
1496 (tr("Wiederherstellen"), s & (DW_MAX | DW_MIN | DW_LEFT | DW_RIGHT) != 0),
1497 (tr("Minimieren"), wf & DWF_NOMIN == 0 && s & DW_MIN == 0),
1498 (tr("Maximieren"), wf & (DWF_NOMAX | DWF_FIXED) == 0 && s & DW_MAX == 0),
1499 (tr("Schließen"), wf & DWF_NOCLOSE == 0),
1500 ];
1501 for (j, (label, ok)) in rows.into_iter().enumerate() {
1502 if j == 3 {
1503 self.menu_sep();
1504 }
1505 if !ok {
1506 self.next_flags(ST_DISABLED);
1507 }
1508 if self.menu_item(pid(id, P_TITEM + j as u32, key), label) & EV_ACT != 0 && ok {
1509 match j {
1510 0 => st.restore(key),
1511 1 => st.minimize(key),
1512 2 => st.maximize(key),
1513 _ => {}
1514 }
1515 rt.evs.push(if j == 3 { DeskEv::Close(key) } else { DeskEv::State(key) });
1516 self.repass = true;
1517 }
1518 }
1519 } else if rt.tmenu_point == menu {
1520 rt.tmenu_point = 0;
1521 }
1522 self.flyout_end();
1523 }
1524 self.focus_group_end();
1525 if !over.is_empty() {
1527 let ow = self.dp(OVER_W);
1528 let r = [area[0] + area[2] - ow, area[1], ow, area[3]];
1529 let oid = pid(id, P_OVER, 0);
1530 self.next_rect_px(r[0], r[1], r[2], r[3]);
1531 self.next_icon(IC_MORE);
1532 self.next_flags(ST_SUBTLE | ST_ICON_ONLY | ST_COMPACT);
1533 if self.button(oid, tr("Weitere Fenster")) & EV_ACT != 0 {
1534 self.popup_open(oid);
1535 if self.wp.ctx.focus_visible {
1536 self.pp_flag(oid, super::popup::PPF_FOCUS);
1537 }
1538 }
1539 if self.flyout_begin(oid, FL_ABOVE | FL_ALIGN_END) {
1540 for &k in &over {
1541 let (key, ref title, icon, _) = wins[k];
1542 let s = st.state(key);
1543 if icon != 0 {
1544 self.next_icon(icon);
1545 }
1546 if self.menu_item(pid(id, P_OITEM, key), &named(title, s & DW_MIN)) & EV_ACT != 0 {
1547 if s & DW_MIN != 0 {
1548 rt.evs.push(DeskEv::State(key));
1549 }
1550 st.activate(key);
1551 rt.focus_kb = self.wp.ctx.focus_visible;
1552 self.repass = true;
1553 }
1554 }
1555 }
1556 self.flyout_end();
1557 }
1558 let focus = self.wp.ctx.focus;
1561 if focus != 0 && (wins.iter().any(|w| pid(id, P_TBTN, w.0) == focus) || focus == pid(id, P_OVER, 0)) {
1562 rt.focus_here = true;
1563 rt.focus_in = true;
1564 }
1565 self.dw_put(rt);
1566 self.box_end();
1567 }
1568}