From cc2168ce6ff20a5f0658d67d81c088b70d5e047e Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Sat, 28 Oct 2023 05:30:49 -0700 Subject: [PATCH 1/2] Mac screensaver: update for MacOS 14.0 Sonoma --- clientscr/Mac_Saver_Module.h | 6 +- clientscr/Mac_Saver_ModuleView.h | 5 +- clientscr/Mac_Saver_ModuleView.m | 185 ++++++++++++++++----------- clientscr/gfx_cleanup.mm | 10 +- clientscr/gfx_switcher.cpp | 20 +-- clientscr/mac_saver_module.cpp | 43 ++++++- clientscr/res/mac_restrict_access.sb | 2 + 7 files changed, 178 insertions(+), 93 deletions(-) diff --git a/clientscr/Mac_Saver_Module.h b/clientscr/Mac_Saver_Module.h index 777b68db02..7b8c27ce63 100644 --- a/clientscr/Mac_Saver_Module.h +++ b/clientscr/Mac_Saver_Module.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2020 University of California +// Copyright (C) 2023 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 @@ -40,6 +40,7 @@ int startBOINCSaver(void); int getSSMessage(char **theMessage, int* coveredFreq); void windowIsCovered(); void drawPreview(CGContextRef myContext); +void stopAllGFXApps(void); void closeBOINCSaver(void); void setDefaultDisplayPeriods(void); bool getShow_default_ss_first(); @@ -61,6 +62,8 @@ extern char gUserName[64]; extern bool gIsMojave; extern bool gIsCatalina; extern bool gIsHighSierra; +extern bool gIsSonoma; +extern bool gCant_Use_Shared_Offscreen_Buffer; #ifdef __cplusplus } // extern "C" @@ -164,6 +167,7 @@ public: int getSSMessage(char **theMessage, int* coveredFreq); void windowIsCovered(void); void drawPreview(CGContextRef myContext); + void Shared_Offscreen_Buffer_Unavailable(void); void ShutdownSaver(); void markAsIncompatible(char *gfxAppName); bool isIncompatible(char *appName); diff --git a/clientscr/Mac_Saver_ModuleView.h b/clientscr/Mac_Saver_ModuleView.h index 452bb24c01..08a2b64eb0 100644 --- a/clientscr/Mac_Saver_ModuleView.h +++ b/clientscr/Mac_Saver_ModuleView.h @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2020 University of California +// Copyright (C) 2023 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 @@ -77,6 +77,7 @@ int startBOINCSaver(void); int getSSMessage(char **theMessage, int* coveredFreq); void windowIsCovered(); void drawPreview(CGContextRef myContext); +void stopAllGFXApps(void); void closeBOINCSaver(void); void setDefaultDisplayPeriods(void); bool getShow_default_ss_first(); @@ -98,6 +99,8 @@ void PrintBacktrace(void); extern bool gIsCatalina; extern bool gIsHighSierra; extern bool gIsMojave; +extern bool gIsSonoma; +extern bool gCant_Use_Shared_Offscreen_Buffer; #ifdef __cplusplus } // extern "C" diff --git a/clientscr/Mac_Saver_ModuleView.m b/clientscr/Mac_Saver_ModuleView.m index 7a462b2c90..a92c1c120e 100644 --- a/clientscr/Mac_Saver_ModuleView.m +++ b/clientscr/Mac_Saver_ModuleView.m @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// Copyright (C) 2023 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 @@ -136,7 +136,6 @@ NSInteger myWindowNumber; NSRect gMovingRect; float gImageXIndent; float gTextBoxHeight; -CGFloat gActualTextBoxHeight; NSPoint gCurrentPosition; NSPoint gCurrentDelta; @@ -196,6 +195,10 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { imageView = nil; } } + } else { + if (gCant_Use_Shared_Offscreen_Buffer) { + stopAllGFXApps(); + } } } @@ -214,6 +217,7 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { gIsMojave = (compareOSVersionTo(10, 14) >= 0); gIsCatalina = (compareOSVersionTo(10, 15) >= 0); gIsBigSur = (compareOSVersionTo(11, 0) >= 0); + gIsSonoma = (compareOSVersionTo(14, 0) >= 0); if (gIsCatalina) { // Under OS 10.15, isPreview is often true even when it shouldn't be @@ -354,8 +358,6 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { gCurrentDelta.x = 1.0; gCurrentDelta.y = 1.0; - gActualTextBoxHeight = MINTEXTBOXHEIGHT; - [ self setAnimationTimeInterval:1/8.0 ]; } @@ -447,12 +449,32 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { NSUInteger n; double maxWaitTime; NSRect currentDrawingRect, eraseRect; + CGFloat actualTextBoxHeight = MINTEXTBOXHEIGHT; NSPoint imagePosition; char *msg; CFStringRef cf_msg; double timeToBlock, frameStartTime = getDTime(); HIThemeTextInfo textInfo; + NSWindow *myWindow = [ self window ]; + NSRect windowFrame = [ myWindow frame ]; + + if (gIsSonoma) { + // Under MacOS 14 Sonoma, screensavers continue to run and "draw" invisibly + // after they are dismissed by user activity, to allow them to be used as + // wallpaper. Since we don't want the BOINC screensaver to be used as wallpaper, + // this would waste system resources. + // The only way I've found to determine that the screensaver has been dismissed + // by the user is this test of the window level. + if ((windowFrame.size.width > 500.) && (windowFrame.size.height > 500.)) { + if ([ [ self window ] level ] == 0) { +//TODO: more cleanup as in stopAnimation ?? + closeBOINCSaver(); + return; + } + } + } + if (myIsPreview) { #if 1 // Currently drawRect just draws our logo in the preview window if (gPreview_Image == NULL) { @@ -474,8 +496,6 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { return; } - NSWindow *myWindow = [ self window ]; - #if ! DEBUG_UNDER_XCODE // For unkown reasons, OS 10.7 Lion screensaver and later delay several seconds // after user activity before calling stopAnimation, so we check user activity here @@ -489,7 +509,6 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { } } - NSRect windowFrame = [ myWindow frame ]; if ( (windowFrame.origin.x != 0) || (windowFrame.origin.y != 0) ) { // Hide window on second display to aid in debugging #ifdef _DEBUG @@ -688,30 +707,18 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { if ( (msg != NULL) && (msg[0] != '\0') ) { - // Set direction of motion to "bounce" off edges of screen - if (currentDrawingRect.origin.x <= SAFETYBORDER) { - gCurrentDelta.x = (float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; - gCurrentDelta.y = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.y)) / 16.; - } - if ( (currentDrawingRect.origin.x + currentDrawingRect.size.width) >= - (viewBounds.origin.x + viewBounds.size.width - SAFETYBORDER) ) { - gCurrentDelta.x = -(float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; - gCurrentDelta.y = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.y)) / 16.; - } - if (currentDrawingRect.origin.y + gTextBoxHeight - gActualTextBoxHeight <= SAFETYBORDER) { - gCurrentDelta.y = (float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; - gCurrentDelta.x = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.x)) / 16.; - } - if ( (currentDrawingRect.origin.y + currentDrawingRect.size.height) >= - (viewBounds.origin.y + viewBounds.size.height - SAFETYBORDER) ) { - gCurrentDelta.y = -(float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; - gCurrentDelta.x = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.x)) / 16.; - } -#if 0 - // For testing - gCurrentDelta.x = 0; - gCurrentDelta.y = 0; -#endif + cf_msg = CFStringCreateWithCString(NULL, msg, kCFStringEncodingMacRoman); + + CTFontRef myFont = CTFontCreateWithName(CFSTR("Helvetica"), 20, NULL); + HIThemeTextInfo theTextInfo = {kHIThemeTextInfoVersionOne, kThemeStateActive, kThemeSpecifiedFont, + kHIThemeTextHorizontalFlushLeft, kHIThemeTextVerticalFlushTop, + kHIThemeTextBoxOptionNone, kHIThemeTextTruncationNone, 0, false, + 0, myFont + }; + textInfo = theTextInfo; + + HIThemeGetTextDimensions(cf_msg, (float)gMovingRect.size.width, &textInfo, NULL, &actualTextBoxHeight, NULL); + gTextBoxHeight = actualTextBoxHeight + TEXTBOXTOPBORDER; if (!isErased) { [[NSColor blackColor] set]; @@ -751,7 +758,34 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { eraseRect = NSInsetRect(eraseRect, -1, -1); NSRectFill(eraseRect); - isErased = true; + isErased = true; + // If text has changed and it now goes below bottom of screen, jump up to show it all. + if ((gCurrentPosition.y - gTextBoxHeight) <= SAFETYBORDER) { + gCurrentPosition.y = SAFETYBORDER + 1 + gTextBoxHeight; + if (gCurrentDelta.y < 0) { + gCurrentDelta.y = (float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; + } + } + + // Set direction of motion to "bounce" off edges of screen + if ( (gCurrentDelta.x < 0) && (gCurrentPosition.x <= SAFETYBORDER) ) { + gCurrentDelta.x = (float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; + gCurrentDelta.y = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.y)) / 16.; + } + if ( (gCurrentDelta.x > 0) && ( (gCurrentPosition.x + gMovingRect.size.width) >= + (viewBounds.origin.x + viewBounds.size.width - SAFETYBORDER) ) ){ + gCurrentDelta.x = -(float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; + gCurrentDelta.y = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.y)) / 16.; + } + if ( (gCurrentDelta.y < 0) && (gCurrentPosition.y - gTextBoxHeight <= SAFETYBORDER) ) { + gCurrentDelta.y = (float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; + gCurrentDelta.x = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.x)) / 16.; + } + if ( (gCurrentDelta.y > 0) && ( (gCurrentPosition.y + gMovingRect.size.height) >= + (viewBounds.origin.y + viewBounds.size.height - SAFETYBORDER) ) ) { + gCurrentDelta.y = -(float)SSRandomIntBetween(MINDELTA, MAXDELTA) / 16.; + gCurrentDelta.x = (float)(SSRandomIntBetween(MINDELTA, MAXDELTA) * signof(gCurrentDelta.x)) / 16.; + } } // Get the new drawing area @@ -762,48 +796,33 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { imagePosition.y = (float) (int)gCurrentPosition.y; [ gBOINC_Logo drawAtPoint:imagePosition fromRect:NSZeroRect operation:NSCompositeCopy fraction:1.0 ]; +#if 0 + // For testing + gCurrentDelta.x = 0; + gCurrentDelta.y = 0; +#endif + CGRect bounds = CGRectMake((float) ((int)gCurrentPosition.x), + viewBounds.size.height - imagePosition.y + TEXTBOXTOPBORDER, + gMovingRect.size.width, + MAXTEXTBOXHEIGHT + ); - if ( (msg != NULL) && (msg[0] != '\0') ) { - cf_msg = CFStringCreateWithCString(NULL, msg, kCFStringEncodingMacRoman); + CGContextSaveGState (myContext); + CGContextTranslateCTM (myContext, 0, viewBounds.origin.y + viewBounds.size.height); + CGContextScaleCTM (myContext, 1.0f, -1.0f); - CGRect bounds = CGRectMake((float) ((int)gCurrentPosition.x), - viewBounds.size.height - imagePosition.y + TEXTBOXTOPBORDER, - gMovingRect.size.width, - MAXTEXTBOXHEIGHT - ); + CGFloat myWhiteComponents[] = {1.0, 1.0, 1.0, 1.0}; + CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB (); + CGColorRef myTextColor = CGColorCreate(myColorSpace, myWhiteComponents); - CGContextSaveGState (myContext); - CGContextTranslateCTM (myContext, 0, viewBounds.origin.y + viewBounds.size.height); - CGContextScaleCTM (myContext, 1.0f, -1.0f); + CGContextSetFillColorWithColor(myContext, myTextColor); - CTFontRef myFont = CTFontCreateWithName(CFSTR("Helvetica"), 20, NULL); + HIThemeDrawTextBox(cf_msg, &bounds, &textInfo, myContext, kHIThemeOrientationNormal); - HIThemeTextInfo theTextInfo = {kHIThemeTextInfoVersionOne, kThemeStateActive, kThemeSpecifiedFont, - kHIThemeTextHorizontalFlushLeft, kHIThemeTextVerticalFlushTop, - kHIThemeTextBoxOptionNone, kHIThemeTextTruncationNone, 0, false, - 0, myFont - }; - textInfo = theTextInfo; - - HIThemeGetTextDimensions(cf_msg, (float)gMovingRect.size.width, &textInfo, NULL, &gActualTextBoxHeight, NULL); - gActualTextBoxHeight += TEXTBOXTOPBORDER; - - CGFloat myWhiteComponents[] = {1.0, 1.0, 1.0, 1.0}; - CGColorSpaceRef myColorSpace = CGColorSpaceCreateDeviceRGB (); - CGColorRef myTextColor = CGColorCreate(myColorSpace, myWhiteComponents); - - CGContextSetFillColorWithColor(myContext, myTextColor); - - HIThemeDrawTextBox(cf_msg, &bounds, &textInfo, myContext, kHIThemeOrientationNormal); - - CGColorRelease(myTextColor); - CGColorSpaceRelease(myColorSpace); - CGContextRestoreGState (myContext); - CFRelease(cf_msg); - } - - gTextBoxHeight = MAXTEXTBOXHEIGHT + TEXTBOXTOPBORDER; - gMovingRect.size.height = [gBOINC_Logo size].height + gTextBoxHeight; + CGColorRelease(myTextColor); + CGColorSpaceRelease(myColorSpace); + CGContextRestoreGState (myContext); + CFRelease(cf_msg); isErased = false; @@ -813,7 +832,6 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { [[NSColor blackColor] set]; isErased = true; NSRectFill(eraseRect); - gTextBoxHeight = MAXTEXTBOXHEIGHT; gMovingRect.size.height = [gBOINC_Logo size].height + gTextBoxHeight; } } @@ -831,7 +849,10 @@ void launchedGfxApp(char * appPath, pid_t thePID, int slot) { // Check for a new graphics app sending us data if (UseSharedOffscreenBuffer() && gfxAppStartTime) { if (mySharedGraphicsController) { - [mySharedGraphicsController testConnection]; + if (!runningSharedGraphics) { + // wait for a connection from a gfx app + [mySharedGraphicsController testConnection]; + } } } } @@ -1089,10 +1110,17 @@ static bool okToDraw; 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(); + } serverPort = MACH_PORT_NULL; } - if(serverPort != MACH_PORT_NULL) + if ((serverPort != MACH_PORT_NULL) && (localPort == MACH_PORT_NULL)) { // Create our own local port. localPort = [[NSMachPort alloc] init]; @@ -1132,14 +1160,14 @@ static bool okToDraw; [serverPort invalidate]; // [serverPort release]; } - serverPort = nil; + serverPort = MACH_PORT_NULL; [localPort removeFromRunLoop:[NSRunLoop currentRunLoop] forMode:NSRunLoopCommonModes]; if ([localPort isValid]) { [localPort invalidate]; } // [localPort release]; - localPort = nil; + localPort = MACH_PORT_NULL; int i; for(i = 0; i < NUM_IOSURFACE_BUFFERS; i++) { @@ -1159,13 +1187,14 @@ static bool okToDraw; } } - if ((serverPort == nil) && (localPort == nil)) { + if ((serverPort == MACH_PORT_NULL) && (localPort == MACH_PORT_NULL)) { runningSharedGraphics = false; [openGLView removeFromSuperview]; // Releases openGLView openGLView = nil; } } } + - (void)handleMachMessage:(void *)msg { union __ReplyUnion___MGCMGSServer_subsystem reply; @@ -1402,6 +1431,12 @@ 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; } diff --git a/clientscr/gfx_cleanup.mm b/clientscr/gfx_cleanup.mm index d4d0fc170a..9ed6455961 100644 --- a/clientscr/gfx_cleanup.mm +++ b/clientscr/gfx_cleanup.mm @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// Copyright (C) 2023 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 @@ -207,7 +207,13 @@ int main(int argc, char* argv[]) { #endif parentPid = getppid(); - bool cover_gfx_window = (compareOSVersionTo(10, 13) >= 0); + // Under MacOS 14.0, the legacyScreenSaver continues to run after the + // screensaver is dismissed. Our code elsewhere now kills it, but if + // that were to fail this black cover would block the user from + // accessing the desktop, so don't use the cover in MacOS 14 for now. + + bool cover_gfx_window = (compareOSVersionTo(10, 13) >= 0) && + (compareOSVersionTo(10, 14) < 0); // Create shared app instance [NSApplication sharedApplication]; diff --git a/clientscr/gfx_switcher.cpp b/clientscr/gfx_switcher.cpp index 5e61389abd..c0b4efdb73 100644 --- a/clientscr/gfx_switcher.cpp +++ b/clientscr/gfx_switcher.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// Copyright (C) 2023 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 @@ -18,9 +18,9 @@ // gfx_switcher.C // // Used by screensaver to: -// - launch graphics application at given slot number as user & group boinc_project -// - launch default graphics application as user & group boinc_project -// - kill graphics application with given process ID as user & group boinc_project +// - launch graphics application at given slot number +// - launch default graphics application +// - kill graphics application with given process ID // // Special logic used only under OS 10.15 Catalina and later: @@ -35,11 +35,11 @@ // app. This script then launches gfx_switcher, which uses fork and execv to // launch the project graphics app. gfx_switcher writes the graphics app's // process ID to shared memory, to be read by the Screensaver Coordinator. -// gfx_switcher waits for the graphics app to exit and notifies then notifies -// the Screensaver Coordinator by writing 0 to the shared memory. +// gfx_switcher waits for the graphics app to exit and then notifies the +// Screensaver Coordinator by writing 0 to the shared memory. // // This Rube Goldberg process is necessary due to limitations on screensavers -// introduced in OS 10.15 Catalina. +// introduced in OS 10.15 Catalina and OS 14.0 Sonoma. // @@ -106,7 +106,7 @@ int main(int argc, char** argv) { CFStringRef cf_gUserName = SCDynamicStoreCopyConsoleUser(NULL, NULL, NULL); CFStringGetCString(cf_gUserName, user_name, sizeof(user_name), kCFStringEncodingUTF8); -// strlcpy(user_name, getlogin(), sizeof(user_name)); +// strlcpy(user_name, getenv("USER"), sizeof(user_name)); strlcpy(group_name, "boinc_project", sizeof(group_name)); // Under fast user switching, the BOINC client may be running under a @@ -319,6 +319,10 @@ void * MonitorScreenSaverEngine(void* param) { print_to_log_file("MonitorScreenSaverEngine: ScreenSaverEngine_Pid=%d", ScreenSaverEngine_Pid); #endif if (ScreenSaverEngine_Pid == 0) { + // legacyScreenSaver name under MacOS 14 Sonoma + ScreenSaverEngine_Pid = getPidIfRunning("com.apple.ScreenSaver.Engine.legacyScreenSaver"); + } + if (ScreenSaverEngine_Pid == 0) { #ifdef __x86_64__ ScreenSaverEngine_Pid = getPidIfRunning("com.apple.ScreenSaver.Engine.legacyScreenSaver.x86_64"); #elif defined(__arm64__) diff --git a/clientscr/mac_saver_module.cpp b/clientscr/mac_saver_module.cpp index 683b085ee3..283effcd35 100644 --- a/clientscr/mac_saver_module.cpp +++ b/clientscr/mac_saver_module.cpp @@ -1,6 +1,6 @@ // This file is part of BOINC. // http://boinc.berkeley.edu -// Copyright (C) 2022 University of California +// Copyright (C) 2023 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 @@ -106,9 +106,14 @@ static pthread_mutexattr_t saver_mutex_attr; pthread_mutex_t saver_mutex; static char passwd_buf[256]; char gUserName[64]; -bool gIsHighSierra = false; // OS 10.13 or later +bool gIsHighSierra = false; // OS 10.13 or later bool gIsMojave = false; // OS 10.14 or later 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; const char * CantLaunchCCMsg = "Unable to launch BOINC application."; const char * LaunchingCCMsg = "Launching BOINC application."; @@ -123,6 +128,7 @@ 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."; @@ -182,6 +188,13 @@ void drawPreview(CGContextRef myContext) { }; +void stopAllGFXApps() { + if (gspScreensaver) { + gspScreensaver->Shared_Offscreen_Buffer_Unavailable(); + } +} + + // If there are multiple displays, this may get called // multiple times (once for each display), so we need to guard // against any problems that may cause. @@ -400,7 +413,7 @@ int CScreensaver::Create() { strlcpy(m_gfx_Cleanup_Path, "\"", sizeof(m_gfx_Cleanup_Path)); strlcat(m_gfx_Cleanup_Path, m_gfx_Switcher_Path, sizeof(m_gfx_Cleanup_Path)); strlcat(m_gfx_Switcher_Path, "/gfx_switcher", sizeof(m_gfx_Switcher_Path)); - strlcat(m_gfx_Cleanup_Path, "/gfx_cleanup\"", sizeof(m_gfx_Switcher_Path)); + strlcat(m_gfx_Cleanup_Path, "/gfx_cleanup\"", sizeof(m_gfx_Cleanup_Path)); // Launch helper app to work around a bug in OS 10.15 Catalina to // kill current graphics app if ScreensaverEngine exits without @@ -466,6 +479,11 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) { return NOTEXTLOGOFREQUENCY; } + if (gCant_Use_Shared_Offscreen_Buffer) { + gspScreensaver->setSSMessageText(NoScreenSaverGraphicsThisMacOS); + goto msgIsSet; + } + CheckDualGPUPowerSource(); switch (saverState) { @@ -636,6 +654,7 @@ int CScreensaver::getSSMessage(char **theMessage, int* coveredFreq) { } } +msgIsSet: if (m_MessageText[0]) { newFrequency = TEXTLOGOFREQUENCY; } else { @@ -657,6 +676,11 @@ void CScreensaver::drawPreview(CGContextRef myContext) { } +void CScreensaver::Shared_Offscreen_Buffer_Unavailable() { + DestroyDataManagementThread(); // Kills current GFX app +} + + void CScreensaver::ShutdownSaver() { DestroyDataManagementThread(); @@ -689,6 +713,14 @@ void CScreensaver::ShutdownSaver() { fflush(m_gfx_Cleanup_IPC); pclose(m_gfx_Cleanup_IPC); } + + // Under MacOS 14.0 Sonoma, screensavers continue to run and "draw" invisibly + // after they are dismissed by user activity, to allow them to be used as + // wallpaper. Since we don't want the BOINC screensaver to be used as wallpaper, + // this would waste system resources. + if (gIsSonoma) { + KillScreenSaver(); + } } @@ -1014,9 +1046,8 @@ void print_to_log_file(const char *format, ...) { char buf[256]; time_t t; #if USE_SPECIAL_LOG_FILE - safe_strcpy(buf, "/Users/"); - safe_strcat(buf, getlogin()); - safe_strcat(buf, "/Documents/test_log.txt"); + safe_strcat(buf, getenv("HOME")); + safe_strcat(buf, "/Documents/ss_test_log.txt"); FILE *f; f = fopen(buf, "a"); if (!f) return; diff --git a/clientscr/res/mac_restrict_access.sb b/clientscr/res/mac_restrict_access.sb index 39798b0a8d..5e0ffac7e6 100644 --- a/clientscr/res/mac_restrict_access.sb +++ b/clientscr/res/mac_restrict_access.sb @@ -6,3 +6,5 @@ (deny file-write* (subpath "/Library/Application Support") ) (allow file-write* (subpath "/Library/Application Support/BOINC Data") (subpath "/private/tmp") ) (allow file-read* (subpath "/Library/Application Support/BOINC Data") (subpath "/private/tmp") ) +(allow file-read* (subpath "/private/var/select/sh") ) +(allow mach-lookup mach-register) From eb0231248cba271a1bb5fbfe4b8c974617c2b600 Mon Sep 17 00:00:00 2001 From: Charlie Fenton Date: Sat, 28 Oct 2023 05:55:06 -0700 Subject: [PATCH 2/2] Mac installer: don't offer to set BOINC as screensaver when running under MacOS 14 Sonoma --- mac_installer/PostInstall.cpp | 37 ++++++++++++++++++++++++----------- 1 file changed, 26 insertions(+), 11 deletions(-) diff --git a/mac_installer/PostInstall.cpp b/mac_installer/PostInstall.cpp index d3683a76fa..131444f59a 100644 --- a/mac_installer/PostInstall.cpp +++ b/mac_installer/PostInstall.cpp @@ -1678,19 +1678,27 @@ OSErr UpdateAllVisibleUsers(long brandID, long oldBrandID) } } - if (! saverAlreadySetForAll) { - if (gCommandLineInstall) { - err = stat("/tmp/setboincsaver.txt", &sbuf); - if (err == noErr) { - puts("setboincsaver.txt file detected\n"); - fflush(stdout); - unlink("/tmp/setboincsaver.txt"); - setSaverForAllUsers = true; - } - } else { - setSaverForAllUsers = ShowMessage(true, + // 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 a future MacOS. + // Also as of MacOS 14.0 Sonoma, we can't set the screensaver + //automatically. I have filed bug report FB13270885 about this. + // See a;so the comment at top of SetScreenSaverSelection(). + if (compareOSVersionTo(14, 0) < 0) { + if (! saverAlreadySetForAll) { + if (gCommandLineInstall) { + err = stat("/tmp/setboincsaver.txt", &sbuf); + if (err == noErr) { + puts("setboincsaver.txt file detected\n"); + fflush(stdout); + unlink("/tmp/setboincsaver.txt"); + setSaverForAllUsers = true; + } + } else { + setSaverForAllUsers = ShowMessage(true, (char *)_("Do you want to set %s as the screensaver for all %s users on this Mac?"), brandName[brandID], brandName[brandID]); + } } } @@ -2008,6 +2016,8 @@ OSErr UpdateAllVisibleUsers(long brandID, long oldBrandID) } +// As of MacOS 14.0 Sonoma, this code no longer will detect the current screensaver, +// and will need to be rewritten. See the comment at top of SetScreenSaverSelection(). OSErr GetCurrentScreenSaverSelection(passwd *pw, char *moduleName, size_t maxLen) { char buf[1024]; FILE *f; @@ -2047,6 +2057,11 @@ OSErr GetCurrentScreenSaverSelection(passwd *pw, char *moduleName, size_t maxLen } +// As of MacOS 14.0 Sonoma, we can't set the screensaver automatically. +// I have filed bug report FB13270885 about this. After this is fixed, +// probably need to put an AppleScript to do this in the launch agent +// we add for each user. See also: +// https://forum.iscreensaver.com/t/understanding-the-macos-sonoma-screensaver-plist/718 OSErr SetScreenSaverSelection(char *moduleName, char *modulePath, int type) { OSErr err = noErr; CFStringRef preferenceName = CFSTR("com.apple.screensaver");