Printing with the system dialog when using PMPrintSession - objective-c

Below is the code I we are using to print on mac. Is there an easy way to allow printing using the system dialog? It looks like at one time PMSessionBeginDocument & PMSessionBeginPage were a thing, but now all I can find is the NoDialog options.
Are these calls still usable with the latest frameworks? Or is there another way to print using the system dialog?
PMPrintSession lPrintSession;
PMCreateSession(&lPrintSession);
PMPrintSettings lPrintSettings;
PMCreatePrintSettings(&lPrintSettings);
PMSessionDefaultPrintSettings(lPrintSession, lPrintSettings);
...
PMSessionSetCurrentPMPrinter(lPrintSession, lPrinter);
...
PMSetPageRange(lPrintSettings, 1, 1);
PMSetCopies(lPrintSettings, inCopies, false);
if (!inUseSystemDialog) {
PMSessionBeginCGDocumentNoDialog(lPrintSession, lPrintSettings, lPageFormat);
PMSessionBeginPageNoDialog(lPrintSession, lPageFormat, NULL);
} else {
// TODO: What do we do here? Are these calls usable?
// PMSessionBeginDocument(lPrintSession, lPrintSettings, lPageFormat);
// PMSessionBeginPage(lPrintSession, lPageFormat, NULL);
}
CGContextRef lGraphics;
PMSessionGetCGGraphicsContext(lPrintSession, &lGraphics);
...
PMSessionEndPageNoDialog(lPrintSession);
PMSessionEndDocumentNoDialog(lPrintSession);

You can run an NSPrintPanel to show the system print dialog. For that, you also need to set up an NSPrintInfo object:
NSPrintInfo* printInfo = [NSPrintInfo new];
// set printInfo.printer if you want to override the default
PMPrintSettings printSettings = printInfo.PMPrintSettings;
// configure printSettings
[printInfo updateFromPMPrintSettings];
PMPageFormat pageFormat = printInfo.PMPageFormat;
// configure pageFormat
[printInfo updateFromPMPageFormat];
Create the panel and run it with that info object:
NSPrintPanel* panel = [NSPrintPanel printPanel];
// configure panel; for example, set its options property
NSInteger result = [panel runModalWithPrintInfo:printInfo];
Use the info as the basis of your print session:
if (result == NSOKButton)
{
PMPrintSession session = printInfo.PMPrintSession;
printSettings = printInfo.PMPrintSettings;
pageFormat = printInfo.PMPageFormat;
PMSessionBeginCGDocumentNoDialog(session, printSettings, pageFormat);
PMSessionBeginPageNoDialog(session, pageFormat, NULL);
CGContextRef lGraphics;
PMSessionGetCGGraphicsContext(session, &lGraphics);
...
PMSessionEndPageNoDialog(session);
PMSessionEndDocumentNoDialog(session);
}

Related

How to get file's "Stationary Pad" flag information using objective c

I need to check for "Stationary Pad" flag of a file but I am not getting any way to read this information.
You have to use the Carbon File Manager API to do this, you can't do it from Cocoa. That said, this code does still work in the Xcode 12 beta.
-(BOOL)isStationaryPad:(NSString *)path
{
static kIsStationary = 0x0800;
CFURLRef url;
FSRef fsRef;
FSCatalogInfo catInfo;
BOOL success;
url = CFURLCreateWithFileSystemPath(NULL, (CFStringRef)path, kCFURLPOSIXPathStyle, FALSE);
if (!url) return NO;
success = CFURLGetFSRef(url, &fsRef);
CFRelease(url);
// catalog info from file system reference; isStationary status from catalog info
if (success && (FSGetCatalogInfo(&fsRef, kFSCatInfoFinderInfo, &catInfo, nil, nil, nil))==noErr)
{
return ((((FileInfo*)catInfo.finderInfo)->finderFlags & kIsStationary) == kIsStationary);
}
return NO;
}
This code is from the open source version of the Bean word processor.

Core Data Cocoa Mac OS delete object Objective-C

