Get MainMenu of other Running Application other then the Main Application - objective-c

I know the question is kinda confusing, but let me explain...
I want to be able to get the Menu Item Titles of all running applications, not just the main application. I know how to get the main application menu items by using the code below:
NSMenu *mainMenu = [[NSApplication sharedApplication] mainMenu];
for (NSMenuItem *item in [mainMenu itemArray]){
NSLog(#"%#", [item title]);
}
And I also know how to get a list of all running applications using the code below:
[[NSWorkspace sharedWorkspace] runningApplications]
Now I want to be able to be able to get the mainMenu of a certain application in the sharedWorkspace.
Is this possible.. If so, please share :) Thanks!

You need to use the Accessibility API to get access to other application's GUI elements. Keep in mind that you (or your app's customers) will need to turn on the "Enable access for assistive devices" in the Universal Access system preference.
To get started see The Accessibility Hierarchy.

Related

NSApplication mainMenu returns nil

the problem I'm having is I cannot add a menu to my app programmatically!
here's where I'm at:
in app delegate
applicationDidFinishLaunching:
create a window and make key and order front.
EDIT:( here if I log [NSApplication sharedApplication].mainMenu prints (null) ) anyway...
create a NSMenu object and [[NSApplication sharedApplication] setMainMenu:myMenu]
also tried [[NSApplication sharedApplication] setMenu:myMenu]
build/run
menu is not there!
EDIT2:
( if still not understanding: )
make a osx app, remove the menu object, run, you'll still see a menu up there with the name of your app, you click it, it turns blue but no submenus, now how do I get a pointer to that!
You won't be able to do this as the OSX menus conform to the Aqua layout. Is there any reason why you'd remove it completely?
It's probably going to be a nightmare for a few reasons:
1) In the standard 'Aqua Menu' you have menu's like 'Services' which are handled by the system and not by the Application.
2) Apple are specific about their design guides, and menu's aren't mentioned and I'd HIGHLY doubt it apple would like you changing the Aqua layout.
I remember once upon a time coming upon a discussion which mentioned setAppleMenu etc... but that was back in the Tiger (I think) days.
edit you won't be able to get a 'pointer; to it using Documented API's, it's system-driven, not application driven i.e. complying with Aqua.
Personally, I'd remove all of the menuItems which can be changed in a sandboxed app, i.e. in User Land, and add/remove the various menuItems yourself.

Cocoa window dragging

I'm using addGlobalMonitorForEventsMatchingMask to listen to events in Cocoa:
[NSEvent addGlobalMonitorForEventsMatchingMask:NSLeftMouseDraggedMask
handler:^(NSEvent *event) {
NSLog(#"Dragged...");
}];
Though I would like to know if I'm dragging/moving a window (and which window that is, I can find the focused window though when holding command and dragging a window it doesn't get focus as far as I know.)
So, can I detect whether or not I'm dragging a window?
Update:
I now have a class: "SATest : NSObject <NSWindowDelegate>" in which I implement the windowDidMove method (and later perhaps windowWillMove too.) Though, now the next step would be attaching this to a window, right? So my question now is: How do I attach the delegate to all windows of all apps?
Update 2:
I now can find a list of all open windows on the screen:
AXUIElementRef _systemWideElement;
_systemWideElement = AXUIElementCreateSystemWide();
CFArrayRef _windows;
AXUIElementCopyAttributeValues(_systemWideElement, kAXWindowsAttribute, 0, 100, &_windows);
Now I have to iterate over the windows, and of each get it's NSWindow so I can add my delegate to it: [window setDelegate:self];
Update 3: To be clear, this question is about detecting the dragging of ALL windows of ALL apps. Not only the windows of my own app.
Also, I'm very new to this event and window management stuff, so no need to keep your answer short I'm happy to read a lot :P
Thanks!
-P
To find out if a window is being dragged you need to have an object that acts as the delegate of the window by responding to the following messages of the NSWindowDelegate protocol:
windowWillMove - this tells the delegate that the window is about to move.
windowDidMove - this tells the delegate that the window has moved.
You can retrieve the NSWindow object in question by sending object to the notification parameter sent to these methods:
e.g.
NSWindow draggedWindow = [notification object];
More information can be found here.
Update:
In response to your request about getting this information for all windows the NSApplication class provides a method which returns an array of all windows owned by the application. The typical way of getting this information is to use one of the NSApplicationDelegate methods to get a reference to your application object.
For example, in your app delegate (pseudocode):
- (void)applicationDidFinishLaunching:(NSNotification *)aNotification
{
NSApplication * app = [aNotification object];
// you now have a reference to your application.
// and can iterate over the collection of windows and call
// [window setDelegate:self]; for each window.
}
Note that you will need to add / remove you delegates as windows are added and removed. The best method for doing this is – applicationDidUpdate:.
This should be enough to get you started solving your problem.
As suggested by Benjamin the answer lies in the accessibility API. I was looking around in this for a while, even before I asked this question, but never got it to do what I wanted. I now have found a pretty nice solution.
At a high-level I do the following:
Listen to the mouse down event and remember both on which window you clicked and it's location.
Listen to the mouse up event and check if the location has changed, if so you know you moved a window
You can do something similar for the size if you also want to know if you resized. There might be a better solution, but after days of trying stuff this is the only way I got it to work the way I wanted.
Hope this helps anyone who was looking for something similar.
-Pablo

