On OSX, how can I ensure that a command-line application shows up in the application switcher once it creates a window? - macos

I'm working on a cross-platform command-line application (in C++ on
Win/Linux and ObjC++ on OSX) which sometimes creates an OpenGL
context. The OpenGL context and window creation code is obviously
different for the different platforms, but on OSX it's done through
NSOpenGLView and NSWindow. There's no nib, and it's not built with
Xcode (it uses a cross-platform build script).
On OSX, the window is created and works fine, but the OpenGL window
doesn't show up in the Application Switcher (Cmd-Tab). This means
that it's tricky to find the window if you 'lose it' behind other
windows, and can often only be found by going to Mission
Control/Expose.
My question is: is there a programmatic way (i.e. a message to send to
the NSWindow object or NSApplication) to ensure that a (unix-style)
command line application will show up in the Cmd-Tab list once the
window is created?

You need to transform the process from an accessory to a regular app. Call [NSApp setActivationPolicy:NSApplicationActivationPolicyRegular].
Once you do that, though, the app will also have a menu bar when it's active. This is good because it's what users expect. However, you probably need to add appropriate items to the menus in that menu bar to get a decent user experience.
Your app will appear in the Dock as well as the Command-Tab application switcher. By default, an unbundled executable will get an icon that looks like a CRT display showing the word "exec". You can use [NSApp setApplicationIconImage:someImage] to set a better icon, although the Dock will revert to showing the generic executable icon briefly as the process exits.

Related

macOS / Qt: Disabling the "Quit" menu item on my application's dock menu

I've writing a macOS application with Qt. This application is a launch agent, meaning that it's launched by launchd and always running in the background. Normally the application only has a menu bar icon, and it doesn't have any open windows or a Dock icon. (i.e. the shared NSApplication instance's activationPolicy property is set to a value of NSApplicationActivationPolicyAccessory.)
However, there are a few menu items available in its menu bar item that open some windows, and when those windows are open the app switches to not being background-only any longer, so it will have a Dock icon and menu bar. (i.e. activationPolicy is changed to NSApplicationActivationPolicyRegular.) With there being a Dock icon, that means it's possible for the user to right-click it and open its menu, and that menu has its default menu item for quitting the application.
Since the app is a launch agent, though, and is intended to always be running, quitting it just causes launchd to relaunch the app. I'd like to disable or remove this menu item if possible, or otherwise prevent the user from being able to quit the app in this manner.
Is there any way to do that? If there's a way to accomplish this purely using Qt's functions that would be great, but if not it's fine for me to use macOS specific functions too.
I should add that because this is a Qt application, I can't use the same method as outlined here because I don't have access to the application's delegate. I would need to use another approach. (For example, it may be possible to swizzle methods on Qt's application delegate, though if there's a cleaner way to accomplish this than I'd much rather do that.)
After doing some more research, I've found that it's not possible to remove the "Quit" menu item from an application's Dock menu, or any of the other standard menu items there as they are created and handled by the Dock itself.
It is possible to stop an application from quitting when the user quits the application via the Dock. In a Qt application the method is to subclass QApplication and override its bool event(QEvent *) method. The overridden method should check for events of type QEvent::Close, call the ignore() method on the event, and then return true. Note though that this will stop the application from quitting via all other conventional methods as well.
edit: It is also possible to tell when the app is being quit via the Dock, at least when using Apple's native API. See: macOS: Is there any way to know when the user has tried to quit an application via its Dock icon?
By using Objective-C method swizzling it's possible to override the applicationShouldTerminate: method of Qt's application delegate and prevent a Qt app from being quit by the dock.

create a program with Xcode-like interface

