From bbd2323c3822821a84bcc359d05243b26dd24b55 Mon Sep 17 00:00:00 2001 From: terminills Date: Thu, 29 Oct 2026 16:21:57 -0500 Subject: [PATCH] printer.device: unit lock, Preferences encoding, PRD_SETJOBINFO Three fixes found while writing a printer driver against the device. pd_Close() indexed pb_UnitLock[] with the PDEV unit number from the prefs file instead of the unit the device was opened on. A printer.prefs without a PDEV chunk (as written before PDEV existed) left that number, and the unit name, as uninitialised stack memory in Printer_Unit(), so closing the device obtained and released a semaphore outside the array ("Semaphore in an illegal state" twice, every time a print finished). Use pd_UnitNumber, set from the opened unit, start the prefs from zero so missing chunks read as empty, and name the driver process "printer.device unit N" when the file gives no name. Printer prefs keep pitch, quality, spacing, paper size and paper type as small numbers (prefs/printertxt.h: PP_ELITE 1, PS_EURO_A4 9, ...), but struct Preferences, which printer.device fills in for the driver, holds them in their bit positions (intuition/preferences.h: ELITE 0x400, EURO_A4 0x90, ...). The values were copied over unconverted, so every paper size but US Letter reached the driver as something it does not know, and the PostScript driver refused to open with PDERR_BADDIMENSION from its PRS_PREINIT. Shift the five fields into place; PostScript and the skeleton driver compare against the Preferences constants throughout, as a driver gets them. Prefs/Printer stored the paper size already shifted, which is why files it saved used to reach the drivers right while files in the AmigaOS layout did not. It stores the index now, as AmigaOS does, so it also reads AmigaOS-made files correctly. A paper size that is a non-zero multiple of 0x10 can only be an old AROS file, so the editor and printer.device take that as already shifted, and existing ENVARC:Sys/printer*.prefs keep working. A print queue can only show job numbers: nothing tells the output device which program is printing what. printer.device now takes the opener's program name when the unit is opened (its CLI command name, else its task name), and a new command, PRD_SETJOBINFO, lets an application name the document (PJIA_Application, PJIA_Document tags). Both are passed on to the output device with the same command when the unit opens and whenever they change. The command is CMD_NONSTD + 15: the NDK and the AmigaOS 4 SDK use + 13 and + 14 for private commands, which the header now names. Output devices get it only if their NSCMD_DEVICEQUERY reply lists it, asked once when the unit opens its output device, since a third-party device may give the number another meaning; the header says the job is per unit and that the receiver must copy the strings. The test developer/debug/test/printer/unitlock writes a preferences file for unit 1 naming device unit 0 and the serial port, opens the unit, closes it, has a second process open it again, and sends PRD_SETJOBINFO. Unit 2 gets the same file with the paper size as the old editor saved it. The two units' existing prefs files are saved and put back. --- compiler/include/devices/printer.h | 15 +- developer/debug/test/printer/mmakefile.src | 9 +- developer/debug/test/printer/unitlock.c | 268 +++++++++++++++++++++ workbench/devs/printer/driver.c | 148 +++++++++++- workbench/devs/printer/printer_intern.h | 8 +- workbench/prefs/printer/editor.c | 16 +- workbench/printers/postscript/postscript.c | 12 +- workbench/printers/skeleton/skeleton.c | 12 +- 8 files changed, 459 insertions(+), 29 deletions(-) create mode 100644 developer/debug/test/printer/unitlock.c diff --git a/compiler/include/devices/printer.h b/compiler/include/devices/printer.h index ddc0c1438f3..397cbdc2c0a 100644 --- a/compiler/include/devices/printer.h +++ b/compiler/include/devices/printer.h @@ -2,7 +2,7 @@ #define DEVICES_PRINTER_H /* - Copyright © 1995-2001, The AROS Development Team. All rights reserved. + Copyright © 1995-2026, The AROS Development Team. All rights reserved. $Id$ Desc: printer device commands and structures @@ -39,6 +39,9 @@ #define PRD_EDITPREFS (CMD_NONSTD + 10) #define PRD_SETERRHOOK (CMD_NONSTD + 11) #define PRD_DUMPRPORTTAGS (CMD_NONSTD + 12) +#define PRD_PRIVATECMD (CMD_NONSTD + 13) /* AmigaOS: private */ +#define PRD_LASTSAVEDPREFS (CMD_NONSTD + 14) /* AmigaOS: private */ +#define PRD_SETJOBINFO (CMD_NONSTD + 15) /* AROS: io_Data = PJIA_ tags */ /* printer command definitions */ @@ -255,6 +258,16 @@ struct DRPSourceMsg ULONG *buf; }; +/* Tags for PRD_SETJOBINFO (AROS): what is being printed, for print queues. + The job is kept per printer.device unit, not per opener. printer.device + passes the command to an output device only if its NSCMD_DEVICEQUERY + reply lists it; the tags are on the sender's stack, so the receiver must + copy the strings. */ + +#define PJIA_Dummy (TAG_USER + 0x80000) +#define PJIA_Application (PJIA_Dummy + 1) /* STRPTR */ +#define PJIA_Document (PJIA_Dummy + 2) /* STRPTR */ + /* Tags for PRD_EDITPREFS */ #define PPRA_Dummy (TAG_USER + 0x70000) diff --git a/developer/debug/test/printer/mmakefile.src b/developer/debug/test/printer/mmakefile.src index ba0a2d1c112..7d03d75f0d3 100644 --- a/developer/debug/test/printer/mmakefile.src +++ b/developer/debug/test/printer/mmakefile.src @@ -12,12 +12,17 @@ EXEDIR := $(AROS_TESTS)/printer USER_CFLAGS += -DADATE="\"$(shell date '+%d.%m.%Y')\"" #MM- test: test-printer +#MM- test-printer : test-printer-commands test-printer-unitlock -#MM test-printer : includes includes-copy +#MM test-printer-commands : includes includes-copy +#MM test-printer-unitlock : includes includes-copy linklibs -%build_progs mmake=test-printer \ +%build_progs mmake=test-printer-commands \ files=$(TESTFILES) targetdir=$(EXEDIR) \ usestartup=no +%build_progs mmake=test-printer-unitlock \ + files=unitlock targetdir=$(EXEDIR) + %common diff --git a/developer/debug/test/printer/unitlock.c b/developer/debug/test/printer/unitlock.c new file mode 100644 index 00000000000..ca9d23aca50 --- /dev/null +++ b/developer/debug/test/printer/unitlock.c @@ -0,0 +1,268 @@ +/* + Copyright (C) 2026, The AROS Development Team. All rights reserved. + + printer.device unit 1 with a preferences file that names device unit 0: + closing it must release the lock of unit 1, so another task can open + unit 1 afterwards, and PRD_SETJOBINFO must be accepted. Unit 2 gets + the same file with the paper size as older Prefs/Printer saved it, + already shifted into its intuition/preferences.h position; the driver + must take both. Existing prefs files of the two units are put back. +*/ + +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include +#include + +#include + +#define UNIT 1 +#define OLDUNIT 2 + +static const char *prefs_file[] = { NULL, "ENV:SYS/printer1.prefs", "ENV:SYS/printer2.prefs" }; +static const char *saved_file[] = { NULL, "T:unitlock-printer1.prefs", "T:unitlock-printer2.prefs" }; +static BOOL had_file[3]; + +static struct Task *parent; +static volatile LONG child_result; +static volatile BOOL child_done; + +static LONG open_unit(LONG unit, struct IOStdReq **iop, struct MsgPort **portp) +{ + *portp = CreateMsgPort(); + *iop = *portp ? (struct IOStdReq *)CreateIORequest(*portp, sizeof(struct IODRPReq)) : NULL; + if (!*iop) + return -1; + return OpenDevice((CONST_STRPTR)"printer.device", unit, (struct IORequest *)*iop, 0); +} + +static void close_unit(struct IOStdReq *io, struct MsgPort *port, BOOL opened) +{ + if (opened) + CloseDevice((struct IORequest *)io); + if (io) + DeleteIORequest((struct IORequest *)io); + if (port) + DeleteMsgPort(port); +} + +static LONG child(void) +{ + struct IOStdReq *io; + struct MsgPort *port; + LONG err = open_unit(UNIT, &io, &port); + + close_unit(io, port, err == 0); + child_result = err; + child_done = TRUE; + Signal(parent, SIGBREAKF_CTRL_E); + return 0; +} + +static BOOL write_chunk(struct IFFHandle *iff, LONG id, APTR data, ULONG size) +{ + if (PushChunk(iff, ID_PREF, id, size)) + return FALSE; + if (WriteChunkBytes(iff, data, size) != (LONG)size) + return FALSE; + return PopChunk(iff) == 0; +} + +static BOOL write_prefs(LONG unitnum, UWORD papersize) +{ + struct PrefHeader hdr = { PHV_CURRENT, 0, 0 }; + struct PrinterTxtPrefs txt = { { 0 } }; + struct PrinterUnitPrefs unit = { { 0 } }; + struct PrinterDeviceUnitPrefs devunit = { { 0 } }; + struct PrinterGfxPrefs gfx = { { 0 } }; + struct IFFHandle *iff; + BOOL ok = FALSE; + + strcpy((char *)txt.pt_Driver, "PostScript"); + txt.pt_Port = PP_SERIAL; + txt.pt_PaperType = PT_SINGLE; + txt.pt_PaperSize = papersize; + txt.pt_PaperLength = 66; + txt.pt_Pitch = PP_PICA; + txt.pt_Spacing = PS_SIX_LPI; + txt.pt_RightMargin = 80; + txt.pt_Quality = PQ_DRAFT; + /* no device name: the serial port, as pt_Port says */ + devunit.pd_UnitNum = 0; /* not the unit being opened */ + strcpy((char *)devunit.pd_UnitName, "unitlock"); + + /* the file is big-endian, as Prefs/Printer writes it */ + txt.pt_PaperType = AROS_WORD2BE(txt.pt_PaperType); + txt.pt_PaperSize = AROS_WORD2BE(txt.pt_PaperSize); + txt.pt_PaperLength = AROS_WORD2BE(txt.pt_PaperLength); + txt.pt_Pitch = AROS_WORD2BE(txt.pt_Pitch); + txt.pt_Spacing = AROS_WORD2BE(txt.pt_Spacing); + txt.pt_RightMargin = AROS_WORD2BE(txt.pt_RightMargin); + txt.pt_Quality = AROS_WORD2BE(txt.pt_Quality); + devunit.pd_UnitNum = AROS_LONG2BE(devunit.pd_UnitNum); + + if (!(iff = AllocIFF())) + return FALSE; + if ((iff->iff_Stream = (IPTR)Open((CONST_STRPTR)prefs_file[unitnum], MODE_NEWFILE))) + { + InitIFFasDOS(iff); + if (!OpenIFF(iff, IFFF_WRITE)) + { + ok = !PushChunk(iff, ID_PREF, ID_FORM, IFFSIZE_UNKNOWN) && + write_chunk(iff, ID_PRHD, &hdr, sizeof(hdr)) && + write_chunk(iff, ID_PTXT, &txt, sizeof(txt)) && + write_chunk(iff, ID_PUNT, &unit, sizeof(unit)) && + write_chunk(iff, ID_PDEV, &devunit, sizeof(devunit)) && + write_chunk(iff, ID_PGFX, &gfx, sizeof(gfx)) && + !PopChunk(iff); + CloseIFF(iff); + } + Close((BPTR)iff->iff_Stream); + } + FreeIFF(iff); + return ok; +} + +/* copy src to dst; FALSE if src does not exist */ +static BOOL copy_file(const char *src, const char *dst) +{ + BPTR in, out; + UBYTE buf[1024]; + LONG n; + + if (!(in = Open((CONST_STRPTR)src, MODE_OLDFILE))) + return FALSE; + if ((out = Open((CONST_STRPTR)dst, MODE_NEWFILE))) + { + while ((n = Read(in, buf, sizeof(buf))) > 0) + Write(out, buf, n); + Close(out); + } + Close(in); + return TRUE; +} + +static void save_prefs(LONG unit) +{ + had_file[unit] = copy_file(prefs_file[unit], saved_file[unit]); +} + +static void restore_prefs(LONG unit) +{ + if (had_file[unit]) + { + copy_file(saved_file[unit], prefs_file[unit]); + DeleteFile((CONST_STRPTR)saved_file[unit]); + } + else + DeleteFile((CONST_STRPTR)prefs_file[unit]); +} + +int main(void) +{ + struct IOStdReq *io = NULL; + struct MsgPort *port = NULL; + LONG err, failures = 0, waited; + + save_prefs(UNIT); + save_prefs(OLDUNIT); + if (!write_prefs(UNIT, PS_EURO_A4) || !write_prefs(OLDUNIT, EURO_A4)) + { + Printf("FAIL: cannot write the preferences files\n"); + restore_prefs(UNIT); + restore_prefs(OLDUNIT); + return RETURN_FAIL; + } + + err = open_unit(UNIT, &io, &port); + if (err) + { + Printf("FAIL: cannot open printer.device unit %ld (%ld)\n", (IPTR)UNIT, (IPTR)err); + failures++; + } + else + Printf("PASS: opened printer.device unit %ld\n", (IPTR)UNIT); + close_unit(io, port, err == 0); + + /* the paper size as the AROS editor saved it before: A4 as 0x90 */ + err = open_unit(OLDUNIT, &io, &port); + if (err) + { + Printf("FAIL: cannot open unit %ld with the old paper size encoding (%ld)\n", (IPTR)OLDUNIT, (IPTR)err); + failures++; + } + else + Printf("PASS: opened unit %ld with the old paper size encoding\n", (IPTR)OLDUNIT); + close_unit(io, port, err == 0); + + /* another task opens the unit after the first closed it */ + parent = FindTask(NULL); + SetSignal(0, SIGBREAKF_CTRL_E); + if (CreateNewProcTags(NP_Entry, (IPTR)child, NP_Name, (IPTR)"unitlock child", TAG_DONE)) + { + for (waited = 0; waited < 100 && !child_done; waited++) + { + if (SetSignal(0, SIGBREAKF_CTRL_E) & SIGBREAKF_CTRL_E) + break; + Delay(5); + } + if (child_done && child_result == 0) + Printf("PASS: a second task could open unit %ld after it was closed\n", (IPTR)UNIT); + else if (!child_done) + { + Printf("FAIL: a second task is still blocked opening unit %ld after 10 seconds\n", (IPTR)UNIT); + failures++; + } + else + { + Printf("FAIL: the second task could not open unit %ld (%ld)\n", (IPTR)UNIT, (IPTR)child_result); + failures++; + } + } + else + { + Printf("FAIL: cannot start the second task\n"); + failures++; + } + +#ifdef PRD_SETJOBINFO + if (child_done && open_unit(UNIT, &io, &port) == 0) + { + struct TagItem tags[] = { + { PJIA_Application, (IPTR)"unitlock" }, + { PJIA_Document, (IPTR)"unit lock test" }, + { TAG_DONE, 0 } + }; + io->io_Command = PRD_SETJOBINFO; + io->io_Data = tags; + io->io_Length = 0; + io->io_Flags = 0; + DoIO((struct IORequest *)io); + if (io->io_Error == 0) + Printf("PASS: PRD_SETJOBINFO accepted\n"); + else + { + Printf("FAIL: PRD_SETJOBINFO error %ld\n", (IPTR)io->io_Error); + failures++; + } + close_unit(io, port, TRUE); + } +#endif + + restore_prefs(UNIT); + restore_prefs(OLDUNIT); + Printf("UNITLOCK %s\n", (IPTR)(failures ? "FAIL" : "PASS")); + return failures ? RETURN_FAIL : RETURN_OK; +} diff --git a/workbench/devs/printer/driver.c b/workbench/devs/printer/driver.c index 99a1272a3aa..6b6b51bb01b 100644 --- a/workbench/devs/printer/driver.c +++ b/workbench/devs/printer/driver.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012-2017, The AROS Development Team. All rights reserved. + * Copyright (C) 2012-2026, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 @@ -17,8 +17,10 @@ #include #include #include +#include #include +#include #include #include @@ -92,6 +94,78 @@ static BOOL initMsgPort(struct MsgPort *port) return TRUE; } +/* "printer.device unit N" for a prefs file without a PDEV chunk */ +static void pd_DefaultUnitName(UBYTE *name, LONG unitnum) +{ + static const char prefix[] = "printer.device unit "; + char digits[12]; + int n = 0, i; + + CopyMem((APTR)prefix, name, sizeof(prefix) - 1); + i = sizeof(prefix) - 1; + do { + digits[n++] = '0' + unitnum % 10; + unitnum /= 10; + } while (unitnum && n < (int)sizeof(digits)); + while (n > 0 && i < UNITNAMESIZE - 1) + name[i++] = digits[--n]; + name[i] = 0; +} + +/* Whether the output device lists PRD_SETJOBINFO in its NSCMD_DEVICEQUERY + reply; a device that does not is never sent it. */ +static void pd_QueryJobInfo(struct PrinterData *pd) +{ + struct PrinterUnit *pu = pd->pd_PUnit; + struct IOStdReq *io = (struct IOStdReq *)&pd->pd_ior0; + struct NSDeviceQueryResult nsd; + UWORD *cmd; + + pu->pu_JobInfoSupported = FALSE; + memset(&nsd, 0, sizeof(nsd)); + io->io_Command = NSCMD_DEVICEQUERY; + io->io_Flags = 0; + io->io_Data = &nsd; + io->io_Length = sizeof(nsd); + io->io_Message.mn_Length = sizeof(*io); + if (DoIO((struct IORequest *)io) != 0 || io->io_Actual < sizeof(nsd) || nsd.SupportedCommands == NULL) + return; + for (cmd = nsd.SupportedCommands; *cmd; cmd++) + if (*cmd == PRD_SETJOBINFO) + pu->pu_JobInfoSupported = TRUE; +} + +/* The opener's program name: its CLI command name, or its task name. */ +static void pd_SetJobApplication(struct PrinterUnit *pu) +{ + struct Task *task = FindTask(NULL); + CONST_STRPTR name = task->tc_Node.ln_Name; + TEXT command[64]; + + if (task->tc_Node.ln_Type == NT_PROCESS && ((struct Process *)task)->pr_CLI != BNULL) { + struct CommandLineInterface *cli = BADDR(((struct Process *)task)->pr_CLI); + LONG len = AROS_BSTR_strlen(cli->cli_CommandName); + + if (len > 0) { + CONST_STRPTR start; + STRPTR c; + + if (len >= (LONG)sizeof(command)) + len = sizeof(command) - 1; + CopyMem(AROS_BSTR_ADDR(cli->cli_CommandName), command, len); + command[len] = 0; + start = command; + for (c = command; *c; c++) + if (*c == ':' || *c == '/') + start = c + 1; + name = start; + } + } + strncpy(pu->pu_JobApplication, name ? (const char *)name : "", sizeof(pu->pu_JobApplication) - 1); + pu->pu_JobApplication[sizeof(pu->pu_JobApplication) - 1] = 0; + pu->pu_JobDocument[0] = 0; +} + STATIC AROS_LH3(LONG, OpenDevice, AROS_LHA(struct IORequest *, io, A1), AROS_LHA(IPTR, unitNumber, D0), @@ -105,6 +179,8 @@ STATIC AROS_LH3(LONG, OpenDevice, if ((mp = CreateMsgPort())) { struct IORequest ior = *io; + + pd_SetJobApplication(pu); ior.io_Message.mn_ReplyPort = mp; ior.io_Command = CMD_OPENDEVICE; ret = DoIO(&ior); @@ -256,6 +332,29 @@ static LONG pd_PBothReady(VOID) return 0; } +/* Tells the output device what is being printed; devices that do not know + PRD_SETJOBINFO ignore it. */ +static void pd_SendJobInfo(struct PrinterData *pd) +{ + struct PrinterUnit *pu = pd->pd_PUnit; + struct IOStdReq *io = (struct IOStdReq *)&pd->pd_ior0; + struct TagItem tags[] = { + { PJIA_Application, (IPTR)pu->pu_JobApplication }, + { PJIA_Document, (IPTR)pu->pu_JobDocument }, + { TAG_END, 0 } + }; + + if ((pd->pd_Flags & PDF_NOIO) || !pu->pu_JobInfoSupported) + return; + WaitIOStd(io); + io->io_Command = PRD_SETJOBINFO; + io->io_Flags = 0; + io->io_Data = tags; + io->io_Length = 0; + io->io_Message.mn_Length = sizeof(*io); + DoIOStd(io); +} + static LONG pd_PRead(char * buffer, LONG *length, struct timeval *tv) { ULONG sigs; @@ -423,6 +522,7 @@ static LONG pd_Init(struct PrinterData *pd) (struct IORequest *)&pd->pd_ior0, 0)) { D(bug("%s: open %s %d for io 0\n", __func__, devname, pd->pd_Preferences.DefaultPrtUnit)); pd->pd_ior0.pd_p0.IOPar.io_Message.mn_Node.ln_Type = 0; + pd_QueryJobInfo(pd); pd->pd_ior1.pd_p1.io_ParFlags = PARF_SHARED; if ((pd->pd_ior1.pd_p1.IOPar.io_Message.mn_ReplyPort=CreateMsgPort())) { @@ -467,7 +567,7 @@ static VOID pd_Close(struct PrinterData *pd, union printerIO *pio) { struct PrinterBase *PrinterBase = pd->pd_PUnit->pu_PrinterBase; struct PrinterExtendedData *ped = &pd->pd_SegmentData->ps_PED; - LONG unitnum = pd->pd_PUnit->pu_Prefs.pp_DeviceUnit.pd_UnitNum; + LONG unitnum = pd->pd_UnitNumber; ped->ped_Close(pio); @@ -581,9 +681,35 @@ static LONG pd_DriverTask(VOID) switch (cmd) { case CMD_OPENDEVICE: err = ped->ped_Open(pio); - if (err == 0) + if (err == 0) { + pd_SendJobInfo(pd); Printer_Text_Write(pd, "\033#1", 3); /* aRIN */ + } break; + case PRD_SETJOBINFO: + { + struct TagItem *tags = (struct TagItem *)pio->ios.io_Data, *tag; + struct PrinterUnit *pu = pd->pd_PUnit; + + while ((tag = LibNextTagItem(&tags))) { + STRPTR dest = NULL; + LONG size = 0; + + if (tag->ti_Tag == PJIA_Application) { + dest = pu->pu_JobApplication; + size = sizeof(pu->pu_JobApplication); + } else if (tag->ti_Tag == PJIA_Document) { + dest = pu->pu_JobDocument; + size = sizeof(pu->pu_JobDocument); + } + if (dest != NULL) { + strncpy(dest, tag->ti_Data ? (const char *)tag->ti_Data : "", size - 1); + dest[size - 1] = 0; + } + } + pd_SendJobInfo(pd); + break; + } case CMD_CLOSEDEVICE: pd_Close(pd, pio); break; @@ -679,17 +805,17 @@ static void pd_SyncPrefs(struct PrinterData *pd) sizeof(dprefs->PrinterFilename)); dprefs->PrinterFilename[sizeof(dprefs->PrinterFilename)-1] = 0; - dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch; - dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality; - dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing; + dprefs->PrintPitch = uprefs->pp_Txt.pt_Pitch << 10; + dprefs->PrintQuality = uprefs->pp_Txt.pt_Quality << 8; + dprefs->PrintSpacing = uprefs->pp_Txt.pt_Spacing << 9; dprefs->PrintLeftMargin = uprefs->pp_Txt.pt_LeftMargin; dprefs->PrintRightMargin = uprefs->pp_Txt.pt_RightMargin; dprefs->PrintImage = uprefs->pp_Gfx.pg_Image; dprefs->PrintAspect = uprefs->pp_Gfx.pg_Aspect; dprefs->PrintShade = uprefs->pp_Gfx.pg_Shade; dprefs->PrintThreshold = uprefs->pp_Gfx.pg_Threshold; - dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize; - dprefs->PaperType = uprefs->pp_Txt.pt_PaperType; + dprefs->PaperSize = uprefs->pp_Txt.pt_PaperSize << 4; + dprefs->PaperType = uprefs->pp_Txt.pt_PaperType << 7; dprefs->PaperLength = uprefs->pp_Txt.pt_PaperLength; if (uprefs->pp_Unit.pu_DeviceName[0] == 0) { @@ -734,13 +860,17 @@ static void pd_SyncPrefs(struct PrinterData *pd) struct PrinterUnit *Printer_Unit(struct PrinterBase *PrinterBase, LONG unitnum) { struct PrinterUnit *pu; - struct PrinterPrefs prefs; + struct PrinterPrefs prefs = { 0 }; BPTR olddir, dir, driverseg; if (!Printer_LoadPrefs(PrinterBase, unitnum, &prefs) || prefs.pp_Txt.pt_Driver[0] == 0) { D(bug("%s: No valid prefs for printer.device %d\n", __func__, unitnum)); return NULL; } + if (prefs.pp_Txt.pt_PaperSize && (prefs.pp_Txt.pt_PaperSize & 0xF) == 0) + prefs.pp_Txt.pt_PaperSize >>= 4; /* saved by an older Prefs/Printer, already shifted */ + if (prefs.pp_DeviceUnit.pd_UnitName[0] == 0) + pd_DefaultUnitName(prefs.pp_DeviceUnit.pd_UnitName, unitnum); if ((dir = Lock("DEVS:Printers", SHARED_LOCK)) != BNULL) { olddir = CurrentDir(dir); diff --git a/workbench/devs/printer/printer_intern.h b/workbench/devs/printer/printer_intern.h index 9749868ba4b..c14226fdedc 100644 --- a/workbench/devs/printer/printer_intern.h +++ b/workbench/devs/printer/printer_intern.h @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, The AROS Development Team. All rights reserved. + * Copyright (C) 2012-2026, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 @@ -42,6 +42,12 @@ struct PrinterUnit { BYTE pt_CRLF; BYTE pt_Spacing; } pu_Text; + + /* What is being printed, passed on to the output device (PRD_SETJOBINFO) + when it lists the command; one job per unit, the last opener's */ + BOOL pu_JobInfoSupported; + TEXT pu_JobApplication[64]; + TEXT pu_JobDocument[128]; }; /*********************************************************************************************/ diff --git a/workbench/prefs/printer/editor.c b/workbench/prefs/printer/editor.c index 46961c9a9bc..3e90752746a 100644 --- a/workbench/prefs/printer/editor.c +++ b/workbench/prefs/printer/editor.c @@ -1,5 +1,5 @@ /* - Copyright (C) 2003-2021, The AROS Development Team. All rights reserved. + Copyright (C) 2003-2026, The AROS Development Team. All rights reserved. */ #define MUIMASTER_YES_INLINE_STDARG @@ -546,6 +546,14 @@ static inline double fromdeci(LONG units, LONG value) return val; } +/* The file holds the PS_ index, as AmigaOS writes it; files this editor + wrote before held the intuition/preferences.h value, the index shifted + by four, which an index never is. */ +STATIC LONG PaperSizeIndex(UWORD saved) +{ + return (saved && (saved & 0xF) == 0) ? saved >> 4 : saved; +} + STATIC void UpdatePrintMax (struct PrinterEditor_DATA *data, int units, BOOL from_prefs) { LONG width, height; @@ -553,7 +561,7 @@ STATIC void UpdatePrintMax (struct PrinterEditor_DATA *data, int units, BOOL fro LONG pt_PaperSize; if (from_prefs) { - pt_PaperSize = printerprefs.pp_Txt.pt_PaperSize; + pt_PaperSize = PaperSizeIndex(printerprefs.pp_Txt.pt_PaperSize) << 4; } else { pt_PaperSize = XGET(data->pt_PaperSize, MUIA_Cycle_Active) << 4; } @@ -642,7 +650,7 @@ STATIC void Gadgets2PrinterPrefs (Class *CLASS, Object *self) strcpy(txt->pt_Driver, (CONST_STRPTR)XGET(data->pt_Driver, MUIA_Text_Contents)); txt->pt_PaperType = XGET(data->pt_PaperType, MUIA_Cycle_Active); - txt->pt_PaperSize = XGET(data->pt_PaperSize, MUIA_Cycle_Active) << 4; + txt->pt_PaperSize = XGET(data->pt_PaperSize, MUIA_Cycle_Active); UpdatePrintMax(data, units, FALSE); @@ -711,7 +719,7 @@ STATIC VOID PrinterPrefs2Gadgets(Class *CLASS, Object *self) NNSET(data->pt_Driver, MUIA_Text_Contents, txt->pt_Driver); NNSET(data->pt_Port, MUIA_Cycle_Active, txt->pt_Port); NNSET(data->pt_PaperType, MUIA_Cycle_Active, txt->pt_PaperType); - NNSET(data->pt_PaperSize, MUIA_Cycle_Active, txt->pt_PaperSize >> 4); + NNSET(data->pt_PaperSize, MUIA_Cycle_Active, PaperSizeIndex(txt->pt_PaperSize)); NNSET(data->pt_PaperLength, MUIA_String_Integer, txt->pt_PaperLength); NNSET(data->pt_Pitch, MUIA_Cycle_Active, txt->pt_Pitch); NNSET(data->pt_Spacing, MUIA_Cycle_Active, txt->pt_Spacing); diff --git a/workbench/printers/postscript/postscript.c b/workbench/printers/postscript/postscript.c index a20882fe9a3..43e3ca70e6c 100644 --- a/workbench/printers/postscript/postscript.c +++ b/workbench/printers/postscript/postscript.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, The AROS Development Team. All rights reserved. + * Copyright (C) 2012-2026, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 @@ -820,16 +820,16 @@ static LONG ps_RenderPreInit(struct IODRPReq *io, LONG flags) } switch (PD->pd_Preferences.PrintPitch) { - case PP_ELITE: ps_FontCPI = 120; break; - case PP_FINE: ps_FontCPI = 171; break; - case PP_PICA: ps_FontCPI = 100; break; + case ELITE: ps_FontCPI = 120; break; + case FINE: ps_FontCPI = 171; break; + case PICA: ps_FontCPI = 100; break; default: return PDERR_BADDIMENSION; } switch (PD->pd_Preferences.PrintSpacing) { - case PS_SIX_LPI: ps_SpacingLPI = 6; break; - case PS_EIGHT_LPI: ps_SpacingLPI = 8; break; + case SIX_LPI: ps_SpacingLPI = 6; break; + case EIGHT_LPI: ps_SpacingLPI = 8; break; default: return PDERR_BADDIMENSION; } diff --git a/workbench/printers/skeleton/skeleton.c b/workbench/printers/skeleton/skeleton.c index 01a7fbb7ea9..5ff16ec7af9 100644 --- a/workbench/printers/skeleton/skeleton.c +++ b/workbench/printers/skeleton/skeleton.c @@ -1,5 +1,5 @@ /* - * Copyright (C) 2012, The AROS Development Team. All rights reserved. + * Copyright (C) 2012-2026, The AROS Development Team. All rights reserved. * Author: Jason S. McMullan * * Licensed under the AROS PUBLIC LICENSE (APL) Version 1.1 @@ -512,16 +512,16 @@ static LONG sk_RenderPreInit(struct IODRPReq *io, LONG flags) } switch (PD->pd_Preferences.PrintPitch) { - case PP_ELITE: sk_FontCPI = 120; break; - case PP_FINE: sk_FontCPI = 171; break; - case PP_PICA: sk_FontCPI = 100; break; + case ELITE: sk_FontCPI = 120; break; + case FINE: sk_FontCPI = 171; break; + case PICA: sk_FontCPI = 100; break; default: return PDERR_BADDIMENSION; } switch (PD->pd_Preferences.PrintSpacing) { - case PS_SIX_LPI: sk_SpacingLPI = 6; break; - case PS_EIGHT_LPI: sk_SpacingLPI = 8; break; + case SIX_LPI: sk_SpacingLPI = 6; break; + case EIGHT_LPI: sk_SpacingLPI = 8; break; default: return PDERR_BADDIMENSION; }