mirror of https://github.com/BOINC/boinc.git
Mac: screensaver fixes for MacOS 14
This commit is contained in:
parent
9464ab7158
commit
8924ba43b6
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -47,14 +47,15 @@ bool getShow_default_ss_first();
|
|||
double getGFXDefaultPeriod();
|
||||
double getGFXSciencePeriod();
|
||||
double getGGFXChangePeriod();
|
||||
void incompatibleGfxApp(char * appPath, pid_t pid, int slot);
|
||||
void incompatibleGfxApp(char * appPath, char * wuName, pid_t pid, int slot);
|
||||
void setShow_default_ss_first(bool value);
|
||||
void setGFXDefaultPeriod(double value);
|
||||
void setGFXSciencePeriod(double value);
|
||||
void setGGFXChangePeriod(double value);
|
||||
double getDTime();
|
||||
void doBoinc_Sleep(double seconds);
|
||||
void launchedGfxApp(char * appPath, pid_t thePID, int slot);
|
||||
void launchedGfxApp(char * appPath, char * wuName, pid_t thePID, int slot);
|
||||
int compareBOINCLibVersionTo(int toMajor, int toMinor);
|
||||
void print_to_log_file(const char *format, ...);
|
||||
void strip_cr(char *buf);
|
||||
void PrintBacktrace(void);
|
||||
|
@ -63,7 +64,8 @@ extern bool gIsMojave;
|
|||
extern bool gIsCatalina;
|
||||
extern bool gIsHighSierra;
|
||||
extern bool gIsSonoma;
|
||||
extern bool gCant_Use_Shared_Offscreen_Buffer;
|
||||
extern bool gMach_bootstrap_unavailable_to_screensavers;
|
||||
extern mach_port_name_t commsPort;
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -51,8 +51,9 @@
|
|||
|
||||
@property (NS_NONATOMIC_IOSONLY, readonly) GLuint currentTextureName;
|
||||
- (void)init:(NSView*)saverView;
|
||||
- (void)portDied:(NSNotification *)notification;
|
||||
- (void)testConnection;
|
||||
- (void)portDied:(NSNotification *)notification;
|
||||
- (void)cleanUpOpenGL;
|
||||
|
||||
@end
|
||||
|
||||
|
@ -84,14 +85,15 @@ bool getShow_default_ss_first();
|
|||
double getGFXDefaultPeriod();
|
||||
double getGFXSciencePeriod();
|
||||
double getGGFXChangePeriod();
|
||||
void incompatibleGfxApp(char * appPath, pid_t pid, int slot);
|
||||
void incompatibleGfxApp(char * appPath, char * wuName, pid_t pid, int slot);
|
||||
void setShow_default_ss_first(bool value);
|
||||
void setGFXDefaultPeriod(double value);
|
||||
void setGFXSciencePeriod(double value);
|
||||
void setGGFXChangePeriod(double value);
|
||||
double getDTime();
|
||||
void doBoinc_Sleep(double seconds);
|
||||
void launchedGfxApp(char * appPath, pid_t thePID, int slot);
|
||||
void launchedGfxApp(char * appPath, char * wuName, pid_t thePID, int slot);
|
||||
int compareBOINCLibVersionTo(int toMajor, int toMinor);
|
||||
void print_to_log_file(const char *format, ...);
|
||||
void strip_cr(char *buf);
|
||||
void PrintBacktrace(void);
|
||||
|
@ -100,7 +102,9 @@ extern bool gIsCatalina;
|
|||
extern bool gIsHighSierra;
|
||||
extern bool gIsMojave;
|
||||
extern bool gIsSonoma;
|
||||
extern bool gCant_Use_Shared_Offscreen_Buffer;
|
||||
extern bool gMach_bootstrap_unavailable_to_screensavers;
|
||||
extern mach_port_name_t commsPort;
|
||||
|
||||
|
||||
#ifdef __cplusplus
|
||||
} // extern "C"
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -150,6 +150,7 @@ static pid_t childPid;
|
|||
static int gfxAppWindowNum;
|
||||
static NSView *imageView;
|
||||
static char gfxAppPath[MAXPATHLEN];
|
||||
static char gfxWuName[MAXPATHLEN];
|
||||
static int taskSlot;
|
||||
static NSRunningApplication *childApp;
|
||||
static double gfxAppStartTime;
|
||||
|
@ -175,12 +176,16 @@ static bool myIsPreview;
|
|||
#define MAXWAITFORCONNECTIONCATALINA 12.0
|
||||
#define MAX_CGWINDOWLIST_TRIES 3
|
||||
|
||||
#define MAJORBOINCGFXLIBNEEDEDFORSONOMA 8
|
||||
#define MINORBOINCGFXLIBNEEDEDFORSONOMA 1
|
||||
|
||||
int signof(float x) {
|
||||
return (x > 0.0 ? 1 : -1);
|
||||
}
|
||||
|
||||
void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
||||
void launchedGfxApp(char * appPath, char * wuName, pid_t thePID, int slot) {
|
||||
strlcpy(gfxAppPath, appPath, sizeof(gfxAppPath));
|
||||
strlcpy(gfxWuName, wuName, sizeof(gfxWuName));
|
||||
childPid = thePID;
|
||||
taskSlot = slot;
|
||||
gfxAppStartTime = getDTime();
|
||||
|
@ -188,16 +193,24 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
|||
if (thePID == 0) {
|
||||
useCGWindowList = false;
|
||||
gfxAppStartTime = 0.0;
|
||||
gfxWuName[0] = '\0';
|
||||
if (mySharedGraphicsController) {
|
||||
[ mySharedGraphicsController cleanUpOpenGL ];
|
||||
}
|
||||
if (imageView) {
|
||||
// removeFromSuperview must be called from main thread
|
||||
if (pthread_equal(mainThreadID, pthread_self())) {
|
||||
if (NSThread.isMainThread) {
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
imageView = nil;
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
});
|
||||
}
|
||||
imageView = nil;
|
||||
}
|
||||
} else {
|
||||
if (gCant_Use_Shared_Offscreen_Buffer) {
|
||||
stopAllGFXApps();
|
||||
} else { // thePID != 0
|
||||
if (childPid) {
|
||||
childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -408,7 +421,13 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
|||
if (imageView) {
|
||||
useCGWindowList = false;
|
||||
// removeFromSuperview must be called from main thread
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
if (NSThread.isMainThread) {
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
});
|
||||
}
|
||||
imageView = nil;
|
||||
}
|
||||
|
||||
|
@ -563,7 +582,7 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
|||
//
|
||||
if (childApp) {
|
||||
if (![ childApp activateWithOptions:NSApplicationActivateIgnoringOtherApps ]) {
|
||||
launchedGfxApp("", 0, -1); // Graphics app is no longer running
|
||||
launchedGfxApp("", "", 0, -1); // Graphics app is no longer running
|
||||
} else if (useCGWindowList) {
|
||||
// As a safety precaution, prevent terminating gfx app while copying its window
|
||||
pthread_mutex_lock(&saver_mutex);
|
||||
|
@ -611,7 +630,13 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
|||
|
||||
if (imageView && !useCGWindowList) {
|
||||
// removeFromSuperview must be called from main thread
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
if (NSThread.isMainThread) {
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[imageView removeFromSuperview]; // Releases imageView
|
||||
});
|
||||
}
|
||||
imageView = nil;
|
||||
}
|
||||
|
||||
|
@ -631,16 +656,26 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) {
|
|||
maxWaitTime = gIsCatalina ? MAXWAITFORCONNECTIONCATALINA : MAXWAITFORCONNECTION;
|
||||
if ((getDTime() - gfxAppStartTime) > maxWaitTime) {
|
||||
if (gIsCatalina) {
|
||||
if (gMach_bootstrap_unavailable_to_screensavers) {
|
||||
// Is the gfx app built with a new enough BOINC graphics library version?
|
||||
if (compareBOINCLibVersionTo(MAJORBOINCGFXLIBNEEDEDFORSONOMA, MINORBOINCGFXLIBNEEDEDFORSONOMA) >= 0) {
|
||||
runningSharedGraphics = true;
|
||||
if (childPid) {
|
||||
gfxAppStartTime = 0.0;
|
||||
childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
|
||||
}
|
||||
}
|
||||
}
|
||||
// CGWindowListCopyWindowInfo and CGWindowListCreateImage can copy
|
||||
// windows between user boinc_project and the user running the
|
||||
// screensaver only if OS < 10.15 (before Catalina)
|
||||
incompatibleGfxApp(gfxAppPath, childPid, taskSlot);
|
||||
incompatibleGfxApp(gfxAppPath, gfxWuName, childPid, taskSlot);
|
||||
} else {
|
||||
if (++CGWindowListTries > MAX_CGWINDOWLIST_TRIES) {
|
||||
// After displaying message for 5 seconds, incompatibleGfxApp
|
||||
// will call launchedGfxApp("", 0, -1) which will clear
|
||||
// gfxAppStartTime and CGWindowListTries
|
||||
incompatibleGfxApp(gfxAppPath, childPid, taskSlot);
|
||||
incompatibleGfxApp(gfxAppPath, gfxWuName, childPid, taskSlot);
|
||||
} else {
|
||||
if ([self setUpToUseCGWindowList]) {
|
||||
CGWindowListTries = 0;
|
||||
|
@ -1088,12 +1123,14 @@ static bool okToDraw;
|
|||
[[NSNotificationCenter defaultCenter] removeObserver:self
|
||||
name:NSPortDidBecomeInvalidNotification object:nil];
|
||||
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification object:nil];
|
||||
|
||||
openGLView = nil;
|
||||
|
||||
[self testConnection];
|
||||
|
||||
if (! gMach_bootstrap_unavailable_to_screensavers) {
|
||||
[[NSNotificationCenter defaultCenter] addObserver:self
|
||||
selector:@selector(portDied:) name:NSPortDidBecomeInvalidNotification object:nil];
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
|
@ -1101,60 +1138,129 @@ static bool okToDraw;
|
|||
{
|
||||
mach_port_t servicePortNum = MACH_PORT_NULL;
|
||||
kern_return_t machErr;
|
||||
char *portName = "edu.berkeley.boincsaver";
|
||||
char *portNameV1 = "edu.berkeley.boincsaver";
|
||||
char *portNameV2 = "edu.berkeley.boincsaver-v2";
|
||||
|
||||
// Try to check in with master.
|
||||
if ((!gMach_bootstrap_unavailable_to_screensavers) || (serverPort == MACH_PORT_NULL)) {
|
||||
// Try to check in with master.
|
||||
// NSMachBootstrapServer is deprecated in OS 10.13, so use bootstrap_look_up
|
||||
// serverPort = [(NSMachPort *)([[NSMachBootstrapServer sharedInstance] portForName:@"edu.berkeley.boincsaver"]) retain];
|
||||
machErr = bootstrap_look_up(bootstrap_port, portName, &servicePortNum);
|
||||
if (machErr == KERN_SUCCESS) {
|
||||
serverPort = (NSMachPort*)[NSMachPort portWithMachPort:servicePortNum];
|
||||
} else {
|
||||
if (machErr == BOOTSTRAP_NOT_PRIVILEGED) {
|
||||
// As of MacOS 14.0, the legacyScreenSave sandbox prevents using
|
||||
// IOSurfaceLookupFromMachPort. I have filed bug report FB13300491
|
||||
// with Apple and hope they will change this in future MacOS.
|
||||
gCant_Use_Shared_Offscreen_Buffer = true;
|
||||
stopAllGFXApps();
|
||||
machErr = bootstrap_look_up(bootstrap_port, portNameV1, &servicePortNum);
|
||||
if (machErr != KERN_SUCCESS) {
|
||||
if (machErr != BOOTSTRAP_NOT_PRIVILEGED) {
|
||||
// bootstrap_look_up() returned error other than BOOTSTRAP_NOT_PRIVILEGED
|
||||
// machErr is probably BOOTSTRAP_UNKNOWN_SERVICE because no gfx app is running
|
||||
// Keep trying bootstrap_look_up() until we get a connection from gfx app
|
||||
serverPort = MACH_PORT_NULL;
|
||||
} else { // bootstrap_look_up() returned error BOOTSTRAP_NOT_PRIVILEGED
|
||||
// As of MacOS 14.0, the legacyScreenSave sandbox prevents using
|
||||
// bootstrap_look_up. I have filed bug report FB13300491 with
|
||||
// Apple and hope they will change this in a future MacOS.
|
||||
machErr = bootstrap_check_in(bootstrap_port, portNameV2, &servicePortNum);
|
||||
if (machErr != KERN_SUCCESS) {
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
gMach_bootstrap_unavailable_to_screensavers = true;
|
||||
} // bootstrap_look_up() returned error BOOTSTRAP_NOT_PRIVILEGED
|
||||
} // bootstrap_look_up() did not return KERN_SUCCESS
|
||||
|
||||
if (machErr == KERN_SUCCESS) {
|
||||
serverPort = (NSMachPort*)[NSMachPort portWithMachPort:servicePortNum];
|
||||
}
|
||||
|
||||
if ((serverPort != MACH_PORT_NULL) && (localPort == MACH_PORT_NULL)) {
|
||||
// Retrieve raw mach port names.
|
||||
serverPortName = [serverPort machPort];
|
||||
|
||||
if (gMach_bootstrap_unavailable_to_screensavers) {
|
||||
// Register server port with the current runloop.
|
||||
[serverPort setDelegate:self];
|
||||
[serverPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
} else { // (! gMach_bootstrap_unavailable_to_screensavers)
|
||||
// Create our own local port.
|
||||
localPort = [[NSMachPort alloc] init];
|
||||
localPortName = [localPort machPort];
|
||||
// Register our local port with the current runloop.
|
||||
[localPort setDelegate:self];
|
||||
[localPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
|
||||
// Check in with server.
|
||||
int kr;
|
||||
kr = _MGCCheckinClient(serverPortName, localPortName, &clientIndex);
|
||||
if(kr != 0) {
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
|
||||
runningSharedGraphics = true;
|
||||
|
||||
if (childPid) {
|
||||
gfxAppStartTime = 0.0;
|
||||
childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
|
||||
}
|
||||
} // (! gMach_bootstrap_unavailable_to_screensavers)
|
||||
} // ((serverPort != MACH_PORT_NULL) && (localPort == MACH_PORT_NULL))
|
||||
} // ((!gMach_bootstrap_unavailable_to_screensavers) || (serverPort == MACH_PORT_NULL))
|
||||
}
|
||||
|
||||
|
||||
- (void)cleanUpOpenGL
|
||||
{
|
||||
if (gMach_bootstrap_unavailable_to_screensavers) {
|
||||
[serverPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
childPid=0;
|
||||
childApp = nil;
|
||||
|
||||
if (gMach_bootstrap_unavailable_to_screensavers ||
|
||||
((serverPort == MACH_PORT_NULL) && (localPort == MACH_PORT_NULL))
|
||||
) {
|
||||
if (openGLView) {
|
||||
if (NSThread.isMainThread) {
|
||||
[openGLView removeFromSuperview]; // Releases openGLView
|
||||
} else {
|
||||
dispatch_sync(dispatch_get_main_queue(), ^{
|
||||
[openGLView removeFromSuperview]; // Releases openGLView
|
||||
});
|
||||
}
|
||||
openGLView = nil;
|
||||
}
|
||||
|
||||
int i;
|
||||
for(i = 0; i < NUM_IOSURFACE_BUFFERS; i++) {
|
||||
if (_ioSurfaceBuffers[i]) {
|
||||
CFRelease(_ioSurfaceBuffers[i]);
|
||||
_ioSurfaceBuffers[i] = nil;
|
||||
}
|
||||
|
||||
// if (glIsTexture(_textureNames[i])) {
|
||||
// glDeleteTextures(1, _textureNames[i]);
|
||||
// }
|
||||
_textureNames[i] = 0;
|
||||
|
||||
if (_ioSurfaceMachPorts[i] != MACH_PORT_NULL) {
|
||||
mach_port_deallocate(mach_task_self(), _ioSurfaceMachPorts[i]);
|
||||
_ioSurfaceMachPorts[i] = MACH_PORT_NULL;
|
||||
}
|
||||
serverPort = MACH_PORT_NULL;
|
||||
}
|
||||
|
||||
if ((serverPort != MACH_PORT_NULL) && (localPort == MACH_PORT_NULL))
|
||||
{
|
||||
// Create our own local port.
|
||||
localPort = [[NSMachPort alloc] init];
|
||||
|
||||
// Retrieve raw mach port names.
|
||||
serverPortName = [serverPort machPort];
|
||||
localPortName = [localPort machPort];
|
||||
|
||||
// Register our local port with the current runloop.
|
||||
[localPort setDelegate:self];
|
||||
[localPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
|
||||
// Check in with server.
|
||||
int kr;
|
||||
kr = _MGCCheckinClient(serverPortName, localPortName, &clientIndex);
|
||||
if(kr != 0)
|
||||
[NSApp terminate:nil];
|
||||
|
||||
runningSharedGraphics = true;
|
||||
|
||||
if (childPid) {
|
||||
gfxAppStartTime = 0.0;
|
||||
childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
|
||||
runningSharedGraphics = false; // Do this last!!
|
||||
if (gMach_bootstrap_unavailable_to_screensavers) {
|
||||
[serverPort scheduleInRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (void)portDied:(NSNotification *)notification
|
||||
{
|
||||
if (gMach_bootstrap_unavailable_to_screensavers) {
|
||||
return; // This should never be called if using MacOS 14 workaround
|
||||
}
|
||||
NSPort *port = [notification object];
|
||||
if(port == serverPort) {
|
||||
childApp = nil;
|
||||
gfxAppStartTime = 0.0;
|
||||
gfxAppPath[0] = '\0';
|
||||
gfxWuName[0] = '\0';
|
||||
|
||||
if ([serverPort isValid]) {
|
||||
[serverPort invalidate];
|
||||
|
@ -1169,29 +1275,7 @@ static bool okToDraw;
|
|||
// [localPort release];
|
||||
localPort = MACH_PORT_NULL;
|
||||
|
||||
int i;
|
||||
for(i = 0; i < NUM_IOSURFACE_BUFFERS; i++) {
|
||||
if (_ioSurfaceBuffers[i]) {
|
||||
CFRelease(_ioSurfaceBuffers[i]);
|
||||
_ioSurfaceBuffers[i] = nil;
|
||||
}
|
||||
|
||||
// if (glIsTexture(_textureNames[i])) {
|
||||
// glDeleteTextures(1, _textureNames[i]);
|
||||
// }
|
||||
_textureNames[i] = 0;
|
||||
|
||||
if (_ioSurfaceMachPorts[i] != MACH_PORT_NULL) {
|
||||
mach_port_deallocate(mach_task_self(), _ioSurfaceMachPorts[i]);
|
||||
_ioSurfaceMachPorts[i] = MACH_PORT_NULL;
|
||||
}
|
||||
}
|
||||
|
||||
if ((serverPort == MACH_PORT_NULL) && (localPort == MACH_PORT_NULL)) {
|
||||
runningSharedGraphics = false;
|
||||
[openGLView removeFromSuperview]; // Releases openGLView
|
||||
openGLView = nil;
|
||||
}
|
||||
[ self cleanUpOpenGL ];
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -1206,13 +1290,16 @@ static bool okToDraw;
|
|||
{
|
||||
kr = mach_msg(reply_header, MACH_SEND_MSG, reply_header->msgh_size, 0, MACH_PORT_NULL,
|
||||
0, MACH_PORT_NULL);
|
||||
if(kr != 0)
|
||||
if(kr != 0) {
|
||||
[NSApp terminate:nil];
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
- (kern_return_t)displayFrame:(int32_t)frameIndex surfacemachport:(mach_port_t)iosurface_port
|
||||
{
|
||||
if (!childPid) return 0;
|
||||
|
||||
nextFrameIndex = frameIndex;
|
||||
|
||||
if(!_ioSurfaceBuffers[frameIndex])
|
||||
|
@ -1239,11 +1326,21 @@ static bool okToDraw;
|
|||
_textureNames[frameIndex] = [openGLView setupIOSurfaceTexture:_ioSurfaceBuffers[frameIndex]];
|
||||
}
|
||||
|
||||
okToDraw = true; // Tell drawRect that we have real data to display
|
||||
if (openGLView) {
|
||||
okToDraw = true; // Tell drawRect that we have real data to display
|
||||
|
||||
[openGLView setNeedsDisplay:YES];
|
||||
[openGLView display];
|
||||
[openGLView setNeedsDisplay:YES];
|
||||
[openGLView display];
|
||||
}
|
||||
|
||||
if (gMach_bootstrap_unavailable_to_screensavers && (runningSharedGraphics == false)) {
|
||||
// We have now heard from gfx app so connection has been established
|
||||
runningSharedGraphics = true;
|
||||
if (childPid) {
|
||||
gfxAppStartTime = 0.0;
|
||||
childApp = [NSRunningApplication runningApplicationWithProcessIdentifier:childPid];
|
||||
}
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -1283,8 +1380,9 @@ kern_return_t _MGSDisplayFrame(mach_port_t server_port, int32_t frame_index, mac
|
|||
|
||||
NSOpenGLPixelFormat *pix_fmt = [[NSOpenGLPixelFormat alloc] initWithAttributes:attribs];
|
||||
|
||||
if(!pix_fmt)
|
||||
if(!pix_fmt) {
|
||||
[ NSApp terminate:nil];
|
||||
}
|
||||
|
||||
self = [super initWithFrame:frame pixelFormat:pix_fmt];
|
||||
|
||||
|
@ -1431,12 +1529,6 @@ static bool UseSharedOffscreenBuffer() {
|
|||
static bool needSharedGfxBuffer = false;
|
||||
|
||||
//return true; // FOR TESTING ONLY
|
||||
// As of MacOS 14.0, the legacyScreenSaver sandbox prevents using
|
||||
// IOSurfaceLookupFromMachPort. I have filed bug report FB13300491
|
||||
// with Apple and hope they will change this in future MacOS.
|
||||
if (gCant_Use_Shared_Offscreen_Buffer) {
|
||||
return false;
|
||||
}
|
||||
if (alreadyTested) {
|
||||
return needSharedGfxBuffer;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -51,9 +51,17 @@ int GFX_PidFromScreensaver = 0;
|
|||
pthread_t MonitorParentThread = 0;
|
||||
bool quit_MonitorParentThread = false;
|
||||
|
||||
// struct ss_shmem_data must be kept in sync in these files:
|
||||
// screensaver.cpp
|
||||
// gfx_switcher.cpp
|
||||
// gfx_cleanup.mm
|
||||
// graphics2_unix.cpp
|
||||
struct ss_shmem_data {
|
||||
pid_t gfx_pid;
|
||||
int gfx_slot;
|
||||
int major_version;
|
||||
int minor_version;
|
||||
int release;
|
||||
};
|
||||
|
||||
static struct ss_shmem_data* ss_shmem = NULL;
|
||||
|
@ -122,6 +130,9 @@ void killGfxApp(pid_t thePID) {
|
|||
if (ss_shmem) {
|
||||
rpc->run_graphics_app("stop", ss_shmem->gfx_slot, "");
|
||||
ss_shmem->gfx_slot = -1;
|
||||
ss_shmem->major_version = 0;
|
||||
ss_shmem->minor_version = 0;
|
||||
ss_shmem->release = 0;
|
||||
}
|
||||
|
||||
rpc->close();
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -82,9 +82,17 @@ static void strip_cr(char *buf);
|
|||
|
||||
void * MonitorScreenSaverEngine(void* param);
|
||||
|
||||
// struct ss_shmem_data must be kept in sync in these files:
|
||||
// screensaver.cpp
|
||||
// gfx_switcher.cpp
|
||||
// gfx_cleanup.mm
|
||||
// graphics2_unix.cpp
|
||||
struct ss_shmem_data {
|
||||
pid_t gfx_pid;
|
||||
int gfx_slot;
|
||||
int major_version;
|
||||
int minor_version;
|
||||
int release;
|
||||
};
|
||||
|
||||
static struct ss_shmem_data* ss_shmem = NULL;
|
||||
|
@ -222,6 +230,9 @@ int main(int argc, char** argv) {
|
|||
pthread_cancel(monitorScreenSaverEngineThread);
|
||||
if (ss_shmem != 0) {
|
||||
ss_shmem->gfx_pid = 0;
|
||||
ss_shmem->major_version = 0;
|
||||
ss_shmem->minor_version = 0;
|
||||
ss_shmem->release = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
@ -287,6 +298,9 @@ int main(int argc, char** argv) {
|
|||
pthread_cancel(monitorScreenSaverEngineThread);
|
||||
if (ss_shmem != 0) {
|
||||
ss_shmem ->gfx_pid = 0;
|
||||
ss_shmem->major_version = 0;
|
||||
ss_shmem->minor_version = 0;
|
||||
ss_shmem->release = 0;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -112,8 +112,8 @@ bool gIsCatalina = false; // OS 10.15 or later
|
|||
bool gIsSonoma = false; // OS 14.0 or later
|
||||
|
||||
// As of MacOS 14.0, the legacyScreenSave sandbox
|
||||
// prevents using IOSurfaceLookupFromMachPort.
|
||||
bool gCant_Use_Shared_Offscreen_Buffer = false;
|
||||
// prevents using bootstrap_look_up.
|
||||
bool gMach_bootstrap_unavailable_to_screensavers = false;
|
||||
|
||||
const char * CantLaunchCCMsg = "Unable to launch BOINC application.";
|
||||
const char * LaunchingCCMsg = "Launching BOINC application.";
|
||||
|
@ -128,7 +128,6 @@ const char * DefaultGFXAppCrashedMsg = "Default screensaver module had an unrec
|
|||
const char * RunningOnBatteryMsg = "Computing and screensaver disabled while running on battery power.";
|
||||
const char * IncompatibleMsg = "Could not connect to screensaver ";
|
||||
const char * CCNotRunningMsg = "BOINC is not running.";
|
||||
const char * NoScreenSaverGraphicsThisMacOS = "BOINC can't show screensaver graphics on this version of MacOS";
|
||||
|
||||
//const char * BOINCExitedSaverMode = "BOINC is no longer in screensaver mode.";
|
||||
|
||||
|
@ -207,7 +206,7 @@ void closeBOINCSaver() {
|
|||
}
|
||||
|
||||
|
||||
void incompatibleGfxApp(char * appPath, pid_t pid, int slot){
|
||||
void incompatibleGfxApp(char * appPath, char * wuName, pid_t pid, int slot){
|
||||
char *p;
|
||||
static char buf[1024];
|
||||
static double msgstartTime = 0.0;
|
||||
|
@ -253,8 +252,8 @@ void incompatibleGfxApp(char * appPath, pid_t pid, int slot){
|
|||
} // End if (msgstartTime == 0.0)
|
||||
|
||||
if (msgstartTime && (getDTime() - msgstartTime > 5.0)) {
|
||||
gspScreensaver->markAsIncompatible(appPath);
|
||||
launchedGfxApp("", 0, -1);
|
||||
gspScreensaver->markAsIncompatible(wuName);
|
||||
launchedGfxApp("", "", 0, -1);
|
||||
msgstartTime = 0.0;
|
||||
gspScreensaver->terminate_v6_screensaver(pid);
|
||||
}
|
||||
|
@ -356,7 +355,6 @@ CScreensaver::CScreensaver() {
|
|||
GetDefaultDisplayPeriods(periods);
|
||||
m_bShow_default_ss_first = periods.Show_default_ss_first;
|
||||
|
||||
|
||||
m_fGFXDefaultPeriod = periods.GFXDefaultPeriod;
|
||||
m_fGFXSciencePeriod = periods.GFXSciencePeriod;
|
||||
m_fGFXChangePeriod = periods.GFXChangePeriod;
|
||||
|
@ -479,11 +477,6 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
|
|||
return NOTEXTLOGOFREQUENCY;
|
||||
}
|
||||
|
||||
if (gCant_Use_Shared_Offscreen_Buffer) {
|
||||
gspScreensaver->setSSMessageText(NoScreenSaverGraphicsThisMacOS);
|
||||
goto msgIsSet;
|
||||
}
|
||||
|
||||
CheckDualGPUPowerSource();
|
||||
|
||||
switch (saverState) {
|
||||
|
@ -654,7 +647,6 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) {
|
|||
}
|
||||
}
|
||||
|
||||
msgIsSet:
|
||||
if (m_MessageText[0]) {
|
||||
newFrequency = TEXTLOGOFREQUENCY;
|
||||
} else {
|
||||
|
|
|
@ -1,6 +1,6 @@
|
|||
// This file is part of BOINC.
|
||||
// http://boinc.berkeley.edu
|
||||
// Copyright (C) 2023 University of California
|
||||
// Copyright (C) 2024 University of California
|
||||
//
|
||||
// BOINC is free software; you can redistribute it and/or modify it
|
||||
// under the terms of the GNU Lesser General Public License
|
||||
|
@ -102,13 +102,23 @@ extern pthread_mutex_t saver_mutex;
|
|||
RESULT* graphics_app_result_ptr = NULL;
|
||||
|
||||
#ifdef __APPLE__
|
||||
// struct ss_shmem_data must be kept in sync in these files:
|
||||
// screensaver.cpp
|
||||
// gfx_switcher.cpp
|
||||
// gfx_cleanup.mm
|
||||
// graphics2_unix.cpp
|
||||
struct ss_shmem_data {
|
||||
pid_t gfx_pid;
|
||||
int gfx_slot;
|
||||
int major_version;
|
||||
int minor_version;
|
||||
int release;
|
||||
};
|
||||
|
||||
static struct ss_shmem_data* ss_shmem = NULL;
|
||||
bool canAccessProjectGFXApps = true;
|
||||
static double graphicsAppStartTime;
|
||||
|
||||
#endif
|
||||
|
||||
bool CScreensaver::is_same_task(RESULT* taska, RESULT* taskb) {
|
||||
|
@ -136,10 +146,10 @@ int CScreensaver::count_active_graphic_apps(RESULTS& res, RESULT* exclude) {
|
|||
if (is_same_task(res.results[i], exclude)) continue;
|
||||
#ifdef __APPLE__
|
||||
// Remove it from the vector if incompatible with current version of OS X
|
||||
if (isIncompatible(res.results[i]->graphics_exec_path)) {
|
||||
if (isIncompatible(res.results[i]->wu_name)) {
|
||||
BOINCTRACE(
|
||||
_T("count_active_graphic_apps -- removing incompatible name = '%s', path = '%s'\n"),
|
||||
res.results[i]->name, res.results[i]->graphics_exec_path
|
||||
res.results[i]->wu_name, res.results[i]->graphics_exec_path
|
||||
);
|
||||
RESULT *rp = res.results[i];
|
||||
res.results.erase(res.results.begin()+i);
|
||||
|
@ -211,23 +221,23 @@ CLEANUP:
|
|||
|
||||
|
||||
#ifdef __APPLE__
|
||||
void CScreensaver::markAsIncompatible(char *gfxAppPath) {
|
||||
char *buf = (char *)malloc(strlen(gfxAppPath)+1);
|
||||
void CScreensaver::markAsIncompatible(char *wuName) {
|
||||
char *buf = (char *)malloc(strlen(wuName)+1);
|
||||
if (buf) {
|
||||
strlcpy(buf, gfxAppPath, malloc_size(buf));
|
||||
strlcpy(buf, wuName, malloc_size(buf));
|
||||
m_vIncompatibleGfxApps.push_back(buf);
|
||||
BOINCTRACE(_T("markAsIncompatible -- path = '%s'\n"), gfxAppPath);
|
||||
BOINCTRACE(_T("markAsIncompatible -- wuName = '%s'\n"), wuName);
|
||||
}
|
||||
}
|
||||
|
||||
bool CScreensaver::isIncompatible(char *appPath) {
|
||||
bool CScreensaver::isIncompatible(char *wuName) {
|
||||
unsigned int i = 0;
|
||||
for (i = 0; i < m_vIncompatibleGfxApps.size(); i++) {
|
||||
BOINCTRACE(
|
||||
_T("isIncompatible -- comparing incompatible path '%s' to candidate path %s\n"),
|
||||
m_vIncompatibleGfxApps[i], appPath
|
||||
m_vIncompatibleGfxApps[i], wuName
|
||||
);
|
||||
if (strcmp(m_vIncompatibleGfxApps[i], appPath) == 0) {
|
||||
if (strcmp(m_vIncompatibleGfxApps[i], wuName) == 0) {
|
||||
return true;
|
||||
}
|
||||
}
|
||||
|
@ -266,7 +276,7 @@ int CScreensaver::launch_screensaver(RESULT* rp, PROCESS_REF& graphics_applicati
|
|||
// V6 Graphics
|
||||
#ifdef __APPLE__
|
||||
graphics_application = 0;
|
||||
|
||||
graphicsAppStartTime = 0;
|
||||
// As of OS 10.15 (Catalina) screensavers can no longer:
|
||||
// - launch apps that run setuid or setgid
|
||||
// - launch apps downloaded from the Internet which have not been
|
||||
|
@ -300,7 +310,8 @@ int CScreensaver::launch_screensaver(RESULT* rp, PROCESS_REF& graphics_applicati
|
|||
fflush(m_gfx_Cleanup_IPC);
|
||||
|
||||
if (graphics_application) {
|
||||
launchedGfxApp(rp->graphics_exec_path, graphics_application, rp->slot);
|
||||
graphicsAppStartTime = getDTime();
|
||||
launchedGfxApp(rp->graphics_exec_path, rp->wu_name, graphics_application, rp->slot);
|
||||
}
|
||||
#else
|
||||
char* argv[3];
|
||||
|
@ -324,6 +335,7 @@ int CScreensaver::launch_screensaver(RESULT* rp, PROCESS_REF& graphics_applicati
|
|||
//
|
||||
int CScreensaver::terminate_v6_screensaver(PROCESS_REF graphics_application) {
|
||||
#ifdef __APPLE__
|
||||
static bool in_terminate_v6_screensaver = false;
|
||||
pid_t thePID;
|
||||
|
||||
// As of OS 10.15 (Catalina) screensavers can no longer launch apps
|
||||
|
@ -338,31 +350,41 @@ int CScreensaver::terminate_v6_screensaver(PROCESS_REF graphics_application) {
|
|||
// able to just call kill_program(graphics_application).
|
||||
//
|
||||
int ignore;
|
||||
|
||||
if (graphics_application == 0) return 0;
|
||||
|
||||
graphicsAppStartTime = 0; // Prevent triggering markAsIncompatible in HasProcessExited()
|
||||
// MUTEX may help prevent crashes when terminating an older gfx app which
|
||||
// we were displaying using CGWindowListCreateImage under OS X >= 10.13
|
||||
// Also prevents reentry when called from our other thread
|
||||
pthread_mutex_lock(&saver_mutex);
|
||||
|
||||
thePID = graphics_application;
|
||||
// fprintf(stderr, "stopping pid %d\n", thePID);
|
||||
if (in_terminate_v6_screensaver) {
|
||||
pthread_mutex_unlock(&saver_mutex);
|
||||
return 0;
|
||||
}
|
||||
|
||||
in_terminate_v6_screensaver = true;
|
||||
// print_to_log_file( "stopping pid %d\n", thePID);
|
||||
rpc->run_graphics_app("stop", thePID, gUserName);
|
||||
|
||||
// Inform our helper app that we have stopped current graphics app
|
||||
fprintf(m_gfx_Cleanup_IPC, "0\n");
|
||||
fflush(m_gfx_Cleanup_IPC);
|
||||
|
||||
launchedGfxApp("", 0, -1);
|
||||
|
||||
for (int i=0; i<200; i++) {
|
||||
boinc_sleep(0.01); // Wait 2 seconds max
|
||||
if (HasProcessExited(graphics_application, ignore)) {
|
||||
break;
|
||||
}
|
||||
}
|
||||
// For safety, call kill_process() even under Apple sandbox security
|
||||
if (graphics_application) {
|
||||
kill_process(graphics_application);
|
||||
}
|
||||
|
||||
launchedGfxApp("", "", 0, -1);
|
||||
|
||||
pthread_mutex_unlock(&saver_mutex);
|
||||
in_terminate_v6_screensaver = false;
|
||||
#endif
|
||||
|
||||
#ifdef _WIN32
|
||||
|
@ -377,10 +399,10 @@ int CScreensaver::terminate_v6_screensaver(PROCESS_REF graphics_application) {
|
|||
kill_process(graphics_application);
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
// For safety, call kill_process() even under Apple sandbox security
|
||||
kill_process(graphics_application);
|
||||
#endif
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
@ -436,7 +458,7 @@ int CScreensaver::launch_default_screensaver(char *dir_path, PROCESS_REF& graphi
|
|||
fflush(m_gfx_Cleanup_IPC);
|
||||
|
||||
if (graphics_application) {
|
||||
launchedGfxApp("boincscr", graphics_application, -1);
|
||||
launchedGfxApp("boincscr", "", graphics_application, -1);
|
||||
}
|
||||
|
||||
BOINCTRACE(_T("launch_default_screensaver returned %d\n"), retval);
|
||||
|
@ -540,6 +562,9 @@ DataMgmtProcType CScreensaver::DataManagementProc() {
|
|||
graphics_app_result_ptr = NULL;
|
||||
|
||||
#ifdef __APPLE__
|
||||
for (int i = 0; i < m_vIncompatibleGfxApps.size(); i++) {
|
||||
free(m_vIncompatibleGfxApps[i]);
|
||||
}
|
||||
m_vIncompatibleGfxApps.clear();
|
||||
default_ss_dir_path = "/Library/Application Support/BOINC Data";
|
||||
char shmem_name[MAXPATHLEN];
|
||||
|
@ -551,6 +576,9 @@ DataMgmtProcType CScreensaver::DataManagementProc() {
|
|||
chmod(shmem_name, 0666);
|
||||
ss_shmem->gfx_pid = 0;
|
||||
ss_shmem->gfx_slot = -1;
|
||||
ss_shmem->major_version = 0;
|
||||
ss_shmem->minor_version = 0;
|
||||
ss_shmem->release = 0;
|
||||
}
|
||||
|
||||
if (!IsUserMemberOfGroup(gUserName, "boinc_master")) canAccessProjectGFXApps = false;
|
||||
|
@ -680,11 +708,15 @@ DataMgmtProcType CScreensaver::DataManagementProc() {
|
|||
// BOINCTRACE(_T("CScreensaver::Ending Default phase: now=%f, default_phase_start_time=%f, default_saver_duration_in_science_phase=%f\n"),
|
||||
// dtime(), default_phase_start_time, default_saver_duration_in_science_phase);
|
||||
ss_phase = SCIENCE_SS_PHASE;
|
||||
default_phase_start_time = 0;
|
||||
default_phase_start_time = 0;
|
||||
default_saver_duration_in_science_phase = 0;
|
||||
science_phase_start_time = dtime();
|
||||
if (m_bDefault_gfx_running) {
|
||||
default_saver_start_time_in_science_phase = science_phase_start_time;
|
||||
for (int i = 0; i < m_vIncompatibleGfxApps.size(); i++) {
|
||||
free(m_vIncompatibleGfxApps[i]);
|
||||
}
|
||||
m_vIncompatibleGfxApps.clear();
|
||||
}
|
||||
switch_to_default_gfx = false;
|
||||
}
|
||||
|
@ -945,7 +977,7 @@ DataMgmtProcType CScreensaver::DataManagementProc() {
|
|||
m_bDefault_gfx_running = false;
|
||||
m_bScience_gfx_running = false;
|
||||
#ifdef __APPLE__
|
||||
launchedGfxApp("", 0, -1);
|
||||
launchedGfxApp("", "", 0, -1);
|
||||
#endif
|
||||
continue;
|
||||
}
|
||||
|
@ -976,6 +1008,12 @@ bool CScreensaver::HasProcessExited(pid_t pid, int &exitCode) {
|
|||
if (ss_shmem) {
|
||||
if (ss_shmem->gfx_pid != 0) return false;
|
||||
if (ss_shmem->gfx_slot > -1) { // -1 means Default GFX, which has no slot number
|
||||
if (graphicsAppStartTime && ((getDTime() - graphicsAppStartTime) < 2)) {
|
||||
if (graphics_app_result_ptr && graphics_app_result_ptr->graphics_exec_path) {
|
||||
markAsIncompatible(graphics_app_result_ptr->wu_name);
|
||||
|
||||
}
|
||||
}
|
||||
// Graphics apps called by screensaver or Manager (via Show
|
||||
// Graphics button) now write files in their slot directory as
|
||||
// the logged in user, not boinc_master. This ugly hack tells
|
||||
|
@ -983,6 +1021,9 @@ bool CScreensaver::HasProcessExited(pid_t pid, int &exitCode) {
|
|||
rpc->run_graphics_app("stop", ss_shmem->gfx_slot, "");
|
||||
ss_shmem->gfx_pid = 0;
|
||||
ss_shmem->gfx_slot = -1;
|
||||
ss_shmem->major_version = 0;
|
||||
ss_shmem->minor_version = 0;
|
||||
ss_shmem->release = 0;
|
||||
}
|
||||
|
||||
}
|
||||
|
@ -1034,3 +1075,19 @@ void CScreensaver::GetDefaultDisplayPeriods(struct ss_periods &periods) {
|
|||
periods.GFXChangePeriod
|
||||
);
|
||||
}
|
||||
|
||||
|
||||
#ifdef __APPLE__
|
||||
// compareBOINCLibVersionTo(x, y) returns:
|
||||
// -1 if the library version is less than x.y
|
||||
// 0 if the library version is equal to x.y
|
||||
// +1 if the library version is lgreater than x.y
|
||||
int compareBOINCLibVersionTo(int toMajor, int toMinor) {
|
||||
if (ss_shmem->major_version < toMajor) return -1;
|
||||
if (ss_shmem->major_version > toMajor) return 1;
|
||||
// if (major == toMajor) compare minor version numbers
|
||||
if (ss_shmem->minor_version < toMinor) return -1;
|
||||
if (ss_shmem->minor_version > toMinor) return 1;
|
||||
return 0;
|
||||
}
|
||||
#endif
|
||||
|
|
Loading…
Reference in New Issue