[Bug/High] Printer properties dialog doesn't apply selected printer and settings from ICCery #186

Closed
opened 2026-09-15 10:20:54 +01:00 by gronod · 4 comments
Owner

Summary

The printer properties button (gear icon) in Stage 2 opens the OS print dialog (NSPrintPanel), but it doesn't apply the paper size, quality, media type, or orientation selected in ICCery.

Related to

Issue #180 — Epson printer quality options limited to default only

Bug Details

Current Behavior

  1. User selects a printer in the Stage 2 printer picker
  2. User clicks the printer properties button (gear icon)
  3. PrintPanelService.showProperties() is called with the selected queue
  4. Problem: The NSPrintPanel opens but:
    • Does not pre-select the paper size chosen in Stage 1 (A4, Letter, custom, etc.)
    • Does not pre-select the print quality chosen in ICCery
    • Does not pre-select the media type selected in ICCery
    • Does not pre-select the orientation chosen in ICCery
    • Color management is disabled (correct), but other settings are not applied

Binding note: "falls back to system default" is not possible on the PM path — PMSessionSetCurrentPMPrinter failure throws sessionBindingFailed (PrintPanelService.swift:83-87), and the NSPrinter(name:) fallback throws noPrinterFound when it can't resolve (:93-100). The realistic residual risk is the display-name fallback binding a different queue — hardware-verify, not a proven defect.

Root Cause Analysis

In PrintPanelService.runNativePanel() (Sources/ICCery/Print/PrintPanelService.swift:64-162):

  1. Creates NSPrintInfo() with default values
  2. Binds session to selected CUPS queue via PMPrinterCreateFromPrinterID + PMSessionSetCurrentPMPrinter
  3. Calls PMSessionDefaultPrintSettings and PMSessionDefaultPageFormat — these load printer defaults, not user-selected values
  4. Applies ColorSync suppression (layers ②–⑤)
  5. Shows panel with panel.runModal(with: printInfo)

Missing:

  • Pre-setting PMPageFormat paper size and PMPrintSettings quality/media/orientation before runModal
  • Capture-return currently parses only cupsOptions/mediaType (PrintPanelService.swift:142-161) — it must extend to paperSize/quality/orientation parsed from the captured k=v string

Expected Behavior

  1. Panel opens bound to the selected printer (not default)
  2. Paper size pre-selected to match Stage 1 pageSize (A4 default)
  3. Print quality pre-selected to match ICCery selection
  4. Media type pre-selected to match ICCery selection
  5. Orientation pre-selected to match ICCery selection (portrait default)

Implementation Notes

  • Need to pass pageSize, selectedQuality, selectedMediaType, printOrientation from PrintSessionViewModel to PrintPanelService.showProperties() — the initial-selections plumbing for paper size + quality is #183 scope; this issue adds media type + orientation
  • In runNativePanel(), before showing panel:
    • Paper size requires BOTH writes: PageSize in PMPrintSettings (drivers/capture read it) and PMPageFormat via PMPaper — the panel's paper dropdown reflects PMPageFormat; PMPrintSettingsSetValue writes print settings only and cannot set the page format. Path: PMPrinterGetPaperList/PMPaperGetID + PMPageFormatCreateWithPMPaper + PMSessionValidatePageFormat; printInfo.paperSize/PMPaperCreateCustom for custom sizes. Verify exact PM calls against PrintCore headers at implementation (deprecated-but-present APIs on macOS 12)
    • Set quality via PMPrintSettingsSetValue with detected quality key (e.g., EPIJ_Qual, cupsPrintQuality)
    • Set media type via PMPrintSettingsSetValue with detected media key
    • Set orientation via PMPrintSettingsSetValue with orientation-requested
  • These settings should be applied after PMSessionDefaultPrintSettings/PMSessionDefaultPageFormat but before ColorSync suppression layers ②–⑤

Spec References

  • 11 §Binding — PMPrinterCreateFromPrinterID → PMSessionSetCurrentPMPrinter
  • 11 §Layer ④ — driver bypass detection (similar approach for quality/media)
  • 10 — PrintOptions structure carries paper_size, media_type, orientation (spec naming; Swift fields are paperSize/mediaType/orientation)

