Making an App appear over the loginwindow at logout on 10.11

I am trying to make a windowed application appear at the loginwindow on OSX 10.11, specifically at logout.


I am calling it using a logouthook script - I can see that the app is called on logout and the delay I have added to the application pauses the logout for 10 seconds but it isn't visible.


The main window does display if triggered with a loginhook and I have tested removing the "canBecomeVisibleWithoutLogin" parameter which causes me to see errors in the system.log relating to the window not having permission to run over the loginwindow.Based on this, I believe the parameter is at least recognised.


I have looked around for examples on the web that use "canBecomeVisibleWithoutLogin" and I haven't been able to determine what step I am missing.


The code below is the only code I have added to the application which consists of a MainMenu.nib and a AppDelegate.swift.


I have also selected "visible at launch" and "Move to Active Space" in Xcode but this hasn't changed the behaviour at logout.


import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate{

@IBOutlet weak var window: NSWindow!

func applicationWillFinishLaunching(notification: NSNotification) {


     self.window.canBecomeVisibleWithoutLogin = true
     self.window.orderFrontRegardless()
     self.window.level = Int(CGWindowLevelForKey(CGWindowLevelKey.StatusWindowLevelKey))

}

func applicationDidFinishLaunching(aNotification: NSNotification) {


     self.window.display()

     let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SEC))

     dispatch_after(time, dispatch_get_main_queue()) {

          NSApplication.sharedApplication().terminate(self)
     }
}


func applicationWillTerminate(aNotification: NSNotification) {


}

}
Answered by MacDeev in 162411022

Thanks Eskimo. I was able to get it working as I need by changing the window level manually so the app appears over the logout window. I will investigate the other options you suggest for future development. Here is my working code. Btw, I put the post in the swift forum because I was looking for a solution written in swift.


Import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    @IBOutlet weak var window: NSWindow!
    func applicationWillFinishLaunching(notification: NSNotification) {
  
    }
  
    func applicationDidFinishLaunching(aNotification: NSNotification) {
       
          self.window.level=2147483631
       
          let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SE
          dispatch_after(time, dispatch_get_main_queue()) {
                    
          NSApplication.sharedApplication().terminate(self)
        }
    }
  
    func applicationWillTerminate(aNotification: NSNotification) {
   
    }
}

I am calling it using a logouthook script …

That is rarely the right approach. I recommend you read up on:

  • launchd pre-login agents

  • authorisation plug-ins

depending on whether you want your UI to block login or not.

launchd pre-login agents are discussed in Technote 2083 Daemons and Agents, although it’s probably best to start with the PreLoginAgents sample code.

In this context the best place to go for information on authorization plug-ins is Technote 2228 Running At Login

IMPORTANT It won’t be safe to implement an authorisation plug-in in Swift until Swift has ABI stability. That’s because the plug-in is loaded into a system process (

SecurityAgent
or
authorizationhost
) that might be hosting other plug-ins, and without ABI stability there’s a chance that two plug-ins might be using incompatible runtimes.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

Thank you for the reply - i will read those articles you linked.


FYI, I am calling it from a logouthook because we are using JAMF Casper to manage the estate and policies can be run at logout using this. Casper already runs an application at logout with a UI element which is launched via the logouthook. Although its not ideal, i am trying to replicate this behaviour for my own application.

What do you want this app to do? In general it’s easier to avoid running at logout, but instead run before the next login. In most cases those are equivalent, the only exception being where you have to run before shutdown.

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"

I want this app to present a friendly GUI that will manage a file syncing process while displaying information such as whether the users home folder is under quota to allow the sync, whether the process is successful and how much data there is to sync. I want to display an error message if it fails as well and I would prefer this to stay on the screen delaying the completion of the logout process so that the user has less chance of walking away thinking their files are on the central storage.


All of this needs to be triggered when they log out because they will only want to sync when they log out and as its for a classroom, I can't have it trigger on login for the previous users files as it would slow the next users login. Any help to get a really basic cocoa application to be visible from a logout hook would be incredibly helpful.

First up, I’m moving this thread over to Core OS > Processes because it has nothing to do with Swift.

How is the user’s home directory mounted?

As I mentioned, in most cases it’s better to do this prior to login rather than during logout. The only gotchas with that approach are:

  • if the user’s home directory unmounts during logout, you don’t have access to it prior to login

  • if the user shuts down rather than logs out, your code won’t run until the Mac starts up next

Keep in mind that a typical logout/login cycle looks like this:

  1. user logs out

  2. that tears down their GUI session

  3. a new GUI session comes back up

  4. loginwindow starts, and starts the login process

  5. various auth plug-ins run

  6. the auth plug-in that displays the login UI runs

  7. various auth plug-ins run

  8. the user is logged in and their standard GUI comes up

My recommendation is that you run your syncing code at step 3. An auth plug-in running at that stage is plugged into the system at a well-defined point. This stands in stark contrast to the logouthook, which is basically a hack.

Any help to get a really basic cocoa application to be visible from a logout hook would be incredibly helpful.

Rest assured that nothing related to interacting with login and logout will be “really basic” (-:

Share and Enjoy

Quinn “The Eskimo!”
Apple Developer Relations, Developer Technical Support, Core OS/Hardware

let myEmail = "eskimo" + "1" + "@apple.com"
Accepted Answer

Thanks Eskimo. I was able to get it working as I need by changing the window level manually so the app appears over the logout window. I will investigate the other options you suggest for future development. Here is my working code. Btw, I put the post in the swift forum because I was looking for a solution written in swift.


Import Cocoa

@NSApplicationMain
class AppDelegate: NSObject, NSApplicationDelegate {
    @IBOutlet weak var window: NSWindow!
    func applicationWillFinishLaunching(notification: NSNotification) {
  
    }
  
    func applicationDidFinishLaunching(aNotification: NSNotification) {
       
          self.window.level=2147483631
       
          let time = dispatch_time(dispatch_time_t(DISPATCH_TIME_NOW), 10 * Int64(NSEC_PER_SE
          dispatch_after(time, dispatch_get_main_queue()) {
                    
          NSApplication.sharedApplication().terminate(self)
        }
    }
  
    func applicationWillTerminate(aNotification: NSNotification) {
   
    }
}
Making an App appear over the loginwindow at logout on 10.11
 
 
Q