Skip to content

Commit

Permalink
Merge pull request #2470 from 4e554c4c/darkmode
Browse files Browse the repository at this point in the history
search for dark or light mode stylesheet
  • Loading branch information
Alexays authored Sep 11, 2023
2 parents 196b400 + fc67558 commit a90e275
Show file tree
Hide file tree
Showing 5 changed files with 180 additions and 4 deletions.
4 changes: 3 additions & 1 deletion include/client.hpp
Original file line number Diff line number Diff line change
Expand Up @@ -7,6 +7,7 @@

#include "bar.hpp"
#include "config.hpp"
#include "util/portal.hpp"

struct zwlr_layer_shell_v1;
struct zwp_idle_inhibitor_v1;
Expand All @@ -33,7 +34,7 @@ class Client {

private:
Client() = default;
const std::string getStyle(const std::string &style);
const std::string getStyle(const std::string &style, std::optional<Appearance> appearance);
void bindInterfaces();
void handleOutput(struct waybar_output &output);
auto setupCss(const std::string &css_file) -> void;
Expand All @@ -52,6 +53,7 @@ class Client {

Glib::RefPtr<Gtk::StyleContext> style_context_;
Glib::RefPtr<Gtk::CssProvider> css_provider_;
std::unique_ptr<Portal> portal;
std::list<struct waybar_output> outputs_;
};

Expand Down
38 changes: 38 additions & 0 deletions include/util/portal.hpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,38 @@
#include <giomm/dbusproxy.h>

#include <string>

#include "fmt/format.h"

namespace waybar {

using namespace Gio;

enum class Appearance {
UNKNOWN = 0,
DARK = 1,
LIGHT = 2,
};
class Portal : private DBus::Proxy {
public:
Portal();
void refreshAppearance();
Appearance getAppearance();

typedef sigc::signal<void, Appearance> type_signal_appearance_changed;
type_signal_appearance_changed signal_appearance_changed() { return m_signal_appearance_changed; }

private:
type_signal_appearance_changed m_signal_appearance_changed;
Appearance currentMode;
void on_signal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& parameters);
};

} // namespace waybar