Dependencies

  • Depends on: #183 (Stage 2 paper size/quality selection must exist), #180 (all quality options available), #181 (correct media type labels)
  • Blocks: None (final integration fix)
  • Scope split with #183: #183 wires showProperties initial-selections for paper size + quality; this issue completes media type + orientation preselect, capture-return of all fields, and binding verification

Acceptance Criteria

  • Printer properties dialog opens with the selected printer pre-bound
  • Paper size in dialog matches Stage 1 selection (A4 default)
  • Print quality in dialog matches ICCery selection
  • Media type in dialog matches ICCery selection
  • Orientation in dialog matches ICCery selection (portrait default)
  • User changes in dialog are captured and returned via PrintPropertiesResult — including paperSize/quality/orientation, not only cupsOptions/mediaType
## Summary The printer properties button (gear icon) in Stage 2 opens the OS print dialog (`NSPrintPanel`), but it doesn't apply the paper size, quality, media type, or orientation selected in ICCery. ## Related to Issue #180 — Epson printer quality options limited to default only ## Bug Details ### Current Behavior 1. User selects a printer in the Stage 2 printer picker 2. User clicks the printer properties button (gear icon) 3. `PrintPanelService.showProperties()` is called with the selected queue 4. **Problem**: The `NSPrintPanel` opens but: - Does not pre-select the paper size chosen in Stage 1 (A4, Letter, custom, etc.) - Does not pre-select the print quality chosen in ICCery - Does not pre-select the media type selected in ICCery - Does not pre-select the orientation chosen in ICCery - Color management is disabled (correct), but other settings are not applied **Binding note:** "falls back to system default" is not possible on the PM path — `PMSessionSetCurrentPMPrinter` failure throws `sessionBindingFailed` (PrintPanelService.swift:83-87), and the `NSPrinter(name:)` fallback throws `noPrinterFound` when it can't resolve (:93-100). The realistic residual risk is the display-name fallback binding a *different* queue — hardware-verify, not a proven defect. ### Root Cause Analysis **In `PrintPanelService.runNativePanel()` (Sources/ICCery/Print/PrintPanelService.swift:64-162):** 1. Creates `NSPrintInfo()` with default values 2. Binds session to selected CUPS queue via `PMPrinterCreateFromPrinterID` + `PMSessionSetCurrentPMPrinter` 3. Calls `PMSessionDefaultPrintSettings` and `PMSessionDefaultPageFormat` — these load **printer defaults**, not user-selected values 4. Applies ColorSync suppression (layers ②–⑤) 5. Shows panel with `panel.runModal(with: printInfo)` **Missing:** - Pre-setting `PMPageFormat` paper size and `PMPrintSettings` quality/media/orientation before `runModal` - Capture-return currently parses only `cupsOptions`/`mediaType` (PrintPanelService.swift:142-161) — it must extend to `paperSize`/`quality`/`orientation` parsed from the captured `k=v` string ### Expected Behavior 1. Panel opens bound to the **selected** printer (not default) 2. Paper size pre-selected to match Stage 1 `pageSize` (A4 default) 3. Print quality pre-selected to match ICCery selection 4. Media type pre-selected to match ICCery selection 5. Orientation pre-selected to match ICCery selection (portrait default) ### Implementation Notes - Need to pass `pageSize`, `selectedQuality`, `selectedMediaType`, `printOrientation` from `PrintSessionViewModel` to `PrintPanelService.showProperties()` — the initial-selections plumbing for paper size + quality is #183 scope; this issue adds media type + orientation - In `runNativePanel()`, before showing panel: - **Paper size requires BOTH writes**: `PageSize` in `PMPrintSettings` (drivers/capture read it) **and** `PMPageFormat` via `PMPaper` — the panel's paper dropdown reflects `PMPageFormat`; `PMPrintSettingsSetValue` writes print settings only and cannot set the page format. Path: `PMPrinterGetPaperList`/`PMPaperGetID` + `PMPageFormatCreateWithPMPaper` + `PMSessionValidatePageFormat`; `printInfo.paperSize`/`PMPaperCreateCustom` for custom sizes. Verify exact PM calls against PrintCore headers at implementation (deprecated-but-present APIs on macOS 12) - Set quality via `PMPrintSettingsSetValue` with detected quality key (e.g., `EPIJ_Qual`, `cupsPrintQuality`) - Set media type via `PMPrintSettingsSetValue` with detected media key - Set orientation via `PMPrintSettingsSetValue` with `orientation-requested` - These settings should be applied **after** `PMSessionDefaultPrintSettings`/`PMSessionDefaultPageFormat` but **before** ColorSync suppression layers ②–⑤ ## Spec References - [11](11-print-macos.md) §Binding — `PMPrinterCreateFromPrinterID` → `PMSessionSetCurrentPMPrinter` - [11](11-print-macos.md) §Layer ④ — driver bypass detection (similar approach for quality/media) - [10](10-print-system.md) — `PrintOptions` structure carries `paper_size`, `media_type`, `orientation` (spec naming; Swift fields are `paperSize`/`mediaType`/`orientation`) ## Dependencies - **Depends on:** #183 (Stage 2 paper size/quality selection must exist), #180 (all quality options available), #181 (correct media type labels) - **Blocks:** None (final integration fix) - **Scope split with #183:** #183 wires `showProperties` initial-selections for paper size + quality; this issue completes media type + orientation preselect, capture-return of all fields, and binding verification ## Acceptance Criteria - [ ] Printer properties dialog opens with the selected printer pre-bound - [ ] Paper size in dialog matches Stage 1 selection (A4 default) - [ ] Print quality in dialog matches ICCery selection - [ ] Media type in dialog matches ICCery selection - [ ] Orientation in dialog matches ICCery selection (portrait default) - [ ] User changes in dialog are captured and returned via `PrintPropertiesResult` — including `paperSize`/`quality`/`orientation`, not only `cupsOptions`/`mediaType`
gronod added this to the M11 — Printer settings completeness & dialog binding milestone 2026-09-15 11:58:23 +01:00
Author
Owner

