How to wait for a Mac OS X application to fully activate - macos

My application is a debugger and I need to frequently switch the active process between a target application and my debugger application as the user steps from one line to another within their code. I am currently using the SetFrontProcessWithOptions(…, kSetFrontProcessFrontWindowOnly) call to accomplish this.
The problem I have is that the SetFrontProcessWithOptions() call returns before the application is fully activated. SetFrontProcessWithOptions() returns when the process becomes the active process, but before its main window has been brought forward and made active. If I call SetFrontProcess again too quickly to reactivate my debugger application, Mac OS X gets confused and the layering of windows becomes muddled. Visually, the wrong window appears to be active and keyboard and menu focus is directed to what appears to be an inactive window.
I have tried using GetFrontProcess() after calling SetFrontProcessWithOptions() to poll, but GetFrontProcess() immediately returns the PSN that my code has activated with SetFrontProcessWithOptions() even though that process's windows are not yet fully activated.
Does anyone know of a way to determine when an application has become fully active with its main window ready to receive keyboard input?

Related

How to automatically restore focus to a launched application on Windows

I have developed a full-screen application that hooks into and launched by a 3rd party/client application. The problem is that the client application gets focus soon after it launches my application, with the result that although my application is full screen, and set to be on top, it does not receive keyboard input, as such the user has to click on it to bring it to focus, which makes for a poor user experience.
How can I restore focus to my application after the client acquires it?
If it matters, my application is written in C++ and has a QT UI.
Not quite the answer but the reason why my application does not have input focus. I'll let Charles Petzold explain (from Programming Windows 5ed, pg 213)
The Window that receives a particular keyboard event is the window that has input focus. The concept of input focus is closely related to the concept of the active window. The window with the input focus is either the active window or a descendant window of the active window -- that is , a child of the active window, or a child of a child of the active window, and so forth.
My Qt application is not spawned spawned by an active window and therefore does not have input focus. The solution therefore would be to parent my application to the active window. Unfortunately this is not straightforward in Qt, if at all possible.
Here is the Qt documentation:
http://doc.qt.io/qt-4.8/qwidget.html#activateWindow
http://doc.qt.io/qt-4.8/qwidget.html#raise
http://doc.qt.io/qt-4.8/qwidget.html#setFocus
Hope it helps when called after launch...

NSWindow and Fullscreen

I am implementing a Cocoa application which supports the fullscreen mode. If the user quits while working on the fullscreen mode, I need to start the application in fullscreen mode,
While starting the application I check whether the application should start in fullscreen mode then call the toggleFullScreen: on NSWindow. Then the, application goes to the fullscreen mode and comes back to the normal window mode.
User can go to the full screen mode while working without any problem. Any tips on what's going wrong on this?
Make sure you really want to do this. Since Lion, there is a window restoration API that you should be using. See Any NSWindowRestoration examples? for how to use it. The caveat is that if "Close windows when quitting an application" in System Preferences is checked (which it is checked by default since 10.8), the window can only be restored upon reboot if the user chooses to do so.
If the user did not opt in for the window restoration setting throughout the OS across quitting applications, then generally you do not have to expect the window of your app to be restored for them. However, if you think you have a good reason otherwise, then I suggest invoking toggleFullScreen: after windowDidLoad: is called. I can only guess that you're calling it too soon and the window autosave might get in the way. It'd be helpful if you showed the relevant code.
Regardless, you should be implementing window restoration anyway and in the case of the window being restored by the API, you simply don't do anything.

How to force windows to appear when pressing Ctrl-Tab, even though app is agent

