0

In my macOS app (objC), the user can trigger tasks that can take some time, like importing files into a database. These tasks do not run on the main thread because they spawn a window (sheet) to show the task's progress and to allow cancelling the task. The window is modal because I don't want the user to do anything during these task (like quitting the app, or undoing stuff), except cancelling the task. At the same time, I don't want the progress window to show immediately, as the task may be quite short (< 1sec). Showing a modal sheet for less than 1 sec would be distracting.

So I'm currently showing the progress window after a delay of 1 second (or don't show it at all if the task took less time). But during this 1 second, nothing prevents the user from doing silly stuff, like deleting a folder in which items are being imported. [By "Folder", I don't mean folders of the Finder, just containers that my app manages].

I could prevent user actions on a case-by-case basis by overriding every method that I don't want to be executed during these tasks (these method would check if some task is ongoing) or I could adapt the code to accommodate the consequences of user actions (e.g. what to do if the folder in which the file are being imported has been deleted). I'am already doing the latter to some extent, but it is difficult to imagine every possible user action with adverse effet. So as a safety measure, I'd like to prevent any user action in my app before the progress window shows.

Some my question is: How do I prevent my app from responding to user actions in an "invisible" manner without blocking the main thread?

8
  • Do you want to block your app or the entire Mac? Commented Jun 24 at 12:50
  • 1
    „Showing a modal sheet for less than 1 sec would be distracting.“ .. as leaving UI unreactive may be irritating. I would suggest that starting the task is already part of the modal, and let the user know that this may take a while. The close the window with some checkmark animation and the user will be happy it took less than a sec! Commented Jun 24 at 13:04
  • 1
    Normally you would disable menu items and controls to not allow whatever, then perform the task and re-enable when complete. Application modal stuff won't stop anyone from deleting folders. Commented Jun 24 at 14:01
  • By "folder", I don't mean folders in the Finder, just equivalent things that my app manages. I need to block my app only, not the system. If the app is unresponsive for 1 sec, it's OK because this would happen just after the user has decided to import thousands of files (using an open panel). They would expect the task to take time. Commented Jun 24 at 15:10
  • 1
    So, your tasks are either quick or take well more than 1s? Otherwise 1.5s tasks would just be as annoying, and all you did was shift the issue. In that case flying that brief modal might be the lesser of the evils. Commented Jun 24 at 19:06

2 Answers 2

1

If you are sure that this is what you want to do, create a custom NSApplication subclass and override - (void)sendEvent:(NSEvent *)event to swallow all events during those periods. Outside just send to super.

Note that to use your custom NSApplication class you need to set it using the NSPrincipalClass key in Info.plist.

Sign up to request clarification or add additional context in comments.

Comments

0

You can create a non-activating overlay window (an NSPanel with .nonactivatingPanel) so it stays visible but doesn’t receive input letting other apps stay focused while your UI sits on top

Then use a CGEventTap at the system level with Accessibility permissions to intercept and drop keyboard and mouse events before they reach any app.

1 Comment

Wouldn't the overlay window have a visual impact on the app? Like changing focus rings, colours of selected rows in table views (which may app has). I want to block user input in a completely invisible manner.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.