Planning errata (verified on develop@736fd08):

  1. "set PMPageFormat paper size via PMPrintSettingsSetValue" — PMPrintSettingsSetValue writes print settings only; the panel's paper dropdown reflects PMPageFormat. Both writes are required: PageSize in PMPrintSettings (drivers/capture read it) and PMPageFormat via PMPaper (PMPrinterGetPaperList/PMPaperGetID + PMPageFormatCreateWithPMPaper + PMSessionValidatePageFormat; printInfo.paperSize/PMPaperCreateCustom for custom). Exact PM calls verified against PrintCore headers at implementation (deprecated-but-present APIs on macOS 12).
  2. "falls back to system default" — impossible on the PM path (bind or throw, PrintPanelService.swift:83–87); the NSPrinter(name:) fallback throws noPrinterFound when nil (:95–99). The realistic failure is a display-name fallback binding a different queue — hardware-verify, not a proven defect.
  3. Capture-return must extend beyond cupsOptions/mediaType (currently the only fields parsed, PrintPanelService.swift:142–157) to paperSize/quality/orientation parsed from the captured k=v string.
Planning errata (verified on develop@736fd08): 1. "set `PMPageFormat` paper size via `PMPrintSettingsSetValue`" — `PMPrintSettingsSetValue` writes **print settings only**; the panel's paper dropdown reflects `PMPageFormat`. Both writes are required: `PageSize` in `PMPrintSettings` (drivers/capture read it) **and** `PMPageFormat` via `PMPaper` (`PMPrinterGetPaperList`/`PMPaperGetID` + `PMPageFormatCreateWithPMPaper` + `PMSessionValidatePageFormat`; `printInfo.paperSize`/`PMPaperCreateCustom` for custom). Exact PM calls verified against PrintCore headers at implementation (deprecated-but-present APIs on macOS 12). 2. "falls back to system default" — impossible on the PM path (bind or throw, PrintPanelService.swift:83–87); the `NSPrinter(name:)` fallback throws `noPrinterFound` when nil (:95–99). The realistic failure is a display-name fallback binding a *different* queue — hardware-verify, not a proven defect. 3. Capture-return must extend beyond `cupsOptions`/`mediaType` (currently the only fields parsed, PrintPanelService.swift:142–157) to `paperSize`/`quality`/`orientation` parsed from the captured `k=v` string.
gronod added the Bug/UIKind/Bug
Priority
High
2
Project/ICCery-v2
labels 2026-09-15 17:47:20 +01:00
Author
Owner

