Merge pull request #7173 from electron/windows-system-color

Add an app API method to fetch the system ColorizationColor
This commit is contained in:
Cheng Zhao 2016-09-20 14:06:21 +09:00 committed by GitHub
commit 77fdc67235
6 changed files with 169 additions and 13 deletions

View file

@ -9,27 +9,20 @@
#include "atom/common/node_includes.h" #include "atom/common/node_includes.h"
#include "native_mate/dictionary.h" #include "native_mate/dictionary.h"
#if defined(OS_WIN)
#include "ui/base/win/shell.h"
#endif
namespace atom { namespace atom {
namespace api { namespace api {
SystemPreferences::SystemPreferences(v8::Isolate* isolate) { SystemPreferences::SystemPreferences(v8::Isolate* isolate) {
Init(isolate); Init(isolate);
#if defined(OS_WIN)
InitializeWindow();
#endif
} }
SystemPreferences::~SystemPreferences() { SystemPreferences::~SystemPreferences() {
} }
#if defined(OS_WIN)
bool SystemPreferences::IsAeroGlassEnabled() {
return ui::win::IsAeroGlassEnabled();
}
#endif
#if !defined(OS_MACOSX) #if !defined(OS_MACOSX)
bool SystemPreferences::IsDarkMode() { bool SystemPreferences::IsDarkMode() {
return false; return false;
@ -48,6 +41,7 @@ void SystemPreferences::BuildPrototype(
prototype->SetClassName(mate::StringToV8(isolate, "SystemPreferences")); prototype->SetClassName(mate::StringToV8(isolate, "SystemPreferences"));
mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate())
#if defined(OS_WIN) #if defined(OS_WIN)
.SetMethod("getAccentColor", &SystemPreferences::GetAccentColor)
.SetMethod("isAeroGlassEnabled", &SystemPreferences::IsAeroGlassEnabled) .SetMethod("isAeroGlassEnabled", &SystemPreferences::IsAeroGlassEnabled)
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
.SetMethod("postNotification", .SetMethod("postNotification",

View file

@ -29,6 +29,17 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences> {
#if defined(OS_WIN) #if defined(OS_WIN)
bool IsAeroGlassEnabled(); bool IsAeroGlassEnabled();
typedef HRESULT (STDAPICALLTYPE *DwmGetColorizationColor)(DWORD *, BOOL *);
DwmGetColorizationColor dwmGetColorizationColor =
(DwmGetColorizationColor) GetProcAddress(LoadLibraryW(L"dwmapi.dll"),
"DwmGetColorizationColor");
std::string GetAccentColor();
void InitializeWindow();
#elif defined(OS_MACOSX) #elif defined(OS_MACOSX)
using NotificationCallback = base::Callback< using NotificationCallback = base::Callback<
void(const std::string&, const base::DictionaryValue&)>; void(const std::string&, const base::DictionaryValue&)>;
@ -64,6 +75,25 @@ class SystemPreferences : public mate::EventEmitter<SystemPreferences> {
#endif #endif
private: private:
#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_;
std::string current_color_;
#endif
DISALLOW_COPY_AND_ASSIGN(SystemPreferences); DISALLOW_COPY_AND_ASSIGN(SystemPreferences);
}; };

View file

@ -0,0 +1,93 @@
// Copyright (c) 2014 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_system_preferences.h"
#include "base/win/wrapped_window_proc.h"
#include "ui/base/win/shell.h"
#include "ui/gfx/win/hwnd_util.h"
namespace atom {
namespace {
const wchar_t kSystemPreferencesWindowClass[] =
L"Electron_SystemPreferencesHostWindow";
} // namespace
namespace api {
bool SystemPreferences::IsAeroGlassEnabled() {
return ui::win::IsAeroGlassEnabled();
}
std::string hexColorDWORDToRGBA(DWORD color) {
std::ostringstream stream;
stream << std::hex << color;
std::string hexColor = stream.str();
return hexColor.substr(2) + hexColor.substr(0, 2);
}
std::string SystemPreferences::GetAccentColor() {
DWORD color = 0;
BOOL opaque = FALSE;
if (FAILED(dwmGetColorizationColor(&color, &opaque))) {
return "";
}
return hexColorDWORDToRGBA(color);
}
void SystemPreferences::InitializeWindow() {
WNDCLASSEX window_class;
base::win::InitializeWindowClass(
kSystemPreferencesWindowClass,
&base::win::WrappedWindowProc<SystemPreferences::WndProcStatic>,
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 system
// colorization color. Create a hidden WS_POPUP window instead of an
// HWND_MESSAGE window, because only top-level windows such as popups can
// receive broadcast messages like "WM_DWMCOLORIZATIONCOLORCHANGED".
window_ = CreateWindow(MAKEINTATOM(atom_),
0, WS_POPUP, 0, 0, 0, 0, 0, 0, instance_, 0);
gfx::CheckWindowCreated(window_);
gfx::SetWindowUserData(window_, this);
}
LRESULT CALLBACK SystemPreferences::WndProcStatic(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
SystemPreferences* msg_wnd = reinterpret_cast<SystemPreferences*>(
GetWindowLongPtr(hwnd, GWLP_USERDATA));
if (msg_wnd)
return msg_wnd->WndProc(hwnd, message, wparam, lparam);
else
return ::DefWindowProc(hwnd, message, wparam, lparam);
}
LRESULT CALLBACK SystemPreferences::WndProc(HWND hwnd,
UINT message,
WPARAM wparam,
LPARAM lparam) {
if (message == WM_DWMCOLORIZATIONCOLORCHANGED) {
DWORD new_color = (DWORD) wparam;
std::string new_color_string = hexColorDWORDToRGBA(new_color);
if (new_color_string != current_color_) {
Emit("accent-color-changed", hexColorDWORDToRGBA(new_color));
current_color_ = new_color_string;
}
}
return ::DefWindowProc(hwnd, message, wparam, lparam);
}
} // namespace api
} // namespace atom

View file

@ -7,6 +7,19 @@ const {systemPreferences} = require('electron')
console.log(systemPreferences.isDarkMode()) console.log(systemPreferences.isDarkMode())
``` ```
## Events
The `systemPreferences` object emits the following events:
### Event: 'accent-color-changed' _Windows_
Returns:
* `event` Event
* `newColor` String - The new RGBA color the user assigned to be there system
accent color.
## Methods ## Methods
### `systemPreferences.isDarkMode()` _macOS_ ### `systemPreferences.isDarkMode()` _macOS_
@ -124,3 +137,16 @@ if (browserOptions.transparent) {
``` ```
[dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx [dwm-composition]:https://msdn.microsoft.com/en-us/library/windows/desktop/aa969540.aspx
### `SystemPreferences.getAccentColor()` _Windows_
Returns the users current system wide color preference in the form of an RGBA
hexadecimal string.
```js
const color = app.getSystemAccentColor() // `"aabbccdd"`
const red = color.substr(0, 2) // "aa"
const green = color.substr(2, 2) // "bb"
const blue = color.substr(4, 2) // "cc"
const alpha = color.substr(6, 2) // "dd"
```

View file

@ -127,6 +127,7 @@
'atom/browser/api/atom_api_system_preferences.cc', 'atom/browser/api/atom_api_system_preferences.cc',
'atom/browser/api/atom_api_system_preferences.h', 'atom/browser/api/atom_api_system_preferences.h',
'atom/browser/api/atom_api_system_preferences_mac.mm', 'atom/browser/api/atom_api_system_preferences_mac.mm',
'atom/browser/api/atom_api_system_preferences_win.cc',
'atom/browser/api/atom_api_tray.cc', 'atom/browser/api/atom_api_tray.cc',
'atom/browser/api/atom_api_tray.h', 'atom/browser/api/atom_api_tray.h',
'atom/browser/api/atom_api_web_contents.cc', 'atom/browser/api/atom_api_web_contents.cc',

View file

@ -3,11 +3,23 @@ const {remote} = require('electron')
const {systemPreferences} = remote const {systemPreferences} = remote
describe('systemPreferences module', function () { describe('systemPreferences module', function () {
describe('systemPreferences.getAccentColor', function () {
if (process.platform !== 'win32') {
return
}
it('should return a non-empty string', function () {
let accentColor = systemPreferences.getAccentColor()
assert.notEqual(accentColor, null)
assert(accentColor.length > 0)
})
})
describe('systemPreferences.getUserDefault(key, type)', function () {
if (process.platform !== 'darwin') { if (process.platform !== 'darwin') {
return return
} }
describe('systemPreferences.getUserDefault(key, type)', function () {
it('returns values for known user defaults', function () { it('returns values for known user defaults', function () {
let locale = systemPreferences.getUserDefault('AppleLocale', 'string') let locale = systemPreferences.getUserDefault('AppleLocale', 'string')
assert.notEqual(locale, null) assert.notEqual(locale, null)