I have a menu displaying files that are stored in a Core Data model. I'm able to add a new object to the model and display it on the menu. Now, I would like to delete one file from the menu when right clicking on it and choose delete, everything I tried didn't work so far:
- (IBAction)RemoveSelectedFile:(id)sender {
if ([((NSMenuItem *)sender).menu isEqual:self.fileRecordContextMenu]) {
// get the indices that have been clicked on
NSIndexSet * indices = [self _indexesToProcessForContextMenuForTable:self.fileRecordsTable];
ClassFileRecord * fileRecord = (self.document && self.document.fileRecordsController && self.document.fileRecordsController.arrangedObjects && indices && indices.count > 0) ? [self.document.fileRecordsController.arrangedObjects objectAtIndex:indices.firstIndex] : nil;
if (fileRecord) {
// Path to the file
NSString * u = fileRecord.sourceFilePath;
if (u) {
// Delete Object
}
}
}
}
UPDATE:
I found an easy solution using the NSArrayController:
NSArray * selectedObjects = self.fileRecordsController.selectedObjects;
[self.fileRecordsController removeObjects:selectedObjects];

Read 'hidden' input for CLI Dart app

What's the best way to receive 'hidden' input from a command-line Dart application? For example, in Bash, this is accomplished with:
read -s SOME_VAR
Set io.stdin.echoMode to false:
import 'dart:io' as io;
void main() {
io.stdin.echoMode = false;
String input = io.stdin.readLineSync();
// or
var input;
while(input != 32) {
input = io.stdin.readByteSync();
if(input != 10) print(input);
}
// restore echoMode
io.stdin.echoMode = true;
}
This is a slightly extended version, key differences are that it uses a finally block to ensure the mode is reset if an exception is thrown whilst the code is executing.
The code also uses a waitFor call (only available in dart cli apps) to turn this code into a synchronous call. Given this is a cli command there is no need for the complications that futures bring to the table.
The code also does the classic output of '*' as you type.
If you are doing much cli work the below code is from the dart package I'm working on called dcli. Have a look at the 'ask' method.
https://pub.dev/packages/dcli
String readHidden() {
var line = <int>[];
try {
stdin.echoMode = false;
stdin.lineMode = false;
int char;
do {
char = stdin.readByteSync();
if (char != 10) {
stdout.write('*');
// we must wait for flush as only one flush can be outstanding at a time.
waitFor<void>(stdout.flush());
line.add(char);
}
} while (char != 10);
} finally {
stdin.echoMode = true;
stdin.lineMode = true;
}
// output a newline as we have suppressed it.
print('');
return Encoding.getByName('utf-8').decode(line);
}

How to add a proxy to NSURLSession in Xamarin.iOS?

I need to load the content of the webview using a proxy.
I have this code (Objective-C):
NSURLSessionConfiguration *configuration = [NSURLSessionConfiguration defaultSessionConfiguration];
configuration.connectionProxyDictionary = #{ (NSString *)kCFStreamPropertyHTTPProxyHost: [proxyURL host], (NSString *)kCFStreamPropertyHTTPProxyPort: [proxyURL port] };
The following Xamarin code doesn't work, ConnectionProxyDictionary is set but application doesn't use this settings:
var configuration = NSUrlSessionConfiguration.DefaultSessionConfiguration;
configuration.ConnectionProxyDictionary = new NSDictionary("kCFStreamPropertyHTTPProxyHost", proxyURL.Host, "kCFStreamPropertyHTTPProxyPort", proxyURL.port);
How to port above Objective-C code to Xamarin.iOS? Is there another way to achieve the same goal?
The reason it does not work is because in Objective-C, the kXX is replaced with an actual reference to a constant, and in C#, you just plugged a string name.
You need to fetch the value of that constant and pass it:
Use this:
using MonoTouch.ObjCRuntime;
...
var keyHost = Dlfcn.GetStringConstant ("kCFStreamPropertyHTTPProxyHost")
var keyPort = Dlfcn.GetStringConstant ("kCFStreamPropertyHTTPProxyPort")
Then use keyHost and keyPort as your parameters in the NSDictionary
var configuration = NSUrlSessionConfiguration.DefaultSessionConfiguration;
NSObject[] values = new NSObject[]
{
NSObject.FromObject(proxyURL.host), //ProxyHost
NSNumber.FromInt32 (proxyURL.port), //Port
NSNumber.FromInt32 (1), //Enable HTTP proxy
};
NSObject[] keys = new NSObject[]
{
NSObject.FromObject("HTTPProxy"),
NSObject.FromObject("HTTPPort"),
NSObject.FromObject("HTTPEnable")
};
NSDictionary proxyDict = NSDictionary.FromObjectsAndKeys (values, keys);
configuration.ConnectionProxyDictionary = proxyDict;
var session = NSUrlSession.FromConfiguration (configuration);
var task = session.CreateDataTask(NSUrl.FromString("http://google.com"));
task.Resume ();

