settings_provider_gtk.cc 5.2 KB

123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142
  1. // Copyright 2017 The Chromium Authors. All rights reserved.
  2. // Use of this source code is governed by a BSD-style license that can be
  3. // found in the LICENSE file.
  4. #include "ui/gtk/settings_provider_gtk.h"
  5. #include "base/strings/string_split.h"
  6. #include "gtk_compat.h"
  7. #include "ui/gtk/gtk_compat.h"
  8. #include "ui/gtk/gtk_ui.h"
  9. #include "ui/gtk/gtk_util.h"
  10. namespace gtk {
  11. namespace {
  12. std::string GetDecorationLayoutFromGtkWindow() {
  13. DCHECK(!GtkCheckVersion(4));
  14. GtkCssContext context = GetStyleContextFromCss("");
  15. gtk_style_context_add_class(context, "csd");
  16. gchar* layout_c = nullptr;
  17. GtkStyleContextGetStyle(context, "decoration-button-layout", &layout_c,
  18. nullptr);
  19. DCHECK(layout_c);
  20. std::string layout(layout_c);
  21. g_free(layout_c);
  22. return layout;
  23. }
  24. void ParseActionString(const std::string& value,
  25. GtkUi::WindowFrameAction* action) {
  26. if (value == "none")
  27. *action = ui::LinuxUi::WindowFrameAction::kNone;
  28. else if (value == "lower")
  29. *action = ui::LinuxUi::WindowFrameAction::kLower;
  30. else if (value == "minimize")
  31. *action = ui::LinuxUi::WindowFrameAction::kMinimize;
  32. else if (value == "toggle-maximize")
  33. *action = ui::LinuxUi::WindowFrameAction::kToggleMaximize;
  34. else if (value == "menu")
  35. *action = ui::LinuxUi::WindowFrameAction::kMenu;
  36. }
  37. } // namespace
  38. SettingsProviderGtk::FrameActionSettingWatcher::FrameActionSettingWatcher(
  39. SettingsProviderGtk* settings_provider,
  40. const std::string& setting_name,
  41. ui::LinuxUi::WindowFrameActionSource action_type,
  42. ui::LinuxUi::WindowFrameAction default_action)
  43. : settings_provider_(settings_provider),
  44. setting_name_(setting_name),
  45. action_type_(action_type),
  46. default_action_(default_action) {
  47. GtkSettings* settings = gtk_settings_get_default();
  48. std::string notify_setting = "notify::" + setting_name;
  49. signal_id_ = g_signal_connect(settings, notify_setting.c_str(),
  50. G_CALLBACK(OnSettingChangedThunk), this);
  51. DCHECK(signal_id_);
  52. OnSettingChanged(settings, nullptr);
  53. }
  54. SettingsProviderGtk::FrameActionSettingWatcher::~FrameActionSettingWatcher() {
  55. if (signal_id_)
  56. g_signal_handler_disconnect(gtk_settings_get_default(), signal_id_);
  57. }
  58. void SettingsProviderGtk::FrameActionSettingWatcher::OnSettingChanged(
  59. GtkSettings* settings,
  60. GParamSpec* param) {
  61. std::string value =
  62. GetGtkSettingsStringProperty(settings, setting_name_.c_str());
  63. GtkUi::WindowFrameAction action = default_action_;
  64. ParseActionString(value, &action);
  65. settings_provider_->delegate_->SetWindowFrameAction(action_type_, action);
  66. }
  67. SettingsProviderGtk::SettingsProviderGtk(GtkUi* delegate)
  68. : delegate_(delegate), signal_id_decoration_layout_(0) {
  69. DCHECK(delegate_);
  70. GtkSettings* settings = gtk_settings_get_default();
  71. if (GtkCheckVersion(3, 14)) {
  72. signal_id_decoration_layout_ = g_signal_connect(
  73. settings, "notify::gtk-decoration-layout",
  74. G_CALLBACK(OnDecorationButtonLayoutChangedThunk), this);
  75. DCHECK(signal_id_decoration_layout_);
  76. OnDecorationButtonLayoutChanged(settings, nullptr);
  77. frame_action_setting_watchers_.push_back(
  78. std::make_unique<FrameActionSettingWatcher>(
  79. this, "gtk-titlebar-middle-click",
  80. ui::LinuxUi::WindowFrameActionSource::kMiddleClick,
  81. ui::LinuxUi::WindowFrameAction::kNone));
  82. frame_action_setting_watchers_.push_back(
  83. std::make_unique<FrameActionSettingWatcher>(
  84. this, "gtk-titlebar-double-click",
  85. ui::LinuxUi::WindowFrameActionSource::kDoubleClick,
  86. ui::LinuxUi::WindowFrameAction::kToggleMaximize));
  87. frame_action_setting_watchers_.push_back(
  88. std::make_unique<FrameActionSettingWatcher>(
  89. this, "gtk-titlebar-right-click",
  90. ui::LinuxUi::WindowFrameActionSource::kRightClick,
  91. ui::LinuxUi::WindowFrameAction::kMenu));
  92. } else {
  93. signal_id_decoration_layout_ =
  94. g_signal_connect_after(settings, "notify::gtk-theme-name",
  95. G_CALLBACK(OnThemeChangedThunk), this);
  96. DCHECK(signal_id_decoration_layout_);
  97. OnThemeChanged(settings, nullptr);
  98. }
  99. }
  100. SettingsProviderGtk::~SettingsProviderGtk() {
  101. if (signal_id_decoration_layout_) {
  102. g_signal_handler_disconnect(gtk_settings_get_default(),
  103. signal_id_decoration_layout_);
  104. }
  105. }
  106. void SettingsProviderGtk::SetWindowButtonOrderingFromGtkLayout(
  107. const std::string& gtk_layout) {
  108. std::vector<views::FrameButton> leading_buttons;
  109. std::vector<views::FrameButton> trailing_buttons;
  110. ParseButtonLayout(gtk_layout, &leading_buttons, &trailing_buttons);
  111. delegate_->SetWindowButtonOrdering(leading_buttons, trailing_buttons);
  112. }
  113. void SettingsProviderGtk::OnDecorationButtonLayoutChanged(GtkSettings* settings,
  114. GParamSpec* param) {
  115. SetWindowButtonOrderingFromGtkLayout(
  116. GetGtkSettingsStringProperty(settings, "gtk-decoration-layout"));
  117. }
  118. void SettingsProviderGtk::OnThemeChanged(GtkSettings* settings,
  119. GParamSpec* param) {
  120. std::string layout = GetDecorationLayoutFromGtkWindow();
  121. SetWindowButtonOrderingFromGtkLayout(layout);
  122. }
  123. } // namespace gtk