I have a Cocoa application which I am running as an agent because it has a status bar component. When my application brings up a window, these windows don't appear in the list when I press Ctrl-Tab to cycle through applications.
Is there a way to force a window in my application to appear?
Not while it's an agent, because it can never become the active application. Agents are meant to have only minimal user interaction, so it's assumed that you won't have an agent window around long enough for the user to need to command-tab away from it. (I personally find this annoying, because I'm constantly losing crash report windows behind application windows for the same reason, but it does make sense.)
However, the app doesn't have to be running as an agent in order for the status bar item to work, so I would just set the LSUIElement flag to NO and be done with it. It can be a regular, non-agent app that just happens to instantiate a status bar item.
If you don't want the application to be able to become active except when a window is visible, then that's more involved. You'd probably need to separate the application and the agent into separate processes, and have the agent launch the application in order to display the window. Then make sure the application quits when the window is closed, leaving just the agent running. Arq (http://www.haystacksoftware.com/arq/) is one example of an app/agent pair that works this way, with perhaps a clearer distinction between the agent and the app than you're after.

What happens 'behind' the windows lock screen?

I have been working on windows automation and monitoring.
What exactly happens when I lock the screen of a windows machine?
I am working with Windows 7 at the moment, are there big differences to the behavior if I switch to Vista or the server versions?
Is there still a desktop that can be accessed via api's?
I know that i can still send key strokes and mouse clicks to specific windows (via ControlSend and ControlClick), but there seems to be no "desktop" itself.
Could someone shed some light on this whole thing or point me at a readable source where I could get an overview over the topic?
Basically what happens is that Windows switches to the secure desktop, makes it the current one, so input is now associated with it.
The old desktop remains where it was: all the HWNDs on the desktop are still there, and any thread attached to that desktop can still access those HWNDs, get their location, and so on. You can still send messages to windows on this desktop, so long as the thread sending the message is also on that desktop.
However, since the desktop is now inactive, it cannot receive input. GetForegroundWindow will return NULL (IIRC), and you can't use SendInput any longer, since input now belongs to [a thread on] a different desktop; no controls on that inactive desktop can receive focus.
Note that sending keypress messages to a control that doesn't have focus can sometimes cause unexpected behavior, since the app or control generally never expects to receive keyboard input without getting the focus first. (This can be problematic for controls that set up some sort of input context in WM_SETFOCUS and clear it up in WM_KILLFOCUS, for example.)
In short, the UI is still there: you can do certain queries against it, but you can no longer automate it as you could on a regular desktop by sending input, and some other functions that relate to focus or input may fail.
I'm not super familiar with AutoHotKey, but the name and description of functionality suggests that it's heavily reliant on the underlying Win32 SendInput API. This won't work at all for keyboard input when a desktop is inactive.
For a reasonable overview of how desktops work and how they relate to winstations, the locked desktop, and so on, check out the Desktop article on MSDN.
One issue that I've run into in the past with desktops and automation is: how to I leave a long-running test that's using some form of user input automation (mouse, keyboard simulation), but still lock my PC so that someone can't just walk by and interfere with it. Once you lock the PC, the desktop is inactive, and so the automation stops working. A similar issue happens if the screensaver kicks in: the desktop switches, and the automation fails.
One solution is to use two PCs: let's call them Main and Test: from Main, open a remote terminal services client onto the Test machine, and then run the automated test on the test machine, but from a terminal services client window on the Main machine. Now the cool part: you can minimize that TSC window, or even lock the Main machine (or let the screensaver kick in), and that virtual session will continue working, thinking that it is still active - it's just that nobody is paying it any attention. This is one way to create a "connected" session with an active desktop, but one that no-one can interfere with, because it's protected behind the locked desktop of the Main machine.
I don't know the details, but I believe the lock screen constitutes a separate "desktop" and maybe also a separate "window station" (as I understand it a window station is merely a container for desktops). The MSDN section on window stations should hopefully be useful: http://msdn.microsoft.com/en-us/library/windows/desktop/ms687098%28v=vs.85%29.aspx
In order to access a desktop, you will need to use the regular windows api's from a thread that is on that desktop. SetThreadDesktop would probably be the easiest way to do that in C, as long as the desktop isn't on a different window station.
Unfortunately, this is already difficult for a regular privileged application, and using AutoHotkey complicates it even more. Since you don't have control over threads or over process initialization, you will probably have to create a new process in the other desktop (you can do this using the CreateProcess API, which appears to have a wrapper available for AHK to which you can supply a desktop name: http://www.autohotkey.com/forum/topic1952.html). Your process will need special privileges to do this; I'm not sure that even running as Administrator is enough.

