diff --git a/atom/browser/api/atom_api_power_monitor.cc b/atom/browser/api/atom_api_power_monitor.cc index 5c28000b4..8145a0950 100644 --- a/atom/browser/api/atom_api_power_monitor.cc +++ b/atom/browser/api/atom_api_power_monitor.cc @@ -46,6 +46,9 @@ PowerMonitor::PowerMonitor(v8::Isolate* isolate) { #endif base::PowerMonitor::Get()->AddObserver(this); Init(isolate); +#if defined(OS_MACOSX) || defined(OS_WIN) + InitPlatformSpecificMonitors(); +#endif } PowerMonitor::~PowerMonitor() { diff --git a/atom/browser/api/atom_api_power_monitor.h b/atom/browser/api/atom_api_power_monitor.h index b4f43d244..c7a6169d8 100644 --- a/atom/browser/api/atom_api_power_monitor.h +++ b/atom/browser/api/atom_api_power_monitor.h @@ -36,6 +36,10 @@ class PowerMonitor : public mate::TrackableObject, void UnblockShutdown(); #endif +#if defined(OS_MACOSX) || defined(OS_WIN) + void InitPlatformSpecificMonitors(); +#endif + // base::PowerObserver implementations: void OnPowerStateChange(bool on_battery_power) override; void OnSuspend() override; @@ -47,6 +51,28 @@ class PowerMonitor : public mate::TrackableObject, const ui::IdleCallback& callback); void QuerySystemIdleTime(const ui::IdleTimeCallback& callback); +#if defined(OS_WIN) + // Static callback invoked when a message comes in to our messaging window. + static LRESULT CALLBACK WndProcStatic(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + LRESULT CALLBACK WndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam); + + // The window class of |window_|. + ATOM atom_; + + // The handle of the module that contains the window procedure of |window_|. + HMODULE instance_; + + // The window used for processing events. + HWND window_; +#endif + DISALLOW_COPY_AND_ASSIGN(PowerMonitor); }; diff --git a/atom/browser/api/atom_api_power_monitor_mac.mm b/atom/browser/api/atom_api_power_monitor_mac.mm new file mode 100644 index 000000000..821f20578 --- /dev/null +++ b/atom/browser/api/atom_api_power_monitor_mac.mm @@ -0,0 +1,74 @@ +// Copyright (c) 2013 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_power_monitor.h" + +#include +#import + +@interface MacLockMonitor : NSObject { +@private + std::vector emitters; +} + +- (void)addEmitter:(atom::api::PowerMonitor*)monitor_; + +@end + +@implementation MacLockMonitor + +- (id)init { + if ((self = [super init])) { + NSDistributedNotificationCenter* distCenter = + [NSDistributedNotificationCenter defaultCenter]; + [distCenter addObserver:self + selector:@selector(onScreenLocked:) + name:@"com.apple.screenIsLocked" + object:nil]; + [distCenter addObserver:self + selector:@selector(onScreenUnlocked:) + name:@"com.apple.screenIsUnlocked" + object:nil]; + } + return self; +} + +- (void)dealloc { + [[NSDistributedNotificationCenter defaultCenter] removeObserver:self]; + [super dealloc]; +} + +- (void)addEmitter:(atom::api::PowerMonitor*)monitor_ { + self->emitters.push_back(monitor_); +} + +- (void)onScreenLocked:(NSNotification*)notification { + for (auto& emitter : self->emitters) { + emitter->Emit("lock-screen"); + } +} + +- (void)onScreenUnlocked:(NSNotification*)notification { + for (auto& emitter : self->emitters) { + emitter->Emit("unlock-screen"); + } +} + +@end + +namespace atom { + +namespace api { + +static MacLockMonitor* g_lock_monitor = nil; + +void PowerMonitor::InitPlatformSpecificMonitors() { + if (!g_lock_monitor) + g_lock_monitor = [[MacLockMonitor alloc] init]; + [g_lock_monitor addEmitter:this]; +} + +} // namespace api + +} // namespace atom diff --git a/atom/browser/api/atom_api_power_monitor_win.cc b/atom/browser/api/atom_api_power_monitor_win.cc new file mode 100644 index 000000000..6889968c2 --- /dev/null +++ b/atom/browser/api/atom_api_power_monitor_win.cc @@ -0,0 +1,71 @@ +// Copyright (c) 2013 GitHub, Inc. +// Use of this source code is governed by the MIT license that can be +// found in the LICENSE file. + +#include "atom/browser/api/atom_api_power_monitor.h" + +#include "base/win/wrapped_window_proc.h" +#include "ui/base/win/shell.h" +#include "ui/gfx/win/hwnd_util.h" +#include "Wtsapi32.h" + +namespace atom { + +namespace { + +const wchar_t kPowerMonitorWindowClass[] = + L"Electron_PowerMonitorHostWindow"; + +} // namespace + +namespace api { + +void PowerMonitor::InitPlatformSpecificMonitors() { + WNDCLASSEX window_class; + base::win::InitializeWindowClass( + kPowerMonitorWindowClass, + &base::win::WrappedWindowProc, 0, 0, 0, + NULL, NULL, NULL, NULL, NULL, &window_class); + instance_ = window_class.hInstance; + atom_ = RegisterClassEx(&window_class); + + // Create an offscreen window for receiving broadcast messages for the + // session lock and unlock events. + window_ = CreateWindow(MAKEINTATOM(atom_), 0, 0, 0, 0, 0, 0, HWND_MESSAGE, 0, + instance_, 0); + gfx::CheckWindowCreated(window_); + gfx::SetWindowUserData(window_, this); + + // Tel windows we want to be notified with session events + WTSRegisterSessionNotification(window_, NOTIFY_FOR_THIS_SESSION); +} + +LRESULT CALLBACK PowerMonitor::WndProcStatic(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + PowerMonitor* msg_wnd = reinterpret_cast( + GetWindowLongPtr(hwnd, GWLP_USERDATA)); + if (msg_wnd) + return msg_wnd->WndProc(hwnd, message, wparam, lparam); + else + return ::DefWindowProc(hwnd, message, wparam, lparam); +} + +LRESULT CALLBACK PowerMonitor::WndProc(HWND hwnd, + UINT message, + WPARAM wparam, + LPARAM lparam) { + if (message == WM_WTSSESSION_CHANGE) { + if (wparam == WTS_SESSION_LOCK) { + Emit("lock-screen"); + } else if (wparam == WTS_SESSION_UNLOCK) { + Emit("unlock-screen"); + } + } + return ::DefWindowProc(hwnd, message, wparam, lparam); +} + +} // namespace api + +} // namespace atom diff --git a/docs/api/power-monitor.md b/docs/api/power-monitor.md index 16927da66..4f45031d5 100644 --- a/docs/api/power-monitor.md +++ b/docs/api/power-monitor.md @@ -47,6 +47,14 @@ invokes `e.preventDefault()`, Electron will attempt to delay system shutdown in order for the app to exit cleanly. If `e.preventDefault()` is called, the app should exit as soon as possible by calling something like `app.quit()`. +### Event: 'lock-screen' _macOS_ _Windows_ + +Emitted when the system is about to lock the screen. + +### Event: 'unlock-screen' _macOS_ _Windows_ + +Emitted as soon as the systems screen is unlocked. + ## Methods The `powerMonitor` module has the following methods: diff --git a/electron.gyp b/electron.gyp index 875000cf7..62dfef265 100644 --- a/electron.gyp +++ b/electron.gyp @@ -165,6 +165,9 @@ # of /SUBSYSTEM:WINDOWS,5.02 'MinimumRequiredVersion': '5.02', 'SubSystem': '2', + 'AdditionalDependencies': [ + 'wtsapi32.lib', + ], }, }, 'copies': [ diff --git a/filenames.gypi b/filenames.gypi index b04c41ad7..47ad0abc3 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -136,6 +136,8 @@ 'atom/browser/api/atom_api_net.h', 'atom/browser/api/atom_api_notification.cc', 'atom/browser/api/atom_api_notification.h', + 'atom/browser/api/atom_api_power_monitor_mac.mm', + 'atom/browser/api/atom_api_power_monitor_win.cc', 'atom/browser/api/atom_api_power_monitor.cc', 'atom/browser/api/atom_api_power_monitor.h', 'atom/browser/api/atom_api_power_save_blocker.cc',