Index: remoting/host/curtain_mode_mac.cc |
diff --git a/remoting/host/curtain_mode_mac.cc b/remoting/host/curtain_mode_mac.cc |
index 07e186de57c1516549f3a0afb94cd4bb86ed268c..a7dedff6ea1ba109f6cec6cd41a4d2b110337788 100644 |
--- a/remoting/host/curtain_mode_mac.cc |
+++ b/remoting/host/curtain_mode_mac.cc |
@@ -18,30 +18,37 @@ const char* kCGSessionPath = |
namespace remoting { |
-CurtainMode::CurtainMode() : event_handler_(NULL) { |
+CurtainMode::CurtainMode(const base::Closure& on_session_activate, |
+ const base::Closure& on_error) |
+ : on_session_activate_(on_session_activate), |
+ on_error_(on_error), |
+ connection_active_(false), |
+ event_handler_(NULL) { |
} |
CurtainMode::~CurtainMode() { |
- if (event_handler_) { |
- RemoveEventHandler(event_handler_); |
- } |
+ SetEnabled(false); |
} |
-bool CurtainMode::Init(const base::Closure& on_session_activate) { |
- DCHECK(on_session_activate_.is_null()); |
- on_session_activate_ = on_session_activate; |
- EventTypeSpec event; |
- event.eventClass = kEventClassSystem; |
- event.eventKind = kEventSystemUserSessionActivated; |
- OSStatus result = InstallApplicationEventHandler( |
- NewEventHandlerUPP(SessionActivateHandler), 1, &event, this, |
- &event_handler_); |
- return result == noErr; |
+void CurtainMode::SetEnabled(bool enabled) { |
+ if (enabled) { |
+ if (connection_active_) { |
+ if (!ActivateCurtain()) { |
+ on_error_.Run(); |
+ } |
+ } |
+ } else { |
+ RemoveEventHandler(); |
+ } |
} |
-void CurtainMode::OnClientAuthenticated(const std::string& jid) { |
- // If the current session is attached to the console and is not showing |
- // the logon screen then switch it out to ensure privacy. |
+bool CurtainMode::ActivateCurtain() { |
+ // Try to install the switch-in handler. Do this before switching out the |
+ // current session so that the console session is not affected if it fails. |
+ if (!InstallEventHandler()) { |
+ return false; |
+ } |
+ |
base::mac::ScopedCFTypeRef<CFDictionaryRef> session( |
CGSessionCopyCurrentDictionary()); |
const void* on_console = CFDictionaryGetValue(session, |
@@ -55,8 +62,29 @@ void CurtainMode::OnClientAuthenticated(const std::string& jid) { |
} else if (child > 0) { |
int status = 0; |
waitpid(child, &status, 0); |
+ if (status != 0) { |
+ LOG(ERROR) << kCGSessionPath << " failed."; |
+ return false; |
+ } |
+ } else { |
+ LOG(ERROR) << "fork() failed."; |
+ return false; |
} |
} |
+ return true; |
+} |
+ |
+// TODO(jamiewalch): This code assumes at most one client connection at a time. |
+// Add OnFirstClientConnected and OnLastClientDisconnected optional callbacks |
+// to the HostStatusObserver interface to address this. |
+void CurtainMode::OnClientAuthenticated(const std::string& jid) { |
+ connection_active_ = true; |
+ SetEnabled(true); |
+} |
+ |
+void CurtainMode::OnClientDisconnected(const std::string& jid) { |
+ SetEnabled(false); |
+ connection_active_ = false; |
} |
OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, |
@@ -68,9 +96,28 @@ OSStatus CurtainMode::SessionActivateHandler(EventHandlerCallRef handler, |
} |
void CurtainMode::OnSessionActivate() { |
- if (!on_session_activate_.is_null()) { |
- on_session_activate_.Run(); |
+ on_session_activate_.Run(); |
+} |
+ |
+bool CurtainMode::InstallEventHandler() { |
+ OSStatus result = noErr; |
+ if (!event_handler_) { |
+ EventTypeSpec event; |
+ event.eventClass = kEventClassSystem; |
+ event.eventKind = kEventSystemUserSessionActivated; |
+ result = ::InstallApplicationEventHandler( |
+ NewEventHandlerUPP(SessionActivateHandler), 1, &event, this, |
+ &event_handler_); |
+ } |
+ return result == noErr; |
+} |
+ |
+bool CurtainMode::RemoveEventHandler() { |
+ OSStatus result = noErr; |
+ if (event_handler_) { |
+ result = ::RemoveEventHandler(event_handler_); |
} |
+ return result == noErr; |
} |
} // namespace remoting |