@@ -25,21 +25,27 @@
+
-NSView is an abstract class which provides facilities for drawing in a window and
- receiving events. It is the superclass of many of the visual elements of the GUI.
+NSView is an abstract class which provides facilities for
+ drawing in a window and receiving events. It is the
+ superclass of many of the visual elements of the GUI.
-In order to display itself, a view must be placed in a window (represented by an
- NSWindow object). Within the window is a hierarchy of NSViews, headed by the window's
- content view. Every other view in a window is a descendant of this view.
+In order to display itself, a view must be placed in a
+ window (represented by an NSWindow object). Within the
+ window is a hierarchy of NSViews, headed by the window's
+ content view. Every other view in a window is a descendant
+ of this view.
-Subclasses can override drawRect:
in order to implement their
- appearance. Other methods of NSView and NSResponder can also be overridden to handle
- user generated events.
+Subclasses can override drawRect:
in order
+ to implement their appearance. Other methods of NSView and
+ NSResponder can also be overridden to handle user generated
+ events.
+
Instance Variables
@@ -47,144 +53,144 @@ Subclasses can override drawRect:
in order to implement their
Methods
Class Methods
@@ -261,6 +267,23 @@ Returns YES
if the view object will accept the first click
- (void) allocateGState;
+
+
+ Tell the view to maintain a private gstate object which
+ encapsulates all the information about drawing, such as coordinate
+ transforms, line widths, etc. If you do not invoke this method,
+ a gstate object is constructed each time the view is lockFocused.
+ Allocating a private gstate may improve the performance of views
+ that are focused a lot and have a lot of customized drawing
+ parameters.
+
+
+
+
+ View subclasses should override the setUpGstate method to set these
+ custom parameters.
+
+
@@ -507,6 +530,12 @@ Returns YES
if the view object will accept the first click
- (int) gState;
+ Returns an identifier that represents the view's gstate object,
+ which is used to encapsulate drawing information about the view.
+ Most of the time a gstate object is created from scratch when
+ the view is focused, so if the view is not currently focused or
+ allocateGState has not been called, then this method will
+ return 0.
@@ -677,6 +706,8 @@ Returns whether or not aPoint lies within aRect.
- (void) releaseGState;
+ Frees the gstate object, if there is one. Note that the next time
+ the view is lockFocused, the gstate will be allocated again.
@@ -741,6 +772,8 @@ Standards: NotMacOS-X NotOpenStep
- (void) renewGState;
+ Invalidates the view's gstate object so it will be set up
+ again using setUpGState the next time the view is focused.
diff --git a/Documentation/gsdoc/NSWindow.html b/Documentation/gsdoc/NSWindow.html
index 0cc00fcea..f31039856 100644
--- a/Documentation/gsdoc/NSWindow.html
+++ b/Documentation/gsdoc/NSWindow.html
@@ -2,9 +2,9 @@
NSWindow
-[Previous]
-[Up]
-[Next]
+[Previous]
+[Up]
+[Next]
NSWindow
Authors
@@ -66,166 +66,166 @@
Methods
Class Methods
@@ -382,6 +382,9 @@
- (void) deminiaturize: (id)sender;
+ Causes the window to deminiaturize. Normally you would not call
+ this method directly. A window is automatically deminiaturized
+ by the user via a mouse cloick event.
@@ -611,6 +614,7 @@
- (BOOL) isMiniaturized;
+ Returns YES
if the window has been miniaturized.
@@ -676,6 +680,8 @@
- (void) miniaturize: (id)sender;
+ Causes the window to miniaturize, that is the window is removed
+ from the screen and it's counterpart (mini)window is displayed.
diff --git a/Documentation/gsdoc/NSWindowController.html b/Documentation/gsdoc/NSWindowController.html
index 7a2d3c906..0d1fd3c73 100644
--- a/Documentation/gsdoc/NSWindowController.html
+++ b/Documentation/gsdoc/NSWindowController.html
@@ -2,9 +2,9 @@
NSWindowController
-[Previous]
-[Up]
-[Next]
+[Previous]
+[Up]
+[Next]
NSWindowController
Authors
@@ -27,27 +27,27 @@
Methods
Instances Methods
diff --git a/Documentation/gsdoc/NSWorkspace.html b/Documentation/gsdoc/NSWorkspace.html
index 209e8d254..de1eaca52 100644
--- a/Documentation/gsdoc/NSWorkspace.html
+++ b/Documentation/gsdoc/NSWorkspace.html
@@ -2,8 +2,8 @@
NSWorkspace
-[Previous]
-[Up]
+[Previous]
+[Up]
NSWorkspace
Authors
@@ -26,35 +26,35 @@
Methods
Class Methods
diff --git a/Headers/gnustep/gui/NSGraphicsContext.h b/Headers/gnustep/gui/NSGraphicsContext.h
index b5c37000b..d21397928 100644
--- a/Headers/gnustep/gui/NSGraphicsContext.h
+++ b/Headers/gnustep/gui/NSGraphicsContext.h
@@ -1,8 +1,10 @@
-/* NSGraphicsContext - Generic drawing DrawContext class.
+/** NSGraphicsContext
- Copyright (C) 1998,1999 Free Software Foundation, Inc.
+ Abstract drawing context class.
- Author: Richard Frith-Macdonald
+ Copyright (C) 1998,1999 Free Software Foundation, Inc.
+
+ Author: richard@brainstorm.co.uk
Date: Feb 1999
Based on code by: Adam Fedor
Date: Nov 1998
@@ -226,7 +228,6 @@ APPKIT_DECLARE NSGraphicsContext *GSCurrentContext();
- (void) DPSsetfont: (int)f ;
- (void) DPSundefinefont: (const char*)name ;
- (void) setFont: (NSFont*) font;
-- (void) useFont: (NSString*) name;
/* ----------------------------------------------------------------------- */
/* Gstate operations */
/* ----------------------------------------------------------------------- */
@@ -538,6 +539,18 @@ APPKIT_DECLARE NSGraphicsContext *GSCurrentContext();
@end
+/* NSGraphicContext constants */
+APPKIT_EXPORT NSString *NSGraphicsContextDestinationAttributeName;
+APPKIT_EXPORT NSString *NSGraphicsContextPDFFormat;
+APPKIT_EXPORT NSString *NSGraphicsContextPSFormat;
+APPKIT_EXPORT NSString *NSGraphicsContextRepresentationFormatAttributeName;
+
+APPKIT_EXPORT NSString *NSImageInterpolationDefault;
+APPKIT_EXPORT NSString *NSImageInterpolationNone;
+APPKIT_EXPORT NSString *NSImageInterpolationLow;
+APPKIT_EXPORT NSString *NSImageInterpolationHigh;
+
+
#endif /* _NSGraphicsContext_h_INCLUDE */
#endif /* STRICT_OPENSTEP */
diff --git a/Headers/gnustep/gui/NSPrintInfo.h b/Headers/gnustep/gui/NSPrintInfo.h
index 549a16e39..f21ffd0fd 100644
--- a/Headers/gnustep/gui/NSPrintInfo.h
+++ b/Headers/gnustep/gui/NSPrintInfo.h
@@ -1,12 +1,13 @@
-/*
- NSPrintInfo.h
+/** NSPrintInfo
- Stores information used in printing
+ Stores information used in printing.
- Copyright (C) 1996,1997 Free Software Foundation, Inc.
+ Copyright (C) 1996,1997 Free Software Foundation, Inc.
- Author: Simon Frankau
+ Author: sgf@frankau.demon.co.uk
Date: July 1997
+ Author: fedor@gnu.org
+ Date: Oct 2001
This file is part of the GNUstep GUI Library.
@@ -121,12 +122,6 @@ typedef enum _NSPrintingPaginationMode {
//
- (NSMutableDictionary *)dictionary;
-//
-// NSCoding protocol
-//
-- (void)encodeWithCoder:aCoder;
-- initWithCoder:aDecoder;
-
@end
//
diff --git a/Headers/gnustep/gui/NSPrintOperation.h b/Headers/gnustep/gui/NSPrintOperation.h
index 4c6cc64de..768b6a086 100644
--- a/Headers/gnustep/gui/NSPrintOperation.h
+++ b/Headers/gnustep/gui/NSPrintOperation.h
@@ -1,15 +1,16 @@
-/*
- NSPrintOperation.h
+/** NSPrintOperation
- Controls operations generating EPS, PDF or PS print jobs.
+ Controls generation of EPS, PDF or PS print jobs.
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996 Free Software Foundation, Inc.
Author: Scott Christley
Date: 1996
- Author: Fred Kiefer
+ Author: FredKiefer@gmx.de
Date: November 2000
Updated to new specification
+ Author: fedor@gnu.org
+ Date: Oct 2001
This file is part of the GNUstep GUI Library.
diff --git a/Headers/gnustep/gui/NSView.h b/Headers/gnustep/gui/NSView.h
index af99fd3da..52986ee99 100644
--- a/Headers/gnustep/gui/NSView.h
+++ b/Headers/gnustep/gui/NSView.h
@@ -1,9 +1,8 @@
-/*
- NSView.h
+/** NSView
- The wonderful view class; it encapsulates all drawing functionality
+ Encapsulates all drawing functionality
- Copyright (C) 1996 Free Software Foundation, Inc.
+ Copyright (C) 1996 Free Software Foundation, Inc.
Author: Scott Christley
Date: 1996
@@ -11,6 +10,8 @@
Date: 1997
Author: Felipe A. Rodriguez
Date: August 1998
+ Author:
+ Date: Oct 2001
This file is part of the GNUstep GUI Library.
diff --git a/Source/NSFont.m b/Source/NSFont.m
index 6ff14b2fd..7bb5e1e24 100644
--- a/Source/NSFont.m
+++ b/Source/NSFont.m
@@ -45,6 +45,9 @@ static BOOL boldSystemCacheNeedsRecomputing = NO;
static BOOL userCacheNeedsRecomputing = NO;
static BOOL userFixedCacheNeedsRecomputing = NO;
+/* Set used to keep track of fonts we are using */
+static NSMutableSet *usedFonts = nil;
+
@interface NSFont (Private)
- (id) initWithName: (NSString*)name
matrix: (const float*)fontMatrix;
@@ -394,9 +397,21 @@ setNSFont(NSString* key, NSFont* font)
+ (void) useFont: (NSString*)name
{
- NSGraphicsContext *ctxt = GSCurrentContext();
+ if (usedFonts == nil)
+ usedFonts = RETAIN([NSMutableSet setWithCapacity: 2]);
- [ctxt useFont: name];
+ [usedFonts addObject: name];
+}
+
++ (void) resetUsedFonts
+{
+ if (usedFonts)
+ [usedFonts removeAllObjects];
+}
+
++ (NSSet *) usedFonts
+{
+ return usedFonts;
}
//
@@ -497,7 +512,7 @@ setNSFont(NSString* key, NSFont* font)
NSGraphicsContext *ctxt = GSCurrentContext();
[ctxt setFont: self];
- [ctxt useFont: fontName];
+ [NSFont useFont: fontName];
}
//
diff --git a/Source/NSGraphicsContext.m b/Source/NSGraphicsContext.m
index 76bee0487..75ce67075 100644
--- a/Source/NSGraphicsContext.m
+++ b/Source/NSGraphicsContext.m
@@ -111,18 +111,6 @@ NSGraphicsContext *GSCurrentContext()
defaultNSGraphicsContextClass = defaultContextClass;
}
-+ defaultContextWithInfo: (NSDictionary *)info;
-{
- NSGraphicsContext *ctxt;
-
- NSAssert(defaultNSGraphicsContextClass,
- @"Internal Error: No default NSGraphicsContext set\n");
- ctxt = [[defaultNSGraphicsContextClass allocWithZone: _globalGSZone]
- initWithContextInfo: info];
- AUTORELEASE(ctxt);
- return ctxt;
-}
-
+ (void) setCurrentContext: (NSGraphicsContext *)context
{
#ifdef GNUSTEP_BASE_LIBRARY
@@ -149,10 +137,25 @@ NSGraphicsContext *GSCurrentContext()
return [GSCurrentContext() isDrawingToScreen];
}
-+ (NSGraphicsContext *) graphicsContextWithAttributes: (NSDictionary *)attributes
++ defaultContextWithInfo: (NSDictionary *)info;
{
- // FIXME: The attributes should determine the concrete class
- return [self defaultContextWithInfo: attributes];
+ return [self graphicsContextWithAttributes: info];
+}
+
++ (NSGraphicsContext *) graphicsContextWithAttributes: (NSDictionary *)info
+{
+ NSGraphicsContext *ctxt;
+ if (self == [NSGraphicsContext class])
+ {
+ NSAssert(defaultNSGraphicsContextClass,
+ @"Internal Error: No default NSGraphicsContext set\n");
+ ctxt = [[defaultNSGraphicsContextClass allocWithZone: _globalGSZone]
+ initWithContextInfo: info];
+ AUTORELEASE(ctxt);
+ }
+ else
+ ctxt = [[self allocWithZone: _globalGSZone] initWithContextInfo: info];
+ return ctxt;
}
+ (NSGraphicsContext *) graphicsContextWithWindow: (NSWindow *)aWindow
@@ -1170,16 +1173,6 @@ NSGraphicsContext *GSCurrentContext()
[self subclassResponsibility: _cmd];
}
-- (void) useFont: (NSString*) name
-{
- /*
- * Do nothing here, printing subclasses will have to register all
- * the fonts used by the current print operation to be able to
- * dump the %%DocumentFonts comment required by the Adobe Document
- * Structuring Convention (see the red book).
- */
-}
-
/* ----------------------------------------------------------------------- */
/* Gstate operations */
/* ----------------------------------------------------------------------- */
diff --git a/Source/NSPageLayout.m b/Source/NSPageLayout.m
index ed03ec38f..411a0e00d 100644
--- a/Source/NSPageLayout.m
+++ b/Source/NSPageLayout.m
@@ -194,7 +194,6 @@ static NSPageLayout *shared_instance;
result = [NSApp runModalForWindow: self];
[self orderOut: self];
- NSLog(@"Model Page Layout ended with code %d", result);
return result;
}
@@ -486,8 +485,7 @@ static NSPageLayout *shared_instance;
[_printInfo setOrientation: [control selectedColumn]+NSPortraitOrientation];
/* Write Size */
- /* FIXME: Currently don't allow writing size. What does that mean
- anyway? Shouldn't we set margins instead? */
+ /* FIXME: Currently don't allow writing custom size. */
}
diff --git a/Source/NSPrintInfo.m b/Source/NSPrintInfo.m
index 0161b1f27..8bc97512f 100644
--- a/Source/NSPrintInfo.m
+++ b/Source/NSPrintInfo.m
@@ -26,7 +26,9 @@
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include
#include
+#include
#include
#include
#include
@@ -47,6 +49,10 @@
#define NSPrintInfo_DEFAULTSTABLE @"PrintDefaults"
#endif
+#define NSNUMBER(val) [NSNumber numberWithInt: val]
+#define DICTSET(dict, obj, key) \
+ [dict setObject: obj forKey: key]
+
// FIXME: retain/release of dictionary with retain/release of printInfo?
// Class variables:
@@ -58,6 +64,16 @@ NSDictionary *paperSizes = nil;
+ initPrintInfoDefaults;
@end
+/**
+
+ Class Description
+
+ NSPrintInfo is a storage object that stores information that describes
+ how a view is to printed and the destination information for printing.
+
+
+*/
+
@implementation NSPrintInfo
//
@@ -98,28 +114,6 @@ NSDictionary *paperSizes = nil;
+ (NSSize)sizeForPaperName:(NSString *)name
{
return [[self defaultPrinter] pageSizeForPaper:name];
- // Alternatively:
-// NSBundle *adminBundle;
-// NSString *path;
-// NSValue *size;
-// if (!paperSizes)
-// {
-// adminBundle = [NSBundle bundleWithPath:NSPrinterAdmin_PATH];
-// path = [adminBundle pathForResource:NSPrintInfo_PAPERFILE ofType:nil];
-// // If not found
-// if (path == nil || [path length] == 0)
-// {
-// [NSException raise:NSGenericException
-// format:@"Could not find paper size index, file %s",
-// [NSPrintInfo_PAPERFILE cString]];
-// // NOT REACHED
-// }
-// paperSizes = RETAIN([NSDictionary dictionaryWithContentsOfFile:path]);
-// }
-// size = [paperSizes objectForKey:name];
-// if (!size)
-// return NSZeroSize;
-// return [size sizeValue];
}
//
@@ -214,19 +208,41 @@ NSDictionary *paperSizes = nil;
- (void)setOrientation:(NSPrintingOrientation)mode
{
+ NSSize size;
[_info setObject:[NSNumber numberWithInt:mode]
forKey:NSPrintOrientation];
+ /* Set the paper size accordingly */
+ size = [self paperSize];
+ if ((mode == NSPortraitOrientation && size.width > size.height)
+ || (mode == NSLandscapeOrientation && size.width < size.height))
+ {
+ float tmp = size.width;
+ size.width = size.height;
+ size.height = tmp;
+ [_info setObject: [NSValue valueWithSize: size]
+ forKey: NSPrintPaperSize];
+ }
}
- (void)setPaperName:(NSString *)name
{
- [_info setObject:name forKey:NSPrintPaperName];
+ DICTSET(_info, name, NSPrintPaperName);
+ DICTSET(_info,
+ [NSValue valueWithSize: [NSPrintInfo sizeForPaperName: name]],
+ NSPrintPaperSize);
}
- (void)setPaperSize:(NSSize)size
{
+ NSPrintingOrientation orient;
[_info setObject:[NSValue valueWithSize:size]
forKey:NSPrintPaperSize];
+ /* Set orientation accordingly */
+ if (size.width <= size.height)
+ orient = NSPortraitOrientation;
+ else
+ orient = NSLandscapeOrientation;
+ DICTSET(_info, NSNUMBER(orient), NSPrintOrientation);
}
- (void)setRightMargin:(float)value
@@ -369,38 +385,62 @@ NSDictionary *paperSizes = nil;
//
+ initPrintInfoDefaults
{
+ NSString *defPrinter, *str;
NSBundle *adminBundle;
NSString *path;
+ NSPrinter *printer;
adminBundle = [NSBundle bundleWithPath:NSPrinterAdmin_PATH];
path = [adminBundle pathForResource:NSPrintInfo_DEFAULTSTABLE ofType:nil];
- // If not found
+ defPrinter = nil;
if (path != nil && [path length] != 0)
{
- printInfoDefaults = RETAIN([NSMutableDictionary dictionaryWithContentsOfFile:path]);
- // NOT REACHED
+ printInfoDefaults = [NSMutableDictionary dictionaryWithContentsOfFile:path];
+ RETAIN(printInfoDefaults);
+ defPrinter = [printInfoDefaults objectForKey:NSPrintPrinter];
+ printer = [NSPrinter printerWithName: defPrinter];
+ if (printer == nil)
+ defPrinter = nil;
}
if (printInfoDefaults == nil)
{
- NSLog(@"Could not find printing defaults table, file %s",
- [NSPrintInfo_DEFAULTSTABLE cString]);
- // FIXME: As a replacement we add a very simple definition
- printInfoDefaults = RETAIN(([NSMutableDictionary dictionaryWithObjectsAndKeys:
- @"Unknown", NSPrintPrinter,
- @"A4", NSPrintPaperName,
- NULL]));
+ NSDebugLog(@"NSPrinter", @"Could not find printing defaults table, file %@",
+ NSPrintInfo_DEFAULTSTABLE);
+ printInfoDefaults = RETAIN([NSMutableDictionary dictionary]);
+ }
+ if (defPrinter == nil)
+ {
+ defPrinter = [[NSPrinter printerNames] objectAtIndex: 0];
+ DICTSET(printInfoDefaults, defPrinter, NSPrintPrinter);
}
- // The loaded dictionary contains the name of the printer for NSPrintPrinter
- // Load the real NSPrinter object...
- [printInfoDefaults
- setObject:[NSPrinter printerWithName:[printInfoDefaults
- objectForKey:NSPrintPrinter]]
- forKey:NSPrintPrinter];
- [printInfoDefaults
- setObject:[NSValue valueWithSize:
- [NSPrintInfo sizeForPaperName:
- [printInfoDefaults objectForKey:NSPrintPaperName]]]
- forKey:NSPrintPaperSize];
+ /* Replace the printer name with a real NSPrinter object */
+ printer = [NSPrinter printerWithName: defPrinter];
+ DICTSET(printInfoDefaults, [NSPrinter printerWithName: defPrinter], NSPrintPrinter);
+
+ /* Set up other defaults from the printer object */
+ str = [printer stringForKey:@"DefaultPageSize" inTable: @"PPD"];
+ /* FIXME: Need to check for AutoSelect and probably a million other things... */
+ if (str == nil)
+ str = @"A4";
+ DICTSET(printInfoDefaults, str, NSPrintPaperName);
+ DICTSET(printInfoDefaults,
+ [NSValue valueWithSize: [NSPrintInfo sizeForPaperName: str]],
+ NSPrintPaperSize);
+
+ /* Set default margins. FIXME: Probably should check ImageableArea */
+ DICTSET(printInfoDefaults, NSNUMBER(36), NSPrintRightMargin);
+ DICTSET(printInfoDefaults, NSNUMBER(36), NSPrintLeftMargin);
+ DICTSET(printInfoDefaults, NSNUMBER(72), NSPrintTopMargin);
+ DICTSET(printInfoDefaults, NSNUMBER(72), NSPrintBottomMargin);
+ DICTSET(printInfoDefaults, NSNUMBER(NSPortraitOrientation),
+ NSPrintOrientation);
+ //DICTSET(printInfoDefaults, NSNUMBER(NSClipPagination),
+ // NSPrintHorizontalPagination);
+ DICTSET(printInfoDefaults, NSNUMBER(NSAutoPagination),
+ NSPrintVerticalPagination);
+ DICTSET(printInfoDefaults, NSNUMBER(1), NSPrintHorizontallyCentered);
+ DICTSET(printInfoDefaults, NSNUMBER(1), NSPrintVerticallyCentered);
+
return self;
}
diff --git a/Source/NSPrintOperation.m b/Source/NSPrintOperation.m
index 2ca00b9b2..c590297bc 100644
--- a/Source/NSPrintOperation.m
+++ b/Source/NSPrintOperation.m
@@ -29,27 +29,46 @@
59 Temple Place - Suite 330, Boston, MA 02111-1307, USA.
*/
+#include
#include
#include
+#include
#include
#include
#include
#include
#include
#include
+#include
#include
#include
#include
#include
#include
+#include
#include
-@interface NSGraphicsContext (Printing)
+#define NSNUMBER(a) [NSNumber numberWithInt: (a)]
+#define NSFNUMBER(a) [NSNumber numberWithFloat: (a)]
-+ (NSGraphicsContext*) postscriptContextWithInfo: (NSDictionary*)info;
-
-@end
+/* Local pagination variables needed while printing */
+typedef struct _page_info_t {
+ NSRect scaledBounds; /* View's rect scaled by the user specified scale
+ and page fitting */
+ NSRect paperBounds; /* Print area of a page in default user space, possibly
+ rotated if printing Landscape */
+ NSRect sheetBounds; /* Print are of a page in default user space */
+ NSSize paperSize; /* Size of the paper */
+ int xpages, ypages;
+ int first, last;
+ double pageScale; /* Scaling determined from page fitting */
+ double printScale; /* User specified scaling */
+ double nupScale; /* Scale required to fit nup pages on the sheet */
+ int nup; /* Number up pages to print on a sheet */
+ double lastWidth, lastHeight;
+ NSPrintingOrientation orient;
+} page_info_t;
@interface NSPrintOperation (Private)
@@ -62,6 +81,13 @@
@end
+@interface NSView (NSPrintOperation)
+- (void) _displayPageInRect: (NSRect)pageRect
+ atPlacement: (NSPoint)location
+ withInfo: (page_info_t)info;
+- (void) _endSheet;
+@end
+
// Subclass for the regular printing
@interface GSPrintOperation: NSPrintOperation
{
@@ -99,6 +125,21 @@
static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
+/**
+
+ Class Description
+
+ NSPrintOperation controls printing of an NSView. When invoked normally
+ it will (optionally) display a standard print panel (NSPrintPanel), and
+ based on the information entered by the user here as well as information
+ about page layout (see NSPageLayout) tells the NSView to print it's
+ contents. NSPrintOperation works with the NSView to paginate the output
+ into appropriately sized and oriented pages and finally delivers the result
+ to the appropriate place, whether it be a printer, and PostScript file,
+ or another output.
+
+
+*/
@implementation NSPrintOperation
//
@@ -196,6 +237,9 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Setting the Print Operation
//
+/** Returns the NSPrintOperation object that is currently performing
+ a print operation (if any).
+*/
+ (NSPrintOperation *)currentOperation
{
NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
@@ -203,6 +247,12 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
return (NSPrintOperation*)[dict objectForKey: NSPrintOperationThreadKey];
}
+/** Set the current NSPrintOperation to the supplied operation
+ object. As this is currently implemented, if a NSPrintOperation
+ is currently running, that operation is lost (along with any
+ associated context), so be careful to call this only when there is
+ no current operation.
+*/
+ (void)setCurrentOperation:(NSPrintOperation *)operation
{
NSMutableDictionary *dict = [[NSThread currentThread] threadDictionary];
@@ -258,6 +308,9 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Determining the Type of Operation
//
+/** Returns YES if the receiver is performing an operation whose output
+ is EPS format.
+*/
- (BOOL)isEPSOperation
{
return NO;
@@ -271,6 +324,8 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Controlling the User Interface
//
+/** Returns the NSPrintPanel associated with the receiver.
+ */
- (NSPrintPanel *)printPanel
{
if (_printPanel == nil)
@@ -279,26 +334,42 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
return _printPanel;
}
+/** Returns YES if the reciever display an NSPrintPanel and other information
+ when running a print operation. */
- (BOOL)showPanels
{
return _showPanels;
}
+/** Sets the NSPrintPanel used by the receiver obtaining and displaying
+ printing information from/to the user.
+*/
- (void)setPrintPanel:(NSPrintPanel *)panel
{
ASSIGN(_printPanel, panel);
}
+/** Use this to set whether a print panel is displayed during a printing
+ operation. If set to NO, then the receiver uses information that
+ was previously set and does not display any status information about the
+ progress of the printing operation.
+*/
- (void)setShowPanels:(BOOL)flag
{
_showPanels = flag;
}
+/** Returns the accessory view used by the NSPrintPanel associated with
+ the receiver.
+*/
- (NSView *)accessoryView
{
return _accessoryView;
}
+/** Set the accessory view used by the NSPrintPanel associated with the
+ receiver.
+*/
- (void)setAccessoryView:(NSView *)aView
{
ASSIGN(_accessoryView, aView);
@@ -307,17 +378,25 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Managing the drawing Context
//
+/** This method is used by the print operation to create a special
+ graphics context for use while running the print operation.
+*/
- (NSGraphicsContext*)createContext
{
[self subclassResponsibility: _cmd];
return nil;
}
+/** Returns the graphic contexts used by the print operation.
+*/
- (NSGraphicsContext *)context
{
return _context;
}
+/** This method is used by the print operation to destroy the special
+ graphic context used while running the print operation.
+*/
- (void)destroyContext
{
[_context destroyContext];
@@ -327,16 +406,23 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Page Information
//
+/** Returns the page currently being printing. Returns 0 if no page
+ is currently being printed
+*/
- (int)currentPage
{
return _currentPage;
}
+/** Returns the page order of printing.
+*/
- (NSPrintingPageOrder)pageOrder
{
return _pageOrder;
}
+/** Set the page order used when printing.
+ */
- (void)setPageOrder:(NSPrintingPageOrder)order
{
_pageOrder = order;
@@ -345,18 +431,26 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Running a Print Operation
//
+/** Called by the print operation and it has finished running a printing
+ operation.
+*/
- (void)cleanUpOperation
{
_currentPage = 0;
[NSPrintOperation setCurrentOperation: nil];
}
+/** Called by the print operation to deliver the results of the printing
+ operation. This might include sending the output to a printer, a file
+ or a previewing program. Returns YES if the output was delivered
+ sucessfully.
+*/
- (BOOL)deliverResult
{
- // FIXME
- return YES;
+ return NO;
}
+/* Private method to run the printing operation */
- (BOOL) _runOperation
{
BOOL result;
@@ -367,23 +461,53 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
return NO;
result = NO;
+ if (_pageOrder == NSUnknownPageOrder)
+ {
+ if ([[[_printInfo dictionary] objectForKey: NSPrintReversePageOrder]
+ boolValue] == YES)
+ _pageOrder = NSDescendingPageOrder;
+ else
+ _pageOrder = NSAscendingPageOrder;
+ }
+
[NSGraphicsContext setCurrentContext: _context];
NS_DURING
{
[self _print];
result = YES;
+ [NSGraphicsContext setCurrentContext: oldContext];
}
NS_HANDLER
{
+ [NSGraphicsContext setCurrentContext: oldContext];
NSRunAlertPanel(@"Error", @"Printing error: %@",
@"OK", NULL, NULL, localException);
}
NS_ENDHANDLER
- [NSGraphicsContext setCurrentContext: oldContext];
[self destroyContext];
return result;
}
+- (void) _setupPrintInfo
+{
+ BOOL knowsPageRange;
+ NSRange viewPageRange;
+ NSMutableDictionary *dict = [_printInfo dictionary];
+
+ knowsPageRange = [_view knowsPageRange: &viewPageRange];
+ if (knowsPageRange == YES)
+ {
+ int first = viewPageRange.location;
+ int last = NSMaxRange(viewPageRange) - 1;
+ [dict setObject: NSNUMBER(first) forKey: NSPrintFirstPage];
+ [dict setObject: NSNUMBER(last) forKey: NSPrintLastPage];
+ }
+}
+
+/** Call this message to run the print operation on a view. This includes
+ (optionally) displaying a print panel and working with the NSView to
+ paginate and draw the contents of the view.
+*/
- (BOOL)runOperation
{
BOOL result;
@@ -394,6 +518,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
int button;
[panel setAccessoryView: _accessoryView];
+ [self _setupPrintInfo];
[panel updateFromPrintInfo];
button = [panel runModal];
[panel setAccessoryView: nil];
@@ -438,6 +563,8 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
withObject: contextInfo];
}
+/** Run a print operation modally with respect to a window.
+ */
- (void)runOperationModalForWindow: (NSWindow *)docWindow
delegate: (id)delegate
didRunSelector: (SEL)didRunSelector
@@ -457,6 +584,7 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
of _showPanels
*/
[panel setAccessoryView: _accessoryView];
+ [self _setupPrintInfo];
[panel updateFromPrintInfo];
[panel beginSheetWithPrintInfo: _printInfo
modalForWindow: docWindow
@@ -470,11 +598,15 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Getting the NSPrintInfo Object
//
+/** Returns the NSPrintInfo object associated with the receiver.
+*/
- (NSPrintInfo *)printInfo
{
return _printInfo;
}
+/** Set the NSPrintInfo object associated with the receiver.
+ */
- (void)setPrintInfo:(NSPrintInfo *)aPrintInfo
{
if (aPrintInfo == nil)
@@ -486,6 +618,8 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
//
// Getting the NSView Object
//
+/** Return the view that is the being printed.
+*/
- (NSView *)view
{
return _view;
@@ -520,11 +654,246 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
return self;
}
+static NSSize
+scaleSize(NSSize size, double scale)
+{
+ size.height *= scale;
+ size.width *= scale;
+ return size;
+}
+
+static NSRect
+scaleRect(NSRect rect, double scale)
+{
+ return NSMakeRect(NSMinX(rect) * scale,
+ NSMinY(rect) * scale,
+ NSWidth(rect) * scale,
+ NSHeight(rect) * scale);
+}
+
+/* Pagination - guess how many pages we need to print. This could be off
+ by one in both X and Y because of the view's ability to adjust the
+ width and height of the printRect during printing. Also set up a bunch
+ of other information needed for printing.
+*/
+- (void) _printPaginateWithInfo: (page_info_t *)info knowsRange: (BOOL)knowsRange
+{
+ NSMutableDictionary *dict;
+ dict = [_printInfo dictionary];
+
+ info->paperSize = [_printInfo paperSize];
+ info->orient = [_printInfo orientation];
+ info->printScale = [[dict objectForKey: NSPrintScalingFactor] doubleValue];
+ info->nup = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
+ info->nupScale = 1;
+ if (info->nup < 1 || (info->nup > 1 && (((info->nup) & 0x1) == 1)))
+ {
+ /* Bad nup value */
+ info->nup = 1;
+ [dict setObject: NSNUMBER(1) forKey: NSPrintPagesPerSheet];
+ }
+
+ /* Subtract the margins from the paper size to get print boundary */
+ info->paperBounds.size = info->paperSize;
+ info->paperBounds.origin.x = [_printInfo leftMargin];
+ info->paperBounds.origin.y = [_printInfo bottomMargin];
+ info->paperBounds.size.width -=
+ ([_printInfo rightMargin]+[_printInfo leftMargin]);
+ info->paperBounds.size.height -=
+ ([_printInfo topMargin]+[_printInfo bottomMargin]);
+
+ info->sheetBounds = info->paperBounds;
+ if (info->orient == NSLandscapeOrientation)
+ {
+ /* Bounding box needs to be in default user space, but the bbox
+ we get is rotated */
+ info->sheetBounds = NSMakeRect(NSMinY(info->paperBounds),
+ NSMinX(info->paperBounds),
+ NSHeight(info->paperBounds),
+ NSWidth(info->paperBounds));
+ }
+ /* Save this for the view to look at */
+ [dict setObject: [NSValue valueWithRect: info->paperBounds]
+ forKey: @"NSPrintPaperBounds"];
+ [dict setObject: [NSValue valueWithRect: info->sheetBounds]
+ forKey: @"NSPrintSheetBounds"];
+
+ /* Scale bounds by the user specified scaling */
+ info->scaledBounds = scaleRect(_rect, info->printScale);
+
+ if (knowsRange == NO)
+ {
+ /* Now calculate page fitting to get page scale */
+ info->pageScale = 1;
+ if ([_printInfo horizontalPagination] == NSFitPagination)
+ info->pageScale = info->paperBounds.size.width
+ / NSWidth(info->scaledBounds);
+ if ([_printInfo verticalPagination] == NSFitPagination)
+ info->pageScale = MIN(info->pageScale,
+ NSHeight(info->paperBounds)/NSHeight(info->scaledBounds));
+ /* Scale bounds by pageScale */
+ info->scaledBounds = scaleRect(info->scaledBounds, info->pageScale);
+
+ /* Now find out how many pages */
+ info->xpages = ceil(NSWidth(info->scaledBounds)/NSWidth(info->paperBounds));
+ info->ypages = ceil(NSHeight(info->scaledBounds)/NSHeight(info->paperBounds));
+ if ([_printInfo horizontalPagination] == NSClipPagination)
+ info->xpages = 1;
+ if ([_printInfo verticalPagination] == NSClipPagination)
+ info->ypages = 1;
+ }
+
+ /* Calculate nup. If nup is an odd multiple of two, secretly change the
+ page orientation to it's complement to make pages fit better.
+ */
+ if (((int)(info->nup / 2) & 0x1) == 1)
+ {
+ float tmp;
+ if (info->orient == NSLandscapeOrientation)
+ info->nupScale =
+ info->paperSize.width/(2*info->paperSize.height);
+ else
+ info->nupScale =
+ info->paperSize.height/(2*info->paperSize.width);
+ info->nupScale /= (info->nup / 2);
+ info->orient = (info->orient == NSPortraitOrientation) ?
+ NSLandscapeOrientation : NSPortraitOrientation;
+ tmp = info->paperSize.width;
+ info->paperSize.width = info->paperSize.height;
+ info->paperSize.height = tmp;
+ [dict setObject: NSNUMBER(info->orient) forKey: NSPrintOrientation];
+ }
+ else if (info->nup > 1)
+ {
+ info->nupScale = 2.0 / (float)info->nup;
+ }
+}
+
+/* Our personnel method to calculate the print rect for the specified page.
+ Note, we assume this function is called in order from our first to last
+ page. The returned pageRect is in the view's coordinate system
+*/
+- (NSRect) _rectForPage: (int)page info: (page_info_t *)info
+{
+ int xpage, ypage;
+ NSRect pageRect;
+
+ xpage = (page - 1) % info->xpages;
+ ypage = (page - 1) % info->ypages;
+ if (xpage == 0)
+ info->lastWidth = 0;
+ if (ypage == 0)
+ info->lastHeight = 0;
+ pageRect = NSMakeRect(info->lastWidth, info->lastHeight,
+ NSWidth(info->paperBounds), NSHeight(info->paperBounds));
+ pageRect = NSIntersectionRect(pageRect, info->scaledBounds);
+ /* Scale to view's coordinate system */
+ return scaleRect(pageRect, 1/(info->pageScale*info->printScale));
+
+}
+
+/* Let the view adjust the page rect we calculated. See assumptions for
+ _rectForPage:
+*/
+- (NSRect) _adjustPagesFirst: (int)first
+ last: (int)last
+ info: (page_info_t *)info
+{
+ int i;
+ double hlimit, wlimit;
+ NSRect pageRect;
+ hlimit = [_view heightAdjustLimit];
+ wlimit = [_view widthAdjustLimit];
+ for (i = first; i <= last; i++)
+ {
+ float newVal, limitVal;
+ pageRect = [self _rectForPage: i info: info];
+ limitVal = NSMaxY(pageRect) - hlimit * NSHeight(pageRect);
+ [_view adjustPageHeightNew: &newVal
+ top: NSMinY(pageRect)
+ bottom: NSMaxY(pageRect)
+ limit: limitVal];
+ if (newVal < NSMaxY(pageRect))
+ pageRect.size.height = MAX(newVal, limitVal) - NSMinY(pageRect);
+ limitVal = NSMaxX(pageRect) - wlimit * NSWidth(pageRect);
+ [_view adjustPageWidthNew: &newVal
+ left: NSMinX(pageRect)
+ right: NSMaxX(pageRect)
+ limit: limitVal];
+ if (newVal < NSMaxX(pageRect))
+ pageRect.size.width = MAX(newVal, limitVal) - NSMinX(pageRect);
+ info->lastWidth = NSMaxX(pageRect)*(info->pageScale*info->printScale);
+ info->lastHeight = NSMaxY(pageRect)*(info->pageScale*info->printScale);
+ }
+ return pageRect;
+}
+
- (void) _print
{
- BOOL knowsPageRange;
+ int i, dir;
+ BOOL knowsPageRange, allPages;
NSRange viewPageRange;
NSString *clocale;
+ NSMutableDictionary *dict;
+ page_info_t info;
+
+ dict = [_printInfo dictionary];
+
+ /* Setup pagination */
+ allPages = [[dict objectForKey: NSPrintAllPages] boolValue];
+ knowsPageRange = [_view knowsPageRange: &viewPageRange];
+ [self _printPaginateWithInfo: &info knowsRange: knowsPageRange];
+ if (knowsPageRange == NO)
+ {
+ viewPageRange = NSMakeRange(1, (info.xpages * info.ypages));
+ }
+ [dict setObject: NSNUMBER(NSMaxRange(viewPageRange) )
+ forKey: @"NSPrintTotalPages"];
+ if (allPages == YES)
+ {
+ info.first = viewPageRange.location;
+ info.last = NSMaxRange(viewPageRange) - 1;
+ }
+ else
+ {
+ info.first = [[dict objectForKey: NSPrintFirstPage] intValue];
+ info.last = [[dict objectForKey: NSPrintLastPage] intValue];
+ info.first = MAX(info.first, viewPageRange.location);
+ info.first = MIN(info.first, NSMaxRange(viewPageRange) - 1);
+ info.last = MAX(info.last, info.first);
+ info.last = MIN(info.last, NSMaxRange(viewPageRange) - 1);
+ viewPageRange = NSMakeRange(info.first, (info.last-info.first)+1);
+ }
+ info.lastWidth = info.lastHeight = 0;
+ [dict setObject: NSFNUMBER(info.nupScale) forKey: @"NSNupScale"];
+ [dict setObject: NSNUMBER(info.first) forKey: NSPrintFirstPage];
+ if (allPages == YES && knowsPageRange == NO)
+ [dict setObject: NSNUMBER(info.first-1) forKey: NSPrintLastPage];
+ else
+ [dict setObject: NSNUMBER(info.last) forKey: NSPrintLastPage];
+ NSDebugLLog(@"NSPrinting", @"Printing pages %d to %d",
+ info.first, info.last);
+ NSDebugLLog(@"NSPrinting", @"Printing rect %@, scaled %@",
+ NSStringFromRect(_rect),
+ NSStringFromRect(info.scaledBounds));
+
+ _currentPage = info.first;
+ dir = 1;
+ if (_pageOrder == NSDescendingPageOrder)
+ {
+ _currentPage = info.last;
+ dir = -1;
+ }
+ if (dir > 0 && _currentPage != 1)
+ {
+ /* Calculate page rects we aren't processing to catch up to the
+ first page we are */
+ NSRect pageRect;
+ pageRect = [self _adjustPagesFirst: 1
+ last: _currentPage-1
+ info: &info];
+ }
+
/* Reset the current locale to a generic C locale so numbers
get printed correctly for PostScript (maybe we should only
set the numeric locale?). Save the current locale for later. */
@@ -534,18 +903,180 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
/* Print the header information */
[_view beginDocument];
- /* Setup pagination */
- knowsPageRange = [_view knowsPageRange: &viewPageRange];
+ /* Print each page */
+ i = 0;
+ while (i < (info.last-info.first+1))
+ {
+ NSPoint location;
+ NSRect pageRect, scaledPageRect;
+ if (knowsPageRange == YES)
+ {
+ pageRect = [_view rectForPage: _currentPage];
+ }
+ else
+ {
+ if (dir < 0)
+ pageRect = [self _adjustPagesFirst: 1
+ last: _currentPage
+ info: &info];
+ else
+ pageRect = [self _adjustPagesFirst: _currentPage
+ last: _currentPage
+ info: &info];
+ }
+ NSDebugLLog(@"NSPrinting", @" current page %d, rect %@",
+ _currentPage, NSStringFromRect(pageRect));
+ if (NSIsEmptyRect(pageRect))
+ break;
- [_view beginPageInRect: _rect atPlacement: NSMakePoint(0,0)];
- [_view displayRectIgnoringOpacity: _rect];
+ scaledPageRect = scaleRect(pageRect, info.printScale*info.pageScale);
+ location = [_view locationOfPrintRect: scaledPageRect];
+
+ /* Draw using our special view routine */
+ [_view _displayPageInRect: pageRect
+ atPlacement: location
+ withInfo: info];
+
+ if (dir > 0 && _currentPage == info.last && allPages == YES)
+ {
+ /* Check if adjust pages forced part of the bounds onto
+ another page */
+ if (NSMaxX(pageRect) < NSMaxX(_rect)
+ && [_printInfo horizontalPagination] != NSClipPagination)
+ {
+ info.xpages++;
+ }
+ if (NSMaxY(pageRect) < NSMaxY(_rect)
+ && [_printInfo verticalPagination] != NSClipPagination)
+ {
+ info.ypages++;
+ }
+ viewPageRange = NSMakeRange(1, (info.xpages * info.ypages));
+ info.last = NSMaxRange(viewPageRange) - 1;
+ }
+ i++;
+ _currentPage += dir;
+ } /* Print each page */
+
+ /* Make sure we end the sheet */
+ if ( info.nup > 1 && (info.last - info.first) % info.nup != info.nup - 1 )
+ {
+ [_view drawSheetBorderWithSize: info.paperBounds.size];
+ [_view _endSheet];
+ }
[_view endDocument];
-
GSSetLocale(clocale);
+
+ /* Setup/reset for next time */
+ [dict setObject: NSNUMBER(info.last) forKey: NSPrintLastPage];
+ if (((int)(info.nup / 2) & 0x1) == 1)
+ {
+ info.orient = (info.orient == NSPortraitOrientation) ?
+ NSLandscapeOrientation : NSPortraitOrientation;
+ [dict setObject: NSNUMBER(info.orient) forKey: NSPrintOrientation];
+ }
}
@end
+@implementation NSView (NSPrintOperation)
+- (void) _displayPageInRect: (NSRect)pageRect
+ atPlacement: (NSPoint)location
+ withInfo: (page_info_t)info
+{
+ int currentPage;
+ float xoffset, yoffset, scale;
+ NSString *label;
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+
+ currentPage = [printOp currentPage];
+
+ label = nil;
+ if (info.nup == 1)
+ label = [NSString stringWithFormat: @"%d", currentPage];
+
+ /* Begin a sheet (i.e. a physical page in Postscript terms). If
+ nup > 1 then this occurs only once every nup pages */
+ if ((currentPage - info.first) % info.nup == 0)
+ {
+ [self beginPage: floor((currentPage - info.first)/info.nup)+1
+ label: label
+ bBox: info.sheetBounds
+ fonts: nil];
+ DPSPrintf(ctxt, "/__GSsheetsaveobject save def\n");
+ if (info.orient == NSLandscapeOrientation)
+ {
+ DPSrotate(ctxt, 90);
+ DPStranslate(ctxt, 0, -info.paperSize.height);
+ }
+ /* Also offset by margins */
+ DPStranslate(ctxt, NSMinX(info.paperBounds), NSMinY(info.paperBounds));
+ }
+
+ /* Begin a logical page */
+ [self beginPageInRect: pageRect atPlacement: location];
+ scale = info.pageScale * info.printScale;
+ if (scale != 1.0)
+ DPSscale(ctxt, scale, scale);
+ if ([self isFlipped])
+ {
+ NSAffineTransformStruct ats = { 1, 0, 0, -1, 0, 1 };
+ NSAffineTransform *matrix, *flip;
+ flip = [NSAffineTransform new];
+ matrix = [NSAffineTransform new];
+ [matrix makeIdentityMatrix];
+ [matrix appendTransform: _boundsMatrix];
+ /*
+ * The flipping process must result in a coordinate system that
+ * exactly overlays the original. To do that, we must translate
+ * the origin by the height of the view.
+ */
+ [flip setTransformStruct: ats];
+ flip->matrix.ty = NSHeight(_bounds);
+ [matrix appendTransform: flip];
+ [matrix concat];
+ yoffset = NSHeight(_frame) - NSMaxY(pageRect);
+ }
+ else
+ yoffset = 0 - NSMinY(pageRect);
+
+ /* Translate so the rect we're printing is on the page */
+ xoffset = 0 - NSMinX(pageRect);
+ DPStranslate(ctxt, xoffset, yoffset);
+
+ if ((currentPage - info.first) % info.nup == 0)
+ [self endPageSetup];
+
+ /* Do the actual drawing */
+ [self displayRectIgnoringOpacity: pageRect];
+
+ /* End a logical page */
+ DPSgrestore(ctxt); // Balance gsave in beginPageInRect:
+ [self drawPageBorderWithSize:
+ scaleSize(info.paperBounds.size, info.nupScale)];
+ [self endPage];
+
+ /* End a physical page */
+ if ( ((currentPage - info.first) % info.nup == info.nup-1) )
+ {
+ [self drawSheetBorderWithSize: info.paperBounds.size];
+ [self _endSheet];
+ }
+}
+
+- (void) _endSheet
+{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ if ([printOp isEPSOperation] == NO)
+ DPSPrintf(ctxt, "showpage\n");
+ DPSPrintf(ctxt, "__GSsheetsaveobject restore\n");
+ DPSPrintf(ctxt, "%%%%PageTrailer\n");
+ DPSPrintf(ctxt, "\n");
+}
+@end
+
@implementation GSPrintOperation
@@ -581,7 +1112,9 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
}
[info setObject: _path forKey: @"NSOutputFile"];
- _context = RETAIN([NSGraphicsContext postscriptContextWithInfo: info]);
+ [info setObject: NSGraphicsContextPSFormat
+ forKey: NSGraphicsContextRepresentationFormatAttributeName];
+ _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]);
return _context;
}
@@ -642,6 +1175,10 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
clocale = GSSetLocale(nil);
GSSetLocale(@"C");
+ /* Save this for the view to look at. Seems like there should
+ be a better way to pass it to beginDocument */
+ [[_printInfo dictionary] setObject: [NSValue valueWithRect: _rect]
+ forKey: @"NSPrintSheetBounds"];
[_view beginDocument];
[_view beginPageInRect: _rect atPlacement: NSMakePoint(0,0)];
[_view displayRectIgnoringOpacity: _rect];
@@ -650,6 +1187,11 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
GSSetLocale(clocale);
}
+- (BOOL)isEPSOperation
+{
+ return YES;
+}
+
- (BOOL)deliverResult
{
if (_data != nil && _path != nil)
@@ -663,6 +1205,22 @@ static NSString *NSPrintOperationThreadKey = @"NSPrintOperationThreadKey";
return YES;
}
+- (NSGraphicsContext*)createContext
+{
+ NSMutableDictionary *info;
+ if (_context)
+ return _context;
+
+ info = [_printInfo dictionary];
+
+ [info setObject: _path forKey: @"NSOutputFile"];
+ [info setObject: NSGraphicsContextPSFormat
+ forKey: NSGraphicsContextRepresentationFormatAttributeName];
+ _context = RETAIN([NSGraphicsContext graphicsContextWithAttributes: info]);
+
+ return _context;
+}
+
@end
@implementation GSPDFPrintOperation
diff --git a/Source/NSPrintPanel.m b/Source/NSPrintPanel.m
index 6cd0affc1..58674b42d 100644
--- a/Source/NSPrintPanel.m
+++ b/Source/NSPrintPanel.m
@@ -144,7 +144,8 @@ static NSPrintPanel *shared_instance;
/* Setup the layout popup */
control = CONTROL(self, NSPPLayoutButton);
- list = [NSArray arrayWithObjects: @"1up", @"2up", @"3up", @"4up", nil];
+ list = [NSArray arrayWithObjects: @"1 up", @"2 up", @"4 up", @"6 up",
+ @"8 up", nil];
[control removeAllItems];
for (i = 0; i < [list count]; i++)
{
@@ -239,11 +240,15 @@ static NSPrintPanel *shared_instance;
else if (tag == NSPPPreviewButton)
{
_picked = NSPPPreviewButton;
+ NSRunAlertPanel(@"Sorry", @"Previewing of print file not implemented",
+ @"OK", NULL, NULL);
+ /* Don't stop the modal session */
+ return;
}
else if (tag ==NSFaxButton )
{
_picked = NSFaxButton;
- NSRunAlertPanel(@"Warning", @"Fax of print file not implemented",
+ NSRunAlertPanel(@"Sorry", @"Faxing of print file not implemented",
@"OK", NULL, NULL);
/* Don't stop the modal session */
return;
@@ -293,7 +298,7 @@ static NSPrintPanel *shared_instance;
NSString *str;
str = [NSString stringWithFormat: @"%d", _pages.location];
[[fromRangeForm cellAtIndex: 0] setStringValue: str];
- str = [NSString stringWithFormat: @"%d", NSMaxRange(_pages)];
+ str = [NSString stringWithFormat: @"%d", NSMaxRange(_pages)-1];
[[toRangeForm cellAtIndex: 0] setStringValue: str];
}
}
@@ -361,7 +366,7 @@ static NSPrintPanel *shared_instance;
dict = [info dictionary];
- NSDebugLLog(@"NSPrintPanel",
+ NSDebugLLog(@"NSPrinting",
@"Update PrintInfo dictionary\n %@ \n --------------", dict);
_pages = NSMakeRange([[dict objectForKey: NSPrintFirstPage] intValue],
[[dict objectForKey: NSPrintLastPage] intValue]);
@@ -375,7 +380,7 @@ static NSPrintPanel *shared_instance;
if (layout > 4)
layout = 4;
control = CONTROL(self, NSPPLayoutButton);
- [control selectItemAtIndex: layout-1];
+ [control selectItemAtIndex: (int)(layout/2)];
/* Setup the resolution popup */
control = CONTROL(_optionPanel, NSPPResolutionButton);
@@ -508,7 +513,7 @@ static NSPrintPanel *shared_instance;
/* Scale */
control = CONTROL(self, NSPPScaleField);
- scale = [control intValue]/100;
+ scale = [control doubleValue]/100.0;
if (scale <= 0)
scale = .1;
if (scale >= 10)
@@ -518,7 +523,9 @@ static NSPrintPanel *shared_instance;
forKey: NSPrintScalingFactor];
/* Layout */
- layout = [CONTROL(self, NSPPLayoutButton) indexOfSelectedItem] + 1;
+ layout = [CONTROL(self, NSPPLayoutButton) indexOfSelectedItem] * 2;
+ if (layout == 0)
+ layout = 1;
[dict setObject: NSNUMBER(layout) forKey: NSPrintPagesPerSheet];
/* Resolution */
@@ -611,7 +618,7 @@ static NSPrintPanel *shared_instance;
}
[info setJobDisposition: sel];
- NSDebugLLog(@"NSPrintPanel",
+ NSDebugLLog(@"NSPrinting",
@"Final info dictionary ----\n %@ \n --------------", dict);
}
diff --git a/Source/NSView.m b/Source/NSView.m
index b8a4c2aeb..105810dc3 100644
--- a/Source/NSView.m
+++ b/Source/NSView.m
@@ -37,6 +37,7 @@
#include
#include
+#include
#include
#include
#include
@@ -46,18 +47,24 @@
#include
#include
#include
+#include
+#include
-#include
-#include
#include
-#include
-#include
+#include
#include
-#include
+#include
+#include
#include
+#include
+#include
#include
#include
#include
+#include
+#include
+#include
+#include
/* Variable tells this view and subviews that we're printing. Not really
a class variable because we want it visible to subviews also
@@ -69,6 +76,11 @@ struct NSWindow_struct
@defs(NSWindow)
};
+@interface NSFont (NSViewFonts)
++ (void) resetUsedFonts;
++ (NSSet *) usedFonts;
+@end
+
@implementation NSView
/*
@@ -1352,7 +1364,6 @@ GSSetDragTypes(NSView* obj, NSArray *types)
a superview so we get printed correctly */
[self _matrixToWindow];
[_matrixToWindow makeIdentityMatrix];
- _visibleRect = _bounds;
}
else
{
@@ -1418,11 +1429,7 @@ GSSetDragTypes(NSView* obj, NSArray *types)
if ([_window gState] == 0)
return;
- if (viewIsPrinting != nil)
- {
- _coordinates_valid = NO;
- }
- else
+ if (viewIsPrinting == nil)
{
/* Restore our original gstate */
DPSgrestore(ctxt);
@@ -2450,16 +2457,10 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
{
NSMutableData *data = [NSMutableData data];
- /* Inform ourselves and subviews that we're printing so we adjust
- the PostScript accordingly. Perhaps this could be in the thread
- dictionary, but that's probably overkill and slow */
- viewIsPrinting = self;
-
[[NSPrintOperation EPSOperationWithView: self
insideRect: aRect
toData: data] runOperation];
- viewIsPrinting = nil;
return data;
}
@@ -2495,7 +2496,15 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
- (NSString *)printJobTitle
{
- return nil;
+ id doc;
+ NSString *title;
+ doc = [[NSDocumentController sharedDocumentController] documentForWindow:
+ [self window]];
+ if (doc)
+ title = [doc displayName];
+ else
+ title = [[self window] title];
+ return title;
}
/*
@@ -2624,8 +2633,31 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
- (NSPoint) locationOfPrintRect: (NSRect)aRect
{
-// FIXME: Should depend on the print info
- return NSZeroPoint;
+ int pages;
+ NSPoint location;
+ NSRect bounds;
+ NSMutableDictionary *dict;
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ NSPrintInfo *printInfo = [printOp printInfo];
+ dict = [printInfo dictionary];
+
+ pages = [[dict objectForKey: @"NSPrintTotalPages"] intValue];
+ if ([dict objectForKey: @"NSPrintPaperBounds"])
+ bounds = [[dict objectForKey: @"NSPrintPaperBounds"] rectValue];
+ else
+ bounds = aRect;
+ location = NSMakePoint(0, NSHeight(bounds)-NSHeight(aRect));
+ /* FIXME: I can't figure out how the location for a multi-page document
+ is computed. Just ignore centering? */
+ if (pages == 1)
+ {
+ if ([printInfo isHorizontallyCentered])
+ location.x = (NSWidth(bounds) - NSWidth(aRect))/2;
+ if ([printInfo isVerticallyCentered])
+ location.y = (NSHeight(bounds) - NSHeight(aRect))/2;
+ }
+
+ return location;
}
- (NSRect) rectForPage: (int)page
@@ -2646,13 +2678,26 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
bBox: (NSRect)pageRect
fonts: (NSString*)fontNames
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+
+ if (aString == nil)
+ aString = [[NSNumber numberWithInt: ordinalNum] description];
+ DPSPrintf(ctxt, "%%%%Page: %s %d\n", [aString cString], ordinalNum);
+ if (NSIsEmptyRect(pageRect) == NO)
+ DPSPrintf(ctxt, "%%%%PageBoundingBox: %d %d %d %d\n",
+ (int)NSMinX(pageRect), (int)NSMinY(pageRect),
+ (int)NSMaxX(pageRect), (int)NSMaxY(pageRect));
+ if (fontNames)
+ DPSPrintf(ctxt, "%%%%PageFonts: %s\n", [fontNames cString]);
+ DPSPrintf(ctxt, "%%%%BeginPageSetup\n");
}
- (void) beginPageSetupRect: (NSRect)aRect placement: (NSPoint)location
{
+ [self beginPageInRect: aRect atPlacement: location];
}
-- (void) beginPrologueBBox: (NSRect)boundingBox
+- (void) beginPrologueBBox: (NSRect)bBox
creationDate: (NSString*)dateCreated
createdBy: (NSString*)anApplication
fonts: (NSString*)fontNames
@@ -2660,6 +2705,57 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
pages: (int)numPages
title: (NSString*)aTitle
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ NSPrintingOrientation orient;
+ BOOL epsOp;
+
+ epsOp = [printOp isEPSOperation];
+ orient = [[printOp printInfo] orientation];
+
+ if (epsOp)
+ DPSPrintf(ctxt, "%%!PS-Adobe-3.0 EPSF-3.0\n");
+ else
+ DPSPrintf(ctxt, "%%!PS-Adobe-3.0\n");
+ DPSPrintf(ctxt, "%%%%Title: %s\n", [aTitle cString]);
+ DPSPrintf(ctxt, "%%%%Creator: %s\n", [anApplication cString]);
+ DPSPrintf(ctxt, "%%%%CreationDate: %s\n",
+ [[dateCreated description] cString]);
+ DPSPrintf(ctxt, "%%%%For: %s\n", [user cString]);
+ if (fontNames)
+ DPSPrintf(ctxt, "%%%%DocumentFonts: %s\n", [fontNames cString]);
+ else
+ DPSPrintf(ctxt, "%%%%DocumentFonts: (atend)\n");
+
+ if (NSIsEmptyRect(bBox) == NO)
+ DPSPrintf(ctxt, "%%%%BoundingBox: %d %d %d %d\n",
+ (int)NSMinX(bBox), (int)NSMinY(bBox),
+ (int)NSMaxX(bBox), (int)NSMaxY(bBox));
+ else
+ DPSPrintf(ctxt, "%%%%BoundingBox: (atend)\n");
+
+ if (epsOp == NO)
+ {
+ if (numPages)
+ DPSPrintf(ctxt, "%%%%Pages: %d\n", numPages);
+ else
+ DPSPrintf(ctxt, "%%%%Pages: (atend)\n");
+ if ([printOp pageOrder] == NSDescendingPageOrder)
+ DPSPrintf(ctxt, "%%%%PageOrder: Descend\n");
+ else if ([printOp pageOrder] == NSAscendingPageOrder)
+ DPSPrintf(ctxt, "%%%%PageOrder: Ascend\n");
+ else if ([printOp pageOrder] == NSSpecialPageOrder)
+ DPSPrintf(ctxt, "%%%%PageOrder: Special\n");
+
+ if (orient == NSPortraitOrientation)
+ DPSPrintf(ctxt, "%%%%Orientation: Portrait\n");
+ else
+ DPSPrintf(ctxt, "%%%%Orientation: Landscape\n");
+ }
+
+ DPSPrintf(ctxt, "%%%%GNUstepVersion: %d.%d.%d\n",
+ GNUSTEP_GUI_MAJOR_VERSION, GNUSTEP_GUI_MINOR_VERSION,
+ GNUSTEP_GUI_SUBMINOR_VERSION);
}
- (void) addToPageSetup
@@ -2668,10 +2764,14 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
- (void) beginSetup
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%BeginSetup\n");
}
- (void) beginTrailer
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%Trailer\n");
}
- (void) drawPageBorderWithSize: (NSSize)borderSize
@@ -2684,39 +2784,203 @@ static NSView* findByTag(NSView *view, int aTag, unsigned *level)
- (void) endHeaderComments
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%EndComments\n\n");
}
- (void) endPrologue
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%EndProlog\n\n");
}
- (void) endSetup
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%EndSetup\n\n");
}
- (void) endPageSetup
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%EndPageSetup\n");
}
- (void) endPage
{
+ int nup;
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ NSDictionary *dict = [[printOp printInfo] dictionary];
+
+ nup = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
+ if (nup > 1)
+ {
+ DPSPrintf(ctxt, "__GSpagesaveobject restore\n\n");
+ }
}
- (void) endTrailer
{
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ DPSPrintf(ctxt, "%%%%EOF\n");
}
+/**
+ Writes header and job information for the PostScript document. This
+ includes at a minimum, PostScript header information. It may also
+ include job setup information if the output is intended for a printer
+ (i.e. not an EPS file). Most of the information for writing the
+ header comes from the NSPrintOperation and NSPrintInfo objects
+ associated with the current print operation.
+
+ There isn't normally anything that the program needs to override
+ at the beginning of a document, although if there is additional
+ setup that needs to be done, you can override the NSView's methods
+ endHeaderComments, endPrologue, beginSetup, and/or endSetup.
+
+ This method calls the above methods in the listed order before
+ or after writing the required information. For an EPS operation, the
+ beginSetup and endSetup methods aren't used. */
- (void)beginDocument
{
+ int first, last, pages, nup;
+ NSRect bbox;
+ NSDictionary *dict;
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ dict = [[printOp printInfo] dictionary];
+ if (printOp == nil)
+ {
+ NSLog(@"[NSView -beginDocument] called without a current print op");
+ return;
+ }
+ /* Inform ourselves and subviews that we're printing so we adjust
+ the PostScript accordingly. Perhaps this could be in the thread
+ dictionary, but that's probably overkill and slow */
+ viewIsPrinting = self;
+
+ /* Get pagination information */
+ nup = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
+ bbox = NSZeroRect;
+ if ([dict objectForKey: @"NSPrintSheetBounds"])
+ bbox = [[dict objectForKey: @"NSPrintSheetBounds"] rectValue];
+ first = [[dict objectForKey: NSPrintFirstPage] intValue];
+ last = [[dict objectForKey: NSPrintLastPage] intValue];
+ pages = last - first + 1;
+ if (nup > 1)
+ pages = ceil((float)pages / nup);
+
+ /* Begin document structure */
+ [self beginPrologueBBox: bbox
+ creationDate: [[NSCalendarDate calendarDate] description]
+ createdBy: [[NSProcessInfo processInfo] processName]
+ fonts: nil
+ forWhom: NSUserName()
+ pages: pages
+ title: [self printJobTitle]];
+ [self endHeaderComments];
+
+ DPSPrintf(ctxt, "%%%%BeginProlog\n");
+ // Prolog goes here !
+ [self endPrologue];
+ if ([printOp isEPSOperation] == NO)
+ {
+ [self beginSetup];
+ // Setup goes here !
+ [self endSetup];
+ }
+
+ [NSFont resetUsedFonts];
+ /* Make sure we set the visible rect so everything is printed. */
+ [self _rebuildCoordinates];
+ _visibleRect = _bounds;
}
- (void)beginPageInRect:(NSRect)aRect
atPlacement:(NSPoint)location
{
+ int nup;
+ float scale;
+ NSRect bounds;
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ NSDictionary *dict = [[printOp printInfo] dictionary];
+
+ if ([dict objectForKey: @"NSPrintPaperBounds"])
+ bounds = [[dict objectForKey: @"NSPrintPaperBounds"] rectValue];
+ else
+ bounds = aRect;
+
+ nup = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
+ if (nup > 1)
+ {
+ int page;
+ float xoff, yoff;
+ DPSPrintf(ctxt, "/__GSpagesaveobject save def\n");
+ page = [printOp currentPage]
+ - [[dict objectForKey: NSPrintFirstPage] intValue];
+ page = page % nup;
+ scale = [[dict objectForKey: @"NSNupScale"] floatValue];
+ if (nup == 2)
+ xoff = page;
+ else
+ xoff = (page % (nup/2));
+ xoff *= NSWidth(bounds) * scale;
+ if (nup == 2)
+ yoff = 0;
+ else
+ yoff = (int)((nup-page-1) / (nup/2));
+ yoff *= NSHeight(bounds) * scale;
+ DPStranslate(ctxt, xoff, yoff);
+ DPSgsave(ctxt);
+ DPSscale(ctxt, scale, scale);
+ }
+ else
+ DPSgsave(ctxt);
+
+ /* Translate to placement */
+ if (location.x != 0 || location.y != 0)
+ DPStranslate(ctxt, location.x, location.y);
}
- (void)endDocument
{
+ int first, last, current, pages;
+ NSSet *fontNames;
+ NSGraphicsContext *ctxt = GSCurrentContext();
+ NSPrintOperation *printOp = [NSPrintOperation currentOperation];
+ NSDictionary *dict = [[printOp printInfo] dictionary];
+
+ first = [[dict objectForKey: NSPrintFirstPage] intValue];
+ last = [[dict objectForKey: NSPrintLastPage] intValue];
+ pages = last - first + 1;
+ [self beginTrailer];
+
+ if (pages == 0)
+ {
+ int nup = [[dict objectForKey: NSPrintPagesPerSheet] intValue];
+ current = [printOp currentPage];
+ pages = current - first; // Current is 1 more than the last page
+ if (nup > 1)
+ pages = ceil((float)pages / nup);
+ DPSPrintf(ctxt, "%%%%Pages: %d\n", pages);
+ }
+ fontNames = [NSFont usedFonts];
+ if (fontNames && [fontNames count])
+ {
+ NSString *name;
+ NSEnumerator *e = [fontNames objectEnumerator];
+ DPSPrintf(ctxt, "%%%%DocumentFonts: %@\n", [e nextObject]);
+ while ((name = [e nextObject]))
+ {
+ DPSPrintf(ctxt, "%%%%+ %@\n", name);
+ }
+ }
+
+ [self endTrailer];
+ [self _invalidateCoordinates];
+ viewIsPrinting = nil;
}
/*
diff --git a/Source/externs.m b/Source/externs.m
index 0f58812f4..e6fbb164f 100644
--- a/Source/externs.m
+++ b/Source/externs.m
@@ -158,6 +158,21 @@ NSString *NSDrawerWillOpenNotification =
NSString *_NSFormCellDidChangeTitleWidthNotification
= @"_NSFormCellDidChangeTitleWidthNotification";
+// NSGraphicContext constants
+NSString *NSGraphicsContextDestinationAttributeName =
+@"NSGraphicsContextDestinationAttributeName";
+NSString *NSGraphicsContextPDFFormat =
+@"NSGraphicsContextPDFFormat";
+NSString *NSGraphicsContextPSFormat =
+@"NSGraphicsContextPSFormat";
+NSString *NSGraphicsContextRepresentationFormatAttributeName =
+@"NSGraphicsContextRepresentationFormatAttributeName";
+
+NSString *NSImageInterpolationDefault = @"NSImageInterpolationDefault";
+NSString *NSImageInterpolationNone = @"NSImageInterpolationNone";
+NSString *NSImageInterpolationLow = @"NSImageInterpolationLow";
+NSString *NSImageInterpolationHigh = @"NSImageInterpolationHigh";
+
// NSHelpManager notifications;
NSString *NSContextHelpModeDidActivateNotification =
@"NSContextHelpModeDidActivateNotification";