From f481e3490147d42d0289fef06b25d6665b87670b Mon Sep 17 00:00:00 2001 From: Matthias Melcher Date: Sun, 29 May 2022 23:45:53 +0200 Subject: [PATCH] Host printer support (#175) * Initial implementation of printing. * Working Printer code for 3 dpi settings * Added Printer Driver files. * Fixed formatting * Disable printer code on unsupported platforms. * Format * Fixes for other platforms * Syntax * Release notes * Name conflict * Include files * Format * Fixing warning --- CMakeLists.txt | 2 +- Drivers/Einstein.rex.src | 1 + Drivers/PrinterDriver/EinsteinDriver.cp | 1 + Drivers/PrinterDriver/EinsteinDriver.impl.h | 1 + Drivers/PrinterDriver/EinsteinDriver.pf | 1 + Drivers/PrinterDriver/EinsteinDriverPrims.a | 1 + Drivers/PrinterDriver/FilesInBuild | 1 + Drivers/PrinterDriver/Makefile | 1 + Drivers/PrinterDriver/Makeout | 0 Drivers/PrinterDriver/printerDriver.pkg | Bin 0 -> 1784 bytes Emulator/CMakeLists.txt | 1 + Emulator/Printer/CMakeLists.txt | 17 + Emulator/Printer/TFLPrinterManager.cpp | 432 ++++++++++++++++++++ Emulator/Printer/TFLPrinterManager.h | 133 ++++++ Emulator/Printer/TPrinterManager.cpp | 150 +++++++ Emulator/Printer/TPrinterManager.h | 136 ++++++ Emulator/TEmulator.cpp | 5 +- Emulator/TEmulator.h | 15 +- Emulator/TNativePrimitives.cpp | 162 ++++++++ Emulator/TNativePrimitives.h | 9 + ReleaseText.md | 12 + Toolkit/TToolkitScriptExt.cpp | 19 +- _Data_/Einstein.rex | Bin 287972 -> 289840 bytes app/FLTK/TFLApp.cpp | 8 +- app/FLTK/TFLApp.h | 1 + 25 files changed, 1104 insertions(+), 5 deletions(-) create mode 100644 Drivers/PrinterDriver/EinsteinDriver.cp create mode 100644 Drivers/PrinterDriver/EinsteinDriver.impl.h create mode 100644 Drivers/PrinterDriver/EinsteinDriver.pf create mode 100644 Drivers/PrinterDriver/EinsteinDriverPrims.a create mode 100644 Drivers/PrinterDriver/FilesInBuild create mode 100644 Drivers/PrinterDriver/Makefile create mode 100644 Drivers/PrinterDriver/Makeout create mode 100644 Drivers/PrinterDriver/printerDriver.pkg create mode 100644 Emulator/Printer/CMakeLists.txt create mode 100644 Emulator/Printer/TFLPrinterManager.cpp create mode 100644 Emulator/Printer/TFLPrinterManager.h create mode 100644 Emulator/Printer/TPrinterManager.cpp create mode 100644 Emulator/Printer/TPrinterManager.h diff --git a/CMakeLists.txt b/CMakeLists.txt index 3e0891e69..a41919171 100644 --- a/CMakeLists.txt +++ b/CMakeLists.txt @@ -7,7 +7,7 @@ cmake_minimum_required(VERSION 3.13) -project( "Einstein" VERSION "2022.4.18" ) +project( "Einstein" VERSION "2022.4.19" ) # ---- Configuration for all targets on all platforms diff --git a/Drivers/Einstein.rex.src b/Drivers/Einstein.rex.src index c108b83d7..b1e054270 100644 --- a/Drivers/Einstein.rex.src +++ b/Drivers/Einstein.rex.src @@ -35,6 +35,7 @@ package "obj/EinsteinSerialVoyager.pkg" package "obj/EinsteinInTranslator.pkg" package "obj/EinsteinOutTranslator.pkg" package "obj/EinsteinNativeCalls.pkg" +package "PrinterDriver/printerDriver.pkg" // Handlers & NS runtime. package "NSRuntime/Einstein NS Runtime.pkg" // NewtTest 1.1i diff --git a/Drivers/PrinterDriver/EinsteinDriver.cp b/Drivers/PrinterDriver/EinsteinDriver.cp new file mode 100644 index 000000000..ac8bb71b9 --- /dev/null +++ b/Drivers/PrinterDriver/EinsteinDriver.cp @@ -0,0 +1 @@ +/* File: EinsteinDriver.cp Contains: Newton printer driver for the Einstein emulator. This is an implementation of the TDotPrinterDriver protocol. Copyright: (c)2022, Matthias Melcher, based on the Kodak sample printer driver included in the DDK © 1992-1994 by Apple Computer, Inc., all rights reserved. */ #ifndef __EINSTEINDRIVER_H #include "EinsteinDriver.impl.h" // **Master File Name** (.impl.h) #endif #ifndef __string_h #include "string.h" #endif #ifndef __stdio_h #include "stdio.h" #endif #ifndef __COMMMANAGERINTERFACE_H #include "CommManagerInterface.h" #endif #ifndef __COMMSERVICES_H #include "CommServices.h" #endif #ifndef __ENDPOINT_H #include "Endpoint.h" #endif #ifndef __SERIALOPTIONS_H #include "SerialOptions.h" #endif /* NATIVE_PRIM 0x0C01, PDNew NATIVE_PRIM 0x0C02, PDDelete NATIVE_PRIM 0x0C03, PDOpen NATIVE_PRIM 0x0C04, PDClose NATIVE_PRIM 0x0C05, PDOpenPage NATIVE_PRIM 0x0C06, PDClosePage NATIVE_PRIM 0x0C07, PDImageBand NATIVE_PRIM 0x0C08, PDCancelJob NATIVE_PRIM 0x0C09, PDIsProblemResolved NATIVE_PRIM 0x0C0A, PDGetPageInfo NATIVE_PRIM 0x0C0B, PDGetBandPrefs NATIVE_PRIM 0x0C0C, PDFaxEndPage */ extern "C" { void PDNew(DRIVERCLASSNAME *self); void PDDelete(DRIVERCLASSNAME *self); NewtonErr PDOpen(DRIVERCLASSNAME *self); NewtonErr PDClose(DRIVERCLASSNAME *self); NewtonErr PDOpenPage(DRIVERCLASSNAME *self); NewtonErr PDClosePage(DRIVERCLASSNAME *self); NewtonErr PDImageBand(DRIVERCLASSNAME *self, PixelMap* theBand, const Rect* minRect); void PDCancelJob(DRIVERCLASSNAME *self, Boolean asyncCancel); PrProblemResolution PDIsProblemResolved(DRIVERCLASSNAME *self); void PDGetPageInfo(DRIVERCLASSNAME *self, PrPageInfo* info); void PDGetBandPrefs(DRIVERCLASSNAME *self, DotPrinterPrefs* prefs); NewtonErr PDFaxEndPage(DRIVERCLASSNAME *self, long pageCount); } PROTOCOL_IMPL_SOURCE_MACRO(DRIVERCLASSNAME) /*----- Globals -----*/ // IMPORTANT: LOADED PROTOCOLS MAY NOT HAVE GLOBALS // If you have driver-global data, it belongs in your object. /*----- Driver Functions -----*/ /*----------------------------------------------------------------------------- NewtonErr Open(void) Initialize and Open the driver. Remember, if this call fails, no other calls will follow. So you must clean up anything you do here (especially allocations). -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::Open(void) { fAsyncIntf = nil; fCurrentError = noErr; // PRINT(("DRIVERCLASSNAME::Open")); { // check user-specified psuedo-driver RefVar routingSlip = fConnect->fConnectInfo; RefVar prRef = GetFrameSlot(routingSlip, SYM(printer)); RefVar modelRef = GetFrameSlot(prRef, SYM(prmodel)); fHWType = (EinsteinVersion) RINT(modelRef); } return PDOpen(this); } /*----------------------------------------------------------------------------- void Delete(void) Historical entry point. Probably shouldn't be used. -----------------------------------------------------------------------------*/ void DRIVERCLASSNAME::Delete(void) { PDDelete(this); } /*----------------------------------------------------------------------------- NewtonErr Close(void) Close the driver. This call should follow this format: send final commands close connection cleanup allocations -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::Close() { return PDClose(this); } /*----------------------------------------------------------------------------- NewtonErr OpenPage(void) Send any commands required to begin a new page. -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::OpenPage() { return PDOpenPage(this); } /*----------------------------------------------------------------------------- NewtonErr ClosePage(void) Send any commands required to finish a page. -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::ClosePage() { return PDClosePage(this); } /*----------------------------------------------------------------------------- NewtonErr ImageBand(PixelMap* theBand, const Rect* minBounds) -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::ImageBand(PixelMap* theBand, const Rect* minBounds) { return PDImageBand(this, theBand, minBounds); } /*----------------------------------------------------------------------------- void CancelJob(Boolean asyncCancel) Called by the print loop if we are going to early-abort a print job. The print loop will still call the appropriate close() calls. This just warns the driver that something fishy is going on. -----------------------------------------------------------------------------*/ void DRIVERCLASSNAME::CancelJob(Boolean asyncCancel) { PDCancelJob(this, asyncCancel); return; } /*----------------------------------------------------------------------------- PrProblemResolution IsProblemResolved(void); Report on the possible resolution of the current problem or error. -----------------------------------------------------------------------------*/ PrProblemResolution DRIVERCLASSNAME::IsProblemResolved(void) { return PDIsProblemResolved(this); } /*----------------------------------------------------------------------------- void GetPageInfo(PrPageInfo* result) -----------------------------------------------------------------------------*/ void DRIVERCLASSNAME::GetPageInfo(PrPageInfo* result) { PrPageInfo dummy; dummy.printerDPI.x = Long2Fixed(300); dummy.printerDPI.y = Long2Fixed(300); dummy.printerPageSize.v = (Short) 10.375*300; dummy.printerPageSize.h = (Short) (2400); *result = dummy; PDGetPageInfo(this, result); return; } /*----------------------------------------------------------------------------- void GetBandPrefs(DotPrinterPrefs* result) -----------------------------------------------------------------------------*/ void DRIVERCLASSNAME::GetBandPrefs(DotPrinterPrefs* result) { DotPrinterPrefs dummy; dummy.minBand = 50; // 50 because of 50 pin head dummy.optimumBand = 50; dummy.asyncBanding = false; dummy.wantMinBounds = true; *result = dummy; PDGetBandPrefs(this, result); return; } /*----------------------------------------------------------------------------- NewtonErr FaxEndPage(long pageCount) This method is used only by the fax driver. For all others, leave empty. -----------------------------------------------------------------------------*/ NewtonErr DRIVERCLASSNAME::FaxEndPage(long pageCount) { return PDFaxEndPage(this, pageCount); } \ No newline at end of file diff --git a/Drivers/PrinterDriver/EinsteinDriver.impl.h b/Drivers/PrinterDriver/EinsteinDriver.impl.h new file mode 100644 index 000000000..77bf5cef6 --- /dev/null +++ b/Drivers/PrinterDriver/EinsteinDriver.impl.h @@ -0,0 +1 @@ +/* File: EinsteinDriver.impl.h Contains: Protocol Implementation header for sample driver Copyright: © 1992-1994 by Apple Computer, Inc., all rights reserved. */ #ifndef __EINSTEINDRIVER_H #define __EINSTEINDRIVER_H #ifndef __DOTDRIVERS_H #include "DotDrivers.h" #endif #define DRIVERCLASSNAME TEinsteinDriver // **Driver Protocol Name** class TEndpoint; typedef enum { k180si = 0, k701 } EinsteinVersion; PROTOCOL DRIVERCLASSNAME : public TDotPrinterDriver PROTOCOLVERSION(1.0) { // Everything in the "public" section is specified by the // protocol definition in "DotDrivers.h". Don't change it. public: PROTOCOL_IMPL_HEADER_MACRO(DRIVERCLASSNAME); void Delete(void); NewtonErr Open(void); NewtonErr Close(void); NewtonErr OpenPage(void); NewtonErr ClosePage(void); NewtonErr ImageBand(PixelMap* theBand, const Rect* minRect); void CancelJob(Boolean asyncCancel); PrProblemResolution IsProblemResolved(void); void GetPageInfo(PrPageInfo* info); void GetBandPrefs(DotPrinterPrefs* prefs); NewtonErr FaxEndPage(long pageCount); // New method for 2.0 // These two fields are automatically created by the // protocol interface (see DotDrivers.h). You will be // able to access them from your code. // PrintConnect* fConnect; // TPrinter* fPrinter; private: // Driver-specific items go here, as private items. void Cleanup(); Boolean InitConnection(); void SendData(Ptr data, long length); void SendString(char* str); void ReleaseConnection(); TEndpoint* fAsyncIntf; EinsteinVersion fHWType; NewtonErr fCurrentError; }; #endif \ No newline at end of file diff --git a/Drivers/PrinterDriver/EinsteinDriver.pf b/Drivers/PrinterDriver/EinsteinDriver.pf new file mode 100644 index 000000000..123b6099e --- /dev/null +++ b/Drivers/PrinterDriver/EinsteinDriver.pf @@ -0,0 +1 @@ +# # File: EinsteinDriver.pf # # Contains: Pram source to build sample print driver # # Copyright: © 1992-1994 by Apple Computer, Inc., all rights reserved. # # # one entry each for the driver(s) we are building # each entry must contain name, driverName, imagingName, and type. # only multiplexed drivers will use the last field; # set it to zero otherwise. # Name driverName imagingName type prModel "EinsteinPrtr 72dpi" TEinsteinDriver TDotPrinter serialSym 0 "EinsteinPrtr 150dpi" TEinsteinDriver TDotPrinter serialSym 1 "EinsteinPrtr 300dpi" TEinsteinDriver TDotPrinter serialSym 2 \ No newline at end of file diff --git a/Drivers/PrinterDriver/EinsteinDriverPrims.a b/Drivers/PrinterDriver/EinsteinDriverPrims.a new file mode 100644 index 000000000..7af7aaae4 --- /dev/null +++ b/Drivers/PrinterDriver/EinsteinDriverPrims.a @@ -0,0 +1 @@ +; ============================== ; File: EinsteinDriverPrims.s ; Project: Einstein ; ; Copyright 2022 by Matthias Melcher (einstein@messagepad.org) ; ; This program is free software; you can redistribute it and/or modify ; it under the terms of the GNU General Public License as published by ; the Free Software Foundation; either version 2 of the License, or ; (at your option) any later version. ; ; This program is distributed in the hope that it will be useful, ; but WITHOUT ANY WARRANTY; without even the implied warranty of ; MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the ; GNU General Public License for more details. ; ; You should have received a copy of the GNU General Public License along ; with this program; if not, write to the Free Software Foundation, Inc., ; 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. ; ============================== MACRO NATIVE_PRIM $id, $symbol AREA $symbol, CODE, READONLY EXPORT $symbol stmdb sp!, {lr} ldr lr, id_for_$symbol mcr p10, 0, lr, c0, c0 ldmia sp!, {pc} id_for_$symbol DCD $id MEND NATIVE_PRIM 0x0C01, PDNew NATIVE_PRIM 0x0C02, PDDelete NATIVE_PRIM 0x0C03, PDOpen NATIVE_PRIM 0x0C04, PDClose NATIVE_PRIM 0x0C05, PDOpenPage NATIVE_PRIM 0x0C06, PDClosePage NATIVE_PRIM 0x0C07, PDImageBand NATIVE_PRIM 0x0C08, PDCancelJob NATIVE_PRIM 0x0C09, PDIsProblemResolved NATIVE_PRIM 0x0C0A, PDGetPageInfo NATIVE_PRIM 0x0C0B, PDGetBandPrefs NATIVE_PRIM 0x0C0C, PDFaxEndPage END ; =========================================================================== ; ; THEGODDESSOFTHENETHASTWISTINGFINGERSANDHERVOICEISLIKEAJAVELININTHENIGHTDUDE ; ; =========================================================================== ; \ No newline at end of file diff --git a/Drivers/PrinterDriver/FilesInBuild b/Drivers/PrinterDriver/FilesInBuild new file mode 100644 index 000000000..1dd28efa0 --- /dev/null +++ b/Drivers/PrinterDriver/FilesInBuild @@ -0,0 +1 @@ +# DDK project created on Tuesday, August 20, 1996 4:38:22 PM # by Newton C++ Tools #PackageofParts LocalLinkOptions="-dupok " LocalARMCppOptions="-cfront -W " LocalCfronttOptions="" LocalCfrontCOptions="-W " LocalCOptions="-d forARM " LocalPackerOptions=" -packageid 'xxxx' -copyright 'Copyright (c) 1997 Apple Computer, Inc.'" # add/change/delete lines like those below for other include files needed by your source files. -i "{DDK_Includes-dir}" -ic "{DDK_Includes-dir}Bootstrap" -ic "{DDK_Includes-dir}CLibrary" -ic "{DDK_Includes-dir}CommAPI" -ic "{DDK_Includes-dir}Communications" -ic "{DDK_Includes-dir}Frames" -ic "{DDK_Includes-dir}HAL" -ic "{DDK_Includes-dir}OS600" -ic "{DDK_Includes-dir}Packages" -ic "{DDK_Includes-dir}Power" -ic "{DDK_Includes-dir}PSS" -ic "{DDK_Includes-dir}QD" -ic "{DDK_Includes-dir}Toolbox" -ic "{DDK_Includes-dir}UtilityClasses" -ic "{DDK_Includes-dir}Printing" -srcdirs ':' -tpart -protocol -aif "{Objects-dir}printerDriver.bin" -autoload -autoRemove # add lines here with the names of your protocol source files EinsteinDriverPrims.s EinsteinDriver.cp -clike EinsteinDriver.impl.h # ARMCpp will compile files named with the suffix .cp # ARMCfront will compile files named with the suffix .cf # ARMCpp -ansic will compile files named with the suffix .c # ARMAsm will compile files named with the suffix .a "{DDK_Libraries-dir}CardGlue.a.o" # Repeat the -tpart line above for other -protocol parts or -frame parts, etc # and follow it with source/library file lines to build it # use a line like this Ô-clike ExampleTool.impl.hÕ for the .impl.h files of a protocol -tpart -frames "{Objects-dir}EinsteinDriver.pf.part" -notify 'prnt' ¶"¶" EinsteinDriver.pf # following line defines the final build target name followed by the Òpackage nameÓ # and any other Packer options you didn't define above in the LocalPackerOptions= definition. -tpackage "{Objects-dir}printerDriver.pkg" "printerDriver" -version 01 \ No newline at end of file diff --git a/Drivers/PrinterDriver/Makefile b/Drivers/PrinterDriver/Makefile new file mode 100644 index 000000000..bda460f2b --- /dev/null +++ b/Drivers/PrinterDriver/Makefile @@ -0,0 +1 @@ +# This makefile was produced at 2:07:23 PM on Tue, Jan 14, 1997 # by MakeMake 2.0d45 (3/16/1994) by Rick Holzgrafe, scott douglass, Jeff Holcomb. MAKEFILE = Makefile Objects-dir = :{NCT-ObjectOut}: LIB = "{NCT-lib}" {NCT-lib-options} {LocalLibOptions} LINK = "{NCT-link}" LINKOPTS = {NCT-link-options} {LocalLinkOptions} Asm = "{NCT-asm}" {NCT-asm-options} {LocalAsmOptions} CFront = "{NCT-cfront}" {NCT-cfront-options} {LocalCFrontOptions} CFrontC = "{NCT-cfront-c}" {NCT-cfront-c-options} {LocalCfrontCOptions} C = "{NCT-ARM6c}" {NCT-ARM6c-options} ARMCPlus = "{NCT-ARMCpp}" {NCT-ARMCpp-options} {LocalARMCppOptions} ProtocolOptions = -package Pram = "{NCT-pram}" {NCT-pram-options} {LocalPRAMOptions} SETFILE = {NCT-setfile-cmd} LocalLinkOptions = -dupok LocalARMCppOptions = -cfront -W LocalCfronttOptions = LocalCfrontCOptions = -W LocalCOptions = -d forARM LocalPackerOptions = -packageid 'xxxx' -copyright 'Copyright (c) 1997 Apple Computer, Inc.' COUNT = Count COUNTOPTS = CTAGS = CTags CTAGSOPTS = -local -update DELETE = Delete DELETEOPTS = -i FILES = Files FILESOPTS = -l LIBOPTS = PRINT = Print PRINTOPTS = REZ = Rez SETFILEOPTS = -t 'MPST' -c 'MPS ' "{Objects-dir}" Ä : TARGETS = "{Objects-dir}printerDriver.bin" ¶ "{Objects-dir}EinsteinDriver.pf.part" "{Objects-dir}printerDriver.pkg" # For "{Objects-dir}printerDriver.bin" OBJS_00 = "{Objects-dir}EinsteinDriver.cp.o" ¶ "{Objects-dir}EinsteinDriver.impl.h.o" ¶ "{Objects-dir}EinsteinDriverPrims.a.o" ¶ # For "{Objects-dir}printerDriver.bin" LIBS_00 = "{DDK_Libraries-dir}CardGlue.a.o" # For "{Objects-dir}EinsteinDriver.pf.part" EXDEPS_01 = EinsteinDriver.pf # For "{Objects-dir}printerDriver.pkg" EXDEPS_02 = "{Objects-dir}printerDriver.bin" ¶ "{Objects-dir}EinsteinDriver.pf.part" AOptions = -i "{DDK_Includes-dir}" COptions = -i "{DDK_Includes-dir}" -i "{DDK_Includes-dir}Bootstrap" ¶ -i "{DDK_Includes-dir}CLibrary" -i "{DDK_Includes-dir}CommAPI" ¶ -i "{DDK_Includes-dir}Communications" -i "{DDK_Includes-dir}Frames" ¶ -i "{DDK_Includes-dir}HAL" -i "{DDK_Includes-dir}OS600" ¶ -i "{DDK_Includes-dir}Packages" -i "{DDK_Includes-dir}Power" ¶ -i "{DDK_Includes-dir}PSS" -i "{DDK_Includes-dir}QD" ¶ -i "{DDK_Includes-dir}Toolbox" -i "{DDK_Includes-dir}UtilityClasses" ¶ -i "{DDK_Includes-dir}Printing" {NCT_DebugSwitch} {LocalCOptions} POptions = -i "{DDK_Includes-dir}" ROptions = -i "{DDK_Includes-dir}" -a all Ä {TARGETS} "{Objects-dir}printerDriver.bin" ÄÄ {OBJS_00} {LIBS_00} {LINK} {LINKOPTS} -o {Targ} {OBJS_00} {LIBS_00} "{Objects-dir}printerDriver.bin" ÄÄ {OBJS_00} {LIBS_00} {SETFILE} {SETFILEOPTS} {Targ} "{Objects-dir}printerDriver.pkg" ÄÄ {EXDEPS_02} "{NCT-packer}" -o {Targ} "printerDriver" {NCT-packer-options} {LocalPackerOptions} -version 01 ¶ -protocol -aif "{Objects-dir}printerDriver.bin" -autoload -autoRemove ¶ -frames "{Objects-dir}EinsteinDriver.pf.part" -notify 'prnt' "" "{Objects-dir}printerDriver.pkg" ÄÄ {EXDEPS_02} {SETFILE} -t "pkg " -c {NCT-package-creator} {Targ} clean Ä {DELETE} {DELETEOPTS} {OBJS_00} clobber Ä clean {DELETE} {DELETEOPTS} {TARGETS} files Ä {FILES} {FILESOPTS} {TARGETS} {MAKEFILE} "{NCTTools}DDKBuildMakefile.Post" ¶ {OBJS_00} print Ä {PRINT} {PRINTOPTS} {MAKEFILE} "{NCTTools}DDKBuildMakefile.Post" tags Ä {CTAGS} {CTAGSOPTS} {NewerDeps} -i "{DDK_Includes-dir}" ¶ -i "{DDK_Includes-dir}Bootstrap" -i "{DDK_Includes-dir}CLibrary" ¶ -i "{DDK_Includes-dir}CommAPI" -i "{DDK_Includes-dir}Communications" ¶ -i "{DDK_Includes-dir}Frames" -i "{DDK_Includes-dir}HAL" ¶ -i "{DDK_Includes-dir}OS600" -i "{DDK_Includes-dir}Packages" ¶ -i "{DDK_Includes-dir}Power" -i "{DDK_Includes-dir}PSS" ¶ -i "{DDK_Includes-dir}QD" -i "{DDK_Includes-dir}Toolbox" ¶ -i "{DDK_Includes-dir}UtilityClasses" -i "{DDK_Includes-dir}Printing" "{Objects-dir}EinsteinDriverPrims.a.o" Ä ¶ EinsteinDriverPrims.a "{Objects-dir}EinsteinDriver.cp.o" Ä ¶ EinsteinDriver.cp EinsteinDriver.impl.h ¶ "{DDK_Includes-dir}Printing:DotDrivers.h" ¶ "{DDK_Includes-dir}Printing:ConfigPrinting.h" ¶ "{DDK_Includes-dir}ConfigGlobal.h" "{DDK_Includes-dir}Newton.h" ¶ "{DDK_Includes-dir}CLibrary:stdlib.h" ¶ "{DDK_Includes-dir}CLibrary:string.h" ¶ "{DDK_Includes-dir}CLibrary:stddef.h" "{DDK_Includes-dir}NewtonTypes.h" ¶ "{DDK_Includes-dir}NewtonWidgets.h" "{DDK_Includes-dir}NewtonTime.h" ¶ "{DDK_Includes-dir}Toolbox:CompMath.h" ¶ "{DDK_Includes-dir}Toolbox:ConfigToolbox.h" ¶ "{DDK_Includes-dir}NewtonMemory.h" ¶ "{DDK_Includes-dir}NewtonExceptions.h" ¶ "{DDK_Includes-dir}CLibrary:setjmp.h" "{DDK_Includes-dir}NewtonDebug.h" ¶ "{DDK_Includes-dir}CLibrary:stdio.h" ¶ "{DDK_Includes-dir}Printing:PrintTypes.h" ¶ "{DDK_Includes-dir}QD:NewtQD.h" "{DDK_Includes-dir}QD:ConfigQD.h" ¶ "{DDK_Includes-dir}Frames:Objects.h" ¶ "{DDK_Includes-dir}Frames:ConfigFrames.h" ¶ "{DDK_Includes-dir}OS600:OSErrors.h" "{DDK_Includes-dir}NewtErrors.h" ¶ "{DDK_Includes-dir}Packages:PartHandler.h" ¶ "{DDK_Includes-dir}Packages:PackageTypes.h" ¶ "{DDK_Includes-dir}OS600:KernelTypes.h" ¶ "{DDK_Includes-dir}OS600:ConfigOS600.h" ¶ "{DDK_Includes-dir}Toolbox:FixedMath.h" ¶ "{DDK_Includes-dir}CommAPI:UserAbort.h" ¶ "{DDK_Includes-dir}UtilityClasses:AEventHandler.h" ¶ "{DDK_Includes-dir}UtilityClasses:ItemComparer.h" ¶ "{DDK_Includes-dir}UtilityClasses:ItemTester.h" ¶ "{DDK_Includes-dir}UtilityClasses:AEvents.h" ¶ "{DDK_Includes-dir}UtilityClasses:TimerQueue.h" ¶ "{DDK_Includes-dir}OS600:LongTime.h" ¶ "{DDK_Includes-dir}OS600:UserPorts.h" ¶ "{DDK_Includes-dir}OS600:UserObjects.h" ¶ "{DDK_Includes-dir}OS600:SharedTypes.h" ¶ "{DDK_Includes-dir}OS600:UserSharedMem.h" ¶ "{DDK_Includes-dir}OS600:UserGlobals.h" "{DDK_Includes-dir}NewtConfig.h" ¶ "{DDK_Includes-dir}HammerConfigBits.h" ¶ "{DDK_Includes-dir}Printing:PrintErrors.h" ¶ "{DDK_Includes-dir}Printing:DriverCallbacks.h" ¶ "{DDK_Includes-dir}OS600:Protocols.h" ¶ "{DDK_Includes-dir}CommAPI:CommManagerInterface.h" ¶ "{DDK_Includes-dir}OS600:SystemEvents.h" ¶ "{DDK_Includes-dir}OS600:NameServer.h" ¶ "{DDK_Includes-dir}CommAPI:OptionArray.h" ¶ "{DDK_Includes-dir}Toolbox:NewtMemory.h" ¶ "{DDK_Includes-dir}CommAPI:CommOptions.h" ¶ "{DDK_Includes-dir}CommAPI:CommServices.h" ¶ "{DDK_Includes-dir}CommAPI:Endpoint.h" ¶ "{DDK_Includes-dir}CommAPI:Transport.h" ¶ "{DDK_Includes-dir}Communications:SerialOptions.h" "{Objects-dir}EinsteinDriver.impl.h.o" Ä ¶ EinsteinDriver.impl.h "{DDK_Includes-dir}Printing:DotDrivers.h" ¶ "{DDK_Includes-dir}Printing:ConfigPrinting.h" ¶ "{DDK_Includes-dir}ConfigGlobal.h" "{DDK_Includes-dir}Newton.h" ¶ "{DDK_Includes-dir}CLibrary:stdlib.h" ¶ "{DDK_Includes-dir}CLibrary:string.h" ¶ "{DDK_Includes-dir}CLibrary:stddef.h" "{DDK_Includes-dir}NewtonTypes.h" ¶ "{DDK_Includes-dir}NewtonWidgets.h" "{DDK_Includes-dir}NewtonTime.h" ¶ "{DDK_Includes-dir}Toolbox:CompMath.h" ¶ "{DDK_Includes-dir}Toolbox:ConfigToolbox.h" ¶ "{DDK_Includes-dir}NewtonMemory.h" ¶ "{DDK_Includes-dir}NewtonExceptions.h" ¶ "{DDK_Includes-dir}CLibrary:setjmp.h" "{DDK_Includes-dir}NewtonDebug.h" ¶ "{DDK_Includes-dir}CLibrary:stdio.h" ¶ "{DDK_Includes-dir}Printing:PrintTypes.h" ¶ "{DDK_Includes-dir}QD:NewtQD.h" "{DDK_Includes-dir}QD:ConfigQD.h" ¶ "{DDK_Includes-dir}Frames:Objects.h" ¶ "{DDK_Includes-dir}Frames:ConfigFrames.h" ¶ "{DDK_Includes-dir}OS600:OSErrors.h" "{DDK_Includes-dir}NewtErrors.h" ¶ "{DDK_Includes-dir}Packages:PartHandler.h" ¶ "{DDK_Includes-dir}Packages:PackageTypes.h" ¶ "{DDK_Includes-dir}OS600:KernelTypes.h" ¶ "{DDK_Includes-dir}OS600:ConfigOS600.h" ¶ "{DDK_Includes-dir}Toolbox:FixedMath.h" ¶ "{DDK_Includes-dir}CommAPI:UserAbort.h" ¶ "{DDK_Includes-dir}UtilityClasses:AEventHandler.h" ¶ "{DDK_Includes-dir}UtilityClasses:ItemComparer.h" ¶ "{DDK_Includes-dir}UtilityClasses:ItemTester.h" ¶ "{DDK_Includes-dir}UtilityClasses:AEvents.h" ¶ "{DDK_Includes-dir}UtilityClasses:TimerQueue.h" ¶ "{DDK_Includes-dir}OS600:LongTime.h" ¶ "{DDK_Includes-dir}OS600:UserPorts.h" ¶ "{DDK_Includes-dir}OS600:UserObjects.h" ¶ "{DDK_Includes-dir}OS600:SharedTypes.h" ¶ "{DDK_Includes-dir}OS600:UserSharedMem.h" ¶ "{DDK_Includes-dir}OS600:UserGlobals.h" "{DDK_Includes-dir}NewtConfig.h" ¶ "{DDK_Includes-dir}HammerConfigBits.h" ¶ "{DDK_Includes-dir}Printing:PrintErrors.h" ¶ "{DDK_Includes-dir}Printing:DriverCallbacks.h" ¶ "{DDK_Includes-dir}OS600:Protocols.h" .cp.o Ä .cp {ARMCPlus} {depDir}{Default}.cp {COptions} -o {targDir}{Default}.cp.o .cf.o Ä .cf {CFront} {depDir}{Default}.cf {COptions} {NCT-cfront-redirection} "{{CPlusScratch}}"X{Default}.cf -o {targDir}{Default}.cf.o {CFrontC} "{{CPlusScratch}}"X{Default}.cf -o {targDir}{Default}.cf.o ; Delete -i "{{CPlusScratch}}"X{Default}.cf .c.o Ä .c {C} {depDir}{Default}.c -o {targDir}{Default}.c.o {COptions} .exp.o Ä .exp "{NCTTools}"NCTBuildMain {depDir}{Default}.exp "{{CPlusScratch}}" {Asm} "{{CplusScratch}}"{Default}.exp.main.a -o {targDir}{Default}.exp.o ; Delete -i "{{CPlusScratch}}"{Default}.exp.main.a .a.o Ä .a {Asm} {depDir}{Default}.a -o {targDir}{Default}.a.o {AOptions} # defualt rule for Pram tool build of Printer DDK form part containing UI strings for System printer selection dialogs .pf.part Ä .pf {Pram} {depDir}{Default}.pf -o {targDir}{Default}.pf.part # # Rules for building protocol glue # # .h.o caller glue (what callers link against) # .impl.h.o implementation glue (linked into provider) # .h.o Ä .h ProtocolGen -InterfaceGlue {depDir}{Default}.h {COptions} -stdout > "{{CPlusScratch}}"{Default}.glue.a {Asm} "{{CPlusScratch}}"{Default}.glue.a -o {targDir}{Default}.h.o ; Delete -i "{{CPlusScratch}}"{Default}.glue.a .impl.h.o Ä .impl.h ProtocolGen -ImplementationGlue {depDir}{Default}.impl.h {ProtocolOptions} {COptions} -stdout >"{{CPlusScratch}}"{Default}.impl.a {Asm} "{{CPlusScratch}}"{Default}.impl.a -o {targDir}{Default}.impl.h.o ; Delete -i "{{CPlusScratch}}"{Default}.impl.a # backward compatability rule for old apple DDK's .j.c.o Ä .j.c {C} {depDir}{Default}.j.c -o {targDir}{Default}.j.c.o {COptions} \ No newline at end of file diff --git a/Drivers/PrinterDriver/Makeout b/Drivers/PrinterDriver/Makeout new file mode 100644 index 000000000..e69de29bb diff --git a/Drivers/PrinterDriver/printerDriver.pkg b/Drivers/PrinterDriver/printerDriver.pkg new file mode 100644 index 0000000000000000000000000000000000000000..cfbab7fa99478e097e605bdda18acf28e035b9e4 GIT binary patch literal 1784 zcma)6U1$?o7(LTY()4HD2>xW-f>A5F&}h>t(iPbTQ&FrMw-wnZ8_iG$n{=FvVtlIL zgFd)hWYJx8cjr+-K}A6nWnV;mSbSCR!D$&xTakbY?!!{gotccO4&ogS-*?abzVqF` zxmxz%;p~Xgb({@ulV~#h+JW$UkE@y&bn4tr{Te{PZ(Y9U@O2f2Ry4g}c>GC>dfpa{ zK|={TRE*#d48*Yp2k|{^621I3(n~Q$V~#>!WaQa9%2`Rlokrrc9CLrukzgj37idsnP>M=#f zPvV`Zmif;&(}`!5$${&# zW%fbTw@)EP#O>b@wI?7Gm}MQy)G+z$w<~9XLH1u+W(M{|6!ry<0|VqnEaE$?6eE=77*Vs@7 zqA4y+H2&XV3s~Cc^g?@oibdb-A2fKNBe)AJ@%dYGZI4pAo-N@n`HpJ7NTY^)gg8T7 zAs!RfgR8UGfW?0PB~yJ?$mSKMGr!H}%ezlY#uXppmyq+XBpsRL8K&@_w=QK}O2EIzShpJ!D4KM#hH^TG$q)NI0B}S8Q=TMxm2#$?eQ^h-@+x%;R^L7;^z;0 Ck@1}X literal 0 HcmV?d00001 diff --git a/Emulator/CMakeLists.txt b/Emulator/CMakeLists.txt index cbf8f62e0..508954976 100644 --- a/Emulator/CMakeLists.txt +++ b/Emulator/CMakeLists.txt @@ -10,6 +10,7 @@ include ( Emulator/NativeCalls/CMakeLists.txt ) include ( Emulator/Network/CMakeLists.txt ) include ( Emulator/PCMCIA/CMakeLists.txt ) include ( Emulator/Platform/CMakeLists.txt ) +include ( Emulator/Printer/CMakeLists.txt ) include ( Emulator/ROM/CMakeLists.txt ) include ( Emulator/Screen/CMakeLists.txt ) include ( Emulator/Serial/CMakeLists.txt ) diff --git a/Emulator/Printer/CMakeLists.txt b/Emulator/Printer/CMakeLists.txt new file mode 100644 index 000000000..421107470 --- /dev/null +++ b/Emulator/Printer/CMakeLists.txt @@ -0,0 +1,17 @@ +# +# Add source files required to build Einstein. +# + +list ( APPEND cmake_sources + Emulator/Printer/CMakeLists.txt +) + +list ( APPEND common_sources + Emulator/Printer/TPrinterManager.cpp + Emulator/Printer/TPrinterManager.h +) + +list ( APPEND app_sources + Emulator/Printer/TFLPrinterManager.cpp + Emulator/Printer/TFLPrinterManager.h +) diff --git a/Emulator/Printer/TFLPrinterManager.cpp b/Emulator/Printer/TFLPrinterManager.cpp new file mode 100644 index 000000000..8d02c2059 --- /dev/null +++ b/Emulator/Printer/TFLPrinterManager.cpp @@ -0,0 +1,432 @@ +// ============================== +// File: TFLPrinterManager.h +// Project: Einstein +// +// Copyright 2022 by Matthias Melcher (einstein@messagepad.org). +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ============================== +// $Id$ +// ============================== + +#include "TFLPrinterManager.h" + +#include "Emulator/TMemory.h" + +#include +#include +#include + +#include + +#if TARGET_OS_WIN32 +#include +#include +#else +#include +#include +#endif + +// Einstein. + +// -------------------------------------------------------------------------- // +// Constantes +// -------------------------------------------------------------------------- // + +// -------------------------------------------------------------------------- // +// * TFLPrinterManager(TLog*) +// -------------------------------------------------------------------------- // +TFLPrinterManager::TFLPrinterManager(TLog* inLog /* = nil */) : + TPrinterManager(inLog) +{ + (void) mLog; +} + +/** + Delete the printer manager and the printer driver if allocated. + + Safely finsh the printing process and delete the FLTK driver + from the main thread. + */ +TFLPrinterManager::~TFLPrinterManager() +{ + // Tell the main thread to delete the printer driver at the next occasion. + if (mPrinter) + { + // Is the page still open? + if (mState == State::PageOpen) + ClosePage(mDrvr); + + // Is the printer still active? + if (mState == State::Open) + Close(mDrvr); + + // Is the FLTK printer driver allocated? + Fl::awake( + [](void* inPrinter) { delete (Fl_Printer*) inPrinter; }, + mPrinter); + mPrinter = nullptr; + mState = State::Uninitialized; + } +} + +/** + Close any active printer connection. + + Safely finsh the printing process and prepare for another print run. + */ +void +TFLPrinterManager::Delete(KUInt32 inDrvr) +{ + // KPrintf("Delete\n"); + if (mPrinter) + { + // Is the page still open? + if (mState == State::PageOpen) + ClosePage(inDrvr); + + // Is the printer still active? + if (mState == State::Open) + Close(inDrvr); + } +} + +/** + Allocate the FLTK printer driver if needed and open the host printer dialog. + + Must be done from the main thread. + */ +KUInt32 +TFLPrinterManager::Open(KUInt32 inDrvr) +{ + // KPrintf("Open\n"); + + KUInt32 ret = 0; + + if (!mPrinter) + { + mDrvr = inDrvr; + Fl::lock(); + mPrinter = new Fl_Printer(); + Fl::unlock(); + mState = State::Allocated; + } + + // Is the page still open? + if (mState == State::PageOpen) + ClosePage(inDrvr); + + if (mState != State::Open) + { + mPromise = new std::promise; + mFuture = mPromise->get_future(); + + Fl::awake( + [](void* userdata) { + TFLPrinterManager* self = (TFLPrinterManager*) userdata; + self->SyncOpen(); + }, + this); + + mFuture.wait(); + ret = mFuture.get(); + if (ret == 1) + { + ret = kPR_ERR_UserCancel; + } else if (ret >= 2) + { + ret = kPR_ERR_PrinterError; + } else + { + ret = 0; + mState = State::Open; + } + + delete mPromise; + } + SetScale(inDrvr); + return ret; +} + +void +TFLPrinterManager::SetScale(KUInt32 inDrvr) +{ + switch (GetSubType(inDrvr)) + { + case kSubtype72dpi: + mPrinter->scale(1.0); // FLTK default is 72dpi + break; + case kSubtype150dpi: + mPrinter->scale(72.0 / 150.0); // FLTK default is 72dpi + break; + case kSubtype300dpi: + mPrinter->scale(72.0 / 300.0); // FLTK default is 72dpi + break; + } +} + +void +TFLPrinterManager::SyncOpen() +{ + int ret = mPrinter->begin_job(); + mPromise->set_value(ret); +} + +KUInt32 +TFLPrinterManager::Close(KUInt32 inDrvr) +{ + // KPrintf("Close\n"); + + KUInt32 ret = 0; + + if (!mPrinter) + return kPR_ERR_NewtonError; + + // Is the page still open? + if (mState == State::PageOpen) + ClosePage(inDrvr); + + if (mState == State::Open) + { + mPromise = new std::promise; + mFuture = mPromise->get_future(); + + Fl::awake( + [](void* userdata) { + TFLPrinterManager* self = (TFLPrinterManager*) userdata; + self->SyncClose(); + }, + this); + + mFuture.wait(); + + mState = State::Allocated; + + delete mPromise; + } + + return ret; +} + +void +TFLPrinterManager::SyncClose() +{ + mPrinter->end_job(); + mPromise->set_value(0); +} + +KUInt32 +TFLPrinterManager::OpenPage(KUInt32 inDrvr) +{ + // KPrintf("OpenPage\n"); + + mPrinter->begin_page(); + mPrinter->push_current(mPrinter); + SetScale(inDrvr); + mPrinter->pop_current(); + return 0; +} + +KUInt32 +TFLPrinterManager::ClosePage(KUInt32 inDrvr) +{ + (void) inDrvr; + // KPrintf("ClosePage\n"); + + mPrinter->end_page(); + return 0; +} + +KUInt32 +TFLPrinterManager::ImageBand(KUInt32 inDrvr, KUInt32 inBand, KUInt32 inRect) +{ + (void) inDrvr; + (void) inBand; + (void) inRect; + // KPrintf("ImageBand\n"); + + // TODO: we currently only support 1 bit bitmaps + // TODO: we should give an error message for unsupported bitmap formats + // #define kPixMapStorage 0xC0000000 // to mask off the appropriate bits + // #define kPixMapHandle 0x00000000 // baseAddr is a handle + // #define kPixMapPtr 0x40000000 // baseAddr is a pointer + // #define kPixMapOffset 0x80000000 // baseAddr is an offset from the PixelMap + // #define kPixMapLittleEndian 0x20000000 // pixMap is little endian + // #define kPixMapAllocated 0x10000000 // pixMap "owns" the bits memory + // #ifdef QD_Gray + // #define kPixMapGrayTable 0x08000000 // grayTable field exists + // #define kPixMapNoPad 0x04000000 // direct pixel format, no pad byte + // #define kPixMapByComponent 0x02000000 // direct pixel format, stored by component + // #define kPixMapAntiAlias 0x01000000 // antialiasing ink text + // #endif + // #define kPixMapVersionMask 0x0000F000 // version of this struct + // #define kPixMapDeviceType 0x00000F00 // bits 8..11 are device type code + // #define kPixMapDevScreen 0x00000000 // screen or offscreen bitmap + // #define kPixMapDevDotPrint 0x00000100 // dot matrix printer + // #define kPixMapDevPSPrint 0x00000200 // postscript printer + // #define kPixMapDepth 0x000000FF // bits 0..7 are chunky pixel depth + struct PixelMap { + KUInt32 baseAddr; + KUInt16 rowBytes, pad; // 300, pads to long + KUInt16 top, left, bottom, right; + KUInt32 pixMapFlags; // 0x40000101, ptr, dot printer, 1 bit + // Point deviceRes; // resolution of input device (0 indicates kDefaultDPI + // UChar* grayTable; // gray tone table + } band; + + mMemory->FastReadBuffer(inBand, sizeof(band), (KUInt8*) &band); + band.baseAddr = htonl(band.baseAddr); + band.rowBytes = htons(band.rowBytes); + band.top = htons(band.top); + band.left = htons(band.left); + band.bottom = htons(band.bottom); + band.right = htons(band.right); + band.pixMapFlags = htonl(band.pixMapFlags); + + // KPrintf("T:%d, L:%d, B:%d, R:%d\n", band.top, band.left, band.bottom, band.right); + + Fl::lock(); + Fl_Printer::push_current(mPrinter); + SetScale(inDrvr); + mPrinter->origin(0, 0); + + fl_push_no_clip(); + fl_color(FL_BLACK); + + int w = band.right - band.left; + int h = band.bottom - band.top; + int rowWords = (band.rowBytes + 3) / 4; // row bytes must be 32bit aligned + int bytes = rowWords * 4 * h; + KUInt8* bits = (KUInt8*) malloc(bytes); + mMemory->FastReadBuffer(band.baseAddr, bytes, bits); + + int nBlack = 0; + int nWhite = 0; + KUInt8* gray = (KUInt8*) malloc(w * h); + KUInt8* dst = gray; + for (int y = 0; y < h; y++) + { + KUInt8* src = bits + y * rowWords * 4; + KUInt8 b = 0; + for (int x = 0; x < w; x++) + { + if ((x & 7) == 0) + b = *src++; + *dst++ = (b & 128) ? 0 : 255; + if (b & 128) + nBlack++; + else + nWhite++; + b = b << 1; + } + } + if (nBlack) + { + Fl_RGB_Image* img = new Fl_RGB_Image(gray, w, h, 1); + img->draw(band.left, band.top); + delete img; + } + free(bits); + free(gray); + + fl_pop_clip(); + + Fl_Printer::pop_current(); + Fl::unlock(); + + return 0; +} + +void +TFLPrinterManager::CancelJob(KUInt32 inDrvr, KUInt32 inAsyncCancel) +{ + (void) inDrvr; + (void) inAsyncCancel; + // KPrintf("CancelJob\n"); +} + +void +TFLPrinterManager::GetPageInfo(KUInt32 inDrvr, KUInt32 inInfo) +{ + // KPrintf("GetPageInfo\n"); + + struct PrPageInfo { + KUInt32 horizontalDPI; // DPI as a fixed point value + KUInt32 verticalDPI; + KUInt16 width; // page width in pixels + KUInt16 height; + } pageInfo; + mMemory->FastReadBuffer(inInfo, sizeof(pageInfo), (KUInt8*) &pageInfo); + + switch (GetSubType(inDrvr)) + { + case kSubtype72dpi: + pageInfo.horizontalDPI = htonl(72 << 16); + pageInfo.verticalDPI = htonl(72 << 16); + break; + case kSubtype150dpi: + pageInfo.horizontalDPI = htonl(150 << 16); + pageInfo.verticalDPI = htonl(150 << 16); + break; + case kSubtype300dpi: + pageInfo.horizontalDPI = htonl(300 << 16); + pageInfo.verticalDPI = htonl(300 << 16); + break; + } + int wdt = 0, hgt = 0; + mPrinter->printable_rect(&wdt, &hgt); + pageInfo.width = htons(wdt); + pageInfo.height = htons(hgt); + mMemory->FastWriteBuffer(inInfo, sizeof(pageInfo), (KUInt8*) &pageInfo); +} + +void +TFLPrinterManager::GetBandPrefs(KUInt32 inDrvr, KUInt32 inPrefs) +{ + // typedef struct DotPrinterPrefs { + // long minBand; /* smallest useable band */ + // long optimumBand; /* a good size to try to default */ + // Boolean asyncBanding; /* true if band data sent async */ + // Boolean wantMinBounds; /* true if minrect is useful */ + // } DotPrinterPrefs; + (void) inDrvr; + (void) inPrefs; + // KPrintf("GetBandPrefs\n"); +} + +KUInt8 +TFLPrinterManager::GetSubType(KUInt32 inDrvr) +{ + KUInt8 subtype = 255; + mMemory->ReadB(inDrvr + 31, subtype); + return subtype; +} + +// ============================================================================= // +// As in Protestant Europe, by contrast, where sects divided endlessly into // +// smaller competing sects and no church dominated any other, all is different // +// in the fragmented world of IBM. That realm is now a chaos of conflicting // +// norms and standards that not even IBM can hope to control. You can buy a // +// computer that works like an IBM machine but contains nothing made or sold by // +// IBM itself. Renegades from IBM constantly set up rival firms and establish // +// standards of their own. When IBM recently abandoned some of its original // +// standards and decreed new ones, many of its rivals declared a puritan // +// allegiance to IBM's original faith, and denounced the company as a divisive // +// innovator. Still, the IBM world is united by its distrust of icons and // +// imagery. IBM's screens are designed for language, not pictures. Graven // +// images may be tolerated by the luxurious cults, but the true IBM faith relies // +// on the austerity of the word. // +// -- Edward Mendelson, "The New Republic", February 22, 1988 // +// ============================================================================= // diff --git a/Emulator/Printer/TFLPrinterManager.h b/Emulator/Printer/TFLPrinterManager.h new file mode 100644 index 000000000..9b80cddb5 --- /dev/null +++ b/Emulator/Printer/TFLPrinterManager.h @@ -0,0 +1,133 @@ +// ============================== +// File: TFLPrinterManager.h +// Project: Einstein +// +// Copyright 2022 by Matthias Melcher (einstein@messagepad.org). +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ============================== +// $Id$ +// ============================== + +#ifndef _TFLPRINTERMANAGER_H +#define _TFLPRINTERMANAGER_H + +#include "Emulator/Printer/TPrinterManager.h" + +#include + +class TLog; +class TMemory; +class Fl_Printer; + +/// +/// Class to handle a single printer. +/// This class is subclassed by host implementations. +/// +class TFLPrinterManager : public TPrinterManager +{ +public: + /// + /// Constructor from a log. + /// + /// \param inLog log interface (can be null) + /// + TFLPrinterManager(TLog* inLog = nil); + + /// + /// Destructor. + /// + ~TFLPrinterManager() override; + + /// + /// Printer is no longer used + /// + void Delete(KUInt32 inDrvr) override; + + /// + /// Open a connection to the host printer + /// + KUInt32 Open(KUInt32 inDrvr) override; + void SyncOpen(); + + /// + /// Close the connection to the printer + /// + KUInt32 Close(KUInt32 inDrvr) override; + void SyncClose(); + + /// + /// Start to print a page + /// + KUInt32 OpenPage(KUInt32 inDrvr) override; + // void SyncOpenPage(); + + /// + /// Finish printing a page + /// + KUInt32 ClosePage(KUInt32 inDrvr) override; + // void SyncClosePage(); + + /// + /// NewtonOS sends a band of pixel data to be printed + /// + KUInt32 ImageBand(KUInt32 inDrvr, KUInt32 inBand, KUInt32 inRect) override; + + /// + /// User or Newton wants to cancel the current print job. + /// + void CancelJob(KUInt32 inDrvr, KUInt32 inAsyncCancel) override; + + /// + /// Fill in the Info structure about our paper size and print resolution + /// + void GetPageInfo(KUInt32 inDrvr, KUInt32 inInfo) override; + + /// + /// Fill in the structure to have bands delivered a certain way + /// + void GetBandPrefs(KUInt32 inDrvr, KUInt32 inPrefs) override; + +protected: + static constexpr KUInt8 kSubtype72dpi = 0; + static constexpr KUInt8 kSubtype150dpi = 1; + static constexpr KUInt8 kSubtype300dpi = 2; + + KUInt8 GetSubType(KUInt32 inDrvr); + + void SetScale(KUInt32 inDrvr); + + enum class State { + Uninitialized, + Allocated, + Open, + PageOpen + }; + State mState = State::Uninitialized; + + Fl_Printer* mPrinter = nullptr; + + KUInt32 mDrvr = 0; + + std::promise* mPromise; + std::future mFuture; +}; + +#endif +// _TFLPRINTERMANAGER_H + +// ========================================= // +// TRANSACTION CANCELLED - FARECARD RETURNED // +// ========================================= // diff --git a/Emulator/Printer/TPrinterManager.cpp b/Emulator/Printer/TPrinterManager.cpp new file mode 100644 index 000000000..8fb9ee813 --- /dev/null +++ b/Emulator/Printer/TPrinterManager.cpp @@ -0,0 +1,150 @@ +// ============================== +// File: TPrinterManager.h +// Project: Einstein +// +// Copyright 2022 by Matthias Melcher (einstein@messagepad.org). +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ============================== +// $Id$ +// ============================== + +#include "TPrinterManager.h" + +#include + +#ifdef TARGET_OS_WIN32 +#include +#else +#include +#endif + +// Einstein. + +// -------------------------------------------------------------------------- // +// Constantes +// -------------------------------------------------------------------------- // + +// -------------------------------------------------------------------------- // +// * TPrinterManager(TLog*) +// -------------------------------------------------------------------------- // +TPrinterManager::TPrinterManager(TLog* inLog) : + mLog(inLog) +{ + (void) mLog; +} + +// -------------------------------------------------------------------------- // +// * ~TPrinterManager() +// -------------------------------------------------------------------------- // +TPrinterManager::~TPrinterManager() +{ +} + +void +TPrinterManager::Delete(KUInt32 inDrvr) +{ + (void) inDrvr; +} + +KUInt32 +TPrinterManager::Open(KUInt32 inDrvr) +{ + (void) inDrvr; + return 0; +} + +KUInt32 +TPrinterManager::Close(KUInt32 inDrvr) +{ + (void) inDrvr; + return 0; +} + +KUInt32 +TPrinterManager::OpenPage(KUInt32 inDrvr) +{ + (void) inDrvr; + return 0; +} + +KUInt32 +TPrinterManager::ClosePage(KUInt32 inDrvr) +{ + (void) inDrvr; + return 0; +} + +KUInt32 +TPrinterManager::ImageBand(KUInt32 inDrvr, KUInt32 inBand, KUInt32 inRect) +{ + (void) inDrvr; + (void) inBand; + (void) inRect; + return 0; +} + +void +TPrinterManager::CancelJob(KUInt32 inDrvr, KUInt32 inAsyncCancel) +{ + (void) inDrvr; + (void) inAsyncCancel; +} + +KUInt32 +TPrinterManager::IsProblemResolved(KUInt32 inDrvr) +{ + (void) inDrvr; + return 1; +} + +void +TPrinterManager::GetPageInfo(KUInt32 inDrvr, KUInt32 inInfo) +{ + (void) inDrvr; + (void) inInfo; +} + +void +TPrinterManager::GetBandPrefs(KUInt32 inDrvr, KUInt32 inPrefs) +{ + (void) inDrvr; + (void) inPrefs; +} + +KUInt32 +TPrinterManager::FaxEndPage(KUInt32 inDrvr, KUInt32 inPageCount) +{ + (void) inDrvr; + (void) inPageCount; + return 0; +} + +// ============================================================================= // +// As in Protestant Europe, by contrast, where sects divided endlessly into // +// smaller competing sects and no church dominated any other, all is different // +// in the fragmented world of IBM. That realm is now a chaos of conflicting // +// norms and standards that not even IBM can hope to control. You can buy a // +// computer that works like an IBM machine but contains nothing made or sold by // +// IBM itself. Renegades from IBM constantly set up rival firms and establish // +// standards of their own. When IBM recently abandoned some of its original // +// standards and decreed new ones, many of its rivals declared a puritan // +// allegiance to IBM's original faith, and denounced the company as a divisive // +// innovator. Still, the IBM world is united by its distrust of icons and // +// imagery. IBM's screens are designed for language, not pictures. Graven // +// images may be tolerated by the luxurious cults, but the true IBM faith relies // +// on the austerity of the word. // +// -- Edward Mendelson, "The New Republic", February 22, 1988 // +// ============================================================================= // diff --git a/Emulator/Printer/TPrinterManager.h b/Emulator/Printer/TPrinterManager.h new file mode 100644 index 000000000..853d0f6d8 --- /dev/null +++ b/Emulator/Printer/TPrinterManager.h @@ -0,0 +1,136 @@ +// ============================== +// File: TPrinterManager.h +// Project: Einstein +// +// Copyright 2022 by Matthias Melcher (einstein@messagepad.org). +// +// This program is free software; you can redistribute it and/or modify +// it under the terms of the GNU General Public License as published by +// the Free Software Foundation; either version 2 of the License, or +// (at your option) any later version. +// +// This program is distributed in the hope that it will be useful, +// but WITHOUT ANY WARRANTY; without even the implied warranty of +// MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the +// GNU General Public License for more details. +// +// You should have received a copy of the GNU General Public License along +// with this program; if not, write to the Free Software Foundation, Inc., +// 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA. +// ============================== +// $Id$ +// ============================== + +#ifndef _TPRINTERMANAGER_H +#define _TPRINTERMANAGER_H + +#include + +class TLog; +class TMemory; + +#define ERRBASE_PRINTING (-44000) // Printing errors +#define PR_ERROR_BASE (ERRBASE_PRINTING) +#define kPR_ERR_PrinterError (PR_ERROR_BASE) +#define kPR_ERR_NewtonError (PR_ERROR_BASE - 1) +#define kPR_ERR_NotFound (PR_ERROR_BASE - 2) +#define kPR_ERR_Busy /* out-box should try again! */ (PR_ERROR_BASE - 3) +#define kPR_ERR_UserCancel (PR_ERROR_BASE - 4) +#define kPR_ERR_LostContact (PR_ERROR_BASE - 5) +#define kPR_ERR_TooComplex (PR_ERROR_BASE - 6) + +/// +/// Class to handle a single printer. +/// This class is subclassed by host implementations. +/// +class TPrinterManager +{ +public: + /// + /// Constructor from a log. + /// + /// \param inLog log interface (can be null) + /// + TPrinterManager(TLog* inLog = nil); + + /// + /// Destructor. + /// + virtual ~TPrinterManager(); + + /// + /// Printer is no longer used + /// + virtual void Delete(KUInt32 inDrvr); + + /// + /// Open a connection to the host printer + /// + virtual KUInt32 Open(KUInt32 inDrvr); + + /// + /// Close the connection to the printer + /// + virtual KUInt32 Close(KUInt32 inDrvr); + + /// + /// Start to print a page + /// + virtual KUInt32 OpenPage(KUInt32 inDrvr); + + /// + /// Finish printing a page + /// + virtual KUInt32 ClosePage(KUInt32 inDrvr); + + /// + /// NewtonOS sends a band of pixel data to be printed + /// + virtual KUInt32 ImageBand(KUInt32 inDrvr, KUInt32 inBand, KUInt32 inRect); + + /// + /// User or Newton wants to cancel the current print job. + /// + virtual void CancelJob(KUInt32 inDrvr, KUInt32 inAsyncCancel); + + /// + /// NewtonOS wants to know if the current problem was solved + /// + virtual KUInt32 IsProblemResolved(KUInt32 inDrvr); + + /// + /// Fill in the Info structure about our paper size and print resolution + /// + virtual void GetPageInfo(KUInt32 inDrvr, KUInt32 inInfo); + + /// + /// Fill in the structure to have bands delivered a certain way + /// + virtual void GetBandPrefs(KUInt32 inDrvr, KUInt32 inPrefs); + + /// + /// For Fax connections only + /// + virtual KUInt32 FaxEndPage(KUInt32 inDrvr, KUInt32 inPageCount); + + /// + /// We need to be able to read and write NewtonOS memory. + /// + void + SetMemory(TMemory* inMemory) + { + mMemory = inMemory; + } + +protected: + TMemory* mMemory = nullptr; ///< Reference to emulated memory. + + TLog* mLog = nullptr; ///< Reference to the log. +}; + +#endif +// _TPRINTERMANAGER_H + +// ========================================= // +// TRANSACTION CANCELLED - FARECARD RETURNED // +// ========================================= // diff --git a/Emulator/TEmulator.cpp b/Emulator/TEmulator.cpp index 356b2f516..da6d2e037 100644 --- a/Emulator/TEmulator.cpp +++ b/Emulator/TEmulator.cpp @@ -75,7 +75,8 @@ TEmulator::TEmulator( TSoundManager* inSoundManager, TScreenManager* inScreenManager, TNetworkManager* inNetworkManager, - KUInt32 inRAMSize /* = 4194304 */) : + KUInt32 inRAMSize /* = 4194304 */, + TPrinterManager* inPrinterManager /* = nullptr */) : SerialPorts(this, inLog), mMemory(inLog, inROMImage, inFlashPath, inRAMSize), mProcessor(inLog, &mMemory), @@ -83,6 +84,7 @@ TEmulator::TEmulator( mDMAManager(nil), mPlatformManager(nil), mNetworkManager(inNetworkManager), + mPrinterManager(inPrinterManager), mSoundManager(inSoundManager), mScreenManager(inScreenManager), mFileManager(NULL), @@ -143,6 +145,7 @@ TEmulator::TEmulator( mDMAManager(nil), mPlatformManager(nil), mNetworkManager(nil), + mPrinterManager(nil), mSoundManager(nil), mScreenManager(nil), mLog(inLog), diff --git a/Emulator/TEmulator.h b/Emulator/TEmulator.h index 527ee0650..34ad68405 100644 --- a/Emulator/TEmulator.h +++ b/Emulator/TEmulator.h @@ -79,7 +79,8 @@ class TEmulator TSoundManager* inSoundManager, TScreenManager* inScreenManager, TNetworkManager* inNetworkManager, - KUInt32 inRAMSize = 0x00400000); + KUInt32 inRAMSize = 0x00400000, + TPrinterManager* inPrinterManager = nullptr); /// /// Constructor from a rom image buffer. @@ -289,6 +290,17 @@ class TEmulator return mInterruptManager; } + /// + /// Accessor on the printer manager interface. + /// + /// \return a pointer to the printer manager. + /// + TPrinterManager* + GetPrinterManager(void) + { + return mPrinterManager; + } + /// /// Accessor on the sound manager interface. /// @@ -473,6 +485,7 @@ class TEmulator TDMAManager* mDMAManager; ///< DMA manager. TPlatformManager* mPlatformManager; ///< Platform manager. TNetworkManager* mNetworkManager; ///< Network manager. + TPrinterManager* mPrinterManager; ///< Printer manager TSoundManager* mSoundManager; ///< Sound manager. TScreenManager* mScreenManager; ///< Screen manager. TFileManager* mFileManager; diff --git a/Emulator/TNativePrimitives.cpp b/Emulator/TNativePrimitives.cpp index 5918bdf31..fe46ed470 100644 --- a/Emulator/TNativePrimitives.cpp +++ b/Emulator/TNativePrimitives.cpp @@ -42,6 +42,7 @@ #include "Emulator/TMemory.h" #include "Emulator/Log/TLog.h" #include "Emulator/Network/TNetworkManager.h" +#include "Emulator/Printer/TPrinterManager.h" #include "Emulator/Screen/TScreenManager.h" #include "Emulator/Serial/TSerialHostPortDirect.h" #include "Emulator/Sound/TSoundManager.h" @@ -85,6 +86,7 @@ struct NewtonPixmap { #define ENABLE_LOG_HOSTCALL (1 << 0x9) #define ENABLE_LOG_NETWORKMANAGER (1 << 0xa) #define ENABLE_LOG_HOSTIOS_NATIVEIOS (1 << 0xb) +#define ENABLE_LOG_PRINTER (1 << 0xc) #define LOG_PLATFORM (mLog && (mLogMask & ENABLE_LOG_PLATFORM)) #define LOG_SOUND (mLog && (mLogMask & ENABLE_LOG_SOUND)) @@ -97,6 +99,7 @@ struct NewtonPixmap { #define LOG_HOSTCALL (mLog && (mLogMask & ENABLE_LOG_HOSTCALL)) #define LOG_NETWORKMANAGER (mLog && (mLogMask & ENABLE_LOG_NETWORKMANAGER)) #define LOG_HOSTIOS_NATIVEIOS (mLog && (mLogMask & ENABLE_LOG_HOSTIOS_NATIVEIOS)) +#define LOG_PRINTER (mLog && (mLogMask & ENABLE_LOG_PRINTER)) // -------------------------------------------------------------------------- // // Constantes @@ -154,6 +157,7 @@ TNativePrimitives::SetEmulator(TEmulator* inEmulator) if (inEmulator) { mNetworkManager = inEmulator->GetNetworkManager(); + mPrinterManager = inEmulator->GetPrinterManager(); mSoundManager = inEmulator->GetSoundManager(); mScreenManager = inEmulator->GetScreenManager(); mPlatformManager = inEmulator->GetPlatformManager(); @@ -162,6 +166,7 @@ TNativePrimitives::SetEmulator(TEmulator* inEmulator) } else { mNetworkManager = nil; + mPrinterManager = nil; mSoundManager = nil; mScreenManager = nil; mPlatformManager = nil; @@ -244,6 +249,10 @@ TNativePrimitives::ExecuteNative(KUInt32 inInstruction) break; #endif + case 0x00000C: + ExecutePrinterDriverNative(inInstruction); + break; + default: if (mLog) { @@ -3226,6 +3235,159 @@ TNativePrimitives::ExecuteHostiOSNativeiOS(KUInt32 inInstruction) } #endif +#ifdef TARGET_UI_FLTK +#include +// -------------------------------------------------------------------------- // +// * ExecutePrinterDriverNative( KUInt32 ) +// -------------------------------------------------------------------------- // +void +TNativePrimitives::ExecutePrinterDriverNative(KUInt32 inInstruction) +{ + KUInt32 ret = 0; + + switch (inInstruction & 0xFF) + { + case 0x01: // never called: void PDNew(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("void PDNew(DRIVERCLASSNAME *self);"); + } + break; + + case 0x02: // void PDDelete(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("void PDDelete(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + mPrinterManager->Delete(mProcessor->GetRegister(0)); + break; + + case 0x03: // NewtonErr PDOpen(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDOpen(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + ret = mPrinterManager->Open(mProcessor->GetRegister(0)); + mProcessor->SetRegister(0, ret); + break; + + case 0x04: // NewtonErr PDClose(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDClose(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + ret = mPrinterManager->Close(mProcessor->GetRegister(0)); + mProcessor->SetRegister(0, ret); + break; + + case 0x05: // NewtonErr PDOpenPage(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDOpenPage(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + ret = mPrinterManager->OpenPage(mProcessor->GetRegister(0)); + mProcessor->SetRegister(0, ret); + break; + + case 0x06: // NewtonErr PDClosePage(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDClosePage(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + ret = mPrinterManager->ClosePage(mProcessor->GetRegister(0)); + mProcessor->SetRegister(0, ret); + break; + + case 0x07: // NewtonErr PDImageBand(DRIVERCLASSNAME *self, PixelMap* theBand, const Rect* minRect); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDImageBand(DRIVERCLASSNAME *self, PixelMap* theBand, const Rect* minRect);"); + } + if (mPrinterManager) + ret = mPrinterManager->ImageBand( + mProcessor->GetRegister(0), + mProcessor->GetRegister(1), + mProcessor->GetRegister(2)); + mProcessor->SetRegister(0, ret); + break; + + case 0x08: // void PDCancelJob(DRIVERCLASSNAME *self, Boolean asyncCancel); + if (LOG_PRINTER) + { + mLog->LogLine("void PDCancelJob(DRIVERCLASSNAME *self, Boolean asyncCancel);"); + } + if (mPrinterManager) + mPrinterManager->CancelJob( + mProcessor->GetRegister(0), + mProcessor->GetRegister(1)); + break; + + case 0x09: // PrProblemResolution PDIsProblemResolved(DRIVERCLASSNAME *self); + if (LOG_PRINTER) + { + mLog->LogLine("PrProblemResolution PDIsProblemResolved(DRIVERCLASSNAME *self);"); + } + if (mPrinterManager) + ret = mPrinterManager->IsProblemResolved(mProcessor->GetRegister(0)); + mProcessor->SetRegister(0, ret); + break; + + case 0x0A: // void PDGetPageInfo(DRIVERCLASSNAME *self, PrPageInfo* info); + if (LOG_PRINTER) + { + mLog->LogLine("void PDGetPageInfo(DRIVERCLASSNAME *self, PrPageInfo* info);"); + } + if (mPrinterManager) + mPrinterManager->GetPageInfo( + mProcessor->GetRegister(0), + mProcessor->GetRegister(1)); + break; + + case 0x0B: // void PDGetBandPrefs(DRIVERCLASSNAME *self, DotPrinterPrefs* prefs); + if (LOG_PRINTER) + { + mLog->LogLine("void PDGetBandPrefs(DRIVERCLASSNAME *self, DotPrinterPrefs* prefs);"); + } + if (mPrinterManager) + mPrinterManager->GetBandPrefs( + mProcessor->GetRegister(0), + mProcessor->GetRegister(1)); + break; + + case 0x0C: // NewtonErr PDFaxEndPage(DRIVERCLASSNAME *self, long pageCount); + if (LOG_PRINTER) + { + mLog->LogLine("NewtonErr PDFaxEndPage(DRIVERCLASSNAME *self, long pageCount);"); + } + if (mPrinterManager) + ret = mPrinterManager->FaxEndPage( + mProcessor->GetRegister(0), + mProcessor->GetRegister(1)); + mProcessor->SetRegister(0, ret); + break; + + default: + if (LOG_PRINTER) + { + mLog->FLogLine("Unknown Printer Driver Call: 0x%08x\n", inInstruction); + } + KPrintf("Unknown Printer Driver Call: 0x%08x\n", inInstruction); + break; + } +} +#else +void +TNativePrimitives::ExecutePrinterDriverNative(KUInt32 inInstruction) +{ + KPrintf("Printer Driver Calls not supported on this platform.\n"); +} +#endif + // -------------------------------------------------------------------------- // // * TransferState( TStream* ) // -------------------------------------------------------------------------- // diff --git a/Emulator/TNativePrimitives.h b/Emulator/TNativePrimitives.h index f70130151..767d42235 100644 --- a/Emulator/TNativePrimitives.h +++ b/Emulator/TNativePrimitives.h @@ -34,6 +34,7 @@ class TEmulator; class TMemory; class TARMProcessor; class TNetworkManager; +class TPrinterManager; class TSoundManager; class TScreenManager; class TPlatformManager; @@ -224,6 +225,13 @@ class TNativePrimitives /// void ExecuteHostiOSNativeiOS(KUInt32 inInstruction); + /// + /// Execute a native instruction for printer drivers + /// + /// \param inInstruction opcode of the instruction to execute. + /// + void ExecutePrinterDriverNative(KUInt32 inInstruction); + /// \name Variables TARMProcessor* mProcessor; ///< Reference to the CPU. TLog* mLog; ///< Interface for logging. @@ -231,6 +239,7 @@ class TNativePrimitives TMemory* mMemory; ///< Interface to the memory. TEmulator* mEmulator; ///< Emulator (interface to hardware). TNetworkManager* mNetworkManager; ///< Network manager. + TPrinterManager* mPrinterManager; ///< Printer manager TSoundManager* mSoundManager; ///< Sound manager TScreenManager* mScreenManager; ///< Screen manager. TPlatformManager* mPlatformManager; ///< Platform manager. diff --git a/ReleaseText.md b/ReleaseText.md index a0f47824a..9e6a1af71 100644 --- a/ReleaseText.md +++ b/ReleaseText.md @@ -1,4 +1,16 @@ +Binary Release v2022.4.19 +========================= + +User Release Notes +------------------ + - printer support, printer driver is built into REX + +Toolkit Release Notes +--------------------- + - NewtonScript host file access + + Binary Release v2022.4.18 ========================= diff --git a/Toolkit/TToolkitScriptExt.cpp b/Toolkit/TToolkitScriptExt.cpp index 10a3ad49f..1dd13ed96 100644 --- a/Toolkit/TToolkitScriptExt.cpp +++ b/Toolkit/TToolkitScriptExt.cpp @@ -169,7 +169,7 @@ NewtMakeBinaryFromARMFile(const char* srcfilename, bool /*literal*/) char objfilename[FL_PATH_MAX + 1]; strncpy(objfilename, basename, FL_PATH_MAX); strncat(objfilename, "inline.o", FL_PATH_MAX); - char binfilename[FL_PATH_MAX]; + char binfilename[FL_PATH_MAX + 1]; strncpy(binfilename, basename, FL_PATH_MAX); strncat(binfilename, "inline", FL_PATH_MAX); char errfilename[FL_PATH_MAX + 1]; @@ -761,6 +761,23 @@ RegisterToolkitScriptExtensions() /* MakeIcon/ImagFormPNG: + Create an app icon from one or more GIF/PNG images. + + App icons can be 1 bit or 4 bit deep, have an alternative image when clicked + (highlighted), and have one 1-bit maks for normal and highlighted each. + There is an option to use no mask, a bitmap mask, or a calculated mask. + Iconsize is usually 26x25 pixels. + + (icon is also used in "viewclass: 76") + + We also want to create image and sound data for scripts. + + V1: icon { mask*, bits, bounds { left, top, right bottom } } + V2: icon, iconPro { unhilited { bounds, bits, mask, colorData [* { cbits, bitDepth } ]* } hilited { } } + V2c: icon { mask*, bits, bounds { left, top, right bottom } colorData { cbits, bitDepth } } + + + B/W image format: newt.app.parts[0].data.icon: { mask: MakeBinaryFromHex( diff --git a/_Data_/Einstein.rex b/_Data_/Einstein.rex index a7996acf783276e48bc1994b15da62258e2bfde0..5db0c9e87f29071b3c97ec82c2e676c5a92d5cfb 100644 GIT binary patch delta 83515 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 delta 93286 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 diff --git a/app/FLTK/TFLApp.cpp b/app/FLTK/TFLApp.cpp index 3dff297e2..6e48d94c2 100644 --- a/app/FLTK/TFLApp.cpp +++ b/app/FLTK/TFLApp.cpp @@ -220,6 +220,7 @@ Developer's Documentation: Basic Ideas, Basic Features, Detailed Class Reference #include "Emulator/Network/TUsermodeNetwork.h" #include "Emulator/PCMCIA/TLinearCard.h" #include "Emulator/Platform/TPlatformManager.h" +#include "Emulator/Printer/TFLPrinterManager.h" #include "Emulator/ROM/TAIFROMImageWithREXes.h" #include "Emulator/ROM/TFlatROMImageWithREX.h" #include "Emulator/ROM/TROMImage.h" @@ -357,12 +358,17 @@ TFLApp::Run(int argc, char* argv[]) InitNetwork(); + TFLPrinterManager* printerManager = new TFLPrinterManager(mLog); + // MP2000: 1MB Dynamic RAM, 4MB Flash RAM // MP2100: 4MB Dynamic RAM, 4MB Flash RAM // eMate: 1MB Dynamic RAM, 2MB Flash RAM mEmulator = new TEmulator(mLog, mROMImage, theFlashPath, - mSoundManager, mScreenManager, mNetworkManager, ramSize << 16); + mSoundManager, mScreenManager, mNetworkManager, + ramSize << 16, printerManager); + mPlatformManager = mEmulator->GetPlatformManager(); + printerManager->SetMemory(mEmulator->GetMemory()); // yes, this is valid C++ code; it tells the emulator to call us so we can tell FLTK to // call us again later from the main thread which then closes all windows, terminating diff --git a/app/FLTK/TFLApp.h b/app/FLTK/TFLApp.h index d070b183a..121acd319 100644 --- a/app/FLTK/TFLApp.h +++ b/app/FLTK/TFLApp.h @@ -48,6 +48,7 @@ class TLog; class TBufferLog; class TPlatformManager; class TNetworkManager; +class TPrinterManager; class TMonitor; class TSymbolList; #if USE_TOOLKIT