electron_api_system_preferences_win.cc 7.8 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229
  1. // Copyright (c) 2014 GitHub, Inc.
  2. // Use of this source code is governed by the MIT license that can be
  3. // found in the LICENSE file.
  4. #include <iomanip>
  5. #include <string_view>
  6. #include <dwmapi.h>
  7. #include <windows.devices.enumeration.h>
  8. #include <wrl/client.h>
  9. #include "shell/browser/api/electron_api_system_preferences.h"
  10. #include "base/containers/fixed_flat_map.h"
  11. #include "base/win/core_winrt_util.h"
  12. #include "base/win/windows_types.h"
  13. #include "base/win/wrapped_window_proc.h"
  14. #include "shell/common/color_util.h"
  15. #include "shell/common/process_util.h"
  16. #include "ui/gfx/color_utils.h"
  17. #include "ui/gfx/win/hwnd_util.h"
  18. namespace electron {
  19. namespace {
  20. const wchar_t kSystemPreferencesWindowClass[] =
  21. L"Electron_SystemPreferencesHostWindow";
  22. using ABI::Windows::Devices::Enumeration::DeviceAccessStatus;
  23. using ABI::Windows::Devices::Enumeration::DeviceClass;
  24. using ABI::Windows::Devices::Enumeration::IDeviceAccessInformation;
  25. using ABI::Windows::Devices::Enumeration::IDeviceAccessInformationStatics;
  26. using Microsoft::WRL::ComPtr;
  27. DeviceAccessStatus GetDeviceAccessStatus(DeviceClass device_class) {
  28. ComPtr<IDeviceAccessInformationStatics> dev_access_info_statics;
  29. HRESULT hr = base::win::GetActivationFactory<
  30. IDeviceAccessInformationStatics,
  31. RuntimeClass_Windows_Devices_Enumeration_DeviceAccessInformation>(
  32. &dev_access_info_statics);
  33. if (FAILED(hr)) {
  34. VLOG(1) << "IDeviceAccessInformationStatics failed: " << hr;
  35. return DeviceAccessStatus::DeviceAccessStatus_Allowed;
  36. }
  37. ComPtr<IDeviceAccessInformation> dev_access_info;
  38. hr = dev_access_info_statics->CreateFromDeviceClass(device_class,
  39. &dev_access_info);
  40. if (FAILED(hr)) {
  41. VLOG(1) << "IDeviceAccessInformation failed: " << hr;
  42. return DeviceAccessStatus::DeviceAccessStatus_Allowed;
  43. }
  44. auto status = DeviceAccessStatus::DeviceAccessStatus_Unspecified;
  45. dev_access_info->get_CurrentStatus(&status);
  46. return status;
  47. }
  48. std::string ConvertDeviceAccessStatus(DeviceAccessStatus value) {
  49. switch (value) {
  50. case DeviceAccessStatus::DeviceAccessStatus_Unspecified:
  51. return "not-determined";
  52. case DeviceAccessStatus::DeviceAccessStatus_Allowed:
  53. return "granted";
  54. case DeviceAccessStatus::DeviceAccessStatus_DeniedBySystem:
  55. return "restricted";
  56. case DeviceAccessStatus::DeviceAccessStatus_DeniedByUser:
  57. return "denied";
  58. default:
  59. return "unknown";
  60. }
  61. }
  62. } // namespace
  63. namespace api {
  64. bool SystemPreferences::IsAeroGlassEnabled() {
  65. return true;
  66. }
  67. std::string hexColorDWORDToRGBA(DWORD color) {
  68. DWORD rgba = color << 8 | color >> 24;
  69. std::ostringstream stream;
  70. stream << std::hex << std::setw(8) << std::setfill('0') << rgba;
  71. return stream.str();
  72. }
  73. std::string SystemPreferences::GetAccentColor() {
  74. DWORD color = 0;
  75. BOOL opaque = FALSE;
  76. if (FAILED(DwmGetColorizationColor(&color, &opaque))) {
  77. return "";
  78. }
  79. return hexColorDWORDToRGBA(color);
  80. }
  81. std::string SystemPreferences::GetColor(gin_helper::ErrorThrower thrower,
  82. const std::string& color) {
  83. static constexpr auto Lookup = base::MakeFixedFlatMap<std::string_view, int>({
  84. {"3d-dark-shadow", COLOR_3DDKSHADOW},
  85. {"3d-face", COLOR_3DFACE},
  86. {"3d-highlight", COLOR_3DHIGHLIGHT},
  87. {"3d-light", COLOR_3DLIGHT},
  88. {"3d-shadow", COLOR_3DSHADOW},
  89. {"active-border", COLOR_ACTIVEBORDER},
  90. {"active-caption", COLOR_ACTIVECAPTION},
  91. {"active-caption-gradient", COLOR_GRADIENTACTIVECAPTION},
  92. {"app-workspace", COLOR_APPWORKSPACE},
  93. {"button-text", COLOR_BTNTEXT},
  94. {"caption-text", COLOR_CAPTIONTEXT},
  95. {"desktop", COLOR_DESKTOP},
  96. {"disabled-text", COLOR_GRAYTEXT},
  97. {"highlight", COLOR_HIGHLIGHT},
  98. {"highlight-text", COLOR_HIGHLIGHTTEXT},
  99. {"hotlight", COLOR_HOTLIGHT},
  100. {"inactive-border", COLOR_INACTIVEBORDER},
  101. {"inactive-caption", COLOR_INACTIVECAPTION},
  102. {"inactive-caption-gradient", COLOR_GRADIENTINACTIVECAPTION},
  103. {"inactive-caption-text", COLOR_INACTIVECAPTIONTEXT},
  104. {"info-background", COLOR_INFOBK},
  105. {"info-text", COLOR_INFOTEXT},
  106. {"menu", COLOR_MENU},
  107. {"menu-highlight", COLOR_MENUHILIGHT},
  108. {"menu-text", COLOR_MENUTEXT},
  109. {"menubar", COLOR_MENUBAR},
  110. {"scrollbar", COLOR_SCROLLBAR},
  111. {"window", COLOR_WINDOW},
  112. {"window-frame", COLOR_WINDOWFRAME},
  113. {"window-text", COLOR_WINDOWTEXT},
  114. });
  115. if (const auto* iter = Lookup.find(color); iter != Lookup.end())
  116. return ToRGBAHex(color_utils::GetSysSkColor(iter->second));
  117. thrower.ThrowError("Unknown color: " + color);
  118. return "";
  119. }
  120. std::string SystemPreferences::GetMediaAccessStatus(
  121. gin_helper::ErrorThrower thrower,
  122. const std::string& media_type) {
  123. if (media_type == "camera") {
  124. return ConvertDeviceAccessStatus(
  125. GetDeviceAccessStatus(DeviceClass::DeviceClass_VideoCapture));
  126. } else if (media_type == "microphone") {
  127. return ConvertDeviceAccessStatus(
  128. GetDeviceAccessStatus(DeviceClass::DeviceClass_AudioCapture));
  129. } else if (media_type == "screen") {
  130. return ConvertDeviceAccessStatus(
  131. DeviceAccessStatus::DeviceAccessStatus_Allowed);
  132. } else {
  133. thrower.ThrowError("Invalid media type");
  134. return {};
  135. }
  136. }
  137. void SystemPreferences::InitializeWindow() {
  138. if (electron::IsUtilityProcess())
  139. return;
  140. // Wait until app is ready before creating sys color listener
  141. // Creating this listener before the app is ready causes global shortcuts
  142. // to not fire
  143. if (Browser::Get()->is_ready())
  144. color_change_listener_ =
  145. std::make_unique<gfx::ScopedSysColorChangeListener>(this);
  146. else
  147. Browser::Get()->AddObserver(this);
  148. WNDCLASSEX window_class;
  149. base::win::InitializeWindowClass(
  150. kSystemPreferencesWindowClass,
  151. &base::win::WrappedWindowProc<SystemPreferences::WndProcStatic>, 0, 0, 0,
  152. nullptr, nullptr, nullptr, nullptr, nullptr, &window_class);
  153. instance_ = window_class.hInstance;
  154. atom_ = RegisterClassEx(&window_class);
  155. // Create an offscreen window for receiving broadcast messages for the system
  156. // colorization color. Create a hidden WS_POPUP window instead of an
  157. // HWND_MESSAGE window, because only top-level windows such as popups can
  158. // receive broadcast messages like "WM_DWMCOLORIZATIONCOLORCHANGED".
  159. window_ = CreateWindow(MAKEINTATOM(atom_), 0, WS_POPUP, 0, 0, 0, 0, 0, 0,
  160. instance_, 0);
  161. gfx::CheckWindowCreated(window_, ::GetLastError());
  162. gfx::SetWindowUserData(window_, this);
  163. }
  164. LRESULT CALLBACK SystemPreferences::WndProcStatic(HWND hwnd,
  165. UINT message,
  166. WPARAM wparam,
  167. LPARAM lparam) {
  168. auto* msg_wnd = reinterpret_cast<SystemPreferences*>(
  169. GetWindowLongPtr(hwnd, GWLP_USERDATA));
  170. if (msg_wnd)
  171. return msg_wnd->WndProc(hwnd, message, wparam, lparam);
  172. else
  173. return ::DefWindowProc(hwnd, message, wparam, lparam);
  174. }
  175. LRESULT CALLBACK SystemPreferences::WndProc(HWND hwnd,
  176. UINT message,
  177. WPARAM wparam,
  178. LPARAM lparam) {
  179. if (message == WM_DWMCOLORIZATIONCOLORCHANGED) {
  180. DWORD new_color = (DWORD)wparam;
  181. std::string new_color_string = hexColorDWORDToRGBA(new_color);
  182. if (new_color_string != current_color_) {
  183. Emit("accent-color-changed", hexColorDWORDToRGBA(new_color));
  184. current_color_ = new_color_string;
  185. }
  186. }
  187. return ::DefWindowProc(hwnd, message, wparam, lparam);
  188. }
  189. void SystemPreferences::OnSysColorChange() {
  190. Emit("color-changed");
  191. }
  192. void SystemPreferences::OnFinishLaunching(base::Value::Dict launch_info) {
  193. color_change_listener_ =
  194. std::make_unique<gfx::ScopedSysColorChangeListener>(this);
  195. }
  196. } // namespace api
  197. } // namespace electron