refactor(tray): cleanup and fixes

This commit is contained in:
Alexis
2018-11-22 15:47:23 +01:00
parent bd62c4cbc5
commit ba79b4d397
14 changed files with 209 additions and 243 deletions

View File

@ -3,7 +3,7 @@
#include <iostream>
waybar::ALabel::ALabel(const Json::Value& config, const std::string format)
waybar::ALabel::ALabel(const Json::Value& config, const std::string& format)
: config_(config),
format_(config_["format"].isString() ? config_["format"].asString() : format),
default_format_(format_)

View File

@ -1,57 +1,52 @@
#include "modules/sni/snh.hpp"
#include "modules/sni/host.hpp"
#include <iostream>
using namespace waybar::modules::SNI;
Host::Host(Glib::Dispatcher* dp, const Json::Value &config)
: dp_(dp), config_(config)
Host::Host(const Json::Value &config, const std::function<void(std::unique_ptr<Item>&)>& on_add,
const std::function<void(std::unique_ptr<Item>&)>& on_remove)
: bus_name_("org.kde.StatusNotifierHost-" + std::to_string(getpid()) + "-1"),
object_path_("/StatusNotifierHost"),
bus_name_id_(Gio::DBus::own_name(Gio::DBus::BusType::BUS_TYPE_SESSION, bus_name_,
sigc::mem_fun(*this, &Host::busAcquired))),
config_(config), on_add_(on_add), on_remove_(on_remove)
{
GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>(
G_BUS_NAME_OWNER_FLAGS_NONE);
bus_name_ = "org.kde.StatusNotifierHost-" + std::to_string(getpid());
object_path_ = "/StatusNotifierHost";
bus_name_id_ = g_bus_own_name(G_BUS_TYPE_SESSION,
bus_name_.c_str(), flags,
&Host::busAcquired, nullptr, nullptr, this, nullptr);
}
void Host::busAcquired(GDBusConnection* connection,
const gchar* name, gpointer data)
Host::~Host()
{
auto host = static_cast<SNI::Host *>(data);
host->watcher_id_ = g_bus_watch_name(
G_BUS_TYPE_SESSION,
"org.kde.StatusNotifierWatcher",
G_BUS_NAME_WATCHER_FLAGS_NONE,
&Host::nameAppeared, &Host::nameVanished, data, nullptr);
Gio::DBus::unwatch_name(bus_name_id_);
}
void Host::nameAppeared(GDBusConnection* connection,
const gchar* name, const gchar* name_owner, gpointer data)
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name)
{
auto host = static_cast<SNI::Host *>(data);
if (host->cancellable_ != nullptr) {
watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher",
sigc::mem_fun(*this, &Host::nameAppeared), sigc::mem_fun(*this, &Host::nameVanished));
}
void Host::nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name,
const Glib::ustring& name_owner)
{
if (cancellable_ != nullptr) {
// TODO
return;
}
host->cancellable_ = g_cancellable_new();
cancellable_ = g_cancellable_new();
sn_watcher_proxy_new(
connection,
conn->gobj(),
G_DBUS_PROXY_FLAGS_NONE,
"org.kde.StatusNotifierWatcher",
"/StatusNotifierWatcher",
host->cancellable_, &Host::proxyReady, data);
cancellable_, &Host::proxyReady, this);
}
void Host::nameVanished(GDBusConnection* connection,
const gchar* name, gpointer data)
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name)
{
auto host = static_cast<SNI::Host *>(data);
g_cancellable_cancel(host->cancellable_);
g_clear_object(&host->cancellable_);
g_clear_object(&host->watcher_);
host->items.clear();
g_cancellable_cancel(cancellable_);
g_clear_object(&cancellable_);
g_clear_object(&watcher_);
items_.clear();
}
void Host::proxyReady(GObject* src, GAsyncResult* res,
@ -105,8 +100,7 @@ void Host::registerHost(GObject* src, GAsyncResult* res,
g_strfreev(items);
}
void Host::itemRegistered(
SnWatcher* watcher, const gchar* service, gpointer data)
void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer data)
{
auto host = static_cast<SNI::Host *>(data);
host->addRegisteredItem(service);
@ -117,35 +111,28 @@ void Host::itemUnregistered(
{
auto host = static_cast<SNI::Host *>(data);
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
for (auto it = host->items.begin(); it != host->items.end(); ++it) {
if (it->bus_name == bus_name && it->object_path == object_path) {
host->items.erase(it);
for (auto it = host->items_.begin(); it != host->items_.end(); ++it) {
if ((*it)->bus_name == bus_name && (*it)->object_path == object_path) {
host->on_remove_(*it);
host->items_.erase(it);
break;
}
}
host->dp_->emit();
}
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
const gchar* service)
const std::string service)
{
std::string bus_name;
std::string object_path;
gchar* tmp = g_strstr_len(service, -1, "/");
if (tmp != nullptr) {
gchar** str = g_strsplit(service, "/", 2);
bus_name = str[0];
object_path = tmp;
g_strfreev(str);
} else {
bus_name = service;
object_path = "/StatusNotifierItem";
auto it = service.find("/");
if (it != std::string::npos) {
return {service.substr(0, it), service.substr(it)};
}
return { bus_name, object_path };
return {service, "/StatusNotifierItem"};
}
void Host::addRegisteredItem(const gchar* service)
void Host::addRegisteredItem(std::string service)
{
auto [bus_name, object_path] = getBusNameAndObjectPath(service);
items.emplace_back(bus_name, object_path, dp_, config_);
items_.emplace_back(new Item(bus_name, object_path, config_));
on_add_(items_.back());
}

View File

@ -1,19 +1,16 @@
#include "modules/sni/sni.hpp"
#include "modules/sni/item.hpp"
#include <iostream>
waybar::modules::SNI::Item::Item(std::string bn, std::string op,
Glib::Dispatcher *dp, Json::Value config)
: bus_name(bn), object_path(op), event_box(Gtk::manage(new Gtk::EventBox())),
icon_size(16), effective_icon_size(0), image(Gtk::manage(new Gtk::Image())),
dp_(dp), config_(config)
waybar::modules::SNI::Item::Item(std::string bn, std::string op, const Json::Value& config)
: bus_name(bn), object_path(op), icon_size(16), effective_icon_size(0)
{
if (config_["icon-size"].isUInt()) {
icon_size = config_["icon-size"].asUInt();
if (config["icon-size"].isUInt()) {
icon_size = config["icon-size"].asUInt();
}
event_box->add(*image);
event_box->add_events(Gdk::BUTTON_PRESS_MASK);
event_box->signal_button_press_event().connect(
event_box.add(image);
event_box.add_events(Gdk::BUTTON_PRESS_MASK);
event_box.signal_button_press_event().connect(
sigc::mem_fun(*this, &Item::handleClick));
cancellable_ = g_cancellable_new();
sn_item_proxy_new_for_bus(
@ -94,12 +91,7 @@ void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res,
} else if (g_strcmp0(key, "IconThemePath") == 0) {
item->icon_theme_path = g_variant_dup_string(value, nullptr);
} else if (g_strcmp0(key, "Menu") == 0) {
auto menu = g_variant_dup_string(value, nullptr);
if (menu != nullptr) {
item->menu = dbusmenu_gtkmenu_new(item->bus_name.data(), menu);
item->gtk_menu = Glib::wrap(GTK_MENU(g_object_ref_sink(item->menu)), false);
item->gtk_menu->attach_to_widget(*item->event_box);
}
item->menu = g_variant_dup_string(value, nullptr);
} else if (g_strcmp0(key, "ItemIsMenu") == 0) {
item->item_is_menu = g_variant_get_boolean(value);
}
@ -119,8 +111,7 @@ void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res,
item->icon_theme_path.c_str());
}
item->updateImage();
item->event_box->set_tooltip_text(item->title);
item->dp_->emit();
// item->event_box.set_tooltip_text(item->title);
// TODO: handle change
}
@ -172,23 +163,10 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
return Glib::RefPtr<Gdk::Pixbuf>{};
}
bool waybar::modules::SNI::Item::showMenu(GdkEventButton *const &ev)
{
if (gtk_menu != nullptr) {
#if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev));
#else
gtk_menu->popup(ev->button, ev->time);
#endif
return true;
}
return false;
}
void waybar::modules::SNI::Item::updateImage()
{
image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image->set_pixel_size(icon_size);
image.set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
image.set_pixel_size(icon_size);
if (!icon_name.empty()) {
try {
// Try to find icons specified by path and filename
@ -203,10 +181,10 @@ void waybar::modules::SNI::Item::updateImage()
// the tray
pixbuf = pixbuf->scale_simple(icon_size, icon_size,
Gdk::InterpType::INTERP_BILINEAR);
image->set(pixbuf);
image.set(pixbuf);
}
} else {
image->set(getIconByName(icon_name, icon_size));
image.set(getIconByName(icon_name, icon_size));
}
} catch (Glib::Error &e) {
std::cerr << "Exception: " << e.what() << std::endl;
@ -215,7 +193,7 @@ void waybar::modules::SNI::Item::updateImage()
// An icon extracted may be the wrong size for the tray
icon_pixmap = icon_pixmap->scale_simple(icon_size, icon_size,
Gdk::InterpType::INTERP_BILINEAR);
image->set(icon_pixmap);
image.set(icon_pixmap);
}
}
@ -242,29 +220,47 @@ waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) {
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
}
void waybar::modules::SNI::Item::handleActivate(GObject *src, GAsyncResult *res,
gpointer data) {
auto item = static_cast<SNI::Item *>(data);
sn_item_call_activate_finish(item->proxy_, res, nullptr);
void waybar::modules::SNI::Item::onMenuDestroyed(Item *self)
{
self->gtk_menu = nullptr;
self->dbus_menu = nullptr;
}
void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src,
GAsyncResult *res, gpointer data) {
auto item = static_cast<SNI::Item *>(data);
sn_item_call_secondary_activate_finish(item->proxy_, res, nullptr);
bool waybar::modules::SNI::Item::makeMenu(GdkEventButton *const &ev)
{
std::cout << bus_name << std::endl;
if (gtk_menu == nullptr) {
if (!menu.empty()) {
dbus_menu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data());
if (dbus_menu != nullptr) {
g_object_ref_sink(G_OBJECT(dbus_menu));
g_object_weak_ref(G_OBJECT(dbus_menu), (GWeakNotify)onMenuDestroyed, this);
gtk_menu = Glib::wrap(GTK_MENU(dbus_menu));
gtk_menu->attach_to_widget(event_box);
}
}
}
if (gtk_menu != nullptr) {
#if GTK_CHECK_VERSION(3, 22, 0)
gtk_menu->popup_at_pointer(reinterpret_cast<GdkEvent*>(ev));
#else
gtk_menu->popup(ev->button, ev->time);
#endif
return true;
}
return false;
}
bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) {
if (ev->type == GDK_BUTTON_PRESS) {
if (!showMenu(ev)) {
sn_item_call_activate(
proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this);
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
if (!makeMenu(ev)) {
return sn_item_call_context_menu_sync(proxy_, ev->x, ev->y, nullptr, nullptr);
}
} else if (ev->type == GDK_2BUTTON_PRESS) {
sn_item_call_secondary_activate(
proxy_, ev->x, ev->y, nullptr, &Item::handleSecondaryActivate, this);
} else {
return false;
} else if (ev->button == 1) {
return sn_item_call_activate_sync(proxy_, ev->x, ev->y, nullptr, nullptr);
} else if (ev->button == 2) {
return sn_item_call_secondary_activate_sync(proxy_, ev->x, ev->y,
nullptr, nullptr);
}
return true;
return false;
}

View File

@ -3,7 +3,9 @@
#include <iostream>
waybar::modules::SNI::Tray::Tray(const Json::Value &config)
: config_(config), watcher_(), host_(&dp, config)
: config_(config), watcher_(), host_(config,
std::bind(&Tray::onAdd, this, std::placeholders::_1),
std::bind(&Tray::onRemove, this, std::placeholders::_1))
{
std::cout << "Tray is in beta, so there may be bugs or even be unusable." << std::endl;
if (config_["spacing"].isUInt()) {
@ -11,12 +13,19 @@ waybar::modules::SNI::Tray::Tray(const Json::Value &config)
}
}
void waybar::modules::SNI::Tray::onAdd(std::unique_ptr<Item>& item)
{
box_.pack_start(item->event_box);
dp.emit();
}
void waybar::modules::SNI::Tray::onRemove(std::unique_ptr<Item>& item)
{
box_.remove(item->event_box);
dp.emit();
}
auto waybar::modules::SNI::Tray::update() -> void {
auto childrens = box_.get_children();
// childrens.erase(childrens.begin(), childrens.end());
for (auto &item : host_.items) {
box_.pack_start(*item.event_box);
}
if (box_.get_children().size() > 0) {
box_.set_name("tray");
box_.show_all();

View File

@ -1,4 +1,4 @@
#include "modules/sni/snw.hpp"
#include "modules/sni/watcher.hpp"
#include <iostream>