template <>
struct fmt::formatter<waybar::Appearance> : formatter<fmt::string_view> {
// parse is inherited from formatter<string_view>.
auto format(waybar::Appearance c, format_context& ctx) const;
};
1 change: 1 addition & 0 deletions meson.build
Original file line number Diff line number Diff line change
Expand Up @@ -171,6 +171,7 @@ src_files = files(
'src/client.cpp',
'src/config.cpp',
'src/group.cpp',
'src/util/portal.cpp',
'src/util/enum.cpp',
'src/util/prepare_for_sleep.cpp',
'src/util/ustring_clen.cpp',
Expand Down
35 changes: 32 additions & 3 deletions src/client.cpp
Original file line number Diff line number Diff line change
Expand Up @@ -151,8 +151,26 @@ void waybar::Client::handleDeferredMonitorRemoval(Glib::RefPtr<Gdk::Monitor> mon
outputs_.remove_if([&monitor](const auto &output) { return output.monitor == monitor; });
}

const std::string waybar::Client::getStyle(const std::string &style) {
auto css_file = style.empty() ? Config::findConfigPath({"style.css"}) : style;
const std::string waybar::Client::getStyle(const std::string &style,
std::optional<Appearance> appearance = std::nullopt) {
std::optional<std::string> css_file;
if (style.empty()) {
std::vector<std::string> search_files;
switch (appearance.value_or(portal->getAppearance())) {
case waybar::Appearance::LIGHT:
search_files.push_back("style-light.css");
break;
case waybar::Appearance::DARK:
search_files.push_back("style-dark.css");
break;
case waybar::Appearance::UNKNOWN:
break;
}
search_files.push_back("style.css");
css_file = Config::findConfigPath(search_files);
} else {
css_file = style;
}
if (!css_file) {
throw std::runtime_error("Missing required resource files");
}
Expand Down Expand Up @@ -235,13 +253,24 @@ int waybar::Client::main(int argc, char *argv[]) {
}
wl_display = gdk_wayland_display_get_wl_display(gdk_display->gobj());
config.load(config_opt);
if (!portal) {
portal = std::make_unique<waybar::Portal>();
}
auto css_file = getStyle(style_opt);
setupCss(css_file);
portal->signal_appearance_changed().connect([&](waybar::Appearance appearance) {
auto css_file = getStyle(style_opt, appearance);
setupCss(css_file);
});
bindInterfaces();
gtk_app->hold();
gtk_app->run();
bars.clear();
return 0;
}

void waybar::Client::reset() { gtk_app->quit(); }
void waybar::Client::reset() {
gtk_app->quit();
// delete signal handler for css changes
portal->signal_appearance_changed().clear();
}
106 changes: 106 additions & 0 deletions src/util/portal.cpp
Original file line number Diff line number Diff line change
@@ -0,0 +1,106 @@
#include "util/portal.hpp"

#include <giomm/dbusproxy.h>
#include <glibmm/variant.h>
#include <spdlog/spdlog.h>

#include <iostream>
#include <string>

#include "fmt/format.h"

namespace waybar {
static constexpr const char* PORTAL_BUS_NAME = "org.freedesktop.portal.Desktop";
static constexpr const char* PORTAL_OBJ_PATH = "/org/freedesktop/portal/desktop";
static constexpr const char* PORTAL_INTERFACE = "org.freedesktop.portal.Settings";
static constexpr const char* PORTAL_NAMESPACE = "org.freedesktop.appearance";
static constexpr const char* PORTAL_KEY = "color-scheme";
} // namespace waybar

using namespace Gio;

auto fmt::formatter<waybar::Appearance>::format(waybar::Appearance c, format_context& ctx) const {
string_view name;
switch (c) {
case waybar::Appearance::LIGHT:
name = "light";
break;
case waybar::Appearance::DARK:
name = "dark";
break;
default:
name = "unknown";
break;
}
return formatter<string_view>::format(name, ctx);
}

waybar::Portal::Portal()
: DBus::Proxy(DBus::Connection::get_sync(DBus::BusType::BUS_TYPE_SESSION), PORTAL_BUS_NAME,
PORTAL_OBJ_PATH, PORTAL_INTERFACE),
currentMode(Appearance::UNKNOWN) {
refreshAppearance();
};

void waybar::Portal::refreshAppearance() {
auto params = Glib::Variant<std::tuple<Glib::ustring, Glib::ustring>>::create(
{PORTAL_NAMESPACE, PORTAL_KEY});
Glib::VariantBase response;
try {
response = call_sync(std::string(PORTAL_INTERFACE) + ".Read", params);
} catch (const Glib::Error& e) {
spdlog::info("Unable to receive desktop appearance: {}", std::string(e.what()));
return;
}

// unfortunately, the response is triple-nested, with type (v<v<uint32_t>>),
// so we have cast thrice. This is a variation from the freedesktop standard
// (it should only be doubly nested) but all implementations appear to do so.
//
// xdg-desktop-portal 1.17 will fix this issue with a new `ReadOne` method,
// but this version is not yet released.
// TODO(xdg-desktop-portal v1.17): switch to ReadOne
auto container = Glib::VariantBase::cast_dynamic<Glib::VariantContainerBase>(response);
Glib::VariantBase modev;
container.get_child(modev, 0);
auto mode =
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::Variant<Glib::Variant<uint32_t>>>>(modev)
.get()
.get()
.get();
auto newMode = Appearance(mode);
if (newMode == currentMode) {
return;
}
spdlog::info("Discovered appearance '{}'", newMode);
currentMode = newMode;
m_signal_appearance_changed.emit(currentMode);
}

waybar::Appearance waybar::Portal::getAppearance() { return currentMode; };

void waybar::Portal::on_signal(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
const Glib::VariantContainerBase& parameters) {
spdlog::debug("Received signal {}", (std::string)signal_name);
if (signal_name != "SettingChanged" || parameters.get_n_children() != 3) {
return;
}
Glib::VariantBase nspcv, keyv, valuev;
parameters.get_child(nspcv, 0);
parameters.get_child(keyv, 1);
parameters.get_child(valuev, 2);
auto nspc = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string>>(nspcv).get();
auto key = Glib::VariantBase::cast_dynamic<Glib::Variant<std::string>>(keyv).get();
if (nspc != PORTAL_NAMESPACE || key != PORTAL_KEY) {
return;
}
auto value =
Glib::VariantBase::cast_dynamic<Glib::Variant<Glib::Variant<uint32_t>>>(valuev).get().get();
auto newMode = Appearance(value);
if (newMode == currentMode) {
return;
}
spdlog::info("Received new appearance '{}'", newMode);
currentMode = newMode;
m_signal_appearance_changed.emit(currentMode);
}

0 comments on commit a90e275

Please sign in to comment.