On Mac it is usual that there is a "hidden" main window.
The usual example is "Text Edit". When you open a file you with you don't see a "main frame". Instead every single file will be opened in its own "Text Edit" instance. This is OSX way of emulating the so-called MDI interface.
However, there is an exception. If you open Xcode and open the project there, you can click on the file and it will be open inside the main Xcode window. And if you double click the file it will be opened in its own independent editor window, keeping the main Xcode window visible.
My question would be: do I need to do anything special in order to make my program behave like an Xcode? Should I use different class for the main frame or maybe react differently on the opening document event?
Any hints/pointers where to look or even to the official Apple documentation would be helpful.
The TextEdit behavior you're describing is much more like “SDI” than “MDI”, and the terms “SDI” and “MDI” weren't even needed until Microsoft invented MDI long after Xerox invented the SDI-type interface of which macOS is a derivative.
Anyway, I think you are misunderstanding Xcode's behavior. You seem to think “its own independent editor window” is a different kind of window than “the main Xcode window”. But in fact the new window is of the same kind as the old window, with some optional parts hidden. You can show those hidden parts and make the new window look exactly like the old window. Demo:
The ability to open multiple windows showing the same document (or, in Xcode's case, project) is a matter of software architecture. If you carefully design your app so that multiple windows can share a single model object graph, and can be notified and redraw themselves when the object graph changes, then you have an app that supports multiple windows showing the same document. If you want multiple kinds of windows showing the same document, nothing about Cocoa stands in your way. As a matter of fact, Xcode does have at least one other kind of window in which it shows some properties of a project:
That project settings sheet is really another window; macOS keeps it attached to the main window, but it is in fact an instance of NSWindow (or a subclass of NSWindow), no doubt with its own custom window controller that references the same project objects as the main window.
If you use the Cocoa NSDocument architecture, then a small amount of multi-window support is built-in: an NSDocument knows about its associated windows (via their window controllers). If you want to use the NSDocument architecture, you should read Document-Based App Programming Guide for Mac.
It is unclear what you are after. The traditional Mac UI has been one window per document - i.e. SDI with a single instance of the app running multiple windows - but there has always been the ability for any app to organise the content of that window as it sees fit, including showing multiple "documents" within one window - i.e MDI type UI.
Apps approach such "MDI" in different ways, e.g. some use panes (views) and others tabs. From macOS Sierra the standard NSWindow supports tabs, this system is (semi)automatic for standard document apps. Read Apple's NSWindow Automatic Window Tabbing section in the Sierra release notes for more details.
If you wish to use multiple panes - e.g. like Xcode - you just use views (NSView) and arrange them how you wish.
HTH

How to open any built-in app through application

my mac os application is running in full screen mode.
On button click i'm opening finder window which allow me to open any another file or application but problem is that, when i open any another app, screen switches back to xCode and that application opens. Need to open selected app/file above same window.
I have tried:
**[[NSWorkspace sharedWorkspace] launchApplication:path];**
passing application path to launchAppication method
How can i do this?????
Help
The issue is basically because using [NSView enterFullScreenMode:withOption:] will set the app's [NSWindow level] to kCGMaximumWindowLevel - 1, so that all other app's windows will appear behind it.
This is kinda what you would expect from a fullscreen app, which implies system-modal behaviour.
I guess the only way of allowing another app to appear in front of the fullscreen app would be to lower the window level, however I have no idea what effect that would have.

Possible to tell if NSApplicationActivationPolicyProhibited application is active?

Using JUCE with TUIO, I'm developing a multi-touch utility to send "hot keys" commands to other applications (I am using a usb touch frame that sends TUIO messages). For instance, I provide an interface through which users can touch-and-hold to program a key combo and then tap that button to send the programmed key combo to another app. They way I accomplish this on OSX is by running my utility as a "background only" application (NSApplicationActivationPolicyProhibited). I use [NSWindow setCanHide: NO] so the GUI of my utility is visible even though it runs as a background app.
It works well except in the case that a window from another application is on top of mine. What happens is that touches get passed through that other app into mine- causing unintentional button pushes in my app. Normally, I could have my app only listen to the TUIO touch callback whenever is is the active application, [NSApp isActive]. But, since my app is background only, it is never active and I have no way to tell if another window is covering it to prevent touches.
So, is there any way for a "background only" app to be able to tell if it is on top of all other windows? Or, is there a way from within my app to get a list of all Cocoa windows from other applications and be able to tell if they are appearing on top of my "background only" app?
Also, does anyone know how I would go about all of the above in Windows? In other words, what is the Windows equivalent of NSApplicationActivationPolicyProhibited and would I be able to tell if it is covered by other applications' windows?

How to assume/steal another process's windows as my own?

I'd like to show another app's windows under my app's taskbar button. It's a background app that reports another process's windows as my app's own. Is there any universal way to do this, e.g. each "new" window, alert glow, progressmeter, and other taskbar features, show under my own app's button?
For example, Winfox runs under its own process and steals Firefox's windows. It also adds features, but that's irrelevant -- I just want to support another app's existing taskbar features under my own app's button -- multiple windows, progressmeter, alert flashing, error flashing, mini-icons, etc. Is there a near-universal way to steal an app, or is it largely app-specific? Thanks!
You should be able to use SetParent() to take ownership of a window, but I'm not sure how much this will help you in your attempt to add taskbar features to the legacy app.

Resources