← luna

Commit 872583f

3
files
+42
added
-6
deleted
@@ -363,7 +363,13 @@ fn main() -> Result<(), Box<dyn Error>> {
363 363 .wrapping_add(state.workspaces as u64 ^ ((state.current_ws as u64) << 8));
364 364 let sig = (open, power_open, state.clock.clone(), th);
365 365 let animating = osd.visible() || notes.visible();
366 - if !frame.events.is_empty() || animating || open || sig != last_sig {
366 + // Ruch myszy nad panelem NIE wymusza przerysowania (brak hoverów) — to było
367 + // głównym źródłem „5 FPS”: każde zdarzenie ruchu odświeżało bufor 1920×680.
368 + let interactive = frame
369 + .events
370 + .iter()
371 + .any(|e| !matches!(e, Event::PointerMotion { .. }));
372 + if interactive || animating || open || sig != last_sig {
367 373 frame.request_frame();
368 374 }
369 375 last_sig = sig;
@@ -167,8 +167,9 @@ pub fn spawn_drm(
167 167 let (cursor_rgba, cw, ch) = cursor_image();
168 168 let mut hw_cursor = true;
169 169 for i in 0..sizes.len() {
170 - // Próba ustawienia obrazu (potem chowamy); gdy sterownik nie umie — kursor programowy.
171 - if !backend.set_cursor_image(i, &cursor_rgba, cw, ch, 0, 0) || !backend.hide_cursor(i) {
170 + // Obraz startowy poza ekranem (nie mruga, nie chowamy osobno ioctlem);
171 + // gdy sterownik nie umie kursora sprzętowego — zostaje programowy.
172 + if !backend.set_cursor_image(i, &cursor_rgba, cw, ch, -1000, -1000) {
172 173 hw_cursor = false;
173 174 }
174 175 }
@@ -178,7 +179,8 @@ pub fn spawn_drm(
178 179 libluna_i18n::tr("DRM hardware cursor unavailable; using software cursor")
179 180 );
180 181 }
181 - let mut cursor_shown = vec![false; sizes.len()];
182 + // Obraz ustawiony → ruchy realizujemy samym `MOVE`.
183 + let mut cursor_shown = vec![hw_cursor; sizes.len()];
182 184
183 185 // Diagnostyka (SELENE_STATS=1): fps i rozbicie czasu na render/present/wait_flip.
184 186 let stats = std::env::var("SELENE_STATS").is_ok();
@@ -284,8 +284,14 @@ fn window_geometry(state: &State, slot: usize) -> Option<(f64, f64, f64, f64)> {
284 284 }
285 285
286 286 fn content_local(state: &State, slot: usize, pos: Point) -> (f64, f64) {
287 - match window_geometry(state, slot) {
288 - Some((x, y, _, _)) => (pos.x - x, pos.y - (y + TITLEBAR)),
287 + // Używamy `content()` — dla paneli/popupów pasek tytułu ma wysokość 0, więc
288 + // współrzędne nie są przesunięte (wcześniej odejmowano `TITLEBAR` zawsze).
289 + let windows = state.windows.lock_or_recover();
290 + match windows.get(slot) {
291 + Some(w) => {
292 + let c = w.content();
293 + (pos.x - c.x(), pos.y - c.y())
294 + }
289 295 None => (pos.x, pos.y),
290 296 }
291 297 }
@@ -1242,6 +1248,28 @@ mod tests {
1242 1248 }
1243 1249 }
1244 1250
1251 + #[test]
1252 + fn content_local_does_not_offset_layer_surfaces() {
1253 + // Panel (powierzchnia warstwowa) nie ma paska tytułu — współrzędne bez przesunięcia.
1254 + let mut s = State::default();
1255 + let mut w = sample_window();
1256 + w.layer = true;
1257 + w.x = 0.0;
1258 + w.y = 0.0;
1259 + s.windows.lock_or_recover().push(w);
1260 + assert_eq!(content_local(&s, 0, Point::new(50.0, 20.0)), (50.0, 20.0));
1261 + }
1262 +
1263 + #[test]
1264 + fn content_local_offsets_titlebar_for_windows() {
1265 + let mut s = State::default();
1266 + s.windows.lock_or_recover().push(sample_window()); // x=100, y=50
1267 + assert_eq!(
1268 + content_local(&s, 0, Point::new(120.0, 80.0)),
1269 + (20.0, 80.0 - (50.0 + TITLEBAR))
1270 + );
1271 + }
1272 +
1245 1273 #[test]
1246 1274 fn workspace_predicate_switch_and_move() {
1247 1275 let mut s = State::default();