Skip to content

Commit 927ff36

Browse files
committed
Support osx idle on screensaver, screenlock
Add fah-screen-agent Support idle/not idle notifications Add tools.scons
1 parent 976ba11 commit 927ff36

File tree

11 files changed

+589
-10
lines changed

11 files changed

+589
-10
lines changed

.gitignore

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
*.app
2222

2323
# Build byproducts
24+
/bin
2425
/build
2526
/package.txt
2627
/package-description.txt

SConstruct

Lines changed: 13 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -67,12 +67,15 @@ if env['PLATFORM'] == 'win32' or int(env.get('cross_mingw', 0)):
6767
duplicate = 0)
6868
Default(hide_console)
6969

70+
tools = SConscript('src/tools.scons', variant_dir = 'build', duplicate = 0)
71+
Default(tools)
72+
Depends(tools, client)
7073
# Clean
71-
Clean(client, ['build', 'config.log'])
74+
Clean(client, ['bin', 'build', 'config.log'])
7275

7376
# Dist
7477
docs = ['README.md', 'CHANGELOG.md', 'LICENSE']
75-
distfiles = docs + [client, 'images/fahlogo.png']
78+
distfiles = docs + client + tools + ['images/fahlogo.png']
7679
if env['PLATFORM'] == 'posix':
7780
distfiles.append('install/lin/fah-client.service')
7881
if hide_console is not None: distfiles.append(hide_console)
@@ -116,26 +119,32 @@ if 'package' in COMMAND_LINE_TARGETS:
116119
home = '.', # abs path or relative to PWD
117120
pkg_scripts = 'build/install/osx/scripts', # relative to home
118121
root = './build/pkg/root', # abs path or relative to PWD
119-
sign_tools = ['usr/local/bin/fah-client'], # relative to root
122+
sign_tools = ['usr/local/bin/*'], # relative to root
120123
must_close_apps = [
121124
'org.foldingathome.fahviewer',
122125
'org.foldingathome.fahcontrol',
123126
'edu.stanford.folding.fahviewer',
124127
'edu.stanford.folding.fahcontrol',
125128
],
126129
pkg_files = [
127-
[str(client[0]), 'usr/local/bin/', 0o755],
128130
['build/install/osx/fahclient.url',
129131
'Applications/Folding@home/[email protected]', 0o644],
130132
['build/install/osx/uninstall.url',
131133
'Applications/Folding@home/uninstall.url', 0o644],
134+
['build/install/osx/fah-screen-agent.plist',
135+
'Library/LaunchAgents/' +
136+
'org.foldingathome.fah-screen-agent.plist', 0o644],
132137
['build/install/osx/launchd.plist',
133138
'Library/LaunchDaemons/' +
134139
'org.foldingathome.fahclient.plist', 0o644]
135140
],
136141
pre_sign_callback = seticon,
137142
)]
138143

144+
pkg_files = pkg_components[0]['pkg_files']
145+
for tool in client + tools:
146+
pkg_files += [[str(tool), 'usr/local/bin/', 0o755]]
147+
139148
# min pkg target macos 10.13
140149
pkg_target = env.get('osx_min_ver', '10.13')
141150
ver = tuple([int(x) for x in pkg_target.split('.')])

install/osx/fah-screen-agent.plist

Lines changed: 25 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,25 @@
1+
<?xml version="1.0" encoding="UTF-8"?>
2+
<!DOCTYPE plist PUBLIC "-//Apple//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
3+
<plist version="1.0">
4+
<dict>
5+
<key>KeepAlive</key>
6+
<dict>
7+
<key>SuccessfulExit</key>
8+
<false/>
9+
</dict>
10+
<key>Label</key>
11+
<string>org.foldingathome.fah-screen-agent</string>
12+
<key>LimitLoadToSessionType</key>
13+
<string>Aqua</string>
14+
<key>LowPriorityIO</key>
15+
<true/>
16+
<key>Program</key>
17+
<string>/usr/local/bin/fah-screen-agent</string>
18+
<key>RunAtLoad</key>
19+
<true/>
20+
<key>StandardOutPath</key>
21+
<string>/dev/null</string>
22+
<key>Umask</key>
23+
<integer>18</integer>
24+
</dict>
25+
</plist>

install/osx/scripts/postinstall

Lines changed: 13 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -11,12 +11,24 @@ chmod -R u+rwX,go-w "$RUN_DIR"
1111
chown -R nobody:nobody "$RUN_DIR"
1212

1313
PLIST=/Library/LaunchDaemons/org.foldingathome.fahclient.plist
14+
AGENT_PLIST="/Library/LaunchAgents/org.foldingathome.fah-screen-agent.plist"
1415

1516
"$SCRIPTS"/organize-credits.sh &
1617

1718
# Start service
18-
chmod 0644 "$PLIST"
19+
chmod 0644 "$PLIST" "$AGENT_PLIST"
1920
launchctl load -w "$PLIST"
2021

