Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension


Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 1 addition & 0 deletions docs/motion-and-high-refresh.md
Original file line number Diff line number Diff line change
Expand Up @@ -67,6 +67,7 @@ Root cause (engine): per `flutter/flutter#160952`, the engine "can render at 120
- **Windows / Linux:** most likely already render at monitor Hz; the job is to **measure and verify**, then ensure no app-side code caps frames (e.g. heavy `setState`, unbounded rebuilds during animation).
- **macOS:** the real high-Hz work — confirm ProMotion behavior; unlock via `refresh_rate` if capped at 60.
- Use `refresh_rate` (or a thin wrapper) primarily for **diagnostics**: a debug-only FPS/Hz overlay and a benchmark to prove smoothness on each machine, plus the macOS unlock call in `main()`.
- **Implementation:** `lib/core/motion/display_refresh_service.dart` calls `RefreshRate.enable()` in `main()`. Debug Hz badge: `flutter run --dart-define=QUERYA_REFRESH_OVERLAY=true`.

---

Expand Down
49 changes: 49 additions & 0 deletions lib/core/motion/display_refresh_service.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,49 @@
import 'package:flutter/foundation.dart';
import 'package:refresh_rate/refresh_rate.dart';

/// Desktop display refresh-rate unlock and diagnostics (UI-A4 / #174).
///
/// Calls [RefreshRate.enable] once at startup (macOS 14+ ProMotion unlock;
/// query on Windows/Linux). Debug overlay: run with
/// `--dart-define=QUERYA_REFRESH_OVERLAY=true`.
abstract final class DisplayRefreshService {
static const bool _overlayFromEnvironment = bool.fromEnvironment(
'QUERYA_REFRESH_OVERLAY',
);

/// Unlock peak refresh where the platform supports it; log Hz in debug builds.
static void initialize() {
RefreshRate.enable();

if (!kDebugMode) return;

_logRefreshInfo();
if (displayRefreshOverlayEnabled(
debugMode: kDebugMode,
overlayFlag: _overlayFromEnvironment,
)) {
RefreshRate.showHz();
}
}

static void _logRefreshInfo() {
final info = RefreshRate.info;
debugPrint(
'Display refresh: ${info.currentRate} Hz '
'(max ${info.maxRate}, variable=${info.isVariableRefreshRate})',
);
}

/// Cached current refresh rate from the platform (Hz), when available.
static double get currentHz => RefreshRate.info.currentRate;

/// Peak supported refresh rate (Hz).
static double get maxHz => RefreshRate.info.maxRate;

@visibleForTesting
static bool displayRefreshOverlayEnabled({
required bool debugMode,
required bool overlayFlag,
}) =>
debugMode && overlayFlag;
}
2 changes: 2 additions & 0 deletions lib/main.dart
Original file line number Diff line number Diff line change
Expand Up @@ -4,11 +4,13 @@ import 'package:flutter/material.dart';
import 'app/app.dart';
import 'core/editor/syntax_highlight_service.dart';
import 'core/layout/ui_scale_controller.dart';
import 'core/motion/display_refresh_service.dart';
import 'core/storage/local_db.dart';
import 'core/theme/theme_controller.dart';

void main() async {
WidgetsFlutterBinding.ensureInitialized();
DisplayRefreshService.initialize();
await LocalDb.initFfi();
await SyntaxHighlightService.ensureInitialized();
await ThemeController.instance.load();
Expand Down
1 change: 1 addition & 0 deletions pubspec.yaml
Original file line number Diff line number Diff line change
Expand Up @@ -12,6 +12,7 @@ dependencies:
sdk: flutter
http: ^1.2.2
crypto: ^3.0.6
refresh_rate: ^1.0.2
shadcn_flutter: ^0.0.52
bitsdojo_window: ^0.1.6
path: ^1.9.0
Expand Down
33 changes: 33 additions & 0 deletions test/core/motion/display_refresh_service_test.dart
Original file line number Diff line number Diff line change
@@ -0,0 +1,33 @@
import 'package:flutter_test/flutter_test.dart';
import 'package:querya_desktop/core/motion/display_refresh_service.dart';

void main() {
group('displayRefreshOverlayEnabled', () {
test('false in release or when flag unset', () {
expect(
DisplayRefreshService.displayRefreshOverlayEnabled(
debugMode: false,
overlayFlag: true,
),
isFalse,
);
expect(
DisplayRefreshService.displayRefreshOverlayEnabled(
debugMode: true,
overlayFlag: false,
),
isFalse,
);
});

test('true only in debug with QUERYA_REFRESH_OVERLAY', () {
expect(
DisplayRefreshService.displayRefreshOverlayEnabled(
debugMode: true,
overlayFlag: true,
),
isTrue,
);
});
});
}
Loading