keepassxc/src/gui/macutils/AppKitImpl.mm
Chih-Hsuan Yen 794cc1eeab Partial fix for building on Mac OS X < 10.12
This commit reverts #3357.

The previous PR is for the new symbol NSEventMaskKeyDown, which is
introduced in #3347. In #3794, #3347 is reverted, so the workaround
in #3357 is no longer needed. Furthermore, it causes build failures
on 10.11 (#3932) as the header file for type NSEventMask is removed
in #3794, too.

Note that this is not a complete fix. A complete patch can be found
at [1]. In MacPorts, the OS version for building a package is the same
as the OS that installs it, so #ifdef can be used to replace @available.
The latter language feature is not available until Xcode 9.

With the patch mentioned in the previous paragraph, KeePassXC 2.5.1
can be built on Mac OS X 10.9 or newer.

Ref: #2899

[1] de1bb703ad/security/KeePassXC/files/patch-old-mac.diff
2019-12-21 09:25:56 -05:00

217 lines
6.4 KiB
Text

/*
* Copyright (C) 2016 Lennart Glauer <mail@lennart-glauer.de>
* Copyright (C) 2017 KeePassXC Team <team@keepassxc.org>
*
* This program is free software: you can redistribute it and/or modify
* it under the terms of the GNU General Public License as published by
* the Free Software Foundation, either version 2 or (at your option)
* version 3 of the License.
*
* This program is distributed in the hope that it will be useful,
* but WITHOUT ANY WARRANTY; without even the implied warranty of
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
* GNU General Public License for more details.
*
* You should have received a copy of the GNU General Public License
* along with this program. If not, see <http://www.gnu.org/licenses/>.
*/
#import "AppKitImpl.h"
#import <AppKit/NSWorkspace.h>
#import <CoreVideo/CVPixelBuffer.h>
@implementation AppKitImpl
- (id) initWithObject:(AppKit*)appkit
{
self = [super init];
if (self) {
m_appkit = appkit;
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self)
selector:@selector(didDeactivateApplicationObserver:)
name:NSWorkspaceDidDeactivateApplicationNotification
object:nil];
[[[NSWorkspace sharedWorkspace] notificationCenter] addObserver:static_cast<id>(self)
selector:@selector(userSwitchHandler:)
name:NSWorkspaceSessionDidResignActiveNotification
object:nil];
}
return self;
}
//
// Update last active application property
//
- (void) didDeactivateApplicationObserver:(NSNotification*) notification
{
NSDictionary* userInfo = notification.userInfo;
NSRunningApplication* app = userInfo[NSWorkspaceApplicationKey];
if (app.processIdentifier != [self ownProcessId]) {
self.lastActiveApplication = app;
}
}
//
// Get process id of frontmost application (-> keyboard input)
//
- (pid_t) activeProcessId
{
return [NSWorkspace sharedWorkspace].frontmostApplication.processIdentifier;
}
//
// Get process id of own process
//
- (pid_t) ownProcessId
{
return [NSProcessInfo processInfo].processIdentifier;
}
//
// Activate application by process id
//
- (bool) activateProcess:(pid_t) pid
{
NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
return [app activateWithOptions:NSApplicationActivateIgnoringOtherApps];
}
//
// Hide application by process id
//
- (bool) hideProcess:(pid_t) pid
{
NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
return [app hide];
}
//
// Get application hidden state by process id
//
- (bool) isHidden:(pid_t) pid
{
NSRunningApplication* app = [NSRunningApplication runningApplicationWithProcessIdentifier:pid];
return [app isHidden];
}
//
// Get state of macOS Dark Mode color scheme
//
- (bool) isDarkMode
{
NSDictionary* dict = [[NSUserDefaults standardUserDefaults] persistentDomainForName:NSGlobalDomain];
id style = [dict objectForKey:@"AppleInterfaceStyle"];
return ( style && [style isKindOfClass:[NSString class]]
&& NSOrderedSame == [style caseInsensitiveCompare:@"dark"] );
}
//
// Notification for user switch
//
- (void) userSwitchHandler:(NSNotification*) notification
{
if ([[notification name] isEqualToString:NSWorkspaceSessionDidResignActiveNotification] && m_appkit)
{
emit m_appkit->lockDatabases();
}
}
//
// Check if accessibility is enabled, may show an popup asking for permissions
//
- (bool) enableAccessibility
{
// Request accessibility permissions for Auto-Type type on behalf of the user
NSDictionary* opts = @{static_cast<id>(kAXTrustedCheckOptionPrompt): @YES};
return AXIsProcessTrustedWithOptions(static_cast<CFDictionaryRef>(opts));
}
//
// Check if screen recording is enabled, may show an popup asking for permissions
//
- (bool) enableScreenRecording
{
if (@available(macOS 10.15, *)) {
// Request screen recording permission on macOS 10.15+
// This is necessary to get the current window title
CGDisplayStreamRef stream = CGDisplayStreamCreate(CGMainDisplayID(), 1, 1, kCVPixelFormatType_32BGRA, nil,
^(CGDisplayStreamFrameStatus status, uint64_t displayTime,
IOSurfaceRef frameSurface, CGDisplayStreamUpdateRef updateRef) {
Q_UNUSED(status);
Q_UNUSED(displayTime);
Q_UNUSED(frameSurface);
Q_UNUSED(updateRef);
});
if (stream) {
CFRelease(stream);
} else {
return NO;
}
}
return YES;
}
@end
//
// ------------------------- C++ Trampolines -------------------------
//
AppKit::AppKit(QObject* parent) : QObject(parent)
{
self = [[AppKitImpl alloc] initWithObject:this];
}
AppKit::~AppKit()
{
[[[NSWorkspace sharedWorkspace] notificationCenter] removeObserver:static_cast<id>(self)];
[static_cast<id>(self) dealloc];
}
pid_t AppKit::lastActiveProcessId()
{
return [static_cast<id>(self) lastActiveApplication].processIdentifier;
}
pid_t AppKit::activeProcessId()
{
return [static_cast<id>(self) activeProcessId];
}
pid_t AppKit::ownProcessId()
{
return [static_cast<id>(self) ownProcessId];
}
bool AppKit::activateProcess(pid_t pid)
{
return [static_cast<id>(self) activateProcess:pid];
}
bool AppKit::hideProcess(pid_t pid)
{
return [static_cast<id>(self) hideProcess:pid];
}
bool AppKit::isHidden(pid_t pid)
{
return [static_cast<id>(self) isHidden:pid];
}
bool AppKit::isDarkMode()
{
return [static_cast<id>(self) isDarkMode];
}
bool AppKit::enableAccessibility()
{
return [static_cast<id>(self) enableAccessibility];
}
bool AppKit::enableScreenRecording()
{
return [static_cast<id>(self) enableScreenRecording];
}