2122
# start, in case RunAtLoad is false
2223
launchctl start org.foldingathome.fahclient || true
24+
25+
# restart any running agents in other sessions
26+
# note that this does not reload their launchd jobs
27+
killall -HUP fah-screen-agent || true
28+
29+
# start agent in user's gui session
30+
conuser=$(/usr/bin/stat -f "%Su" /dev/console) || conuser="root"
31+
conuid=$(/usr/bin/id -u "$conuser") || conuid=0
32+
if [[ $conuid != 0 ]]; then
33+
launchctl bootstrap gui/$conuid "$AGENT_PLIST" || true
34+
fi

install/osx/scripts/preinstall

Lines changed: 10 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,7 @@ SCRIPTS="$(dirname "$0")"
1010
OLD_LAUNCHD="/Library/LaunchDaemons/FAHClient.plist"
1111
OLD_LAUNCHD2="/Library/LaunchDaemons/edu.stanford.folding.fahclient.plist"
1212
NEW_LAUNCHD="/Library/LaunchDaemons/org.foldingathome.fahclient.plist"
13+
AGENT_PLIST="/Library/LaunchAgents/org.foldingathome.fah-screen-agent.plist"
1314

1415
if [ -f "$NEW_LAUNCHD" ]; then
1516
launchctl unload -w "$NEW_LAUNCHD" || true
@@ -23,6 +24,15 @@ if [ -f "$OLD_LAUNCHD" ]; then
2324
rm -f "$OLD_LAUNCHD" || true
2425
fi
2526

27+
if [ -f "$AGENT_PLIST" ]; then
28+
# stop agent running in console user's session and unload job
29+
conuser=$(/usr/bin/stat -f "%Su" /dev/console) || conuser="root"
30+
conuid=$(/usr/bin/id -u "$conuser") || conuid=0
31+
if [[ $conuid != 0 ]]; then
32+
launchctl bootout gui/$conuid "$AGENT_PLIST" || true
33+
fi
34+
fi
35+
2636
# Assuming upgrade, remove old stuff
2737
F1="/Applications/FAHClient.url"
2838
F2="/Applications/Folding@home/Web Control.url"

src/fah/client/osx/OSXOSImpl.cpp

Lines changed: 70 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -46,6 +46,8 @@
4646
#include <pwd.h>
4747
#include <unistd.h>
4848

