lazarus/components/printers/cocoa/cocoaprinters.inc

701 lines
18 KiB
PHP

{%MainUnit ../osprinters.pas}
{**************************************************************
Implementation for carbonprinter
***************************************************************}
uses InterfaceBase, LCLIntf, LCLProc;
const
CleanPMRect: PMRect = (top: 0; left: 0; bottom: 0; right: 0);
CleanPMOrientation: PMOrientation = 0;
{ TCocoaPrinterView }
function TCocoaPrinterView.initWithFrame(frameRect: NSRect): id;
begin
PageMin := 1;
PageMax := 1;
PageFrom := 1;
PageTo := 1;
Result:=inherited initWithFrame(frameRect);
//Image := NSImage.alloc.initWithSize(Size);
end;
procedure TCocoaPrinterView.dealloc;
begin
//Image.release();
inherited dealloc();
end;
procedure TCocoaPrinterView.drawRect(dirtyRect: NSRect);
var
pageHeight: Double;
lRect: NSRect;
lCurPage: Integer;
begin
// image page printing alternative
//Image.drawInRect_fromRect_operation_fraction(Self.frame, NSZeroRect, NSCompositeSourceAtop, 1.0);
if Canvas = nil then Exit;
pageHeight := calculatePrintHeight();
lRect := updateSize(False);
// figure out which page this is
lCurPage := Round((lRect.size.height - dirtyRect.origin.y) / pageHeight);
Canvas.DrawRecording(Self, dirtyRect, lCurPage - PageFrom);
end;
// Return the number of pages available for printing
function TCocoaPrinterView.knowsPageRange(range: NSRangePointer): Boolean;
begin
updateSize(True);
range^.location := PageFrom;
range^.length := PageTo - PageFrom + 1;
Result := True;
end;
function TCocoaPrinterView.rectForPage(page: NSInteger): NSRect;
var
lBounds: NSRect;
pageHeight, pageWidth: Double;
begin
pageHeight := calculatePrintHeight();
pageWidth := calculatePrintWidth();
// page Y starting pos is Bottom-Left of page 1 - (pagenr-zero-based) * pageHeight, so:
// pageHeight * ((PageTo - PageFrom) - (page - PageFrom)), which simplifies to:
Result := NSMakeRect(0, pageHeight * (PageTo - page),
pageWidth, pageHeight);
end;
// Calculate the vertical size of the view that fits on a single page
function TCocoaPrinterView.calculatePrintHeight: Double;
var
pi: NSPrintInfo;
paperSize: NSSize;
pageHeight, scale: Double;
begin
// Obtain the print info object for the current operation
pi := NSPrintOperation.currentOperation.printInfo;
// Calculate the page height in points
paperSize := pi.paperSize;
pageHeight := paperSize.height - pi.topMargin - pi.bottomMargin;
// Convert height to the scaled view
scale := pi.dictionary.objectForKey(NSPrintScalingFactor).floatValue;
Result := pageHeight / scale;
end;
function TCocoaPrinterView.calculatePrintWidth: Double;
var
pi: NSPrintInfo;
paperSize: NSSize;
pageWidth, scale: Double;
begin
// Obtain the print info object for the current operation
pi := NSPrintOperation.currentOperation.printInfo;
// Calculate the page width in points
paperSize := pi.paperSize;
pageWidth := paperSize.width - pi.leftMargin - pi.rightMargin;
// Convert height to the scaled view
scale := pi.dictionary.objectForKey(NSPrintScalingFactor).floatValue;
Result := pageWidth / scale;
end;
function TCocoaPrinterView.updateSize(ADoSetFrame: Boolean): NSRect;
var
Size: NSSize;
begin
Size.height := calculatePrintHeight();
Size.height := Size.height * (PageTo - PageFrom + 1);
Size.width := calculatePrintWidth();
if ADoSetFrame then
Self.setFrameSize(Size);
Result := NSMakeRect(0, 0, Size.width, Size.height);
end;
{ TCocoaPrinter }
function TCocoaPrinter.CreatePageFormat(APaper: String): PMPageFormat;
var
I: Integer;
S: TStringList;
const
SName = 'CreatePageFormat';
begin
{ if APaper = '' then
begin
I := -1;
S := nil;
end
else
begin
S := TStringList.Create;
BeginEnumPapers(S);
I := S.IndexOf(APaper);
end;
try
if I < 0 then
begin
Result:=nil;
if OSError(PMCreatePageFormat(Result), Self, SName, 'PMCreatePageFormat') then
raise EPrinter.Create('Error initializing printing for Carbon: Unable to create page format!');
OSError(PMSessionDefaultPageFormat(PrintSession, Result), Self, SName, 'PMSessionDefaultPageFormat');
end
else
begin
OSError(PMCreatePageFormatWithPMPaper(Result,
PMPaper(CFArrayGetValueAtIndex(FPaperArray, I))),
Self, SName, 'PMCreatePageFormatWithPMPaper');
end;
finally
if S <> nil then
begin
EndEnumPapers;
S.Free;
end;
end; }
end;
function TCocoaPrinter.ValidatePageFormat: Boolean;
begin
Result := False;
if PMSessionValidatePageFormat(GetPrintSession(), GetPageFormat(), @Result) <> noErr then Exit;
end;
function TCocoaPrinter.ValidatePrintSettings: Boolean;
begin
Result := False;
if PMSessionValidatePrintSettings(GetPrintSession(), GetPrintSettings(), @Result) <> noErr then Exit;
end;
function TCocoaPrinter.GetCurrentCarbonPrinter: PMPrinter;
begin
Result := nil;
if PMSessionGetCurrentPrinter(GetPrintSession(), Result) <> noErr then Exit;
{ Result := CFStringToStr(PMPrinterGetName(P));
if Trim(Result) = '' then
Result := ''; }
end;
function TCocoaPrinter.GetPrintSession: PMPrintSession;
begin
Result := FPrintInfo.PMPrintSession();
end;
function TCocoaPrinter.GetPrintSettings: PMPrintSettings;
begin
Result := FPrintInfo.PMPrintSettings();
end;
function TCocoaPrinter.GetPageFormat: PMPageFormat;
begin
Result := FPrintInfo.PMPageFormat();
end;
procedure TCocoaPrinter.BeginPage;
{var
PaperRect: PMRect; }
begin
{if FBeginDocumentStatus = noErr then
begin
FNewPageStatus := PMSessionBeginPage(PrintSession, nil, nil);
OSError(FNewPageStatus, Self, 'BeginPage', 'PMSessionBeginPage', '', kPMCancel);
// update printer context
if OSError(PMSessionGetCGGraphicsContext(PrintSession, FPrinterContext.CGContext),
Self, 'BeginPage', 'PMSessionGetCGGraphicsContext') then
FPrinterContext.Release
else
FPrinterContext.Reset;
// translate the context from his paper (0,0) origin
// to our working imageable area
if PMGetAdjustedPaperRect(PageFormat, PaperRect{%H-})=noErr then
CGContextTranslateCTM(FPrinterContext.CGContext, -PaperRect.left, -PaperRect.top);
if Assigned(Canvas) then
Canvas.Handle := HDC(FPrinterContext);
end; }
end;
procedure TCocoaPrinter.EndPage;
begin
{FPrinterContext.Release;
if Assigned(Canvas) then Canvas.Handle := 0;
if FBeginDocumentStatus = noErr then
begin
if FNewPageStatus = noErr then
OSError(PMSessionEndPage(PrintSession), Self, 'EndPage', 'PMSessionEndPage', '', kPMCancel);
end; }
end;
procedure TCocoaPrinter.FindDefaultPrinter;
{var
P: PMPrinter;
I, C: CFIndex;
pa: CFArrayRef; }
begin
{pa:=nil;
if OSError(PMServerCreatePrinterList(kPMServerLocal, pa),
Self, 'DoEnumPrinters', 'PMServerCreatePrinterList') then Exit;
if not Assigned(pa) then Exit;
C := CFArrayGetCount(pa);
for I := 0 to C - 1 do
begin
P := CFArrayGetValueAtIndex(pa, I);
if PMPrinterIsDefault(P) then
begin
FDefaultPrinter := CFStringToStr(PMPrinterGetName(P));
Break;
end;
end;
CFRelease(pa); }
end;
constructor TCocoaPrinter.Create;
var
FPrintViewRect: NSRect;
begin
inherited Create;
FPrintViewRect := GetNSRect(0, 0, 1000, 1000);
FPrintView := TCocoaPrinterView.alloc.initWithFrame(FPrintViewRect);
FPrintView.Canvas := Canvas as TCocoaPrinterCanvas;
FPrintOp := NSPrintOperation.printOperationWithView(FPrintView);
FPrintInfo := FPrintOp.printInfo();
//CreatePrintSettings;
//FPageFormat := CreatePageFormat('');
//FindDefaultPrinter;
//UpdatePrinter;
//DebugLn('Current ' + GetCurrentPrinterName);
//DebugLn('Default ' + FDefaultPrinter);
end;
procedure TCocoaPrinter.DoDestroy;
begin
FPrintView.release();
inherited DoDestroy;
end;
function TCocoaPrinter.Write(const Buffer; Count: Integer; out Written: Integer): Boolean;
begin
Result := False;
CheckRawMode(True);
Written := 0;
DebugLn('TCocoaPrinter.Write Error: Raw mode is not supported for Cocoa!');
end;
procedure TCocoaPrinter.RawModeChanging;
begin
//
end;
procedure TCocoaPrinter.Validate;
var
P: String;
begin
ValidatePrintSettings();
ValidatePageFormat();
// if target paper is not supported, use the default
P := DoGetPaperName();
if PaperSize.SupportedPapers.IndexOf(P) = -1 then
DoSetPaperName(DoGetDefaultPaperName());
end;
procedure TCocoaPrinter.UpdatePrinter;
{var
s: string;
Res: PMResolution;}
begin
{s := GetCurrentPrinterName;
if trim(s) = '' then // Observed if Default printer set to "Use last printer", and no printing done
s := '*'; // so select lcl default
SetPrinter(s);
// set the page format resolution
Res := GetOutputResolution;
PMSetResolution(PageFormat, Res);
Validate; }
end;
function TCocoaPrinter.GetOutputResolution: PMResolution;
var
res: OSStatus;
FPrintSettings: PMPrintSettings;
begin
FPrintSettings := GetPrintSettings();
res := PMPrinterGetOutputResolution(GetCurrentCarbonPrinter(), FPrintSettings, Result);
if res <> noErr then
begin
Result.vRes := 72;
Result.hRes := 72;
end;
end;
function TCocoaPrinter.DoDoGetPaperName(APageFormat: PMPageFormat): string;
var
FPaper: PMPaper = nil;
lCFString: CFStringRef = nil;
begin
Result := '';
if APageFormat = nil then APageFormat := GetPageFormat();
if PMGetPageFormatPaper(APageFormat, FPaper) <> noErr then Exit;
if PMPaperGetName(FPaper, lCFString) <> noErr then Exit;
Result := CFStringToStr(lCFString);
end;
function TCocoaPrinter.GetXDPI: Integer;
var
dpi: PMResolution;
begin
dpi := GetOutputResolution;
result := round(dpi.hRes);
end;
function TCocoaPrinter.GetYDPI: Integer;
var
dpi: PMResolution;
begin
dpi := GetOutputResolution;
result := round(dpi.hRes);
end;
procedure TCocoaPrinter.DoBeginDoc;
begin
inherited DoBeginDoc;
//DebugLn('TCocoaPrinter.DoBeginDoc ' + DbgS(Printing));
Validate;
//FBeginDocumentStatus := PMSessionBeginCGDocument(PrintSession, PrintSettings, PageFormat);
//OSError(FBeginDocumentStatus, Self, 'DoBeginDoc', 'PMSessionBeginCGDocument', '', kPMCancel);
BeginPage;
end;
procedure TCocoaPrinter.DoNewPage;
begin
inherited DoNewPage;
EndPage;
BeginPage;
end;
procedure TCocoaPrinter.DoEndDoc(aAborded: Boolean);
begin
inherited DoEndDoc(aAborded);
EndPage;
FPrintOp.setShowsPrintPanel(False);
FPrintOp.runOperation();
end;
procedure TCocoaPrinter.DoAbort;
begin
inherited DoAbort;
//OSError(PMSessionSetError(PrintSession, kPMCancel), Self, 'DoAbort', 'PMSessionSetError');
end;
//Enum all defined printers. First printer it's default
procedure TCocoaPrinter.DoEnumPrinters(Lst: TStrings);
var
I, PrinterCount: CFIndex;
NewPrinterNSName: NSString;
NewPrinterName: String;
FPrinterArray: NSArray;
//NewPrinter: NSPrinter;
begin
FPrinterArray := NSPrinter.printerNames();
FPrinterArray.retain;
if FPrinterArray = nil then Exit;
for I := 0 to FPrinterArray.count - 1 do
begin
NewPrinterNSName := NSString(FPrinterArray.objectAtIndex(i));
NewPrinterName := NSStringToString(NewPrinterNSName);
// Felipe: This could be used for appending the printer to the TStrings, but what for?
// also it would be hard to release the NSPrinter later
//NewPrinter := NSPrinter.printerWithName(NewPrinterNSName);
//NewPrinter.retain;
//DebugLn(DbgS(I) + ' ' + PrinterName);
if NewPrinterName = FDefaultPrinter then
Lst.InsertObject(0, NewPrinterName, nil{TObject(NewPrinter)})
else
Lst.AddObject(NewPrinterName, nil{TObject(NewPrinter)});
end;
end;
procedure TCocoaPrinter.DoResetPrintersList;
begin
inherited DoResetPrintersList;
end;
// Cocoa doesn't support this =( We need to use Carbon here
// http://lists.apple.com/archives/cocoa-dev/2005/Nov/msg01227.html
// See Also "Using Cocoa and Core Printing Together"
// https://developer.apple.com/library/mac/technotes/tn2248/_index.html
procedure TCocoaPrinter.DoEnumPapers(Lst: TStrings);
var
P: PMPaper;
FPaperArray: CFArrayRef;
I, C: CFIndex;
CFString: CFStringRef;
PaperName: String;
CarbonCurrentPrinter: PMPrinter;
begin
FPaperArray := nil;
CarbonCurrentPrinter := GetCurrentCarbonPrinter();
if PMPrinterGetPaperList(CarbonCurrentPrinter, FPaperArray) <> noErr then Exit;
FPaperArray := CFRetain(FPaperArray);
C := CFArrayGetCount(FPaperArray);
for I := 0 to C - 1 do
begin
P := CFArrayGetValueAtIndex(FPaperArray, I);
CFString:=nil;
if PMPaperGetName(P, CFString) <> noErr then Continue;
PaperName := CFStringToStr(CFString);
Lst.Add(PaperName);
end;
if FPaperArray<>nil then
CFRelease(FPaperArray);
end;
function TCocoaPrinter.DoGetPaperName: string;
begin
Result := DoDoGetPaperName(FPrintInfo.PMPageFormat());
end;
function TCocoaPrinter.DoGetDefaultPaperName: string;
var
FPageFormat: PMPageFormat;
begin
Result := '';
FPageFormat := CreatePageFormat('');
Result := DoDoGetPaperName(FPageFormat);
end;
procedure TCocoaPrinter.DoSetPaperName(aName: string);
var
FOrientation: TPrinterOrientation;
begin
FOrientation := DoGetOrientation();
{if FPageFormat <> nil then PMRelease(PMObject(FPageFormat));
FPageFormat := CreatePageFormat(AName);
DoSetOrientation(FOrientation);}
ValidatePageFormat;
end;
function TCocoaPrinter.DoGetPaperRect(aName: string; var aPaperRc: TPaperRect
): Integer;
{var
T: PMPageFormat;
PaperRect, PageRect: PMRect;
S: Double;
O: PMOrientation;
Res: PMResolution;
const
SName = 'DoGetPaperRect'; }
begin
{Result := -1;
T := CreatePageFormat(AName);
try
// copy scale
S:=0.0;
OSError(PMGetScale(PageFormat, S), Self, SName, 'PMGetScale');
OSError(PMSetScale(T, S), Self, SName, 'PMSetScale');
// copy orientation
O:=CleanPMOrientation;
OSError(PMGetOrientation(PageFormat, O), Self, SName, 'PMGetOrientation');
OSError(PMSetOrientation(T, O, False), Self, SName, 'PMSetOrientation');
// copy resolution
Res := GetOutputResolution;
OSError(PMSetResolution(T, Res), self, SName, 'PMSetResolution');
// update
OSError(PMSessionValidatePageFormat(PrintSession, T, nil),
Self, SName, 'PMSessionValidatePageFormat');
PaperRect:=CleanPMRect;
OSError(PMGetAdjustedPaperRect(T, PaperRect), Self, SName, 'PMGetAdjustedPaperRect');
PageRect:=CleanPMRect;
OSError(PMGetAdjustedPageRect(T, PageRect), Self, SName, 'PMGetAdjustedPageRect');
finally
PMRelease(PMObject(T));
end;
ValidatePageFormat;
APaperRc.PhysicalRect.Left := 0;
APaperRc.PhysicalRect.Top := 0;
APaperRc.PhysicalRect.Right := Round(PaperRect.right - PaperRect.left);
APaperRc.PhysicalRect.Bottom := Round(PaperRect.bottom - PaperRect.top);
APaperRc.WorkRect.Left := Round(-PaperRect.left);
APaperRc.WorkRect.Top := Round(-PaperRect.top);
APaperRc.WorkRect.Right := Round(PageRect.right - PageRect.left - PaperRect.left);
APaperRc.WorkRect.Bottom := Round(PageRect.bottom - PageRect.top - PaperRect.top);
Result := 1; }
end;
function TCocoaPrinter.DoSetPrinter(aName: string): Integer;
{var
S: TStringList;
P: PMPrinter; }
begin
{S := TStringList.Create;
BeginEnumPrinters(S);
try
Result := S.IndexOf(AName);
if Result >= 0 then
begin
//DebugLn('DoSetPrinter ' + DbgS(Result));
//DebugLn('TCocoaPrinter.DoSetPrinter ' + AName + ' ' + DbgS(PrintSession) + ' ' + DbgS(Printers.Objects[Result]));
P := PMPrinter(CFArrayGetValueAtIndex(FPrinterArray, Integer(S.Objects[Result])));
PMRetain(PMObject(P));
if OSError(PMSessionSetCurrentPMPrinter(PrintSession, P),
Self, 'DoSetPrinter', 'PMSessionSetCurrentPMPrinter') then
raise EPrinter.CreateFmt('The system is unable to select printer "%s"!', [AName]);
end;
finally
EndEnumPrinters;
S.Free;
end; }
end;
function TCocoaPrinter.DoGetCopies: Integer;
var
NumCopies: UInt32;
begin
Result := inherited DoGetCopies;
NumCopies := 0;
if PMGetCopies(GetPrintSettings(), NumCopies) <> noErr then Exit;
Result := NumCopies;
end;
procedure TCocoaPrinter.DoSetCopies(aValue: Integer);
begin
inherited DoSetCopies(AValue);
if PMSetCopies(GetPrintSettings(), AValue, False) <> noErr then Exit;
FPrintInfo.updateFromPMPrintSettings();
ValidatePrintSettings;
end;
function TCocoaPrinter.DoGetOrientation: TPrinterOrientation;
var
FOrientation: PMOrientation;
FPageFormat: PMPageFormat;
begin
Result := inherited DoGetOrientation;
FOrientation := CleanPMOrientation;
FPageFormat := FPrintInfo.PMPageFormat();
if PMGetOrientation(FPageFormat, FOrientation) <> noErr then Exit;
case FOrientation of
kPMPortrait: Result := poPortrait;
kPMLandscape: Result := poLandscape;
kPMReversePortrait: Result := poReversePortrait;
kPMReverseLandscape: Result := poReverseLandscape;
end;
end;
procedure TCocoaPrinter.DoSetOrientation(aValue: TPrinterOrientation);
var
FOrientation: PMOrientation;
FPageFormat: PMPageFormat;
begin
inherited DoSetOrientation(aValue);
case AValue of
poPortrait: FOrientation := kPMPortrait;
poLandscape: FOrientation := kPMLandscape;
poReversePortrait: FOrientation := kPMReversePortrait;
poReverseLandscape: FOrientation := kPMReverseLandscape;
end;
FPageFormat := FPrintInfo.PMPageFormat();
PMSetOrientation(FPageFormat, FOrientation, kPMUnlocked);
FPrintInfo.updateFromPMPageFormat();
ValidatePageFormat;
end;
function TCocoaPrinter.GetPrinterType: TPrinterType;
var
IsRemote: Boolean;
begin
Result := ptLocal;
IsRemote := false;
if PMPrinterIsRemote(GetCurrentCarbonPrinter(), IsRemote) <> noErr then Exit;
if IsRemote then Result := ptNetwork;
end;
function TCocoaPrinter.DoGetPrinterState: TPrinterState;
var
State: PMPrinterState;
begin
Result := psNoDefine;
State:=0;
if PMPrinterGetState(GetCurrentCarbonPrinter(), State) <> noErr then Exit;
case State of
kPMPrinterIdle: Result := psReady;
kPMPrinterProcessing: Result := psPrinting;
kPMPrinterStopped: Result := psStopped;
end;
end;
function TCocoaPrinter.DoGetDefaultCanvasClass: TPrinterCanvasRef;
begin
Result := TCocoaPrinterCanvas;
end;
function TCocoaPrinter.GetCanPrint: Boolean;
begin
Result := (DoGetPrinterState() <> psStopped);
end;
function TCocoaPrinter.GetCanRenderCopies: Boolean;
begin
Result := True;
end;
initialization
Printer := TCocoaPrinter.Create;
finalization
FreeAndNil(Printer);