aboutsummaryrefslogtreecommitdiff
path: root/AppKit/GTMNSWorkspace+ScreenSaver.m
blob: 7ca5d70afb2dca88f5ada2d49f6514ddf0c5415b (plain)
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
106
107
108
109
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
//
//  GTMNSWorkspace+ScreenSaver.m
//
//  Copyright 2006-2008 Google Inc.
//
//  Licensed under the Apache License, Version 2.0 (the "License"); you may not
//  use this file except in compliance with the License.  You may obtain a copy
//  of the License at
// 
//  http://www.apache.org/licenses/LICENSE-2.0
// 
//  Unless required by applicable law or agreed to in writing, software
//  distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
//  WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.  See the
//  License for the specific language governing permissions and limitations under
//  the License.
//

#import <Carbon/Carbon.h>
#import <ScreenSaver/ScreenSaver.h>
#import "GTMNSWorkspace+ScreenSaver.h"
#import "GTMDefines.h"
#import "GTMGarbageCollection.h"

// Interesting class descriptions extracted from ScreenSaver.framework using
// class-dump. Note that these are "not documented".

@protocol ScreenSaverControl

- (BOOL)screenSaverIsRunning;
- (BOOL)screenSaverCanRun;
- (void)setScreenSaverCanRun:(BOOL)fp8;
- (void)screenSaverStartNow;
- (void)screenSaverStopNow;
- (void)restartForUser:(id)fp8;
- (double)screenSaverTimeRemaining;
- (void)screenSaverDidFade;
- (BOOL)screenSaverIsRunningInBackground;
- (void)screenSaverDidFadeInBackground:(BOOL)fp8 
                                 psnHi:(unsigned int)fp12 
                                 psnLow:(unsigned int)fp16;

@end

@interface ScreenSaverController : NSObject <ScreenSaverControl> {
  NSConnection *_connection;
  id _daemonProxy;
  void *_reserved;
}

+ (id)controller;
+ (id)monitor;
+ (id)daemonConnectionName;
+ (id)enginePath;
- (void)_connectionClosed:(id)fp8;
- (id)init;
- (void)dealloc;
- (BOOL)screenSaverIsRunning;
- (BOOL)screenSaverCanRun;
- (void)setScreenSaverCanRun:(BOOL)fp8;
- (void)screenSaverStartNow;
- (void)screenSaverStopNow;
- (void)restartForUser:(id)fp8;
- (double)screenSaverTimeRemaining;
- (void)screenSaverDidFade;
- (BOOL)screenSaverIsRunningInBackground;
- (void)screenSaverDidFadeInBackground:(BOOL)fp8 
                                 psnHi:(unsigned int)fp12 
                                 psnLow:(unsigned int)fp16;

@end

// end of extraction

@implementation NSWorkspace (GTMScreenSaverAddition)
// Check if the screen saver is running.
+ (BOOL)gtm_isScreenSaverActive {
  BOOL answer = NO;
  ScreenSaverController *controller = nil;
  // We're calling into an "undocumented" framework here, so we are going to
  // step rather carefully (and in 10.5.2 it's only 32bit).

#if !__LP64__
  Class screenSaverControllerClass = NSClassFromString(@"ScreenSaverController");
  _GTMDevAssert(screenSaverControllerClass, 
                @"Are you linked with ScreenSaver.framework?"
                " Can't find ScreenSaverController class.");
  if ([screenSaverControllerClass respondsToSelector:@selector(controller)]) {
    controller = [ScreenSaverController controller];
    if (controller) {
      if ([controller respondsToSelector:@selector(screenSaverIsRunning)]) {
        answer = [controller screenSaverIsRunning];
      } else {
        // COV_NF_START
        _GTMDevLog(@"ScreenSaverController no longer supports -screenSaverIsRunning?");  
        controller = nil;
        // COV_NF_END
      }
    }
  }
#endif // !__LP64__
  
  if (!controller) {
    // COV_NF_START
    // If we can't get the controller, chances are we are being run from the
    // command line and don't have access to the window server. As such we are
    // going to fallback to the older method of figuring out if a screen saver
    // is running.
    ProcessSerialNumber psn;
    // Check if the saver is already running
    require_noerr(GetFrontProcess(&psn), CantGetFrontProcess);
    
    CFDictionaryRef cfProcessInfo 
      = ProcessInformationCopyDictionary(&psn, 
                                         kProcessDictionaryIncludeAllInformationMask);
    
    require(cfProcessInfo, CantGetFrontProcess);
    NSDictionary *processInfo = [GTMNSMakeCollectable(cfProcessInfo) autorelease];
    NSString *bundlePath = [processInfo objectForKey:@"BundlePath"];

    // ScreenSaverEngine is the frontmost app if the screen saver is actually
    // running Security Agent is the frontmost app if the "enter password"
    // dialog is showing
    answer = [bundlePath hasSuffix:@"ScreenSaverEngine.app"] || 
             [bundlePath hasSuffix:@"SecurityAgent.app"];
    // COV_NF_END
  }
CantGetFrontProcess:
  return answer;
}

@end