Cocoa Button Launch outside Application - objective-c

I have the following setup:
A grid of 4x4 (16 total) buttons (standard NSButton buttons) in an NSWindow.
The NSWindow will come to the front when I press a hotkey combination (DDHotKey)
Now, what I'd like to do is give my buttons the following functionality:
When the button is clicked, open a dialog that shows the /Applications/ directory and allow me to select any of the applications listed there.
When the application is selected store it in a variable (I'm guessing) (or string?) and make it so that when the buttons Key Equivalent is pressed, that application launches
I'm looking around and I'm not exactly sure what to do or really where to begin looking...any clues?
I have this in my appdelegate.m file:
- (void)openDoc:(id)sender
{
int result;
NSArray *fileTypes = [NSArray arrayWithObject:#"td"];
NSOpenPanel *oPanel = [NSOpenPanel openPanel];
[oPanel setAllowsMultipleSelection:YES];
result = [oPanel runModalForDirectory:NSHomeDirectory()
file:nil types:fileTypes];
if (result == NSOKButton) {
NSArray *filesToOpen = [oPanel filenames];
int i, count = [filesToOpen count];
for (i=0; i<count; i++) {
NSString *aFile = [filesToOpen objectAtIndex:i];
id currentDoc = [[ToDoDoc alloc] initWithFile:aFile];
}
}
}
How do I link the button to it?

You can use an NSOpenPanel to choose the application.
Then to launch the application, take a look at this stack overflow question.

store the path to application, then when you want to open them. You can use the system() function.
system("open -a /Applications/someApplication.app");

Related

How to set an external application always being frontmost on OS X?

I am trying to launch the built-in calculator.app on my Mac(which means it is external to my application) within my application and force the calculator to stay frontmost permanently on screen.
Here is my process. Firstly, I launch the calculator and place it frontmost temporarily.
if ([[NSWorkspace sharedWorkspace] respondsToSelector:#selector(launchApplicationAtURL:options:configuration:error:)])
[[NSWorkspace sharedWorkspace] launchApplicationAtURL:[NSURL fileURLWithPath:#"/Applications/Calculator.app/Contents/MacOS/Calculator" isDirectory:NO]
options:NSWorkspaceLaunchDefault
configuration:nil
error:NULL];
After that, I recognize the Calculator by it's owner name and try to pin Calculator.app frontmost. I was stuck here. What I would like to do is either these two ways:
1.Set an attribute to place it always frontmost. (Can't find suitable
attribute, only found attributes to resize or position)
2.Get the NSWindow of Calculator and set the level to frontmost. (Seems to be non-viable: How to convert a Carbon AXUIElementRef to Cocoa NSWindow)
But seems that both of them are not available.
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly | kCGWindowListExcludeDesktopElements, kCGNullWindowID);
NSArray *arr = CFBridgingRelease(windowList);
for (NSMutableDictionary *entry in arr){
NSString *ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
if([ownerName isEqualToString:#"Calculator"]){
pid_t pid = [[entry objectForKey:(id)kCGWindowOwnerPID] intValue];
AXUIElementRef appRef = AXUIElementCreateApplication(pid);
CFArrayRef windowList;
AXUIElementCopyAttributeValue(appRef, kAXWindowsAttribute, (CFTypeRef *)&windowList);
AXUIElementRef windowRef = (AXUIElementRef) CFArrayGetValueAtIndex( windowList, 0);
CFTypeRef role;
AXUIElementCopyAttributeValue(windowRef, kAXRoleAttribute, (CFTypeRef *)&role);
/*Would like to get the window of the application or assign some attribute to set Calculator frontmost*/
}
Are there any ways to achieve the two aspects I've mentioned above? Or are there any suggestions for setting an external application always being frontmost?

Which framework do I need to import for using NSOpenPanel class in Objective-C?

I want to Open File Dialog in my application to upload a particular selected file onto the server in Objective-C. I am using the following code in my application, but it seems to give an error while creating an object of NSOpenPanel.
Please help me out.
NSOpenPanel *openPanel = [NSOpenPanel openPanel];
openPanel.title = #"Choose a .TXT file";
openPanel.showsResizeIndicator = YES;
openPanel.showsHiddenFiles = NO;
openPanel.canChooseDirectories = NO;
openPanel.canCreateDirectories = YES;
openPanel.allowsMultipleSelection = NO;
openPanel.allowedFileTypes = #[#"txt", #"jpg", #"jpeg", #"zip", #"png"];
[openPanel beginSheetModalForWindow:appDelegate.controlsWindow
completionHandler:^(NSInteger result) {
if (result==NSOKButton) {
NSURL *selection = openPanel.URLs[0];
NSString* path = [selection.path stringByResolvingSymlinksInPath];
//do something with the file at "path"
}
}];
NSOpenPanel doesn't exist on iOS. The whole concept of files is pretty well hidden from users in most cases. What's the end goal here? What kind of "files" do you want to upload to a server?
UIKit has the UIImagePickerController, which you can use to select images from the Photo Library, for instance.

Getting filename from NSOpenPanel dialog

It's been a year since I last played with Cocoa and it seems a lot has changed.
I am trying to run an open dialog and retrieve the file path. This used to be very simple but now...
The code is:
-(NSString *)getFileName{
NSOpenPanel* panel = [NSOpenPanel openPanel];
__block NSString *returnedFileName;
// This method displays the panel and returns immediately.
// The completion handler is called when the user selects an
// item or cancels the panel.
[panel beginWithCompletionHandler:^(NSInteger result){
if (result == NSFileHandlingPanelOKButton) {
NSURL* theDoc = [[panel URLs] objectAtIndex:0];
// Open the document.
returnedFileName = [theDoc absoluteString];
}
}];
return returnedFileName;
}
-(IBAction)openAFile:(id)sender{
NSLog(#"openFile Pressed");
NSString* fileName = [self getFileName];
NSLog(#"The file is: %#", fileName);
}
(The indentation has been screwed up in the post but it's correct in the code)
My problem is that the final NSLog statement is being executed as soon as the open dialog opens and not waiting until the dialog closes. That leaves the fileName variable null which is what the final NSLog reports.
What is causing this?
Thanks.
There is a similar question to yours:
How do I make my program wait for NSOpenPanel to close?
Maybe
[openPanel runModal]
helps you. It waits until the user closes the panel
The stuff I had written a year ago used runModal so on Christoph's advice I went back to that.
It would appear that the beginWithCompletionHandler block is unnecessary, at least in this case. Removing it also had the advantage of removing the necessity to use the __block identifier.
The following now works as required
-(NSString *)getFileName{
NSOpenPanel* panel = [NSOpenPanel openPanel];
NSString *returnedFileName;
// This method displays the panel and returns immediately.
// The completion handler is called when the user selects an
// item or cancels the panel.
if ([panel runModal] == NSModalResponseOK) {
NSURL* theDoc = [[panel URLs] objectAtIndex:0];
// Open the document.
returnedFileName = [theDoc absoluteString];
}
return returnedFileName;
}
And well done Apple for deprecating the obvious and easy and replacing it with increased complexity.

NSWindow hide active window and focus on other

How to hide the active current NSWindow A and focus on the last other one B (one level behind the current window) and make it active?
I'm trying with this followed code but it does not work (B will become to front window but not active):
[_parentWindow orderBack:nil];
// Now i want to do some stuffs with last opened App (NSWindow) and it should be focused and activated now.
[_parentWindow orderFront:nil];
Try makeKeyAndOrderFront: instead.
[_window makeKeyAndOrderFront:nil];
Supplement to #bluedome response. You can get information about windows in the current user session:
CFArrayRef windowList = CGWindowListCopyWindowInfo(kCGWindowListOptionOnScreenOnly, kCGNullWindowID);
for (NSDictionary* entry in (__bridge NSArray *)windowList) {
NSString *ownerName = [entry objectForKey:(id)kCGWindowOwnerName];
NSInteger ownerPID = [[entry objectForKey:(id)kCGWindowOwnerPID] integerValue];
NSString *windowName = [entry objectForKey:(id)kCGWindowName];
NSLog(#"%#:%ld, %#", ownerName, (long)ownerPID, windowName);
}

CGWindowListCreate generates a hugely long list of windows

When I use CGWindowListCreate from quartz window services, it generates a very long array of window id's. I tried to turn on the option to exclude desktop elements, but I get a list of 30-40 windows even if there are only 3 or 4 of what I would call windows open.
Here is how I am doing it:
CGWindowListOption opt = 1 << 4;
CFArrayRef windowids =CGWindowListCreate(opt,kCGNullWindowID);
I am wondering what I am doing wrong that is causing this problem, and what I can do to fix it. I simply want the program to list windows created by applications, such as finder windows or browser windows, and not whatever else it is including. Thank you in advance for your help.
This will return every window whether it is on screen or off screen, you should combine it with the option kCGWindowListOptionOnScreenOnly (and also don't hardcode the one you are using). It will look like this:
CGWindowListOption opt = kCGWindowListOptionOnScreenOnly|kCGWindowListExcludeDesktopElements;
CFArrayRef windowids =CGWindowListCreate(opt,kCGNullWindowID);
That is what I gathered from the docs anyway.
I discovered a solution is to filter the window list to only those windows "below" the Dock (in terms of window layering).
The code below worked well for me. It fetches all on screen windows (excluding desktop elements). It extracts the window ID for the "Dock" window out of the list. Then fetches on screen windows again, filtering to only those windows "below" the Dock window.
// Fetch all on screen windows
CFArrayRef windowListArray = CGWindowListCreate(kCGWindowListOptionOnScreenOnly|kCGWindowListExcludeDesktopElements, kCGNullWindowID);
NSArray *windows = CFBridgingRelease(CGWindowListCreateDescriptionFromArray(windowListArray));
NSLog(#"All on screen windows: %#", windows);
// Find window ID of "Dock" window
NSNumber *dockWindowNumber = nil;
for (NSDictionary *window in windows) {
if ([(NSString *)window[(__bridge NSString *)kCGWindowName] isEqualToString:#"Dock"]) {
dockWindowNumber = window[(__bridge NSString *)kCGWindowNumber];
break;
}
}
NSLog(#"dockWindowNumber: %#", dockWindowNumber);
CFRelease(windowListArray);
if (dockWindowNumber) {
// Fetch on screen windows again, filtering to those "below" the Dock window
// This filters out all but the "standard" application windows
windowListArray = CGWindowListCreate(kCGWindowListOptionOnScreenBelowWindow|kCGWindowListExcludeDesktopElements, [dockWindowNumber unsignedIntValue]);
NSArray *windows = CFBridgingRelease(CGWindowListCreateDescriptionFromArray(windowListArray));
NSLog(#"On screen application windows: %#", windows);
}
else {
NSLog(#"Could not find Dock window description");
}