From 0d2838fcd59c6c04aa2b36e45dcb558e86e23947 Mon Sep 17 00:00:00 2001
From: Nolan Prochnau <parvus.mortalis@gmail.com>
Date: Sat, 19 Dec 2020 12:22:27 -0500
Subject: [PATCH] feat(xkeyboard): Add variant support to layout label (#2163)

* Add variant support to xkeyboard layout label

Solves #316

* Run style checks, I guess?

* Add comment

* Return nothing if there is no variant

* Update CHANGELOG
---
 CHANGELOG.md                   |  2 ++
 include/x11/extensions/xkb.hpp | 11 +++++++----
 src/modules/xkeyboard.cpp      | 17 ++++++++---------
 src/x11/extensions/xkb.cpp     | 17 ++++++++++++++++-
 4 files changed, 33 insertions(+), 14 deletions(-)

diff --git a/CHANGELOG.md b/CHANGELOG.md
index c50feeb9..e5a5abab 100644
--- a/CHANGELOG.md
+++ b/CHANGELOG.md
@@ -33,6 +33,8 @@ and this project adheres to [Semantic Versioning](https://semver.org/spec/v2.0.0
   ([`#2294`](https://github.com/polybar/polybar/issues/2294))
 - `internal/network`: `speed-unit = B/s` can be used to customize how network
   speeds are displayed.
+- `internal/xkeyboard`: `%variant%` can be used to parse the layout variant
+  ([`#316`](https://github.com/polybar/polybar/issues/316))
 
 ### Changed
 - Slight changes to the value ranges the different ramp levels are responsible
diff --git a/include/x11/extensions/xkb.hpp b/include/x11/extensions/xkb.hpp
index 06f7f1ff..603882a9 100644
--- a/include/x11/extensions/xkb.hpp
+++ b/include/x11/extensions/xkb.hpp
@@ -44,7 +44,7 @@ namespace evt {
   using xkb_action_message = xpp::xkb::event::action_message<connection&>;
   using xkb_access_x_notify = xpp::xkb::event::access_x_notify<connection&>;
   using xkb_extension_device_notify = xpp::xkb::event::extension_device_notify<connection&>;
-}
+}  // namespace evt
 
 class keyboard {
  public:
@@ -62,15 +62,18 @@ class keyboard {
   };
 
   explicit keyboard(vector<layout>&& layouts_, map<indicator::type, indicator>&& indicators_, unsigned char group)
-      : layouts(forward<decltype(layouts)>(layouts_)), indicators(forward<decltype(indicators)>(indicators_)), current_group(group) {}
+      : layouts(forward<decltype(layouts)>(layouts_))
+      , indicators(forward<decltype(indicators)>(indicators_))
+      , current_group(group) {}
 
   const indicator& get(const indicator::type& i) const;
   void set(unsigned int state);
   bool on(const indicator::type&) const;
-  void current(unsigned char  group);
+  void current(unsigned char group);
   unsigned char current() const;
   const string group_name(size_t index = 0) const;
   const string layout_name(size_t index = 0) const;
+  const string variant_name(size_t index = 0) const;
   const string indicator_name(const indicator::type&) const;
   size_t size() const;
 
@@ -90,6 +93,6 @@ namespace xkb_util {
   vector<keyboard::layout> get_layouts(connection& conn, xcb_xkb_device_spec_t device);
   map<keyboard::indicator::type, keyboard::indicator> get_indicators(connection& conn, xcb_xkb_device_spec_t device);
   string parse_layout_symbol(string&& name);
-}
+}  // namespace xkb_util
 
 POLYBAR_NS_END
diff --git a/src/modules/xkeyboard.cpp b/src/modules/xkeyboard.cpp
index ebfa9a74..0d160333 100644
--- a/src/modules/xkeyboard.cpp
+++ b/src/modules/xkeyboard.cpp
@@ -1,12 +1,12 @@
 #include "modules/xkeyboard.hpp"
+
 #include "drawtypes/iconset.hpp"
 #include "drawtypes/label.hpp"
+#include "modules/meta/base.inl"
 #include "utils/factory.hpp"
 #include "x11/atoms.hpp"
 #include "x11/connection.hpp"
 
-#include "modules/meta/base.inl"
-
 POLYBAR_NS
 
 namespace modules {
@@ -25,8 +25,6 @@ namespace modules {
    */
   xkeyboard_module::xkeyboard_module(const bar_settings& bar, string name_)
       : static_module<xkeyboard_module>(bar, move(name_)), m_connection(connection::make()) {
-
-
     // Setup extension
     // clang-format off
     m_connection.xkb().select_events_checked(XCB_XKB_ID_USE_CORE_KBD,
@@ -81,7 +79,7 @@ namespace modules {
       m_indicator_icons_on = factory_util::shared<iconset>();
 
       auto icon_pair = string_util::tokenize(m_conf.get(name(), DEFAULT_INDICATOR_ICON, ""s), ';');
-      if(icon_pair.size() == 2) {
+      if (icon_pair.size() == 2) {
         m_indicator_icons_off->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[0]));
         m_indicator_icons_on->add(DEFAULT_INDICATOR_ICON, factory_util::shared<label>(icon_pair[1]));
       } else {
@@ -121,6 +119,7 @@ namespace modules {
     if (m_layout) {
       m_layout->reset_tokens();
       m_layout->replace_token("%name%", m_keyboard->group_name(m_keyboard->current()));
+      m_layout->replace_token("%variant%", m_keyboard->variant_name(m_keyboard->current()));
 
       auto const current_layout = m_keyboard->layout_name(m_keyboard->current());
       auto icon = m_layout_icons->get(current_layout, DEFAULT_LAYOUT_ICON);
@@ -141,9 +140,9 @@ namespace modules {
         }
 
         auto indicator_on = m_keyboard->on(it);
-        auto &indicator_labels = indicator_on ? m_indicator_on_labels : m_indicator_off_labels;
-        auto &indicator_icons = indicator_on ? m_indicator_icons_on : m_indicator_icons_off;
-        auto &indicator_state = indicator_on ? m_indicator_state_on : m_indicator_state_off;
+        auto& indicator_labels = indicator_on ? m_indicator_on_labels : m_indicator_off_labels;
+        auto& indicator_icons = indicator_on ? m_indicator_icons_on : m_indicator_icons_off;
+        auto& indicator_state = indicator_on ? m_indicator_state_on : m_indicator_state_off;
 
         label_t indicator;
         if (indicator_labels.find(it) != indicator_labels.end()) {
@@ -287,6 +286,6 @@ namespace modules {
       update();
     }
   }
-}
+}  // namespace modules
 
 POLYBAR_NS_END
diff --git a/src/x11/extensions/xkb.cpp b/src/x11/extensions/xkb.cpp
index 8695ce51..7ffacafe 100644
--- a/src/x11/extensions/xkb.cpp
+++ b/src/x11/extensions/xkb.cpp
@@ -64,6 +64,21 @@ const string keyboard::layout_name(size_t index) const {
   return layouts[index].symbols[index];
 }
 
+/**
+ * Get current variant name
+ * "GROUP (VARIANT)"
+ *         ^^^^^^^
+ */
+const string keyboard::variant_name(size_t index) const {
+  string group_name = this->group_name(index);
+  if (int start = group_name.find('(') + 1) {
+    int num_chars = group_name.find(')') - start;
+    return group_name.substr(start, num_chars);
+  } else {
+    return "";
+  }
+}
+
 /**
  * Get indicator name
  */
@@ -212,6 +227,6 @@ namespace xkb_util {
     }
     return move(name);
   }
-}
+}  // namespace xkb_util
 
 POLYBAR_NS_END