How to add the iOS "Open In..." feature to an app

I would like to know how to present the "Open In..." Action Sheet (iPhone) / Popover (iPad) from my app, preferably an IBAction
I would hope that it'd be similar to declaring a file type then creating the view and opening the app selected by the user, but I know it is more complicated then that.
I realize that a similar question has been asked on StackOverflow, but I cannot make sense of the answer that was accepted: How to use "open in..." feature to iOS app?, and I have found some Apple Documentation on Document Interaction Programming. But, I can't really make sense of these.
Create a UIDocumentInteractionController by using the interactionControllerWithURL: class method (pass the URL of the file you want to open in another app).
Then call either presentOpenInMenuFromRect:inView:animated: or presentOpenInMenuFromBarButtonItem:animated:. The controller takes care of presenting the popover with available apps for that file type and opening the selected app.
If you want to know when the menu was dismissed and which app was selected, you need to implement the UIDocumentInteractionControllerDelegate protocol.
omz makes some good points on how to do that in his answer, however this procedure is much easier with the introduction of new APIs in iOS 6. Here's a simple and efficient way to show the UIActionSheet Open-In-Menu in iOS 6 and up:
NSArray *dataToShare = #[contentData]; //Or whatever data you want to share - does not need to be an NSArray
UIActivityViewController *activityViewController = [[UIActivityViewController alloc] initWithActivityItems:dataToShare applicationActivities:nil];
[self presentViewController:activityViewController animated:YES completion:nil];
Also, if your app is compatible with versions of iOS lower than 6.0 you may want to check if the Share Service exists:
if ([UIActivityViewController class])
Once you present the sheet, iOS will automatically handle the rest for you. It will display a beautiful uiactionsheet with icons showing each app or service the user can open / share your data with:
Note that depending on the contents of the data, iOS will show different services in the Share Sheet
EDIT: The method above shares the file content, but not the file itself. Refer to omz's answer for more on that.
I've personally never had to do this, but your answer can most certainly be found in this Apple Documentation: http://developer.apple.com/library/ios/#documentation/FileManagement/Conceptual/DocumentInteraction_TopicsForIOS/Articles/PreviewingandOpeningItems.html#//apple_ref/doc/uid/TP40010410-SW1.

prevent windows from opening (windowless application)

I want to make a windowless application. The problem is that I'm using a framework that shows some alert boxes sometimes, and I'm not able to suppress them (at least not without a crash).
I've set LSBackgroundOnly to 1 (in the info.plist app file), but this doesn't seem to work. Any chance I'm missing something here (maybe some other settings that I need to set)?
I've also tried creating a category for NSWindow:
Overwritten alloc and allocWithZone: so that no window gets created. This works on some situations, but starting a modal session throws exception (because sending a nil parameter to beginModalSessionForWindow:).
Tried overwriting NSApplication's beginModalSessionForWindow: and returned nil everytime, but this leads to EXC_BADACCESS somewhere in the framework (runModalSession: and endModalSession: were also overwritten, but the crash is before any of them being called).
Any other ideas will be welcome.
In case it helps, the framework that I'm using is Twain.Framework, so if instead anyone knows a way to block all UI from twain (this includes error alerts shown when a device is not connected) it would be great if you share.
It's not clear what you're hoping for. Are you hoping for an app that doesn't normally display windows but does allow the third-party framework to show its alerts? Or are you hoping to find a way to prevent the framework from showing its alerts so your app absolutely never has any windows?
If it's the former, you're probably looking for LSUIElement. That's an app which can have some UI elements, but doesn't show in the Dock or the Command-Tab application switcher and doesn't have a menu bar.
I managed to make it 'windowless' (some windows are still shown, but at least they're not visible, and they're automatically closed). I only handled modal windows, since these where shown in my situation.
I made a category for NSWindow, so that all windows are invisible, and can't become key or main windows:
-(BOOL)canBecomeKeyWindow{
[self setOpaque:NO];
self.alphaValue = 0;
return NO;
}
-(BOOL)canBecomeMainWindow{
[self setOpaque:NO];
self.alphaValue = 0;
return NO;
}
Subclassed NSApplication:
-(NSInteger)runModalForWindow:(NSWindow *)aWindow{
return NSCancelButton;
}
-(NSModalSession)beginModalSessionForWindow:(NSWindow *)aWindow{
NSModalSession session = [super beginModalSessionForWindow:aWindow];
[aWindow performSelector:#selector(close) withObject:nil afterDelay:1];
return session;
}
However, this didn't help much. In case of runModalForWindow: everything was good, since the owner of the window received a response. In case of beginModalSessionForWindow: the application got stuck, most probably because the window's owner was waiting for a specific event (e.g. button click) which it never received.

NSStatusItem to be always left?

I'm working on an app that displays certain information on the status menu, and I was wondering if there's any Cocoa API that can make my NSStatusItem always placed on the most-left, no matter when it's started or if other apps are started after it.
NSStatusBar *bar = [NSStatusBar systemStatusBar];
barItem = [[bar statusItemWithLength:NSVariableStatusItemLength] retain];
Thanks.
Taking you ultra-literally for a moment, what if two applications used such an API? They would fight and roll off the end of the menu bar. ☺
There is no supported way to do it, but there is an undocumented/unsupported way to specify the “priority” of the status item when you create it. Of course, use at your own risk, and be sure to do a respondsToSelector: check to fall back on the supported way if the unsupported way goes away.