diff --git a/include/components/builder.hpp b/include/components/builder.hpp
index ebf63f49..5cd8c89c 100644
--- a/include/components/builder.hpp
+++ b/include/components/builder.hpp
@@ -154,7 +154,7 @@ class builder {
     if (!label || !*label)
       return;
 
-    auto text = label->m_text;
+    auto text = label->get();
 
     if (label->m_maxlen > 0 && text.length() > label->m_maxlen) {
       text = text.substr(0, label->m_maxlen) + "...";
diff --git a/include/components/types.hpp b/include/components/types.hpp
index c1d66167..4b2f44dc 100644
--- a/include/components/types.hpp
+++ b/include/components/types.hpp
@@ -105,4 +105,7 @@ struct action_block {
 #endif
 };
 
+struct wmsettings_bspwm {
+};
+
 LEMONBUDDY_NS_END
diff --git a/include/drawtypes/label.hpp b/include/drawtypes/label.hpp
index cf283f23..f12386b0 100644
--- a/include/drawtypes/label.hpp
+++ b/include/drawtypes/label.hpp
@@ -14,23 +14,21 @@ namespace drawtypes {
 
   class label : public non_copyable_mixin<label> {
    public:
-    string m_text{""};
-    string m_foreground{""};
-    string m_background{""};
-    string m_underline{""};
-    string m_overline{""};
-    int m_font{0};
-    int m_padding{0};
-    int m_margin{0};
-    size_t m_maxlen{0};
-    bool m_ellipsis{true};
+    string m_foreground;
+    string m_background;
+    string m_underline;
+    string m_overline;
+    int m_font = 0;
+    int m_padding = 0;
+    int m_margin = 0;
+    size_t m_maxlen = 0;
+    bool m_ellipsis = true;
 
-    explicit label(string text, int font) : m_text(text), m_font(font) {}
+    explicit label(string text, int font) : m_font(font), m_text(text), m_tokenized(m_text) {}
     explicit label(string text, string foreground = "", string background = "",
         string underline = "", string overline = "", int font = 0, int padding = 0, int margin = 0,
         size_t maxlen = 0, bool ellipsis = true)
-        : m_text(text)
-        , m_foreground(foreground)
+        : m_foreground(foreground)
         , m_background(background)
         , m_underline(underline)
         , m_overline(overline)
@@ -38,7 +36,13 @@ namespace drawtypes {
         , m_padding(padding)
         , m_margin(margin)
         , m_maxlen(maxlen)
-        , m_ellipsis(ellipsis) {}
+        , m_ellipsis(ellipsis)
+        , m_text(text)
+        , m_tokenized(m_text) {}
+
+    string get() const {
+      return m_tokenized;
+    }
 
     operator bool() {
       return !m_text.empty();
@@ -49,8 +53,12 @@ namespace drawtypes {
           m_padding, m_margin, m_maxlen, m_ellipsis)};
     }
 
+    void reset_tokens() {
+      m_tokenized = m_text;
+    }
+
     void replace_token(string token, string replacement) {
-      m_text = string_util::replace_all(m_text, token, replacement);
+      m_tokenized = string_util::replace_all(m_tokenized, token, replacement);
     }
 
     void replace_defined_values(label_t label) {
@@ -63,6 +71,9 @@ namespace drawtypes {
       if (!label->m_overline.empty())
         m_overline = label->m_overline;
     }
+
+   private:
+    string m_text, m_tokenized;
   };
 
   inline label_t get_config_label(const config& conf, string section, string name = "label",
diff --git a/include/modules/backlight.hpp b/include/modules/backlight.hpp
index c4a6a94f..6a5ba6e0 100644
--- a/include/modules/backlight.hpp
+++ b/include/modules/backlight.hpp
@@ -27,9 +27,6 @@ namespace modules {
       if (m_formatter->has(TAG_RAMP))
         m_ramp = get_config_ramp(m_conf, name(), TAG_RAMP);
 
-      if (m_label)
-        m_tokenized = m_label->clone();
-
       // Build path to the file where the current/maximum brightness value is located
       m_path_val = string_util::replace(PATH_BACKLIGHT_VAL, "%card%", card);
       m_path_max = string_util::replace(PATH_BACKLIGHT_MAX, "%card%", card);
@@ -55,22 +52,21 @@ namespace modules {
 
       m_percentage = static_cast<int>(float(m_val) / float(m_max) * 100.0f + 0.5f);
 
-      if (!m_label)
-        return true;
-
-      m_tokenized->m_text = m_label->m_text;
-      m_tokenized->replace_token("%percentage%", to_string(m_percentage) + "%");
+      if (m_label) {
+        m_label->reset_tokens();
+        m_label->replace_token("%percentage%", to_string(m_percentage) + "%");
+      }
 
       return true;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_BAR)
         builder->node(m_progressbar->output(m_percentage));
       else if (tag == TAG_RAMP)
         builder->node(m_ramp->get_by_percentage(m_percentage));
       else if (tag == TAG_LABEL)
-        builder->node(m_tokenized);
+        builder->node(m_label);
       else
         return false;
       return true;
@@ -87,7 +83,6 @@ namespace modules {
 
     ramp_t m_ramp;
     label_t m_label;
-    label_t m_tokenized;
     progressbar_t m_progressbar;
 
     string m_path_val;
diff --git a/include/modules/battery.hpp b/include/modules/battery.hpp
index bf0c3175..0c648026 100644
--- a/include/modules/battery.hpp
+++ b/include/modules/battery.hpp
@@ -57,16 +57,13 @@ namespace modules {
       if (m_formatter->has(TAG_LABEL_CHARGING, FORMAT_CHARGING)) {
         m_label_charging =
             get_optional_config_label(m_conf, name(), TAG_LABEL_CHARGING, "%percentage%");
-        m_label_charging_tokenized = m_label_charging->clone();
       }
       if (m_formatter->has(TAG_LABEL_DISCHARGING, FORMAT_DISCHARGING)) {
         m_label_discharging =
             get_optional_config_label(m_conf, name(), TAG_LABEL_DISCHARGING, "%percentage%");
-        m_label_discharging_tokenized = m_label_discharging->clone();
       }
       if (m_formatter->has(TAG_LABEL_FULL, FORMAT_FULL)) {
         m_label_full = get_optional_config_label(m_conf, name(), TAG_LABEL_FULL, "%percentage%");
-        m_label_full_tokenized = m_label_full->clone();
       }
 
       // }}}
@@ -124,17 +121,17 @@ namespace modules {
         return false;
       }
 
-      if (m_label_charging_tokenized) {
-        m_label_charging_tokenized->m_text = m_label_charging->m_text;
-        m_label_charging_tokenized->replace_token("%percentage%", to_string(percentage) + "%");
+      if (m_label_charging) {
+        m_label_charging->reset_tokens();
+        m_label_charging->replace_token("%percentage%", to_string(percentage) + "%");
       }
-      if (m_label_discharging_tokenized) {
-        m_label_discharging_tokenized->m_text = m_label_discharging->m_text;
-        m_label_discharging_tokenized->replace_token("%percentage%", to_string(percentage) + "%");
+      if (m_label_discharging) {
+        m_label_discharging->reset_tokens();
+        m_label_discharging->replace_token("%percentage%", to_string(percentage) + "%");
       }
-      if (m_label_full_tokenized) {
-        m_label_full_tokenized->m_text = m_label_full->m_text;
-        m_label_full_tokenized->replace_token("%percentage%", to_string(percentage) + "%");
+      if (m_label_full) {
+        m_label_full->reset_tokens();
+        m_label_full->replace_token("%percentage%", to_string(percentage) + "%");
       }
 
       m_state = state;
@@ -143,7 +140,7 @@ namespace modules {
       return true;
     }
 
-    string get_format() {
+    string get_format() const {
       if (m_state == STATE_FULL)
         return FORMAT_FULL;
       else if (m_state == STATE_CHARGING)
@@ -152,7 +149,7 @@ namespace modules {
         return FORMAT_DISCHARGING;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_ANIMATION_CHARGING)
         builder->node(m_animation_charging->get());
       else if (tag == TAG_BAR_CAPACITY) {
@@ -160,11 +157,11 @@ namespace modules {
       } else if (tag == TAG_RAMP_CAPACITY)
         builder->node(m_ramp_capacity->get_by_percentage(m_percentage));
       else if (tag == TAG_LABEL_CHARGING)
-        builder->node(m_label_charging_tokenized);
+        builder->node(m_label_charging);
       else if (tag == TAG_LABEL_DISCHARGING)
-        builder->node(m_label_discharging_tokenized);
+        builder->node(m_label_discharging);
       else if (tag == TAG_LABEL_FULL)
-        builder->node(m_label_full_tokenized);
+        builder->node(m_label_full);
       else
         return false;
       return true;
@@ -222,11 +219,8 @@ namespace modules {
     ramp_t m_ramp_capacity;
     progressbar_t m_bar_capacity;
     label_t m_label_charging;
-    label_t m_label_charging_tokenized;
     label_t m_label_discharging;
-    label_t m_label_discharging_tokenized;
     label_t m_label_full;
-    label_t m_label_full_tokenized;
 
     string m_battery;
     string m_adapter;
diff --git a/include/modules/bspwm.hpp b/include/modules/bspwm.hpp
index b63b2915..050a8a14 100644
--- a/include/modules/bspwm.hpp
+++ b/include/modules/bspwm.hpp
@@ -269,8 +269,9 @@ namespace modules {
           if (!monitor_focused)
             label->replace_defined_values(m_statelabels.find(bspwm_flag::WORKSPACE_DIMMED)->second);
 
+          label->reset_tokens();
           label->replace_token("%name%", value);
-          label->replace_token("%icon%", icon->m_text);
+          label->replace_token("%icon%", icon->get());
           label->replace_token("%index%", to_string(++workspace_n));
 
           m_workspaces.emplace_back(make_unique<bspwm_workspace>(workspace_flag, std::move(label)));
@@ -286,14 +287,14 @@ namespace modules {
       return true;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag != TAG_LABEL_STATE)
         return false;
 
       int workspace_n = 0;
 
       for (auto&& ws : m_workspaces) {
-        if (!ws.get()->label->m_text.empty())
+        if (!ws.get()->label->get().empty())
           builder->cmd(mousebtn::LEFT, string(EVENT_CLICK) + to_string(++workspace_n));
 
         builder->node(ws.get()->label);
@@ -302,7 +303,7 @@ namespace modules {
           for (auto&& mode : m_modes) builder->node(mode);
         }
 
-        if (!ws.get()->label->m_text.empty())
+        if (!ws.get()->label->get().empty())
           builder->cmd_close(true);
       }
 
diff --git a/include/modules/counter.hpp b/include/modules/counter.hpp
index 4179ebc5..64a488ac 100644
--- a/include/modules/counter.hpp
+++ b/include/modules/counter.hpp
@@ -21,7 +21,7 @@ namespace modules {
       return true;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_COUNTER) {
         builder->node(to_string(m_counter));
         return true;
diff --git a/include/modules/cpu.hpp b/include/modules/cpu.hpp
index f197d143..1c0df5a4 100644
--- a/include/modules/cpu.hpp
+++ b/include/modules/cpu.hpp
@@ -37,10 +37,8 @@ namespace modules {
         m_rampload = get_config_ramp(m_conf, name(), TAG_RAMP_LOAD);
       if (m_formatter->has(TAG_RAMP_LOAD_PER_CORE))
         m_rampload_core = get_config_ramp(m_conf, name(), TAG_RAMP_LOAD_PER_CORE);
-      if (m_formatter->has(TAG_LABEL)) {
+      if (m_formatter->has(TAG_LABEL))
         m_label = get_optional_config_label(m_conf, name(), TAG_LABEL, "%percentage%");
-        m_tokenized = m_label->clone();
-      }
 
       // warmup
       read_values();
@@ -67,18 +65,17 @@ namespace modules {
 
       m_total = m_total / static_cast<float>(cores_n);
 
-      if (m_tokenized) {
-        m_tokenized->m_text = m_label->m_text;
-        m_tokenized->replace_token(
-            "%percentage%", to_string(static_cast<int>(m_total + 0.5f)) + "%");
+      if (m_label) {
+        m_label->reset_tokens();
+        m_label->replace_token("%percentage%", to_string(static_cast<int>(m_total + 0.5f)) + "%");
       }
 
       return true;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_LABEL)
-        builder->node(m_tokenized);
+        builder->node(m_label);
       else if (tag == TAG_BAR_LOAD)
         builder->node(m_barload->output(m_total));
       else if (tag == TAG_RAMP_LOAD)
@@ -127,7 +124,7 @@ namespace modules {
       return !m_cputimes.empty();
     }
 
-    float get_load(size_t core) {
+    float get_load(size_t core) const {
       if (m_cputimes.empty() || m_cputimes_prev.empty())
         return 0;
       else if (core >= m_cputimes.size() || core >= m_cputimes_prev.size())
@@ -159,7 +156,6 @@ namespace modules {
     ramp_t m_rampload;
     ramp_t m_rampload_core;
     label_t m_label;
-    label_t m_tokenized;
 
     vector<cpu_time_t> m_cputimes;
     vector<cpu_time_t> m_cputimes_prev;
diff --git a/include/modules/date.hpp b/include/modules/date.hpp
index 6f51cc9f..69d0eadb 100644
--- a/include/modules/date.hpp
+++ b/include/modules/date.hpp
@@ -46,7 +46,7 @@ namespace modules {
       return m_builder->flush();
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_DATE)
         builder->node(m_buffer);
       return tag == TAG_DATE;
diff --git a/include/modules/i3.hpp b/include/modules/i3.hpp
index 5d3efef2..38e5ea66 100644
--- a/include/modules/i3.hpp
+++ b/include/modules/i3.hpp
@@ -167,9 +167,10 @@ namespace modules {
           auto icon = m_icons->get(workspace->name, DEFAULT_WS_ICON);
           auto label = m_statelabels.find(flag)->second->clone();
 
+          label->reset_tokens();
           label->replace_token("%output%", workspace->output);
           label->replace_token("%name%", wsname);
-          label->replace_token("%icon%", icon->m_text);
+          label->replace_token("%icon%", icon->get());
           label->replace_token("%index%", to_string(workspace->num));
           m_workspaces.emplace_back(
               make_unique<i3_workspace>(workspace->num, flag, std::move(label)));
@@ -184,7 +185,7 @@ namespace modules {
       // }}}
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       // Output workspace info {{{
 
       if (tag != TAG_LABEL_STATE)
diff --git a/include/modules/memory.hpp b/include/modules/memory.hpp
index 1372ec6d..5d94cd79 100644
--- a/include/modules/memory.hpp
+++ b/include/modules/memory.hpp
@@ -25,11 +25,8 @@ namespace modules {
         m_bars[memtype::USED] = get_config_bar(m_bar, m_conf, name(), TAG_BAR_USED);
       if (m_formatter->has(TAG_BAR_FREE))
         m_bars[memtype::FREE] = get_config_bar(m_bar, m_conf, name(), TAG_BAR_FREE);
-
-      if (m_formatter->has(TAG_LABEL)) {
+      if (m_formatter->has(TAG_LABEL))
         m_label = get_optional_config_label(m_conf, name(), TAG_LABEL, "%percentage_used%");
-        m_tokenized = m_label->clone();
-      }
     }
 
     bool update() {
@@ -72,38 +69,36 @@ namespace modules {
       m_perc[memtype::USED] = 100 - m_perc[memtype::FREE];
 
       // replace tokens
-      if (m_tokenized) {
-        m_tokenized->m_text = m_label->m_text;
+      if (m_label) {
+        m_label->reset_tokens();
 
         auto replace_unit = [](label_t& label, string token, float value, string unit) {
-          if (label->m_text.find(token) == string::npos)
-            return;
           auto formatted = string_util::from_stream(
               stringstream() << std::setprecision(2) << std::fixed << value << " " << unit);
           label->replace_token(token, formatted);
         };
 
-        replace_unit(m_tokenized, "%gb_used%", (kb_total - kb_avail) / 1024 / 1024, "GB");
-        replace_unit(m_tokenized, "%gb_free%", kb_avail / 1024 / 1024, "GB");
-        replace_unit(m_tokenized, "%gb_total%", kb_total / 1024 / 1024, "GB");
-        replace_unit(m_tokenized, "%mb_used%", (kb_total - kb_avail) / 1024, "MB");
-        replace_unit(m_tokenized, "%mb_free%", kb_avail / 1024, "MB");
-        replace_unit(m_tokenized, "%mb_total%", kb_total / 1024, "MB");
+        replace_unit(m_label, "%gb_used%", (kb_total - kb_avail) / 1024 / 1024, "GB");
+        replace_unit(m_label, "%gb_free%", kb_avail / 1024 / 1024, "GB");
+        replace_unit(m_label, "%gb_total%", kb_total / 1024 / 1024, "GB");
+        replace_unit(m_label, "%mb_used%", (kb_total - kb_avail) / 1024, "MB");
+        replace_unit(m_label, "%mb_free%", kb_avail / 1024, "MB");
+        replace_unit(m_label, "%mb_total%", kb_total / 1024, "MB");
 
-        m_tokenized->replace_token("%percentage_used%", to_string(m_perc[memtype::USED]) + "%");
-        m_tokenized->replace_token("%percentage_free%", to_string(m_perc[memtype::FREE]) + "%");
+        m_label->replace_token("%percentage_used%", to_string(m_perc[memtype::USED]) + "%");
+        m_label->replace_token("%percentage_free%", to_string(m_perc[memtype::FREE]) + "%");
       }
 
       return true;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_BAR_USED) {
-        builder->node(m_bars[memtype::USED]->output(m_perc[memtype::USED]));
+        builder->node(m_bars.at(memtype::USED)->output(m_perc.at(memtype::USED)));
       } else if (tag == TAG_BAR_FREE)
-        builder->node(m_bars[memtype::FREE]->output(m_perc[memtype::FREE]));
+        builder->node(m_bars.at(memtype::FREE)->output(m_perc.at(memtype::FREE)));
       else if (tag == TAG_LABEL)
-        builder->node(m_tokenized);
+        builder->node(m_label);
       else
         return false;
       return true;
@@ -115,7 +110,7 @@ namespace modules {
     static constexpr auto TAG_BAR_FREE = "<bar-free>";
 
     label_t m_label;
-    label_t m_tokenized;
+    progressbar_t m_bar_free;
     map<memtype, progressbar_t> m_bars;
     map<memtype, int> m_perc;
   };
diff --git a/include/modules/menu.hpp b/include/modules/menu.hpp
index 257b2e9f..250886c9 100644
--- a/include/modules/menu.hpp
+++ b/include/modules/menu.hpp
@@ -58,7 +58,7 @@ namespace modules {
       }
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_LABEL_TOGGLE && m_level == -1) {
         builder->cmd(mousebtn::LEFT, string(EVENT_MENU_OPEN) + "0");
         builder->node(m_labelopen);
diff --git a/include/modules/meta.hpp b/include/modules/meta.hpp
index 7eb66e15..19778ed8 100644
--- a/include/modules/meta.hpp
+++ b/include/modules/meta.hpp
@@ -287,7 +287,7 @@ namespace modules {
         return "";
       }
 
-      auto format_name = CAST_MODULE(Impl)->get_format();
+      auto format_name = CONST_CAST_MODULE(Impl).get_format();
       auto format = m_formatter->get(format_name);
 
       int i = 0;
@@ -299,7 +299,7 @@ namespace modules {
         if (tag[0] == '<' && tag[tag.length() - 1] == '>') {
           if (i > 0)
             m_builder->space(format->spacing);
-          if (!(tag_built = CAST_MODULE(Impl)->build(m_builder.get(), tag)) && i > 0)
+          if (!(tag_built = CONST_CAST_MODULE(Impl).build(m_builder.get(), tag)) && i > 0)
             m_builder->remove_trailing_space(format->spacing);
           if (tag_built)
             i++;
@@ -361,7 +361,7 @@ namespace modules {
       CAST_MODULE(Impl)->broadcast();
     }
 
-    bool build(builder*, string) {
+    bool build(builder*, string) const {
       return true;
     }
   };
@@ -427,17 +427,14 @@ namespace modules {
         CAST_MODULE(Impl)->broadcast();
 
         while (CONST_CAST_MODULE(Impl).enabled()) {
-          CAST_MODULE(Impl)->idle();
-          {
-            std::lock_guard<threading_util::spin_lock> lck(this->update_lock);
-
-            if (!CAST_MODULE(Impl)->has_event())
-              continue;
-            if (!CAST_MODULE(Impl)->update())
-              continue;
+          std::lock_guard<threading_util::spin_lock> lck(this->update_lock);
 
+          if (!CAST_MODULE(Impl)->has_event())
+            CAST_MODULE(Impl)->idle();
+          else if (!CAST_MODULE(Impl)->update())
+            CAST_MODULE(Impl)->idle();
+          else
             CAST_MODULE(Impl)->broadcast();
-          }
         }
       } catch (const std::exception& err) {
         this->m_log.err("%s: %s", this->name(), err.what());
diff --git a/include/modules/mpd.hpp b/include/modules/mpd.hpp
index acd8ce56..0d7e1a99 100644
--- a/include/modules/mpd.hpp
+++ b/include/modules/mpd.hpp
@@ -57,12 +57,10 @@ namespace modules {
       if (m_formatter->has(TAG_LABEL_SONG)) {
         m_label_song =
             get_optional_config_label(m_conf, name(), TAG_LABEL_SONG, "%artist% - %title%");
-        m_label_song_tokenized = m_label_song->clone();
       }
       if (m_formatter->has(TAG_LABEL_TIME)) {
         m_label_time =
             get_optional_config_label(m_conf, name(), TAG_LABEL_TIME, "%elapsed% / %total%");
-        m_label_time_tokenized = m_label_time->clone();
       }
       if (m_formatter->has(TAG_ICON_RANDOM) || m_formatter->has(TAG_ICON_REPEAT) ||
           m_formatter->has(TAG_ICON_REPEAT_ONE)) {
@@ -83,64 +81,58 @@ namespace modules {
         m_mpd = make_unique<mpdconnection>(m_log, m_host, m_port, m_pass);
         m_mpd->connect();
         m_status = m_mpd->get_status();
-      } catch (const mpd_exception& e) {
-        m_log.err("%s: %s", name(), e.what());
+      } catch (const mpd_exception& err) {
+        m_log.err("%s: %s", name(), err.what());
+        m_mpd.reset();
       }
     }
 
-    void teardown() {
-      if (m_mpd && m_mpd->connected()) {
-        try {
-          m_mpd->disconnect();
-        } catch (const mpd_exception& e) {
-          m_log.trace("%s: %s", name(), e.what());
-        }
-      } else {
-        wakeup();
-      }
+    inline bool connected() const {
+      return m_mpd && m_mpd->connected();
     }
 
     void idle() {
-      if (m_mpd && m_mpd->connected())
+      if (connected())
         sleep(80ms);
       else {
-        sleep(10s);
+        sleep(2s);
       }
     }
 
     bool has_event() {
-      if (!m_mpd->connected()) {
-        m_connection_state_broadcasted = false;
+      if (!m_mpd)
+        m_mpd = make_unique<mpdconnection>(m_log, m_host, m_port, m_pass);
 
-        try {
+      try {
+        if (!connected())
           m_mpd->connect();
-        } catch (const mpd_exception& e) {
-          m_log.trace("%s: %s", name(), e.what());
-        }
-
-        if (!m_mpd->connected()) {
-          return false;
-        }
+        if (m_connection_state_broadcasted)
+          m_connection_state_broadcasted = false;
+      } catch (const mpd_exception& err) {
+        m_log.trace("%s: %s", name(), err.what());
+        m_mpd.reset();
+        return !m_connection_state_broadcasted;
       }
 
+      if (!connected())
+        return !m_connection_state_broadcasted;
+
       if (!m_status)
         m_status = m_mpd->get_status_safe();
 
       try {
         m_mpd->idle();
-
-        int idle_flags;
-
+        int idle_flags = 0;
         if ((idle_flags = m_mpd->noidle()) != 0) {
           m_status->update(idle_flags, m_mpd.get());
           return true;
         } else if (m_status->match_state(mpdstate::PLAYING)) {
           m_status->update_timer();
         }
-      } catch (const mpd_exception& e) {
-        m_log.err(e.what());
-        m_mpd->disconnect();
-        return true;
+      } catch (const mpd_exception& err) {
+        m_log.err(err.what());
+        m_mpd.reset();
+        return !m_connection_state_broadcasted;
       }
 
       if ((m_label_time || m_bar_progress) && m_status->match_state(mpdstate::PLAYING)) {
@@ -156,12 +148,14 @@ namespace modules {
     }
 
     bool update() {
-      if (!m_mpd->connected())
-        return true;
-      if (!m_status && !(m_status = m_mpd->get_status_safe()))
-        return true;
-
-      m_connection_state_broadcasted = true;
+      if (m_connection_state_broadcasted) {
+        if (!connected())
+          return false;
+        if (!m_status && !(m_status = m_mpd->get_status_safe()))
+          return false;
+      } else {
+        m_connection_state_broadcasted = true;
+      }
 
       string artist;
       string album;
@@ -170,52 +164,55 @@ namespace modules {
       string total_str;
 
       try {
-        elapsed_str = m_status->get_formatted_elapsed();
-        total_str = m_status->get_formatted_total();
-        auto song = m_mpd->get_song();
-        if (song && song.get()) {
-          artist = song->get_artist();
-          album = song->get_album();
-          title = song->get_title();
+        if (m_status) {
+          elapsed_str = m_status->get_formatted_elapsed();
+          total_str = m_status->get_formatted_total();
         }
-      } catch (const mpd_exception& e) {
-        m_log.err(e.what());
-        m_mpd->disconnect();
-        return true;
+        if (m_mpd) {
+          auto song = m_mpd->get_song();
+          if (song && song.get()) {
+            artist = song->get_artist();
+            album = song->get_album();
+            title = song->get_title();
+          }
+        }
+      } catch (const mpd_exception& err) {
+        m_log.err(err.what());
+        m_mpd.reset();
       }
 
-      if (m_label_song_tokenized) {
-        m_label_song_tokenized->m_text = m_label_song->m_text;
-        m_label_song_tokenized->replace_token(
+      if (m_label_song) {
+        m_label_song->reset_tokens();
+        m_label_song->replace_token(
             "%artist%", !artist.empty() ? artist : "untitled artist");
-        m_label_song_tokenized->replace_token("%album%", !album.empty() ? album : "untitled album");
-        m_label_song_tokenized->replace_token("%title%", !title.empty() ? title : "untitled track");
+        m_label_song->replace_token("%album%", !album.empty() ? album : "untitled album");
+        m_label_song->replace_token("%title%", !title.empty() ? title : "untitled track");
       }
 
-      if (m_label_time_tokenized) {
-        m_label_time_tokenized->m_text = m_label_time->m_text;
-        m_label_time_tokenized->replace_token("%elapsed%", elapsed_str);
-        m_label_time_tokenized->replace_token("%total%", total_str);
+      if (m_label_time) {
+        m_label_time->reset_tokens();
+        m_label_time->replace_token("%elapsed%", elapsed_str);
+        m_label_time->replace_token("%total%", total_str);
       }
 
       if (m_icons->has("random"))
         m_icons->get("random")->m_foreground =
-            m_status->random() ? m_toggle_on_color : m_toggle_off_color;
+            m_status && m_status->random() ? m_toggle_on_color : m_toggle_off_color;
       if (m_icons->has("repeat"))
         m_icons->get("repeat")->m_foreground =
-            m_status->repeat() ? m_toggle_on_color : m_toggle_off_color;
+            m_status && m_status->repeat() ? m_toggle_on_color : m_toggle_off_color;
       if (m_icons->has("repeat_one"))
         m_icons->get("repeat_one")->m_foreground =
-            m_status->single() ? m_toggle_on_color : m_toggle_off_color;
+            m_status && m_status->single() ? m_toggle_on_color : m_toggle_off_color;
 
       return true;
     }
 
-    string get_format() {
-      return m_mpd->connected() ? FORMAT_ONLINE : FORMAT_OFFLINE;
+    string get_format() const {
+      return connected() ? FORMAT_ONLINE : FORMAT_OFFLINE;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       bool is_playing = false;
       bool is_paused = false;
       bool is_stopped = true;
@@ -239,9 +236,9 @@ namespace modules {
       };
 
       if (tag == TAG_LABEL_SONG && !is_stopped)
-        builder->node(m_label_song_tokenized);
+        builder->node(m_label_song);
       else if (tag == TAG_LABEL_TIME && !is_stopped)
-        builder->node(m_label_time_tokenized);
+        builder->node(m_label_time);
       else if (tag == TAG_BAR_PROGRESS && !is_stopped)
         builder->node(m_bar_progress->output(elapsed_percentage));
       else if (tag == TAG_LABEL_OFFLINE)
@@ -312,8 +309,9 @@ namespace modules {
           mpd->seek(status->get_songid(), status->get_seek_position(percentage));
         } else
           return false;
-      } catch (const mpd_exception& e) {
-        m_log.err("%s: %s", name(), e.what());
+      } catch (const mpd_exception& err) {
+        m_log.err("%s: %s", name(), err.what());
+        m_mpd.reset();
       }
 
       return true;
@@ -359,9 +357,7 @@ namespace modules {
     progressbar_t m_bar_progress;
     iconset_t m_icons;
     label_t m_label_song;
-    label_t m_label_song_tokenized;
     label_t m_label_time;
-    label_t m_label_time_tokenized;
     label_t m_label_offline;
 
     unique_ptr<mpdconnection> m_mpd;
@@ -383,7 +379,7 @@ namespace modules {
 
     // This flag is used to let thru a broadcast once every time
     // the connection state changes
-    stateflag m_connection_state_broadcasted{true};
+    stateflag m_connection_state_broadcasted{false};
   };
 }
 
diff --git a/include/modules/network.hpp b/include/modules/network.hpp
index c0d79fa2..389b5519 100644
--- a/include/modules/network.hpp
+++ b/include/modules/network.hpp
@@ -38,13 +38,13 @@ namespace modules {
       if (m_formatter->has(TAG_LABEL_CONNECTED, FORMAT_CONNECTED)) {
         m_label[connection_state::CONNECTED] =
             get_optional_config_label(m_conf, name(), TAG_LABEL_CONNECTED, "%ifname% %local_ip%");
-        m_tokenized[connection_state::CONNECTED] = m_label[connection_state::CONNECTED]->clone();
       }
 
       // Create elements for format-disconnected
       if (m_formatter->has(TAG_LABEL_DISCONNECTED, FORMAT_DISCONNECTED)) {
         m_label[connection_state::DISCONNECTED] =
             get_optional_config_label(m_conf, name(), TAG_LABEL_DISCONNECTED, "");
+        m_label[connection_state::DISCONNECTED]->reset_tokens();
         m_label[connection_state::DISCONNECTED]->replace_token("%ifname%", m_interface);
       }
 
@@ -56,8 +56,6 @@ namespace modules {
         if (m_formatter->has(TAG_LABEL_PACKETLOSS, FORMAT_PACKETLOSS)) {
           m_label[connection_state::PACKETLOSS] =
               get_optional_config_label(m_conf, name(), TAG_LABEL_PACKETLOSS, "");
-          m_tokenized[connection_state::PACKETLOSS] =
-              m_label[connection_state::PACKETLOSS]->clone();
         }
         if (m_formatter->has(TAG_ANIMATION_PACKETLOSS, FORMAT_PACKETLOSS))
           m_animation_packetloss = get_config_animation(m_conf, name(), TAG_ANIMATION_PACKETLOSS);
@@ -112,6 +110,7 @@ namespace modules {
 
       // Update label contents
       const auto replace_tokens = [&](label_t& label) {
+        label->reset_tokens();
         label->replace_token("%ifname%", m_interface);
         label->replace_token("%local_ip%", network->ip());
         label->replace_token("%upspeed%", upspeed);
@@ -126,22 +125,15 @@ namespace modules {
         }
       };
 
-      if (m_label[connection_state::CONNECTED]) {
-        m_tokenized[connection_state::CONNECTED]->m_text =
-            m_label[connection_state::CONNECTED]->m_text;
-        replace_tokens(m_tokenized[connection_state::CONNECTED]);
-      }
-
-      if (m_label[connection_state::PACKETLOSS]) {
-        m_tokenized[connection_state::PACKETLOSS]->m_text =
-            m_label[connection_state::PACKETLOSS]->m_text;
-        replace_tokens(m_tokenized[connection_state::PACKETLOSS]);
-      }
+      if (m_label[connection_state::CONNECTED])
+        replace_tokens(m_label[connection_state::CONNECTED]);
+      if (m_label[connection_state::PACKETLOSS])
+        replace_tokens(m_label[connection_state::PACKETLOSS]);
 
       return true;
     }
 
-    string get_format() {
+    string get_format() const {
       if (!m_connected)
         return FORMAT_DISCONNECTED;
       else if (m_packetloss && m_ping_nth_update > 0)
@@ -150,13 +142,13 @@ namespace modules {
         return FORMAT_CONNECTED;
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_LABEL_CONNECTED)
-        builder->node(m_tokenized[connection_state::CONNECTED]);
+        builder->node(m_label.at(connection_state::CONNECTED));
       else if (tag == TAG_LABEL_DISCONNECTED)
-        builder->node(m_label[connection_state::DISCONNECTED]);
+        builder->node(m_label.at(connection_state::DISCONNECTED));
       else if (tag == TAG_LABEL_PACKETLOSS)
-        builder->node(m_tokenized[connection_state::PACKETLOSS]);
+        builder->node(m_label.at(connection_state::PACKETLOSS));
       else if (tag == TAG_ANIMATION_PACKETLOSS)
         builder->node(m_animation_packetloss->get());
       else if (tag == TAG_RAMP_SIGNAL)
@@ -200,7 +192,6 @@ namespace modules {
     ramp_t m_ramp_quality;
     animation_t m_animation_packetloss;
     map<connection_state, label_t> m_label;
-    map<connection_state, label_t> m_tokenized;
 
     stateflag m_connected{false};
     stateflag m_packetloss{false};
diff --git a/include/modules/script.hpp b/include/modules/script.hpp
index c94c1be4..5f47d335 100644
--- a/include/modules/script.hpp
+++ b/include/modules/script.hpp
@@ -129,7 +129,7 @@ namespace modules {
       return m_builder->flush();
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag != TAG_OUTPUT)
         return false;
       builder->node(string_util::replace_all(m_output, "\n", ""));
diff --git a/include/modules/text.hpp b/include/modules/text.hpp
index 98768f60..e92390cb 100644
--- a/include/modules/text.hpp
+++ b/include/modules/text.hpp
@@ -19,7 +19,7 @@ namespace modules {
           string_util::replace_all(m_formatter->get("content")->value, " ", BUILDER_SPACE_TOKEN);
     }
 
-    string get_format() {
+    string get_format() const {
       return "content";
     }
 
diff --git a/include/modules/unsupported.hpp b/include/modules/unsupported.hpp
index 34c42067..9379ad53 100644
--- a/include/modules/unsupported.hpp
+++ b/include/modules/unsupported.hpp
@@ -11,7 +11,7 @@
       throw application_error("No built-in support for '" + string{MODULE_TYPE} + "'"); \
     }                                                                                   \
     void start() {}                                                                     \
-    bool build(builder*, string) {                                                      \
+    bool build(builder*, string) const {                                                \
       return true;                                                                      \
     }                                                                                   \
   }
diff --git a/include/modules/volume.hpp b/include/modules/volume.hpp
index 5254a4ab..4fce553e 100644
--- a/include/modules/volume.hpp
+++ b/include/modules/volume.hpp
@@ -98,11 +98,9 @@ namespace modules {
       if (m_formatter->has(TAG_LABEL_VOLUME, FORMAT_VOLUME)) {
         m_label_volume =
             get_optional_config_label(m_conf, name(), TAG_LABEL_VOLUME, "%percentage%");
-        m_label_volume_tokenized = m_label_volume->clone();
       }
       if (m_formatter->has(TAG_LABEL_MUTED, FORMAT_MUTED)) {
         m_label_muted = get_optional_config_label(m_conf, name(), TAG_LABEL_MUTED, "%percentage%");
-        m_label_muted_tokenized = m_label_muted->clone();
       }
 
       // }}}
@@ -172,13 +170,13 @@ namespace modules {
       // }}}
       // Replace label tokens {{{
 
-      if (m_label_volume_tokenized) {
-        m_label_volume_tokenized->m_text = m_label_volume->m_text;
-        m_label_volume_tokenized->replace_token("%percentage%", to_string(m_volume) + "%");
+      if (m_label_volume) {
+        m_label_volume->reset_tokens();
+        m_label_volume->replace_token("%percentage%", to_string(m_volume) + "%");
       }
-      if (m_label_muted_tokenized) {
-        m_label_muted_tokenized->m_text = m_label_muted->m_text;
-        m_label_muted_tokenized->replace_token("%percentage%", to_string(m_volume) + "%");
+      if (m_label_muted) {
+        m_label_muted->reset_tokens();
+        m_label_muted->replace_token("%percentage%", to_string(m_volume) + "%");
       }
 
       // }}}
@@ -186,7 +184,7 @@ namespace modules {
       return true;
     }
 
-    string get_format() {
+    string get_format() const {
       return m_muted ? FORMAT_MUTED : FORMAT_VOLUME;
     }
 
@@ -202,7 +200,7 @@ namespace modules {
       return m_builder->flush();
     }
 
-    bool build(builder* builder, string tag) {
+    bool build(builder* builder, string tag) const {
       if (tag == TAG_BAR_VOLUME)
         builder->node(m_bar_volume->output(m_volume));
       else if (tag == TAG_RAMP_VOLUME && (!m_headphones || !*m_ramp_headphones))
@@ -210,9 +208,9 @@ namespace modules {
       else if (tag == TAG_RAMP_VOLUME && m_headphones && *m_ramp_headphones)
         builder->node(m_ramp_headphones->get_by_percentage(m_volume));
       else if (tag == TAG_LABEL_VOLUME)
-        builder->node(m_label_volume_tokenized);
+        builder->node(m_label_volume);
       else if (tag == TAG_LABEL_MUTED)
-        builder->node(m_label_muted_tokenized);
+        builder->node(m_label_muted);
       else
         return false;
       return true;
@@ -283,9 +281,7 @@ namespace modules {
     ramp_t m_ramp_volume;
     ramp_t m_ramp_headphones;
     label_t m_label_volume;
-    label_t m_label_volume_tokenized;
     label_t m_label_muted;
-    label_t m_label_muted_tokenized;
 
     map<mixer, mixer_t> m_mixers;
     map<control, control_t> m_controls;