Errata above incorporated into the issue body — the ticket itself is now the corrected contract.

Errata above incorporated into the issue body — the ticket itself is now the corrected contract.
Author
Owner

Implementation landed in PR #196 at 6adbf99 on milestone/m11-print-settings.

Acceptance evidence:

  • Printer properties dialog opens bound to the selected (non-default) queue via PMPrinterCreateFromPrinterID + PMSessionSetCurrentPMPrinter — PrintPanelService runNativePanel; testPanelResultSwitchesToKnownQueue, testPanelResultGhostQueueIgnored (PrintSessionViewModelTests)
  • Paper size pre-selected to match Stage 1 pageSize — written to BOTH PMPrintSettings PageSize and PMPageFormat/PMPaper via PMCreatePageFormatWithPMPaper + PMSessionValidatePageFormat (named-paper match, validation, copy, and custom PMPaperCreateCustom path); PrintPanelStubTests coverage
  • Print quality pre-selected via PMPrintSettingsSetValue with the detected quality key (e.g., EPIJ_Qual) — stub coverage in PrintPanelStubTests (testOkResultExtractsNewFields, testOkResultExtractsVendorMediaKey)
  • Media type pre-selected via PMPrintSettingsSetValue with the detected media key, with vendor-roster extraction extended — testExtractMediaTypeRosterFallback (CupsParserTests)
  • Orientation pre-selected via PMPrintSettingsSetValue (orientation-requested 3/4, portrait default) — testExtractQualityAndOrientation (CupsParserTests)
  • All preselection writes ordered after PMSessionDefaultPrintSettings/PMSessionDefaultPageFormat and before ColorSync suppression layers ②–⑤ — ordering preserved in runNativePanel; preselection/fallback failures are warning-only
  • User changes captured and returned via PrintPropertiesResult including paperSize/quality/orientation/mediaType/cupsOptions; VM applies all back (workflow.pageSize untouched) — testCapturedStringMapsAllFields, testOkResultExtractsNewFields, testPanelResultAppliesBackSelections, testPanelResultAppliesBackOrientationAndMedia, testPanelResultUnknownPaperLeavesSelection (core); UI testPanelResultAppliesBackToPickers, testPanelResultAppliesBackOrientationAndMedia (Milestone11PrintSettingsUITests)
  • Cancel → nil + info notice; NSPrinter display-name fallback unchanged (+ warn log) — testCancelIsNil (PrintPanelStubTests), testPanelCancelLeavesSelections (PrintSessionViewModelTests); UI testPreferencesCancelIsInfo (Milestone3UITests)

Verification at milestone/m11-print-settings 6adbf99bd9:

  • xcodebuild test -scheme ICCery -destination 'platform=macOS' -derivedDataPath build/DerivedData-m11-final ARCHS="$(uname -m)" CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY='-' (x86_64): passed
  • full host-arch ICCeryCoreTests: 483 passed, 0 failed
  • full ICCeryUITests: 67 passed, 0 failed (genuine xctest pass summary; single allowed clean rerun consumed for an app-activation attach flake in run 1 — testAboutDialogShowsVersionAndBuildDate, no assertion failure)