OS X design decisions. Terminate the app on last window close?

Unlike Windows, GNOME and most other GUI's, OS X application programs do not all terminate if the main window (or all the windows) of that application are closed.
For example, fire up Firefox, Safari, Word, or most document based apps. Either click the red dot in the corner or type cmdW to close the window. You can see that the menu of that program is still active, and the program is still running. With OS X newbies, sometimes you will see dozens of these windowless zombies running and they wonder why their computer is getting slower.
With some document based programs, there is some sense to not terminating the application if it has no windows. For example, with Safari or Word, you can still type CmdN and get a new document window for whatever that application was designed to do: browse the web (Safari) or type a new document (Word).
Apple is mixed with their design philosophy on this. Some close on the last window closed and some do not. Third party apps are even more mixed.
There are other apps that do close when their red close button is clicked. System Preferences, Dictionary, the Mac App Store, iPhoto and Calculator do terminate when the sole or last window is closed. iCal, Address Book, iTunes, DVD Player do not terminate.
What I find particularly annoying is the applications that do not have a logical "New Document" or "Open" function yet they do not terminate when the document window is closed. Example: fire up iTunes or Address Book and terminate the main window. There sits a zombie with no window and no function other than manually selecting "Quit".
It is easy to close the application after the last window closes. Cocoa even gives you notification of that event. Just add this to your application delegate:
- (BOOL)applicationShouldTerminateAfterLastWindowClosed:(NSApplication *)sender
{
return YES;
}
My question is this: Is there any reason I should NOT terminate my application after the last window closes? Why is this so variable on OS X software? Unless the app has a "new" or "open" or some other clearly understood reason to not terminate with no window open, the failure to terminate seems like a bug to me.
Per Apple's Human Interface Guidelines (a guide for Mac developers):
In most cases, applications that are
not document-based should quit when
the main window is closed. For
Example, System Preferences quits if
the user closes the window. If an
application continues to perform some
function when the main window is
closed, however, it may be appropriate
to leave it running when the main
window is closed. For example, iTunes
continues to play when the user closes
the main window.
In general, never close a document based application when the last window closes. The user will expect to be able to open a new document without relaunching the application, and it will confuse them if they can't.
For non-document based applications, you need to consider a few things:
How long does it take for my application to open? If it takes more than a second, you should probably not quit.
Does my application need a window to be useful? If your application can do work without windows, you should not quit.
iTunes doesn't quit because, as Anne mentioned, you don't need a window to play music (question 2). It is also not based on Cocoa, so it is much more difficult to close after the last window, especially since it allows you to open windows for specific playlists so there are an indefinite number of possible windows to be open.
In my opinion, Address Book does not need to stay open. This could be a left-over design decision from older versions of OS X, or it could be that someone at Apple just thought it was better to leave it open (maybe so you can add a contact?). Both iTunes and Address Book provide access to their main interfaces through the Window menu, as well as a keyboard shortcut (Option+Command+1 for iTunes, Command+0 for Address Book).
The main iTunes window can be reopened from the 'Window' menu. Mail.app has similar behavior. I can't think of any applications that close when the last window is closed, and as such I don't think there's a good reason that your app should behave that way (in fact, i'm surprised its not in Apple's user experience guidelines, it would really bother me!).
One reason why you'd want to close e.g. the iTunes main window but keep the app open is to be able to use the app as sort of a server for third party scripts/applications. I rarely use the main iTunes interface, but instead control my music with a third party app. I also write AppleScripts for other apps that I launch instead of interacting with that app's interface.

Resources