From 5dd5dbb3d8420a060cda3bcb6fe3311d0f3c3904 Mon Sep 17 00:00:00 2001 From: Samuel Attard Date: Sat, 17 Sep 2016 02:00:22 +1000 Subject: [PATCH] Add a systemPreferences API method to fetch the system ColorizationColor This is useful for automatical app theming * Fetches the color from the registry * Returns an empty string if the fetch fails (a falsey value) --- .../api/atom_api_system_preferences.cc | 14 +-- .../browser/api/atom_api_system_preferences.h | 30 ++++++ .../api/atom_api_system_preferences_win.cc | 93 +++++++++++++++++++ filenames.gypi | 1 + 4 files changed, 128 insertions(+), 10 deletions(-) create mode 100644 atom/browser/api/atom_api_system_preferences_win.cc diff --git a/atom/browser/api/atom_api_system_preferences.cc b/atom/browser/api/atom_api_system_preferences.cc index ba6c9720da6e..f0b966e86a87 100644 --- a/atom/browser/api/atom_api_system_preferences.cc +++ b/atom/browser/api/atom_api_system_preferences.cc @@ -9,27 +9,20 @@ #include "atom/common/node_includes.h" #include "native_mate/dictionary.h" -#if defined(OS_WIN) -#include "ui/base/win/shell.h" -#endif - namespace atom { namespace api { SystemPreferences::SystemPreferences(v8::Isolate* isolate) { Init(isolate); + #if defined(OS_WIN) + InitializeWindow(); + #endif } SystemPreferences::~SystemPreferences() { } -#if defined(OS_WIN) -bool SystemPreferences::IsAeroGlassEnabled() { - return ui::win::IsAeroGlassEnabled(); -} -#endif - #if !defined(OS_MACOSX) bool SystemPreferences::IsDarkMode() { return false; @@ -49,6 +42,7 @@ void SystemPreferences::BuildPrototype( mate::ObjectTemplateBuilder(isolate, prototype->PrototypeTemplate()) #if defined(OS_WIN) .SetMethod("isAeroGlassEnabled", &SystemPreferences::IsAeroGlassEnabled) + .SetMethod("getAccentColor", &SystemPreferences::GetAccentColor) #elif defined(OS_MACOSX) .SetMethod("postNotification", &SystemPreferences::PostNotification) diff --git a/atom/browser/api/atom_api_system_preferences.h b/atom/browser/api/atom_api_system_preferences.h index f855ab0ebb3d..e257dc518a31 100644 --- a/atom/browser/api/atom_api_system_preferences.h +++ b/atom/browser/api/atom_api_system_preferences.h @@ -29,6 +29,17 @@ class SystemPreferences : public mate::EventEmitter { #if defined(OS_WIN) 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) using NotificationCallback = base::Callback< void(const std::string&, const base::DictionaryValue&)>; @@ -64,6 +75,25 @@ class SystemPreferences : public mate::EventEmitter { #endif 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); }; diff --git a/atom/browser/api/atom_api_system_preferences_win.cc b/atom/browser/api/atom_api_system_preferences_win.cc new file mode 100644 index 000000000000..0c8e96a8a9c3 --- /dev/null +++ b/atom/browser/api/atom_api_system_preferences_win.cc @@ -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 kSystemPreferencestWindowClass[] = + 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( + kSystemPreferencestWindowClass, + &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 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( + 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 diff --git a/filenames.gypi b/filenames.gypi index 1f4c9e440f2c..88a8dc0510e1 100644 --- a/filenames.gypi +++ b/filenames.gypi @@ -127,6 +127,7 @@ 'atom/browser/api/atom_api_system_preferences.cc', 'atom/browser/api/atom_api_system_preferences.h', '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.h', 'atom/browser/api/atom_api_web_contents.cc',