Hide on Close

Hello,

There are many Apps that if you click the red X (close) , the App will not close but the window will hide instead.
I have an App with one Window. It has a ‘Quit’ button that calls quit.
I want the window to hide when the red X is clicked.

I assumed I could just do Me.Hide and Return True in the CancelClose of the window.
That seems to works but the window doesn’t restore when the dock App icon is clicked again.

How do I show the window again when the dock App icon is clicked? Or is there a better way to do this?

Show the window in the App.Activate event.

If you want to limit it to only the Dock icon clicks, you can respond to the AppleEvent that’s generated when the user does that. I’m not in front of my computer at the moment or I’d tell you exactly what that is.

Ah, cool. Almost there. :slight_smile:
That works but only if the App lost focus. Otherwise the event won’t fire.
So if I ‘close’ the App (it hides), the App is still active. When I click the dock icon, nothing happens. Only when I click another App first and then click the dock icon, it opens again.

Now I’m about to find a way to make it lose focus but is that really the way to do it? It seems odd.

[quote=210670:@Marco Hof]Ah, cool. Almost there. :slight_smile:
That works but only if the App lost focus. Otherwise the event won’t fire.
So if I ‘close’ the App (it hides), the App is still active. When I click the dock icon, nothing happens. Only when I click another App first and then click the dock icon, it opens again.

Now I’m about to find a way to make it lose focus but is that really the way to do it? It seems odd.[/quote]

Use App.HandleAppleEvent.

HandleAppleEvent fires for more than just clicking the dock icon. You want to test the parameters to identify your kind of event and only handle that (I forgot this recently and the docks Quit menu item stopped working because I always returned true).

Anyways, if it passes the if condition then the dock icon was clicked. The wasFront variable is extra and tells you if your app was in front or in the background when the click happened. I use this so if the app is in the background the first click brings it forward, then the next click shows a special window.

[code]//App Event
Function HandleAppleEvent(theEvent As AppleEvent, eventClass As String, eventID As String) As Boolean

if eventClass = “aevt” and eventID = “rapp” then

dim wasFront As boolean = theEvent.BooleanParam("frnt")

System.DebugLog "dock clicked, app was front: " + Str(wasFront)

return true

end

return false

End Function
[/code]

Excellent! App.HandleEvent works.
And I love the ‘wasfront’!

For future reference, to Hide the App instead of closing when the red X close was clicked, put this in the CancelClose of the Window1:

If Not appQuitting Then Me.Hide Return True End If

This way, Quit (or if the user uses Quit via the dock) normally works.
Then put Window1.Show in the App.HandleAppleEvent

Everything was working great. However, a user pointed out an issue.

So the App is ‘hidden’ and it Shows when the dock icon is clicked or if something is dropped on it. Great.

But nothing happens if the user used command-tab to go back to the App.
App.HandleEvent doesn’t fire.

Does anyone know if there’s an event raised when command-tab is used?

Anytime the app is brought to the front for any reason, you will get App.Activate. However, normal behavior on OS X is that switching to the app via cmd-tab will not open a new window, only clicking on the Dock. Try it out with something like Safari.

I’m not sure what you mean.
What I have now is that App.Activate indeed fires but only if it’s not the first on the row of icons you see with command-tab.

So if the App is hidden and before clicking anywhere else, the Apps icon is the first in the row of icons in command-tab. I guess that means that the App is still the Active one?
When I command-tab to the App’s icon, nothing happens. Both App.Activate and App.HandleEvent aren’t fired.

When I click somewhere else, the App icon in command-tab becomes the second one. Then App.Activate is fired.
Is that what you mean?

Is some other event raised or is it possible to ‘de-activate’ my App?

When you press command-tab and the highlighted icon is your app, yes, it is indeed already active. In fact, your app’s name should appear in the menubar. No event will fire in that case because nothing has really happened.

A solution might be to activate another app once the user closes the last window in your app, and for that you’d need either declares or an AppleScript (you can use System Events for this). The question is, which app do you activate? If you don’t care, this AppleScript should do the trick:

tell application "System Events"
	try
		set p to first application process whose background only is false and ¬
			visible is true and ¬
			bundle identifier is not "my.bundle.identifier"
		tell p to activate
	end try
end tell

Replace “my.bundle.identifier” with the identifier for your app. This will keep it from activating your own app if that’s the first one it finds.

An alternative is to hide your own app:

tell application "System Events"
	set p to first application process whose bundle identifier is "my.bundle.identifier"
	set visible of p to false
end tell

For future searchers…
I stumbled on a declare-way to do it. This way of hiding the App moves the focus automatically so the Cmd-Tab works correctly.

In the CancelClose event of the Window:

  If Not appQuitting Then
    
    // This way of hiding makes Cmd-Tab work correctly.
    #if TargetCocoa
      Declare Function NSClassFromString Lib "Cocoa"(inName As CFStringRef) As Ptr
      Declare Function sharedApplication Lib "Cocoa" selector "sharedApplication"(classRef As Ptr) As Ptr
      Dim thisApp As Ptr = sharedApplication(NSClassFromString("NSApplication"))
      Declare Sub Hide Lib "Cocoa" Selector "hide:"(id As Ptr)
      Hide thisApp
    #else
      Self.Hide
    #endif   
    
    Return True
  End If

The Show -part stays the same in App.HandleAppleEvent.