Hardware item remains a milestone gate (not this issue's merge gate).
Closing manually only after code and tests are present on the milestone branch.

Implementation landed in PR #196 at 6adbf99 on milestone/m11-print-settings. Acceptance evidence: - [x] Printer properties dialog opens bound to the selected (non-default) queue via `PMPrinterCreateFromPrinterID` + `PMSessionSetCurrentPMPrinter` — PrintPanelService `runNativePanel`; `testPanelResultSwitchesToKnownQueue`, `testPanelResultGhostQueueIgnored` (PrintSessionViewModelTests) - [x] Paper size pre-selected to match Stage 1 `pageSize` — written to BOTH `PMPrintSettings` `PageSize` and `PMPageFormat`/`PMPaper` via `PMCreatePageFormatWithPMPaper` + `PMSessionValidatePageFormat` (named-paper match, validation, copy, and custom `PMPaperCreateCustom` path); PrintPanelStubTests coverage - [x] Print quality pre-selected via `PMPrintSettingsSetValue` with the detected quality key (e.g., `EPIJ_Qual`) — stub coverage in PrintPanelStubTests (`testOkResultExtractsNewFields`, `testOkResultExtractsVendorMediaKey`) - [x] Media type pre-selected via `PMPrintSettingsSetValue` with the detected media key, with vendor-roster extraction extended — `testExtractMediaTypeRosterFallback` (CupsParserTests) - [x] Orientation pre-selected via `PMPrintSettingsSetValue` (`orientation-requested` 3/4, portrait default) — `testExtractQualityAndOrientation` (CupsParserTests) - [x] All preselection writes ordered after `PMSessionDefaultPrintSettings`/`PMSessionDefaultPageFormat` and before ColorSync suppression layers ②–⑤ — ordering preserved in `runNativePanel`; preselection/fallback failures are warning-only - [x] User changes captured and returned via `PrintPropertiesResult` including `paperSize`/`quality`/`orientation`/`mediaType`/`cupsOptions`; VM applies all back (`workflow.pageSize` untouched) — `testCapturedStringMapsAllFields`, `testOkResultExtractsNewFields`, `testPanelResultAppliesBackSelections`, `testPanelResultAppliesBackOrientationAndMedia`, `testPanelResultUnknownPaperLeavesSelection` (core); UI `testPanelResultAppliesBackToPickers`, `testPanelResultAppliesBackOrientationAndMedia` (Milestone11PrintSettingsUITests) - [x] Cancel → `nil` + info notice; `NSPrinter` display-name fallback unchanged (+ warn log) — `testCancelIsNil` (PrintPanelStubTests), `testPanelCancelLeavesSelections` (PrintSessionViewModelTests); UI `testPreferencesCancelIsInfo` (Milestone3UITests) Verification at milestone/m11-print-settings 6adbf99bd9aaefd84a55a35442f1bd18bf8ab2c3: - `xcodebuild test -scheme ICCery -destination 'platform=macOS' -derivedDataPath build/DerivedData-m11-final ARCHS="$(uname -m)" CODE_SIGNING_ALLOWED=YES CODE_SIGN_IDENTITY='-'` (x86_64): passed - full host-arch ICCeryCoreTests: 483 passed, 0 failed - full ICCeryUITests: 67 passed, 0 failed (genuine xctest pass summary; single allowed clean rerun consumed for an app-activation attach flake in run 1 — `testAboutDialogShowsVersionAndBuildDate`, no assertion failure) Hardware item remains a milestone gate (not this issue's merge gate). Closing manually only after code and tests are present on the milestone branch.
Author
Owner

Follow-up filed: #217 — on real hardware (Epson XP-55) the dialog still opens on driver defaults. Root cause identified post-#201: the captured PrintTicket is never restored into the panel's NSPrintInfo (PMTicketBridge.restore is wired to NativeTargetSpooler only), and the four-key pre-select this issue added is never validated via PMSessionValidatePrintSettings before runModal. Details + proposed restore-then-override fix in #217.

Follow-up filed: #217 — on real hardware (Epson XP-55) the dialog still opens on driver defaults. Root cause identified post-#201: the captured `PrintTicket` is never restored into the panel's `NSPrintInfo` (`PMTicketBridge.restore` is wired to `NativeTargetSpooler` only), and the four-key pre-select this issue added is never validated via `PMSessionValidatePrintSettings` before `runModal`. Details + proposed restore-then-override fix in #217.
Sign in to join this conversation.
1 Participants
Notifications
Due Date
No due date set.
Reference: gronod/iccery-v2-mac#186