49+
#include <fah/screen-agent/defines.h>
50+
4951
using namespace FAH::Client;
5052
using namespace cb;
5153
using namespace std;
@@ -60,6 +62,9 @@ enum {
6062

6163

6264
namespace {
65+
CFStringRef kScreenIdle = CFSTR(SCREEN_IDLE_NOTIFICATION);
66+
CFStringRef kScreenNotIdle = CFSTR(SCREEN_NOT_IDLE_NOTIFICATION);
67+
6368
#pragma mark c callbacks
6469
void consoleUserCB(SCDynamicStoreRef s, CFArrayRef keys, void *info) {
6570
OSXOSImpl::instance().consoleUserChanged(s, keys, info);
@@ -85,6 +90,20 @@ namespace {
8590
<< CFStringGetCStringPtr(name, kCFStringEncodingUTF8));
8691
OSXOSImpl::instance().requestExit();
8792
}
93+
94+
95+
void screenIdleCB(CFNotificationCenterRef center, void *observer,
96+
CFNotificationName name, const void *object,
97+
CFDictionaryRef info) {
98+
OSXOSImpl::instance().noteScreenIdle();
99+
}
100+
101+
102+
void screenNotIdleCB(CFNotificationCenterRef center, void *observer,
103+
CFNotificationName name, const void *object,
104+
CFDictionaryRef info) {
105+
OSXOSImpl::instance().noteScreenNotIdle();
106+
}
88107
}
89108

90109

@@ -187,9 +206,10 @@ void OSXOSImpl::finishInit() {
187206

188207

189208
void OSXOSImpl::updateSystemIdle() {
190-
bool shouldBeIdle = displayPower == kDisplayPowerOff || loginwindowIsActive ||
191-
screensaverIsActive || screenIsLocked;
192-
209+
bool shouldBeIdle;
210+
if (gotScreenNotIdleRecently()) shouldBeIdle = false;
211+
else shouldBeIdle = displayPower == kDisplayPowerOff || loginwindowIsActive ||
212+
gotScreenIdleRecently();
193213
if (shouldBeIdle == systemIsIdle) return;
194214
systemIsIdle = shouldBeIdle;
195215

@@ -415,10 +435,57 @@ bool OSXOSImpl::registerForConsoleUserNotifications() {
415435
}
416436

417437

438+
void OSXOSImpl::noteScreenIdle() {
439+
screenIdleExpiry =
440+
dispatch_time(DISPATCH_TIME_NOW, SCREEN_NOTIFICATION_EXPIRES * NSEC_PER_SEC);
441+
bool wasIdle = screenIdle;
442+
screenIdle = true;
443+
dispatch_after(screenIdleExpiry + NSEC_PER_SEC, dispatch_get_main_queue(), ^{
444+
updateSystemIdle();
445+
});
446+
if (!wasIdle) delayedUpdateSystemIdle(5);
447+
}
448+
449+
450+
void OSXOSImpl::noteScreenNotIdle() {
451+
screenNotIdleExpiry =
452+
dispatch_time(DISPATCH_TIME_NOW, SCREEN_NOTIFICATION_EXPIRES * NSEC_PER_SEC);
453+
screenNotIdle = true;
454+
dispatch_after(screenNotIdleExpiry + NSEC_PER_SEC,dispatch_get_main_queue(),^{
455+
updateSystemIdle();
456+
});
457+
updateSystemIdle();
458+
}
459+
460+
461+
bool OSXOSImpl::gotScreenIdleRecently() {
462+
if (!screenIdle) return false;
463+
if (dispatch_time(DISPATCH_TIME_NOW, 0) < screenIdleExpiry) return true;
464+
screenIdle = false;
465+
return false;
466+
}
467+
468+
469+
bool OSXOSImpl::gotScreenNotIdleRecently() {
470+
if (!screenNotIdle) return false;
471+
if (dispatch_time(DISPATCH_TIME_NOW, 0) < screenNotIdleExpiry) return true;
472+
screenNotIdle = false;
473+
return false;
474+
}
475+
476+
418477
bool OSXOSImpl::registerForDarwinNotifications() {
419478
CFNotificationCenterRef nc = CFNotificationCenterGetDarwinNotifyCenter();
420479
if (!nc) return false;
421480

481+
CFNotificationCenterAddObserver(
482+
nc, (void *)this, &screenIdleCB, kScreenIdle, 0,
483+
CFNotificationSuspensionBehaviorCoalesce);
484+
485+
CFNotificationCenterAddObserver(
486+
nc, (void *)this, &screenNotIdleCB, kScreenNotIdle, 0,
487+
CFNotificationSuspensionBehaviorCoalesce);
488+
422489
string user = "nobody";
423490
struct passwd *pwent = getpwuid(getuid());
424491
if (pwent && pwent->pw_name) user = pwent->pw_name;

src/fah/client/osx/OSXOSImpl.h

Lines changed: 10 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -47,8 +47,6 @@ namespace FAH {
4747
static OSXOSImpl *singleton;
4848

4949
std::atomic<bool> systemIsIdle = false;
50-
bool screensaverIsActive = false;
51-
bool screenIsLocked = false;
5250
bool loginwindowIsActive = false;
5351

5452
io_service_t displayWrangler = 0;
@@ -62,6 +60,12 @@ namespace FAH {
6260

6361
int displayPower = 0;
6462

63+
// these are notification received bools; both are needed
64+
bool screenIdle = false;
65+
bool screenNotIdle = false;
66+
dispatch_time_t screenIdleExpiry = 0;
67+
dispatch_time_t screenNotIdleExpiry = 0;
68+
6569
public:
6670
OSXOSImpl(App &app);
6771
~OSXOSImpl();
@@ -82,12 +86,16 @@ namespace FAH {
8286
void displayPowerChanged
8387
(void *context, io_service_t service, natural_t mtype, void *marg);
8488
void finishInit();
89+
void noteScreenIdle();
90+
void noteScreenNotIdle();
8591

8692
protected:
8793
void initialize();
8894
void addHeartbeatTimerToRunLoop(CFRunLoopRef loop);
8995
void deregisterForConsoleUserNotifications();
9096
bool registerForConsoleUserNotifications();
97+
bool gotScreenIdleRecently();
98+
bool gotScreenNotIdleRecently();
9199
bool registerForDarwinNotifications();
92100
void deregisterForDisplayPowerNotifications();
93101
bool registerForDisplayPowerNotifications();

src/fah/screen-agent/defines.h

Lines changed: 39 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,39 @@
1+
/******************************************************************************\
2+
3+
This file is part of the Folding@home Client.
4+
5+
The fah-client runs Folding@home protein folding simulations.
6+
Copyright (c) 2001-2023, foldingathome.org
7+
All rights reserved.
8+
9+
This program is free software; you can redistribute it and/or modify
10+
it under the terms of the GNU General Public License as published by
11+
the Free Software Foundation; either version 3 of the License, or
12+
(at your option) any later version.
13+
14+
This program is distributed in the hope that it will be useful,
15+
but WITHOUT ANY WARRANTY; without even the implied warranty of
16+
MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
17+
GNU General Public License for more details.
18+
19+
You should have received a copy of the GNU General Public License along
20+
with this program; if not, write to the Free Software Foundation, Inc.,
21+
51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.
22+
23+
For information regarding this software email:
24+
Joseph Coffland
25+
26+
27+
\******************************************************************************/
28+
29+
#pragma once
30+
31+
// Defines shared with fah-client
32+
33+
#define SCREEN_IDLE_NOTIFICATION "org.foldingathome.screen.idle"
34+
#define SCREEN_NOT_IDLE_NOTIFICATION "org.foldingathome.screen.notidle"
35+
36+
#define SCREEN_NOTIFICATION_INTERVAL 60
37+
#define SCREEN_NOTIFICATION_LEEWAY 2
38+
#define SCREEN_NOTIFICATION_EXPIRES (\
39+
SCREEN_NOTIFICATION_INTERVAL + 2 * SCREEN_NOTIFICATION_LEEWAY + 1)

0 commit comments

Comments
 (0)