[Afsluiten][P1] macOS: Cmd+Q, Dock-Stop en uitloggen slaan de sluitbewaking over — geen vraag over niet-opgeslagen werk, opname en call niet afgerond #2678

Closed
opened 2026-10-31 09:47:38 +00:00 by brenno · 4 comments
Owner

Symptoom

Op macOS sluit Cmd+Q de app meteen af — net als OciDeck → Stop OciDeck, Dock → Stop en uitloggen/herstarten. De vraag "Er zijn bestanden met niet-opgeslagen wijzigingen…" verschijnt niet; via de rode sluitknop verschijnt hij wél. De opruimstappen draaien evenmin:

  • een lopende opname wordt niet netjes gestopt (stopRecordingBeforeQuit);
  • een actieve call wordt niet verlaten (leaveMeetingBeforeQuit);
  • lessessies worden niet gesloten;
  • de herstelbestanden en het sessielock (#2656) blijven liggen.

Het werk zelf is via de herstelbestanden bij de volgende start nog terug te halen. Maar de gebruiker krijgt de keuze niet, en een opname of call eindigt als een harde kill.

Oorzaak

  • Het app-menu gebruikt PlatformProvidedMenuItem(type: quit) (lib/widgets/shell/app_menu_bar.dart:220). Dat roept NSApplication.terminate: aan, en die route komt niet langs de willClose-hook van het venster (lib/platform/native_window_io.dart:29-31). Aan die hook hangt AppShell._onWillClose → _handleClose → _destroy (lib/widgets/app_shell.dart:476-530).
  • macOS vraagt het framework wél om toestemming (System.requestAppExit). De enige luisteraar (lib/main.dart:158-171) rondt alleen het log af en antwoordt AppExitResponse.exit. Het commentaar daar zegt het al: "Het antwoord blijft wat het zonder deze luisteraar ook was".

Voorgestelde oplossing

  1. Laat de shell beslissen in plaats van main.dart. AppShell registreert een exit-handler, op dezelfde manier als setWillCloseCallback. Die handler start _handleClose() en geeft AppExitResponse.cancel terug. Kiest de gebruiker Doorgaan, dan eindigt _handleClose toch al in quitApp(). Bij Annuleren blijft de app open.
  2. Is er geen shell (de toestemmingspoort, #1207), dan blijft het huidige exit gelden.
  3. Een tweede Cmd+Q terwijl de dialoog open staat, vangt _closeInProgress al af.
  4. Bij uitloggen of afsluiten van macOS laat cancel het systeem melden dat OciDeck het tegenhoudt. Dat is het gewenste gedrag bij niet-opgeslagen werk; TextEdit en Pages doen hetzelfde.

Wat overeind moet blijven

  • Wie de toestemmingspoort niet accepteert, moet nog steeds met Cmd+Q weg kunnen (#1207).
  • Het log wordt netjes afgerond (#2618): quitApp roept closeLog aan.
  • Windows en Linux blijven ongewijzigd. Daar mag de vraag niet vóór de sluitbewaking komen (zie het commentaar in main.dart).

Toets

  • Widgettest met een vuil tabblad: tester.binding.handleRequestAppExit() geeft cancel en de opslaan-dialoog verschijnt. Zonder vuil tabblad loopt het via _destroy naar quitApp.
  • Handmatig op macOS: wijzig een deck en druk Cmd+Q. De dialoog moet verschijnen.

Gevonden bij codelezing tijdens de vervolginspectie van 31-10-2026. Nog niet in de draaiende app nagespeeld.

## Symptoom Op macOS sluit **Cmd+Q** de app meteen af — net als *OciDeck → Stop OciDeck*, *Dock → Stop* en uitloggen/herstarten. De vraag "Er zijn bestanden met niet-opgeslagen wijzigingen…" verschijnt niet; via de rode sluitknop verschijnt hij wél. De opruimstappen draaien evenmin: - een lopende opname wordt niet netjes gestopt (`stopRecordingBeforeQuit`); - een actieve call wordt niet verlaten (`leaveMeetingBeforeQuit`); - lessessies worden niet gesloten; - de herstelbestanden en het sessielock (#2656) blijven liggen. Het werk zelf is via de herstelbestanden bij de volgende start nog terug te halen. Maar de gebruiker krijgt de keuze niet, en een opname of call eindigt als een harde kill. ## Oorzaak - Het app-menu gebruikt `PlatformProvidedMenuItem(type: quit)` (`lib/widgets/shell/app_menu_bar.dart:220`). Dat roept `NSApplication.terminate:` aan, en die route komt niet langs de willClose-hook van het venster (`lib/platform/native_window_io.dart:29-31`). Aan die hook hangt `AppShell._onWillClose` → `_handleClose` → `_destroy` (`lib/widgets/app_shell.dart:476-530`). - macOS vraagt het framework wél om toestemming (`System.requestAppExit`). De enige luisteraar (`lib/main.dart:158-171`) rondt alleen het log af en antwoordt `AppExitResponse.exit`. Het commentaar daar zegt het al: *"Het antwoord blijft wat het zonder deze luisteraar ook was"*. ## Voorgestelde oplossing 1. Laat de shell beslissen in plaats van `main.dart`. `AppShell` registreert een exit-handler, op dezelfde manier als `setWillCloseCallback`. Die handler start `_handleClose()` en geeft `AppExitResponse.cancel` terug. Kiest de gebruiker *Doorgaan*, dan eindigt `_handleClose` toch al in `quitApp()`. Bij *Annuleren* blijft de app open. 2. Is er geen shell (de toestemmingspoort, #1207), dan blijft het huidige `exit` gelden. 3. Een tweede Cmd+Q terwijl de dialoog open staat, vangt `_closeInProgress` al af. 4. Bij uitloggen of afsluiten van macOS laat `cancel` het systeem melden dat OciDeck het tegenhoudt. Dat is het gewenste gedrag bij niet-opgeslagen werk; TextEdit en Pages doen hetzelfde. ## Wat overeind moet blijven - Wie de toestemmingspoort niet accepteert, moet nog steeds met Cmd+Q weg kunnen (#1207). - Het log wordt netjes afgerond (#2618): `quitApp` roept `closeLog` aan. - Windows en Linux blijven ongewijzigd. Daar mag de vraag niet vóór de sluitbewaking komen (zie het commentaar in `main.dart`). ## Toets - Widgettest met een vuil tabblad: `tester.binding.handleRequestAppExit()` geeft `cancel` en de opslaan-dialoog verschijnt. Zonder vuil tabblad loopt het via `_destroy` naar `quitApp`. - Handmatig op macOS: wijzig een deck en druk Cmd+Q. De dialoog moet verschijnen. Gevonden bij codelezing tijdens de vervolginspectie van 31-10-2026. Nog niet in de draaiende app nagespeeld.
Author
Owner

Opgepakt. Tak: fix/vervolginspectie-3110. Verwachte reikwijdte: de bestanden die in de oorzaak van dit issue staan, plus een regressietest.

Opgepakt. Tak: fix/vervolginspectie-3110. Verwachte reikwijdte: de bestanden die in de oorzaak van dit issue staan, plus een regressietest.
Author
Owner

Opgepakt. Tak: fix/vervolginspectie-3110. Verwachte reikwijdte: lib/main.dart, lib/widgets/app_shell.dart, lib/platform/macos_quit.dart, lib/platform/native_window_io.dart, test/macos_quit_guard_test.dart.

Opgepakt. Tak: fix/vervolginspectie-3110. Verwachte reikwijdte: lib/main.dart, lib/widgets/app_shell.dart, lib/platform/macos_quit.dart, lib/platform/native_window_io.dart, test/macos_quit_guard_test.dart.
Author
Owner

Staat op main in a6b4dc066 (1ec8ce0a3). Cmd+Q loopt via System.requestAppExit en de sluitbewaking in lib/widgets/shell/macos_exit_guard.dart. Zonder de shell sluit de app nog steeds meteen. De toets speelt het verzoek na via handleRequestAppExit, niet met een echte Cmd+Q in de draaiende app.

Staat op main in a6b4dc066 (1ec8ce0a3). Cmd+Q loopt via System.requestAppExit en de sluitbewaking in lib/widgets/shell/macos_exit_guard.dart. Zonder de shell sluit de app nog steeds meteen. De toets speelt het verzoek na via handleRequestAppExit, niet met een echte Cmd+Q in de draaiende app.
Author
Owner

Opgelost op main in a6b4dc066. De zin „Op macOS sluit Cmd+Q de app meteen af“ is gedekt door lib/widgets/shell/macos_exit_guard.dart: de shell annuleert het afsluitverzoek en start dezelfde sluitbewaking als de vensterknop. Niet meegenomen: Cmd+Q is niet met de hand in de draaiende app nagespeeld; de widgettoets dekt handleRequestAppExit.

Opgelost op main in a6b4dc066. De zin „Op macOS sluit Cmd+Q de app meteen af“ is gedekt door lib/widgets/shell/macos_exit_guard.dart: de shell annuleert het afsluitverzoek en start dezelfde sluitbewaking als de vensterknop. Niet meegenomen: Cmd+Q is niet met de hand in de draaiende app nagespeeld; de widgettoets dekt handleRequestAppExit.
Sign in to join this conversation.
No milestone
No project
No assignees
1 participant
Notifications
Due date
The due date is invalid or out of range. Please use the format "yyyy-mm-dd".

No due date set.

Dependencies

No dependencies set

Reference
LibreKAT/Ocideck#2678
No description provided.