Calling App Expose In Lion - objective-c

Is there any way to call App Expose in Lion programmatically, for example on an event tap, etc?

If you don't mind using a TOTALLY UNDOCUMENTED API, which might change at any point without notice:
void CoreDockSendNotification(CFStringRef, void *);
(...)
CoreDockSendNotification(#"com.apple.expose.front.awake", NULL);
Other known arguments are #"com.apple.expose.awake" and #"com.apple.dashboard.awake", which activate Mission Control and Dashboard, respectively. #"com.apple.showdesktop.awake" used to activate Show Desktop, but no longer works on current versions of macOS.
Note that most applications should not use these calls -- these actions are intended to be invoked directly by the user.

Expose does not exist in Lion, it has been merged with Spaces into the Mission Control application.
You can launch Mission Control:
[[NSWorkspace sharedWorkspace] launchApplication:#"Mission Control"];

Related

Is it OK to have Mac OS X application without an NSApplication instance?

In the Info.plist, I have one key "Application is background only" and its value is "Yes".
Most of the code is in C++.
The usual last line
return NSApplicationMain(argc, argv);
in main() is removed. Instead main starts some thread(s), blocks and waits on some condition to exit.
Yes and no.
You can have a process (colloquially an application) without it, and it will work just fine with the Unix side of things, and behave just like any other headless process.
What you cannot have is an Application in the sense of a full-fledged Cocoa Application, because an instance of NSApplication (or a subclass) isn't just a part of your application, in a very real sense the main application object is the application. Things like reading the Info.plist, hooking into the Cocoa Application System, Applescript System, and so on is all done by NSApplicationMain(), making it a requirement of a capital-A Application.
It is possible you could set some of these things up yourself, but I don't know of any ways to do so, and even if I did, I would not recommend it. If you want your program to behave like an application and interact with the Cocoa side of things, return NSApplicationMain(argc, argv); is the wait to end main() .
Yes it is OK. NSApplication is declared in AppKit so it is used only in GUI apps. An app can use Foundation, which does not require NSApplication.

Controlling level and focus of windows other apps with CGPrivate functions

Question
How to use these private functions on other windows? It would be nice to have this knowledge back in the wild. I am specifically trying to get CGSOrderWindow and CGSSetWindowLevel to work.
I was trying in the direction of:
temporarily register as the dock and then register the dock as the dock again immediately afterwards
or
code injection into the Dock process per this comment:
Also, the author of the above project seems determined to make all core functionality available as a framework. It seems to be implemented as code injection into the Dock process.
Reason I know this is possible
I have been doing work on trying to setLevel on window of another app, and focus window of another app if focused. I am posting this again with the info I learned because from my searching online, I know this was done in the past, its just the knowledge is not publicly out there anymore. The sourceforge pages are no longer there. So I was wondering if you could help me make this information public again.
This is the topic I read that gave me this information - http://cocoadev.com/HowtoControlOtherAppsWindows
Here you see comments like:
You cannot control an another app's windows from a user-level process, unfortunately.
SlavaKarpenko
You can, Slava, you just need to register as the Dock. It might be possible to temporarily register as the dock and then register the dock as the dock again immediately afterwards, not sure. I think the call you'd be wanting to investigate as CoreDockRegisterDockOwner in HIServices.framework.
FinlayDobbie
You could also use APE or similar to do control the windows, or (as mentioned above) register as the Dock (look for the private APIs with Universal Connection in their name). Has anyone found a polite way of getting the Dock to give up its universal connection? The only way I can find is to force quit the Dock and grab the universal connection when it's not looking (which prevents the dock reloading).
SamTaylor
There's an open source project up on sourceforge.net that looks much more like the window managers I've used on Unix boxes than Space.app (or Space.dock): http://wsmanager.sourceforge.net/
SteveCook
Verifying things work
This is what I learned, from the sources at bottom of this post, we see all these functions work with CGWindowIds, so how do I get that, this is how:
Get all windows with CGWindowListCopyWindowInfo. Then access each element from that array with CFArrayGetValueAtIndex and then get the CGWindowId with objectForKey:, kCGWindowNumber, and then integerValue.
Now if I try to focus or set level of a window that is OWNED by the app running the code, it works fantastic. For instance:
MY_TARGET_CGWINDOW_ID = 179;
rez_CGError = CGSOrderWindow(_CGSDefaultConnection, MY_TARGET_CGWINDOW_ID, kCGSOrderAbove, 0);
Will focus it, rez_CGError is 0. Even if the window is minimized, it is unminimized, without animation, and shown.
Now however, if I try this on a window of a different app we get some errors:
MY_TARGET_CGWINDOW_ID_of_other_app = 40;
rez_CGError = CGSOrderWindow(_CGSDefaultConnection, MY_TARGET_CGWINDOW_ID_of_other_app, kCGSOrderAbove, 0);
This fails and rez_CGError is 1000, which I suspect means "cid (CGSConnection) used does not have permission to modify target window". The same happens if I first do [app activateWithOptions: (NSApplicationActivateIgnoringOtherApps | NSApplicationActivateAllWindows)] before making the call above.
So I first get the cid of that owning window like this:
var rez_CGError = CGSGetWindowOwner(_CGSDefaultConnection, MY_TARGET_CGWINDOW_ID_of_other_app, &ownerCid);
This works good and I get ownerCid is set to a value. Then I do the focus command with this new connection:
rez_CGError = CGSOrderWindow(ownerCid, MY_TARGET_CGWINDOW_ID_of_other_app, kCGSOrderAbove, 0);
However this gives rez_CGError of 268435459, which I suspect means "current app does not have permission to use this ConnectionId (cid)". (Same happens if I call activateWithOptions first.
My Sources for the Private Functions
Here is the sources for some private functions I found - https://code.google.com/p/undocumented-goodness/source/browse/trunk/CoreGraphics/CGSPrivate.h
This one source here contains a function that is not in the above link - CGSGetConnectionIDForPSN - i test it and it exists - from - https://github.com/mnutt/libqxt/blob/767498816dfa1742a6f3aee787281745afec11b8/src/gui/qxtwindowsystem_mac.h#L80

Objective C - "Reset Content and Settings" programmatically in test files

I am playing around with the new UI testing introduced in Xcode 7 beta. In one of my UI testing scenarios, I need to add some code that does the same thing as clicking Simulator -> Reset Content and Settings in the setup() of my test file, which is a XCTestCase. Can the reset be done programmatically? Or, can we mimic the effect of a factory reset on an app in test code?
Not entirely programmatically, but you can always write a bash file to delete:
${user.home}/Library/Application Support/iPhone Simulator/${simulator.version}
That will clear the settings on the simulator.
My understanding is that you won't be able to that from within your app, as apps are sandboxed.
Usually people were using shell scripts or apple scripts. However, using hard reset is absolutely not necessary.
You shouldn't care about data in other apps, you should care only about the data in your app. You can always delete your app data (files, user defaults) in the beginning of your tests. So, why should you do a hard reset?
A better solution is mocking. If your test supposes that, for example, some variable in NSUserDefaults is not set, you don't have to care about the actual value stored there, just mock the method your implementation is using (e.g. objectForKey: and let it return nil.

AIR application Mouse.hide() not working

I created a fullscreen app with the following to hide the mouse...
// need this hack to hide the mouse for AIR for some reason...for OSX
// http://blog.formatlos.de/2008/11/16/air-hiding-the-mouse/
stage.nativeWindow.activate();
stage.nativeWindow.orderToBack();
stage.nativeWindow.orderToFront();
Mouse.hide();
This works on my machine at home running OSX Lion...but when this is installed on the client's machine (also running OSX...I need to find out the version), the mouse does not hide?
When I take out the 3 line hack before the Mouse.hide(), the mouse does not hide on my machine. Will test this out on the client's machine too.
Anyone experience this before?
Are you including flash.ui.Mouse in your code?
import flash.ui.Mouse;
Take a look in this site: http://samhassan.co.uk/2008/10/08/air-10-mousehide-work-around/
You could try to hide mouse cursor when the first enterFrame event is fired. Some elements are not fully available till the first frame is build:
// i.e. on main app initilize event handler
addEventListener(Event.ENTER_FRAME, onEnterFrame);
private function onEnterFrame(event:Event):void {
Mouse.hide();
removeEventListener(Event.ENTER_FRAME, onEnterFrame);
}
This way, you have not to rely on hacks or workarounds.

Register a global hotkey without support for assistive devices enabled

Using this code, I may register a global event handler:
[NSEvent addGlobalMonitorForEventsMatchingMask: NSKeyDownMask
handler: ^(NSEvent *incomingEvent) {
NSString *chars = [[incomingEvent characters] lowercaseString];
unichar character = [chars characterAtIndex:0];
// do something useful
NSLog(#"keydown globally! Which key? This key: %c", character);
}];
Unfortunately, events get passed along to this monitor, if support for assistive devices is enabled. Without assistive devices being enabled, no events get passed along.
Form the documentation:
Key-related events may only be monitored if accessibility is enabled or if your
application is trusted for accessibility access (see AXIsProcessTrusted).
I wonder, if another method exists, which passes along events without forcing the user to enable specific features of OS X.
While I didn't find a solution in Apple's docs, a solution must exist. E.g. the MAS-downloaded version of Alfred allows to define a hotkey.
Interestingly, Alfred's preferences only shows special keys and points out, that certain special key combinations may not work.
Since I basically want to show / hide a 'global' non-activating panel, I probably should simply prepare a system service. Should I?
You could try creating a Quartz Event Tap, with kCGSessionEventTap as the location.
Quartz Event Services Reference
Sample code from Mac OS X Internals