Get an NSWindow object from NSWorkspace? - objective-c

I have the following which opens TextEdit using a Cocoa objective-c application:
[[NSWorkspace sharedWorkspace] openFile:#"/Users/abs/Documents/my.txt" withApplication:#"TextEdit"];
NSDictionary * currentAppInfo = [[NSWorkspace sharedWorkspace] activeApplication];
int pid = [[currentAppInfo objectForKey: #"NSApplicationProcessIdentifier"] intValue];
However, I am trying to get a NSWindow object or the likes for the application that I've just opened. So I can set height and width and various other things. How can I do this?

AppleScript is the way to go:
set theFile to "/Users/Anne/Desktop/File.txt"
tell application "TextEdit"
open (POSIX file theFile) as alias
set bounds of window 1 to {10, 10, 100, 100}
end tell
Use NSAppleScript to run the script:
NSString *path = #"/Users/Anne/Desktop/File.txt";
int X = 10;
int Y = 10;
int width = 400;
int height = 800;
NSString *theSource = [NSString stringWithFormat:#""
"set theFile to \"%#\"\n"
"tell application \"TextEdit\"\n"
"open (POSIX file theFile) as alias\n"
"set bounds of window 1 to {%d, %d, %d, %d}\n"
"end tell",
path,X,Y,width,height];
NSAppleScript *theScript = [[NSAppleScript alloc] initWithSource:theSource];
[theScript executeAndReturnError:nil];

Can’t imagine how that’s possible (what if you opened a Carbon app? or the app didn’t open a window at all?).
Sometimes the Accessibility API lets you do things of this nature.

Related

Programmatically change the state of a UIButton

I've got a pop-up view that loads when a user clicks on a TableView with Core Data elements. On the pop-up view I have a label that represents an int value.
The pop-up view has two butons, one for decreasing the value of the label by 1 and one for increasing it by one. So + and -
What I want to do is to disable the minus button if the label's value is 0. What I've tried is:
-(void)viewDidLayoutSubviews{
NSString *daString = currentVal.text;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:daString];
int number = [myNumber intValue];
if (number==0)
minus.enabled = NO;
else
minus.enabled = YES
}
The problem with my code is that the button stays disabled after I increase the label's value, and it's no longer equal to 0.
Any suggestions?
You should keep a reference to minus button e.g.
#property (strong, nonatomic) IBOutlet UIButton *minusButton;
Set it with a value of your minus button, or connect outlet in Interface Builder
in your action handler for plusButton, do something like that
-(IBAction)plusAction:(id)sender {
//Do your business logic
...
self.minusButton.enabled = YES;
}
//In your minusButton action handler
-(IBAction)minusAction:(id)sender {
//Do your business logic
...
NSString *daString = currentVal.text;
NSNumberFormatter * f = [[NSNumberFormatter alloc] init];
[f setNumberStyle:NSNumberFormatterDecimalStyle];
NSNumber * myNumber = [f numberFromString:daString];
int number = [myNumber intValue];
if (number==0)
self.minusButton.enabled = NO;
else
self.minusButton.enabled = YES
}
It seems like you have things the other way around. I would take a totally different approach:
Keep an instance variable (which we'll call 'count') in this viewController which holds the number. it can be an NSInteger. now add a target (self) to both buttons with a #selector(buttonPressed:). now this is how this selector should look like:
- (void)buttonPressed:(id)sender{
if (sender==plusButton)
self.count++;
if (sender==minusButton)
self.count--;
label.text = [NSString stringWithFormat:#"%d",self.count];
minusButton.enabled = (self.count>0);
}
I would just do this with a UIStepper, instead of the 2 buttons. You can set properties right in your storyboard/IB file that specify the max and min, increments, and a bunch of other useful things too. There are a couple video tutorials posted on YouTube that probably cover everything you'll need to know to use it.
Also, I have noticed one thing that...
If the button in disabled state and you are trying to change the title of normal state, it wont work.
I had to change the state to enabled and then I could manipulate title and set back to disabled.

how to detect free space around object

i've got few objects in view and i want to detect if space (for ex. [myObject frame] - 5px) is free.
now i must detect when my object is clicked but how can i detect free space?
NSString *currPuzzle = [NSString stringWithFormat:#"%d", currentPuzzle];
currentObject = [puzzleArray objectForKey:currPuzzle];
currentObjectFrame = [currentObject frame];
currentObjectCenter = [currentObject center];
int left = currentObjectFrame.origin.x - 1;
int right = currentObjectFrame.origin.x + 1;
int top = currentObjectFrame.origin.y - 1;
int bottom = currentObjectFrame.origin.y + 1;
i've got no idea how solve it.
any idea?
ok i resolve it. i create temporary rectangle and i detect intersect with this rect. all work great.

Read from iPhoto Library programmatically

I want to create an Application that connects to the iPhoto Library. So now I would like to read the Events and the pictures themselves from the library.
Is there an elegant / easy way to do this or do I have to manually read the Bundle Structure of the iPhoto User Data?
So far I have only found a picture taker: Is there a UIImagePicker for the Mac Desktop
Update: I found another relevant SO post: Selecting iPhoto images within a cocoa application
You can do it with NSAppleScript. This is some copy/paste from my app, hacked up a bit just to show the idea.
NSAppleEventDescriptor d = .. compile this script ..
#"tell application \"iPhoto\" to properties of albums"
for (int i = 0; i < [d numberOfItems]; i++)
{
NSAppleEventDescriptor *albumDesc = [d descriptorAtIndex:i];
// <NSAppleEventDescriptor: 'ipal'{
// 'ID ':4.265e+09,
// 'purl':'utxt'("http://www.flickr.com/photos/..."),
// 'pnam':'utxt'("Vacation"),
// 'alTy':'pubs',
// 'alCh':[ ],
// 'alPx':'msng' }>
NSString *albumName = [[albumDesc descriptorForKeyword:'pnam'] stringValue];
NSString *albumId = [[albumDesc descriptorForKeyword:'ID '] stringValue];
You can do the same thing to find the images
NSString *scp =
[NSString stringWithFormat:#"tell application \"iPhoto\" to properties of photos of album id %#",
[album objectForKey:#"id"]];
NSAppleEventDescriptor *d = ... compile scp ...
// 1 based!?
for (int i = 1; i <= [d numberOfItems]; i++)
{
NSAppleEventDescriptor *photoDesc = [d descriptorAtIndex:i];
// Yes.. this happens. Not sure why?!
if (!photoDesc)
continue;
// <NSAppleEventDescriptor: 'ipmr'{
// 'pnam':'utxt'("IMG_0058.JPG"),
// 'pwid':768,
// 'pdim':[ 768, 1024 ],
// 'alti':1.79769e+308,
// 'filn':'utxt'("3133889525_10975ba071_b.jpg"),
// 'ipth':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Masters/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg"),
// 'idat':'ldt '($F57C69C500000000$),
// 'rate':0,
// 'titl':'utxt'("IMG_0058.JPG"),
// 'phit':1024,
// 'itpt':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Thumbnails/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg.jpg"),
// 'ID ':4.295e+09,
// 'lati':'msng',
// 'pcom':'utxt'(""),
// 'opth':'utxt'("/Users/lagnat/Pictures/iPhoto Library/Masters/2010/11/10/20101110-002341/3133889525_10975ba071_b.jpg"),
// 'lngt':'msng',
// 'tiln':'utxt'("3133889525_10975ba071_b.jpg.jpg") }>
NSString *path = [[photoDesc descriptorForKeyword:'ipth'] stringValue];
NSString *imgname = [[photoDesc descriptorForKeyword:'pnam'] stringValue];
If releasing apps on the App Store you are now required now required to use the Sandbox, this stops the previous AppleScript method from working (the iPhoto app launches but an empty set is returned).
iPhoto libraries consist of a directory structure containing photos, databases and XML files. The contents changes with each version of iPhoto so be careful if manually accessing these files.
If you just want the album details you can parse the file AlbumData.xml
If you would like photos you can browse the Masters folder. The files structure follows date rather than by the sets configured in iPhoto.
More information can be found on the internals of the iPhoto library here:
http://www.fatcatsoftware.com/iplm/Help/iphoto%20library%20internals.html
The majority of the databases are in SQLite format and so can be programmatically accessed through Objective C, though again you can expect schema changes between different versions of iPhoto. The main databases of interest are Library.apdb and Properties.apdb in Database/apdb.
If you still want to use the Apple Script method, here's a version of the previous answer with the Apple script execution part included:
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:#"tell application \"iPhoto\" to properties of albums"];
NSAppleEventDescriptor *d = [script executeAndReturnError:nil];
NSLog(#"photo library count: %ld", (long)[d numberOfItems]);
for (int i = 0; i < [d numberOfItems]; i++)
{
NSAppleEventDescriptor *albumDesc = [d descriptorAtIndex:i];
NSString *albumName = [[albumDesc descriptorForKeyword:'pnam'] stringValue];
NSLog(#"%#", albumName);
}

Editing Mac OS X login items in Objective-C through AppleScript

In my Cocoa program, I want to examine what programs are registered to run at startup and modify that list as I feel appropriate. In order to be compatible with Tiger it seems like I need to work through AppleScript. I currently have the following code:
NSDictionary* errorDict;
NSAppleEventDescriptor* returnDescriptor = NULL;
NSString *appleSource = #"tell application \"System Events\"\n\
get every login item\n\
end tell";
NSAppleScript *appleScript = [[NSAppleScript alloc] initWithSource: appleSource];
returnDescriptor = [appleScript executeAndReturnError: &errorDict];
If I run that command in AppleScript, I get back an array of login items. However, I can't figure out how to iterate through this array in Objective-C. More specifically, I want to examine the names and paths of the programs registered to run at startup.
Any ideas?
Edit: I figured this out. Here is some sample code. The key is using AEKeyword's, which are very poorly documented. The best reference is here: http://developer.apple.com/mac/library/releasenotes/AppleScript/ASTerminology_AppleEventCodes/TermsAndCodes.html
const AEKeyword aeName = 'pnam';
const AEKeyword aePath = 'ppth';
...
NSDictionary* errorDict;
NSAppleEventDescriptor* getLoginItemsRD = NULL;
NSString *getLoginItemsSrc = #"tell application \"System Events\"\n\
get properties of every login item\n\
end tell";
NSAppleScript *getLoginItemsScript = [[NSAppleScript alloc] initWithSource: getLoginItemsSrc];
getLoginItemsRD = [getLoginItemsScript executeAndReturnError: &errorDict];
[getLoginItemsScript release];
int i;
int numLoginItems = [getLoginItemsRD numberOfItems];
for (i = 1; i <= numLoginItems; i++)
{
NSAppleEventDescriptor *loginItem = [getLoginItemsRD descriptorAtIndex:i];
NSString *loginItemName = [[loginItem descriptorForKeyword:aeName] stringValue];
NSString *loginItemPath = [[loginItem descriptorForKeyword:aePath] stringValue];
}
Apple has some source code which can manage login items for Tiger and earlier. I believe you're supposed to get it from ADC but I found it floating around here:
LoginItemAPI.h
LoginItemAPI.c

How do I get the details of an application using Objective-C?

I have the following code to detect the current window. How can I get 1) application internal name, 2) location, 3) publisher and 4) description of the window/application?
NSAutoreleasePool *pool = [[NSAutoreleasePool alloc] init];
//Get info about the currently active application.
NSWorkspace* workspace = [NSWorkspace sharedWorkspace];
NSDictionary* currentAppInfo = [workspace activeApplication];
//Get the PSN of the current application.
UInt32 lowLong = [[currentAppInfo objectForKey:#"NSApplicationProcessSerialNumberLow"] longValue];
UInt32 highLong = [[currentAppInfo objectForKey:#"NSApplicationProcessSerialNumberHigh"] longValue];
ProcessSerialNumber currentAppPSN = {highLong,lowLong};
//Grab window information from the window server.
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
ProcessSerialNumber myPSN = {kNoProcess, kNoProcess};
//Loop through the windows, the window list is ordered from front to back.
for (NSMutableDictionary* entry in (NSArray*) windowList)
{
int pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
GetProcessForPID(pid, &myPSN);
//If the process of the current window in the list matches our process, get the front window number.
if(myPSN.lowLongOfPSN == currentAppPSN.lowLongOfPSN && myPSN.highLongOfPSN == currentAppPSN.highLongOfPSN)
{
NSNumber *windowNumber = [entry objectForKey:(id)kCGWindowNumber];
windowNumber = [entry objectForKey:(id)kCGWindowNumber];
NSString* applicationName = [entry objectForKey:(id)kCGWindowOwnerName];
NSLog(#"Capture the window: %# with window ID: %#.",applicationName,windowNumber);
return applicationName;
//Break because we only want the front window.
break;
}
}
CFRelease(windowList);
[pool release];
You should use the ProcessInformationCopyDictionary function from the Process Manager API. Give it &myPSN and kProcessDictionaryIncludeAllInformationMask as arguments and you will get the information you are looking for.
I was looking for something related with this topic. I need a WindowRef of the window or window part at a certain location (mouse position) and it has to be over all the windows of all running applications...
I´ve tried it with Carbon (´Cos my App is entirely written in C++) but I´ve found that Some Carbon Functions Doesn´t work properly (MacFindWindow, FindWindow, HIWindowFindAtLocation, FindWindowOfClass, HIWindowGetCGWindowID...)
Maybe I´m doing it wrong, It´s difficult to believe that those Carbon functions won´t work any more in 64 bits architectures...
So, related with your question I found the same code and I tried this but it isn´t what I need, I hope it helps you in any way and I´ll keep searching and trying till I get it (If the O.S can do it everybody should).
//if the process of the current window in the list matches our process, get the front window number
if(myPSN.lowLongOfPSN == currentAppPSN.lowLongOfPSN && myPSN.highLongOfPSN == currentAppPSN.highLongOfPSN)
{
NSNumber* windowNumber = [entry objectForKey:(id)kCGWindowNumber];
NSString* applicationName = [entry objectForKey:(id)kCGWindowOwnerName];
NSLog(#"The current app is %# and the window number of its front window is %#.",applicationName,windowNumber);
CGRect bounds;
CGRectMakeWithDictionaryRepresentation((CFDictionaryRef)[entry objectForKey:(id)kCGWindowBounds], &bounds);
NSLog(#"WINDOW RECT BOUNDS; (x,y,width, height) = (%d,%d, %d, %d)", bounds.origin.x, bounds.origin.y, bounds.size.width, bounds.size.height);
break;
}
Also, follow this link, I´t will help you. I´m sure:
http://code.google.com/p/blazingstars/source/browse/trunk/PokerHK/HKLowLevel.m?r=70