Set Custom KeyEquivalent in Services Menu

OmniFocus has a Cocoa Service that allows you to create tasks based upon selected items.
It has a preference that allows you to set the keyboard shortcut that triggers the Service. This is not just a global hotkey, it's a bona fide Service that shows up in the menu.
You can the keyboard shortcut to pretty much any combination, including combinations with ⌥ and ^. This functionality is not documented - the docs seem to say that KeyEquivalents must be a ⌘+[⇧]+someKey.
Once this is set, I observe three things:
The OmniFocus Info.plist file does not contain a KeyEquivalent listed. This is not surprising, as the file is read-only.
The pbs -dump_pboard utility lists NSKeyEquivalent = {}; for the service.
Using NSDebugServices lists this interesting line that does not show up with most debugging sessions (Obviously, for keyboard shortcut ⌃⌥⌘M): OmniFocus: Send to Inbox (com.omnigroup.OmniFocus) has a custom key equivalent: <NSKeyboardShortcut: 0x7fb18a0d18f0 (⌃⌥⌘M)>.
So my questions are twofold, and I suspect they are related:
How do you dynamically change a service's KeyEquivalent?
How do you set the KeyEquivalent to a combination including ⌃ and ⌥
Thank you!
Figured it out. The basic process is described here: Register NSService with Command Alt NSKeyEquivalent
The code is this:
//Bundle identifier from Info.plist
NSString* bundleIdentifier = #"com.whatever.MyApp";
//Services -> Menu -> Menu item title from Info.plist
NSString* appServiceName = #"Launch My Service";
//Services -> Instance method name from Info.plist
NSString* methodNameForService = #"myServiceMethod";
//The key equivalent
NSString* keyEquivalent = #"#~r";
CFStringRef serviceStatusName = (CFStringRef)[NSString stringWithFormat:#"%# - %# - %#", bundleIdentifier, appServiceName, methodNameForService];
CFStringRef serviceStatusRoot = CFSTR("NSServicesStatus");
CFPropertyListRef pbsAllServices = (CFPropertyListRef) CFMakeCollectable ( CFPreferencesCopyAppValue(serviceStatusRoot, CFSTR("pbs")) );
// the user did not configure any custom services
BOOL otherServicesDefined = pbsAllServices != NULL;
BOOL ourServiceDefined = NO;
if ( otherServicesDefined ) {
ourServiceDefined = NULL != CFDictionaryGetValue((CFDictionaryRef)pbsAllServices, serviceStatusName);
}
NSUpdateDynamicServices();
NSMutableDictionary *pbsAllServicesNew = nil;
if (otherServicesDefined) {
pbsAllServicesNew = [NSMutableDictionary dictionaryWithDictionary:(NSDictionary*)pbsAllServices];
} else {
pbsAllServicesNew = [NSMutableDictionary dictionaryWithCapacity:1];
}
NSDictionary *serviceStatus = [NSDictionary dictionaryWithObjectsAndKeys:
(id)kCFBooleanTrue, #"enabled_context_menu",
(id)kCFBooleanTrue, #"enabled_services_menu",
keyEquivalent, #"key_equivalent", nil];
[pbsAllServicesNew setObject:serviceStatus forKey:(NSString*)serviceStatusName];
CFPreferencesSetAppValue (
serviceStatusRoot,
(CFPropertyListRef) pbsAllServicesNew,
CFSTR("pbs"));
Boolean result = CFPreferencesAppSynchronize(CFSTR("pbs"));
if (result) {
NSUpdateDynamicServices();
NSLog(#"successfully installed our alt-command-r service");
} else {
NSLog(#"couldn't install our alt-command-r service");
}
If the code succeeds, you can view this in ~/Library/Preferences/pbs.plist
You should see something like:
NSServicesStatus = {
"com.whatever.MyApp - Launch My Service - myServiceMethod" = {
enabled_context_menu = :true;
enabled_services_menu = :true;
key_equivalent = "#~r";
};