The biggest problem I encountered with OpenCV windows on macOS is that they never open on top of my current window when an application using OpenCV is launched. So I created a helper function that does just that.
Let’s start with the code:
#ifdef __APPLE__
# include <objc/runtime.h>
# include <objc/message.h>
# include <objc/NSObjCRuntime.h>
#endif
inline void createWindow(const std::string& name)
{
cv::namedWindow(name);
#ifdef __APPLE__
Class applicationClass = objc_getClass("NSApplication");
id application = reinterpret_cast<id (*)(Class, SEL)>(&objc_msgSend)(applicationClass, sel_getUid("sharedApplication")); // [NSApplication sharedApplication]
id windows = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(application, sel_getUid("windows")); // [application windows]
NSUInteger windowCount = reinterpret_cast<NSUInteger (*)(id, SEL)>(&objc_msgSend)(windows, sel_getUid("count")); // [windows count]
for (NSUInteger i = 0; i < windowCount; ++i)
{
id window = reinterpret_cast<id (*)(id, SEL, NSUInteger)>(&objc_msgSend)(windows, sel_getUid("objectAtIndex:"), i); // [windows objectAtIndex:i]
id title = reinterpret_cast<id (*)(id, SEL)>(&objc_msgSend)(window, sel_getUid("title")); // [window title]
const char* titleString = reinterpret_cast<const char* (*)(id, SEL)>(&objc_msgSend)(title, sel_getUid("UTF8String")); // [string UTF8String]
if (name == titleString)
reinterpret_cast<void (*)(id, SEL)>(&objc_msgSend)(window, sel_getUid("orderFrontRegardless")); // [window orderFrontRegardless]
}
#endif
}
I added #ifdef __APPLE__
so that the code get’s compilet only on macOS. First I create the OpenCV window with cv::namedWindow. I use Objective-C runtime functions to send Objective-C messages. I get an instance of NSApplication class by calling the C equivalent of [NSApplication sharedApplication]
. After getting the pointer of the main application I get the list of all windows ([application windows]
) and iterate through them ([windows count]
). For every window ([windows objectAtIndex:i]
) I get its title ([window title]
) convert it to C string ([string UTF8String]
) and compare it to the name of the window. If they match, then I bring it to front ([window orderFrontRegardless]
).
To use the code just call createWindow
instead of cv::namedWindow
.