NSAppleScript Opens iTunes automatically - objective-c

This shouldn't get the song name when iTunes is closed because iTunes has to open for it to check and return false.
Please Help.
//run applescript
NSAppleScript *script = [[NSAppleScript alloc] initWithSource:#"try\n tell application \"System Events\" to set checkIfItunesIsRunning to (name of processes) contains \"iTunes\"\n if checkIfItunesIsRunning is equal to true then\n tell application \"iTunes\" to get name of current track\n else\n return \"No Song\"\n end if\n on error errmsg number errNum\n return \"No Song\"\n end try"];
NSAppleEventDescriptor *theResult = [script executeAndReturnError:nil];
//Set MenuItem
[song setTitle:[theResult stringValue]];

You might have better luck with something like:
if ([[NSRunningApplication runningApplicationsWithBundleIdentifier:#"com.apple.iTunes"] count] != 0) {
// run your script
} else {
// itunes isn't running
}

Related

Change system time, time zone and auto checkbox in time and date settings programmatically

I'm trying to figure out how to edit the time and the 'Set Date and Time Automatically' check box programmatically. I've spent a while and cant find the solution.
I've tried looking at the NSUserDefault keys but don't see them.
NSLog(#"%#", [[[NSUserDefaults standardUserDefaults] dictionaryRepresentation] allKeys]);
help appreciated. This is OSX (not iphone).
This is not a complete answer. I just code below will just change the system time. Note: changing the system time requires root permission. Running the code via Xcode IDE as is will fail. Running from Terminal using sudo command works.
//
// main.m
// TimeChange
//
// Created by ... on 4/13/15.
// Copyright (c) 2015 .... All rights reserved.
//
#import <Foundation/Foundation.h>
#import <sys/time.h>
#include <errno.h>
extern int errno;
void NSLogTime(const struct tm *restrict temp, suseconds_t microseconds)
{
char tmbuf[64], buf[64];
strftime(tmbuf, sizeof tmbuf, "%Y-%m-%d %H:%M:%S", temp);
snprintf(buf, sizeof buf, "%s.%06d\n", tmbuf, microseconds);
NSLog(#" %#", [[NSString alloc] initWithUTF8String:buf]);
}
int main(int argc, const char * argv[]) {
#autoreleasepool {
// Built from samples based on the URL listed below
// http://stackoverflow.com/questions/2408976/struct-timeval-to-printable-format
// http://www.linuxquestions.org/questions/programming-9/c-code-to-change-date-time-on-linux-707384/
// Do whatever you need to set the following variable
// In this example I am hard-coding it
int month = 2;
int day = 27;
int year = 2002;
NSLog(#"Getting current date/time...");
struct timeval currentTime;
int success = gettimeofday(&currentTime, 0); // should check for success
struct tm *localTime = localtime(&currentTime.tv_sec);
NSLogTime(localTime, currentTime.tv_usec);
if (localTime)
{
NSLog(#"...create new date/time structure...");
localTime->tm_mon = month - 1;
localTime->tm_mday = day;
localTime->tm_year = year - 1900;
const struct timeval tv = {mktime(localTime), 0};
success = settimeofday(&tv, 0);
// check if we are success
if (success == 0)
{
NSLog(#"...time was changed!");
// get the new time from the system and display it
struct timeval updatedTime;
gettimeofday(&updatedTime, 0); // should check for success
NSLogTime(localtime(&updatedTime.tv_sec), updatedTime.tv_usec);
}
else
{
// display the error message
NSLog(#"Error Setting Date: %s", strerror(errno));
}
}
}
return 0;
}
Below is screen shot of the coding running in the terminal.
Note: the one hour time difference in the output is because Daylight Saving Time (DST) was not in-effect back in Feb 22, 2002.
So I discovered that I could write an applescript that would execute bash script commands. Then I called the script with NSApplescript.
The cool thing is apple script has an elegant password dialog and it only needs to be handled once for everything. This is far nicer than making the terminal appear.
The downside was the process for calling the applescript with NSApplescript.
What should have been a simple process of passing 3 args to the script needed to be handled by about 50 lines of outdated NSAppleEvent code that didn't even work in Apples docs. Luckily, I found a post where someone knew the constants missing from the absent Carbon framework.
The Code:
// Caller responsible for well formed ip address.
+(BOOL)setDateAndTimePreferences:(NSString*)ipAddress setAutoNetworkTime:(BOOL)yNo withTimezone:(NSString*)timezone{
// Load the script from a resource by fetching its URL from within our bundle
// Note: if the script if stored in a nother file location, NSBundle may not be
// necessary. Make sure the path to the script is correct.
NSString* path = [[NSBundle mainBundle] pathForResource:#"date_time_pref" ofType:#"scpt"];
if (path != nil){
NSURL* url = [NSURL fileURLWithPath:path];
if (url != nil)
{
NSDictionary* errors = [NSDictionary dictionary];
NSAppleScript* appleScript =
[[NSAppleScript alloc] initWithContentsOfURL:url error:&errors];
if (appleScript != nil)
{
// Get the value of the setAutoNetwork checkbox.
NSString *chkBox = (yNo == YES)? #"on": #"off";
// Create the arg parameters
NSAppleEventDescriptor* firstParameter =
[NSAppleEventDescriptor descriptorWithString:ipAddress];
NSAppleEventDescriptor* secondParameter =
[NSAppleEventDescriptor descriptorWithString:chkBox];
NSAppleEventDescriptor* thirdParameter =
[NSAppleEventDescriptor descriptorWithString:timezone];
// Create and populate the list of parameters.
NSAppleEventDescriptor* parameters = [NSAppleEventDescriptor listDescriptor];
[parameters insertDescriptor:firstParameter atIndex:1];
[parameters insertDescriptor:secondParameter atIndex:2];
[parameters insertDescriptor:thirdParameter atIndex:3];
// Create the AppleEvent target
ProcessSerialNumber psn = {0, kCurrentProcess};
NSAppleEventDescriptor* target = [NSAppleEventDescriptor
descriptorWithDescriptorType:typeProcessSerialNumber
bytes:&psn length:sizeof(ProcessSerialNumber)];
// We need these constants from the Carbon OpenScripting
// framework, but we don't actually need Carbon.framework.
#define kASAppleScriptSuite 'ascr'
#define kASSubroutineEvent 'psbr'
#define keyASSubroutineName 'snam'
// Create an NSAppleEventDescriptor with the script's method name to call,
// this is used for the script statement: "on set_preferences(arg1,arg2arg3)"
// Note that the routine name must be in lower case.
NSAppleEventDescriptor* handler =
[NSAppleEventDescriptor descriptorWithString:
[#"set_preferences" lowercaseString]];
// Create the event for an AppleScript subroutine,
// set the method name and the list of parameters
NSAppleEventDescriptor* event =
[NSAppleEventDescriptor appleEventWithEventClass:kASAppleScriptSuite
eventID:kASSubroutineEvent
targetDescriptor:target
returnID:kAutoGenerateReturnID
transactionID:kAnyTransactionID];
[event setParamDescriptor:handler forKeyword:keyASSubroutineName];
[event setParamDescriptor:parameters forKeyword:keyDirectObject];
// call the event in AppleScript
if (![appleScript executeAppleEvent:event error:&errors])
{
// report any errors from 'errors'
NSLog(#"Errors %#",[errors description]);
}
[appleScript release];
}
else{
// report any errors from 'errors'
NSLog(#"Error: applescript is nil");
}
}else{
NSLog(#"Could not locate the time_date_preferences script");
return NO;
}
}else{
NSLog(#"Could not locate the time_date_preferences script");
return NO;
}
return YES;
}
The Script:
on set_preferences(ipaddress, chkbox, timezone)
global timezonelist
do shell script "/usr/sbin/systemsetup -setusingnetworktime " & chkbox password "passwordhere" with administrator privileges
do shell script "/usr/sbin/systemsetup -setnetworktimeserver " & ipaddress with administrator privileges
set timezonelist to (do shell script "/usr/sbin/systemsetup -listtimezones" with administrator privileges)
if timezonelist contains timezone then
do shell script "/usr/sbin/systemsetup -settimezone " & timezone with administrator privileges
else
display notification "Please open Date and Time Preferences and set your time zone manually." with title ("Invalid Time Zone")
delay 1
end if
end set_preferences

Objective C - Restore an external running application from minimize to normal

So I have code like this:
- (void)sendAnswerXlite:(NSDictionary*)softPhone
{
__block NSString * identifier = [softPhone objectForKey:kSoftPhoneAppIdentifier];
NSAssert(identifier != nil, #"Nil identifier argument in answer input");
dispatch_async(dispatch_get_menu_hotkey_queue(), ^{
// check if app is running
NSArray * apps = [NSRunningApplication runningApplicationsWithBundleIdentifier:identifier];
if (apps != nil && [apps count] > 0)
{
NSRunningApplication * frontmostApp = [[NSWorkspace sharedWorkspace] frontmostApplication];
NSRunningApplication * runningApp = [apps objectAtIndex:0];
if ( !([runningApp isEqualTo:frontmostApp]) )
{
[runningApp activateWithOptions:NSApplicationActivateAllWindows];
//[runningApp activateIgnoringOtherApps:YES];
[NSThread sleepForTimeInterval:1];
}
}
}
But even if I use activateWithOptions or activateIgnoringOtherApps, it will only set focus to the external application, but if application was already minimized then it will not show the window X-Lite but the menu bar will show (in this case)X-Lite. The identifier is just the bundle identifier of the application.

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