refactor(tray): cleanup and fixes
parent
bd62c4cbc5
commit
ba79b4d397
|
@ -7,7 +7,7 @@ namespace waybar {
|
||||||
|
|
||||||
class ALabel : public IModule {
|
class ALabel : public IModule {
|
||||||
public:
|
public:
|
||||||
ALabel(const Json::Value&, const std::string format);
|
ALabel(const Json::Value&, const std::string& format);
|
||||||
virtual ~ALabel() = default;
|
virtual ~ALabel() = default;
|
||||||
virtual auto update() -> void;
|
virtual auto update() -> void;
|
||||||
virtual std::string getIcon(uint16_t, const std::string& alt = "");
|
virtual std::string getIcon(uint16_t, const std::string& alt = "");
|
||||||
|
@ -24,7 +24,7 @@ class ALabel : public IModule {
|
||||||
bool handleToggle(GdkEventButton* const& ev);
|
bool handleToggle(GdkEventButton* const& ev);
|
||||||
bool handleScroll(GdkEventScroll*);
|
bool handleScroll(GdkEventScroll*);
|
||||||
bool alt = false;
|
bool alt = false;
|
||||||
const std::string default_format_;
|
const std::string& default_format_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar
|
} // namespace waybar
|
||||||
|
|
|
@ -0,0 +1,40 @@
|
||||||
|
#pragma once
|
||||||
|
|
||||||
|
#include <gtkmm.h>
|
||||||
|
#include <json/json.h>
|
||||||
|
#include <tuple>
|
||||||
|
#include <dbus-status-notifier-watcher.h>
|
||||||
|
#include "modules/sni/item.hpp"
|
||||||
|
|
||||||
|
namespace waybar::modules::SNI {
|
||||||
|
|
||||||
|
class Host {
|
||||||
|
public:
|
||||||
|
Host(const Json::Value&, const std::function<void(std::unique_ptr<Item>&)>&,
|
||||||
|
const std::function<void(std::unique_ptr<Item>&)>&);
|
||||||
|
~Host();
|
||||||
|
private:
|
||||||
|
void busAcquired(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
|
||||||
|
void nameAppeared(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring, const Glib::ustring&);
|
||||||
|
void nameVanished(const Glib::RefPtr<Gio::DBus::Connection>&, Glib::ustring);
|
||||||
|
static void proxyReady(GObject*, GAsyncResult*, gpointer);
|
||||||
|
static void registerHost(GObject*, GAsyncResult*, gpointer);
|
||||||
|
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
|
||||||
|
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
|
||||||
|
|
||||||
|
std::tuple<std::string, std::string> getBusNameAndObjectPath(const std::string);
|
||||||
|
void addRegisteredItem(std::string service);
|
||||||
|
|
||||||
|
std::vector<std::unique_ptr<Item>> items_;
|
||||||
|
const std::string bus_name_;
|
||||||
|
const std::string object_path_;
|
||||||
|
std::size_t bus_name_id_;
|
||||||
|
std::size_t watcher_id_;
|
||||||
|
GCancellable* cancellable_ = nullptr;
|
||||||
|
SnWatcher* watcher_ = nullptr;
|
||||||
|
const Json::Value &config_;
|
||||||
|
std::function<void(std::unique_ptr<Item>&)> on_add_;
|
||||||
|
std::function<void(std::unique_ptr<Item>&)> on_remove_;
|
||||||
|
};
|
||||||
|
|
||||||
|
}
|
|
@ -14,15 +14,16 @@ namespace waybar::modules::SNI {
|
||||||
|
|
||||||
class Item {
|
class Item {
|
||||||
public:
|
public:
|
||||||
Item(std::string, std::string, Glib::Dispatcher*, Json::Value);
|
Item(std::string, std::string, const Json::Value&);
|
||||||
|
~Item() = default;
|
||||||
|
|
||||||
std::string bus_name;
|
std::string bus_name;
|
||||||
std::string object_path;
|
std::string object_path;
|
||||||
Gtk::EventBox *event_box;
|
|
||||||
|
|
||||||
int icon_size;
|
int icon_size;
|
||||||
int effective_icon_size;
|
int effective_icon_size;
|
||||||
Gtk::Image *image;
|
Gtk::Image image;
|
||||||
|
Gtk::EventBox event_box;
|
||||||
std::string category;
|
std::string category;
|
||||||
std::string id;
|
std::string id;
|
||||||
std::string status;
|
std::string status;
|
||||||
|
@ -35,26 +36,25 @@ public:
|
||||||
std::string attention_icon_name;
|
std::string attention_icon_name;
|
||||||
std::string attention_movie_name;
|
std::string attention_movie_name;
|
||||||
std::string icon_theme_path;
|
std::string icon_theme_path;
|
||||||
DbusmenuGtkMenu *menu = nullptr;
|
std::string menu;
|
||||||
|
DbusmenuGtkMenu *dbus_menu = nullptr;
|
||||||
Gtk::Menu *gtk_menu = nullptr;
|
Gtk::Menu *gtk_menu = nullptr;
|
||||||
bool item_is_menu;
|
bool item_is_menu;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void proxyReady(GObject *obj, GAsyncResult *res, gpointer data);
|
static void proxyReady(GObject *obj, GAsyncResult *res, gpointer data);
|
||||||
static void getAll(GObject *obj, GAsyncResult *res, gpointer data);
|
static void getAll(GObject *obj, GAsyncResult *res, gpointer data);
|
||||||
static void handleActivate(GObject *, GAsyncResult *, gpointer);
|
|
||||||
static void handleSecondaryActivate(GObject *, GAsyncResult *, gpointer);
|
|
||||||
|
|
||||||
void updateImage();
|
void updateImage();
|
||||||
bool showMenu(GdkEventButton *const &ev);
|
|
||||||
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
|
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
|
||||||
Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size);
|
Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size);
|
||||||
|
static void onMenuDestroyed(Item *self);
|
||||||
|
bool makeMenu(GdkEventButton *const &ev);
|
||||||
bool handleClick(GdkEventButton *const & /*ev*/);
|
bool handleClick(GdkEventButton *const & /*ev*/);
|
||||||
|
|
||||||
Glib::Dispatcher *dp_;
|
Glib::RefPtr<Gio::DBus::Connection> conn_;
|
||||||
GCancellable *cancellable_ = nullptr;
|
GCancellable *cancellable_ = nullptr;
|
||||||
SnItem *proxy_ = nullptr;
|
SnItem *proxy_ = nullptr;
|
||||||
Json::Value config_;
|
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::SNI
|
} // namespace waybar::modules::SNI
|
|
@ -1,38 +0,0 @@
|
||||||
#pragma once
|
|
||||||
|
|
||||||
#include <gtkmm.h>
|
|
||||||
#include <json/json.h>
|
|
||||||
#include <tuple>
|
|
||||||
#include <dbus-status-notifier-watcher.h>
|
|
||||||
#include "modules/sni/sni.hpp"
|
|
||||||
|
|
||||||
namespace waybar::modules::SNI {
|
|
||||||
|
|
||||||
class Host {
|
|
||||||
public:
|
|
||||||
Host(Glib::Dispatcher*, const Json::Value&);
|
|
||||||
std::vector<Item> items;
|
|
||||||
private:
|
|
||||||
static void busAcquired(GDBusConnection*, const gchar*, gpointer);
|
|
||||||
static void nameAppeared(GDBusConnection*, const gchar*, const gchar*,
|
|
||||||
gpointer);
|
|
||||||
static void nameVanished(GDBusConnection*, const gchar*, gpointer);
|
|
||||||
static void proxyReady(GObject*, GAsyncResult*, gpointer);
|
|
||||||
static void registerHost(GObject*, GAsyncResult*, gpointer);
|
|
||||||
static void itemRegistered(SnWatcher*, const gchar*, gpointer);
|
|
||||||
static void itemUnregistered(SnWatcher*, const gchar*, gpointer);
|
|
||||||
|
|
||||||
std::tuple<std::string, std::string> getBusNameAndObjectPath(const gchar*);
|
|
||||||
void addRegisteredItem(const gchar* service);
|
|
||||||
|
|
||||||
uint32_t bus_name_id_;
|
|
||||||
uint32_t watcher_id_;
|
|
||||||
std::string bus_name_;
|
|
||||||
std::string object_path_;
|
|
||||||
Glib::Dispatcher* dp_;
|
|
||||||
GCancellable* cancellable_ = nullptr;
|
|
||||||
SnWatcher* watcher_ = nullptr;
|
|
||||||
const Json::Value &config_;
|
|
||||||
};
|
|
||||||
|
|
||||||
}
|
|
|
@ -4,8 +4,8 @@
|
||||||
#include <thread>
|
#include <thread>
|
||||||
#include "util/json.hpp"
|
#include "util/json.hpp"
|
||||||
#include "IModule.hpp"
|
#include "IModule.hpp"
|
||||||
#include "modules/sni/snw.hpp"
|
#include "modules/sni/watcher.hpp"
|
||||||
#include "modules/sni/snh.hpp"
|
#include "modules/sni/host.hpp"
|
||||||
|
|
||||||
namespace waybar::modules::SNI {
|
namespace waybar::modules::SNI {
|
||||||
|
|
||||||
|
@ -15,6 +15,9 @@ class Tray : public IModule {
|
||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
operator Gtk::Widget &();
|
operator Gtk::Widget &();
|
||||||
private:
|
private:
|
||||||
|
void onAdd(std::unique_ptr<Item>& item);
|
||||||
|
void onRemove(std::unique_ptr<Item>& item);
|
||||||
|
|
||||||
std::thread thread_;
|
std::thread thread_;
|
||||||
const Json::Value& config_;
|
const Json::Value& config_;
|
||||||
Gtk::Box box_;
|
Gtk::Box box_;
|
||||||
|
|
|
@ -83,9 +83,9 @@ if dbusmenu_gtk.found()
|
||||||
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
|
add_project_arguments('-DHAVE_DBUSMENU', language: 'cpp')
|
||||||
src_files += files(
|
src_files += files(
|
||||||
'src/modules/sni/tray.cpp',
|
'src/modules/sni/tray.cpp',
|
||||||
'src/modules/sni/snw.cpp',
|
'src/modules/sni/watcher.cpp',
|
||||||
'src/modules/sni/snh.cpp',
|
'src/modules/sni/host.cpp',
|
||||||
'src/modules/sni/sni.cpp'
|
'src/modules/sni/item.cpp'
|
||||||
)
|
)
|
||||||
endif
|
endif
|
||||||
|
|
||||||
|
|
|
@ -1,78 +1,47 @@
|
||||||
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
<!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN"
|
||||||
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
"http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd">
|
||||||
<node>
|
<node>
|
||||||
<interface name="org.kde.StatusNotifierItem">
|
<interface name='org.kde.StatusNotifierItem'>
|
||||||
<annotation name="org.gtk.GDBus.C.Name" value="Item" />
|
<annotation name="org.gtk.GDBus.C.Name" value="Item" />
|
||||||
<property name="Category" type="s" access="read"/>
|
<method name='ContextMenu'>
|
||||||
<property name="Id" type="s" access="read"/>
|
<arg type='i' direction='in' name='x'/>
|
||||||
<property name="Title" type="s" access="read"/>
|
<arg type='i' direction='in' name='y'/>
|
||||||
<property name="Status" type="s" access="read"/>
|
|
||||||
<property name="WindowId" type="i" access="read"/>
|
|
||||||
<property name="Menu" type="o" access="read" />
|
|
||||||
|
|
||||||
<!-- main icon -->
|
|
||||||
<!-- names are preferred over pixmaps -->
|
|
||||||
<property name="IconName" type="s" access="read" />
|
|
||||||
<property name="IconThemePath" type="s" access="read" />
|
|
||||||
|
|
||||||
<!-- struct containing width, height and image data-->
|
|
||||||
<!-- implementation has been dropped as of now -->
|
|
||||||
<property name="IconPixmap" type="a(iiay)" access="read" />
|
|
||||||
|
|
||||||
<!-- not used in ayatana code, no test case so far -->
|
|
||||||
<property name="OverlayIconName" type="s" access="read"/>
|
|
||||||
<property name="OverlayIconPixmap" type="a(iiay)" access="read" />
|
|
||||||
|
|
||||||
<!-- Requesting attention icon -->
|
|
||||||
<property name="AttentionIconName" type="s" access="read"/>
|
|
||||||
|
|
||||||
<!--same definition as image-->
|
|
||||||
<property name="AttentionIconPixmap" type="a(iiay)" access="read" />
|
|
||||||
|
|
||||||
<!-- tooltip data -->
|
|
||||||
<!-- unimplemented as of now -->
|
|
||||||
<!--(iiay) is an image-->
|
|
||||||
<property name="ToolTip" type="(sa(iiay)ss)" access="read" />
|
|
||||||
|
|
||||||
|
|
||||||
<!-- interaction: actually, we do not use them. -->
|
|
||||||
<method name="Activate">
|
|
||||||
<arg name="x" type="i" direction="in"/>
|
|
||||||
<arg name="y" type="i" direction="in"/>
|
|
||||||
</method>
|
</method>
|
||||||
<method name="SecondaryActivate">
|
<method name='Activate'>
|
||||||
<arg name="x" type="i" direction="in"/>
|
<arg type='i' direction='in' name='x'/>
|
||||||
<arg name="y" type="i" direction="in"/>
|
<arg type='i' direction='in' name='y'/>
|
||||||
</method>
|
</method>
|
||||||
<method name="Scroll">
|
<method name='SecondaryActivate'>
|
||||||
<arg name="delta" type="i" direction="in"/>
|
<arg type='i' direction='in' name='x'/>
|
||||||
<arg name="dir" type="s" direction="in"/>
|
<arg type='i' direction='in' name='y'/>
|
||||||
</method>
|
</method>
|
||||||
|
<method name='Scroll'>
|
||||||
<!-- Signals: the client wants to change something in the status-->
|
<arg type='i' direction='in' name='delta'/>
|
||||||
<signal name="NewTitle"></signal>
|
<arg type='s' direction='in' name='orientation'/>
|
||||||
<signal name="NewIcon"></signal>
|
</method>
|
||||||
<signal name="NewIconThemePath">
|
<signal name='NewTitle'/>
|
||||||
<arg type="s" name="icon_theme_path" direction="out" />
|
<signal name='NewIcon'/>
|
||||||
|
<signal name='NewAttentionIcon'/>
|
||||||
|
<signal name='NewOverlayIcon'/>
|
||||||
|
<signal name='NewToolTip'/>
|
||||||
|
<signal name='NewStatus'>
|
||||||
|
<arg type='s' name='status'/>
|
||||||
</signal>
|
</signal>
|
||||||
<signal name="NewAttentionIcon"></signal>
|
<property name='Category' type='s' access='read'/>
|
||||||
<signal name="NewOverlayIcon"></signal>
|
<property name='Id' type='s' access='read'/>
|
||||||
<signal name="NewToolTip"></signal>
|
<property name='Title' type='s' access='read'/>
|
||||||
<signal name="NewStatus">
|
<property name='Status' type='s' access='read'/>
|
||||||
<arg name="status" type="s" />
|
<property name='WindowId' type='u' access='read'/>
|
||||||
</signal>
|
<property name='IconThemePath' type='s' access='read'/>
|
||||||
|
<property name='IconName' type='s' access='read'/>
|
||||||
<!-- ayatana labels -->
|
<property name='IconPixmap' type='a(iiay)' access='read'/>
|
||||||
<!-- These are commented out because GDBusProxy would otherwise require them,
|
<property name='OverlayIconName' type='s' access='read'/>
|
||||||
but they are not available for KDE indicators
|
<property name='OverlayIconPixmap' type='a(iiay)' access='read'/>
|
||||||
-->
|
<property name='AttentionIconName' type='s' access='read'/>
|
||||||
<!--<signal name="XAyatanaNewLabel">
|
<property name='AttentionIconPixmap' type='a(iiay)' access='read'/>
|
||||||
<arg type="s" name="label" direction="out" />
|
<property name='AttentionMovieName' type='s' access='read'/>
|
||||||
<arg type="s" name="guide" direction="out" />
|
<property name='ToolTip' type='(sa(iiay)ss)' access='read'/>
|
||||||
</signal>
|
<property name='Menu' type='o' access='read'/>
|
||||||
<property name="XAyatanaLabel" type="s" access="read" />
|
<property name='ItemIsMenu' type='b' access='read'/>
|
||||||
<property name="XAyatanaLabelGuide" type="s" access="read" />-->
|
|
||||||
|
|
||||||
|
|
||||||
</interface>
|
</interface>
|
||||||
</node>
|
</node>
|
|
@ -3,7 +3,7 @@
|
||||||
|
|
||||||
#include <iostream>
|
#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),
|
: config_(config),
|
||||||
format_(config_["format"].isString() ? config_["format"].asString() : format),
|
format_(config_["format"].isString() ? config_["format"].asString() : format),
|
||||||
default_format_(format_)
|
default_format_(format_)
|
||||||
|
|
|
@ -1,57 +1,52 @@
|
||||||
#include "modules/sni/snh.hpp"
|
#include "modules/sni/host.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
using namespace waybar::modules::SNI;
|
using namespace waybar::modules::SNI;
|
||||||
|
|
||||||
Host::Host(Glib::Dispatcher* dp, const Json::Value &config)
|
Host::Host(const Json::Value &config, const std::function<void(std::unique_ptr<Item>&)>& on_add,
|
||||||
: dp_(dp), config_(config)
|
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,
|
Host::~Host()
|
||||||
const gchar* name, gpointer data)
|
|
||||||
{
|
{
|
||||||
auto host = static_cast<SNI::Host *>(data);
|
Gio::DBus::unwatch_name(bus_name_id_);
|
||||||
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);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::nameAppeared(GDBusConnection* connection,
|
void Host::busAcquired(const Glib::RefPtr<Gio::DBus::Connection>& conn, Glib::ustring name)
|
||||||
const gchar* name, const gchar* name_owner, gpointer data)
|
|
||||||
{
|
{
|
||||||
auto host = static_cast<SNI::Host *>(data);
|
watcher_id_ = Gio::DBus::watch_name(conn, "org.kde.StatusNotifierWatcher",
|
||||||
if (host->cancellable_ != nullptr) {
|
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
|
// TODO
|
||||||
return;
|
return;
|
||||||
}
|
}
|
||||||
host->cancellable_ = g_cancellable_new();
|
cancellable_ = g_cancellable_new();
|
||||||
sn_watcher_proxy_new(
|
sn_watcher_proxy_new(
|
||||||
connection,
|
conn->gobj(),
|
||||||
G_DBUS_PROXY_FLAGS_NONE,
|
G_DBUS_PROXY_FLAGS_NONE,
|
||||||
"org.kde.StatusNotifierWatcher",
|
"org.kde.StatusNotifierWatcher",
|
||||||
"/StatusNotifierWatcher",
|
"/StatusNotifierWatcher",
|
||||||
host->cancellable_, &Host::proxyReady, data);
|
cancellable_, &Host::proxyReady, this);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::nameVanished(GDBusConnection* connection,
|
void Host::nameVanished(const Glib::RefPtr<Gio::DBus::Connection>& conn, const Glib::ustring name)
|
||||||
const gchar* name, gpointer data)
|
|
||||||
{
|
{
|
||||||
auto host = static_cast<SNI::Host *>(data);
|
g_cancellable_cancel(cancellable_);
|
||||||
g_cancellable_cancel(host->cancellable_);
|
g_clear_object(&cancellable_);
|
||||||
g_clear_object(&host->cancellable_);
|
g_clear_object(&watcher_);
|
||||||
g_clear_object(&host->watcher_);
|
items_.clear();
|
||||||
host->items.clear();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::proxyReady(GObject* src, GAsyncResult* res,
|
void Host::proxyReady(GObject* src, GAsyncResult* res,
|
||||||
|
@ -105,8 +100,7 @@ void Host::registerHost(GObject* src, GAsyncResult* res,
|
||||||
g_strfreev(items);
|
g_strfreev(items);
|
||||||
}
|
}
|
||||||
|
|
||||||
void Host::itemRegistered(
|
void Host::itemRegistered(SnWatcher* watcher, const gchar* service, gpointer data)
|
||||||
SnWatcher* watcher, const gchar* service, gpointer data)
|
|
||||||
{
|
{
|
||||||
auto host = static_cast<SNI::Host *>(data);
|
auto host = static_cast<SNI::Host *>(data);
|
||||||
host->addRegisteredItem(service);
|
host->addRegisteredItem(service);
|
||||||
|
@ -117,35 +111,28 @@ void Host::itemUnregistered(
|
||||||
{
|
{
|
||||||
auto host = static_cast<SNI::Host *>(data);
|
auto host = static_cast<SNI::Host *>(data);
|
||||||
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
|
auto [bus_name, object_path] = host->getBusNameAndObjectPath(service);
|
||||||
for (auto it = host->items.begin(); it != host->items.end(); ++it) {
|
for (auto it = host->items_.begin(); it != host->items_.end(); ++it) {
|
||||||
if (it->bus_name == bus_name && it->object_path == object_path) {
|
if ((*it)->bus_name == bus_name && (*it)->object_path == object_path) {
|
||||||
host->items.erase(it);
|
host->on_remove_(*it);
|
||||||
|
host->items_.erase(it);
|
||||||
break;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
host->dp_->emit();
|
|
||||||
}
|
}
|
||||||
|
|
||||||
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
|
std::tuple<std::string, std::string> Host::getBusNameAndObjectPath(
|
||||||
const gchar* service)
|
const std::string service)
|
||||||
{
|
{
|
||||||
std::string bus_name;
|
auto it = service.find("/");
|
||||||
std::string object_path;
|
if (it != std::string::npos) {
|
||||||
gchar* tmp = g_strstr_len(service, -1, "/");
|
return {service.substr(0, it), service.substr(it)};
|
||||||
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";
|
|
||||||
}
|
}
|
||||||
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);
|
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());
|
||||||
}
|
}
|
|
@ -1,19 +1,16 @@
|
||||||
#include "modules/sni/sni.hpp"
|
#include "modules/sni/item.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
waybar::modules::SNI::Item::Item(std::string bn, std::string op,
|
waybar::modules::SNI::Item::Item(std::string bn, std::string op, const Json::Value& config)
|
||||||
Glib::Dispatcher *dp, Json::Value config)
|
: bus_name(bn), object_path(op), icon_size(16), effective_icon_size(0)
|
||||||
: 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)
|
|
||||||
{
|
{
|
||||||
if (config_["icon-size"].isUInt()) {
|
if (config["icon-size"].isUInt()) {
|
||||||
icon_size = config_["icon-size"].asUInt();
|
icon_size = config["icon-size"].asUInt();
|
||||||
}
|
}
|
||||||
event_box->add(*image);
|
event_box.add(image);
|
||||||
event_box->add_events(Gdk::BUTTON_PRESS_MASK);
|
event_box.add_events(Gdk::BUTTON_PRESS_MASK);
|
||||||
event_box->signal_button_press_event().connect(
|
event_box.signal_button_press_event().connect(
|
||||||
sigc::mem_fun(*this, &Item::handleClick));
|
sigc::mem_fun(*this, &Item::handleClick));
|
||||||
cancellable_ = g_cancellable_new();
|
cancellable_ = g_cancellable_new();
|
||||||
sn_item_proxy_new_for_bus(
|
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) {
|
} else if (g_strcmp0(key, "IconThemePath") == 0) {
|
||||||
item->icon_theme_path = g_variant_dup_string(value, nullptr);
|
item->icon_theme_path = g_variant_dup_string(value, nullptr);
|
||||||
} else if (g_strcmp0(key, "Menu") == 0) {
|
} else if (g_strcmp0(key, "Menu") == 0) {
|
||||||
auto menu = g_variant_dup_string(value, nullptr);
|
item->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);
|
|
||||||
}
|
|
||||||
} else if (g_strcmp0(key, "ItemIsMenu") == 0) {
|
} else if (g_strcmp0(key, "ItemIsMenu") == 0) {
|
||||||
item->item_is_menu = g_variant_get_boolean(value);
|
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->icon_theme_path.c_str());
|
||||||
}
|
}
|
||||||
item->updateImage();
|
item->updateImage();
|
||||||
item->event_box->set_tooltip_text(item->title);
|
// item->event_box.set_tooltip_text(item->title);
|
||||||
item->dp_->emit();
|
|
||||||
// TODO: handle change
|
// TODO: handle change
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -172,23 +163,10 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
|
||||||
return Glib::RefPtr<Gdk::Pixbuf>{};
|
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()
|
void waybar::modules::SNI::Item::updateImage()
|
||||||
{
|
{
|
||||||
image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
|
image.set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU);
|
||||||
image->set_pixel_size(icon_size);
|
image.set_pixel_size(icon_size);
|
||||||
if (!icon_name.empty()) {
|
if (!icon_name.empty()) {
|
||||||
try {
|
try {
|
||||||
// Try to find icons specified by path and filename
|
// Try to find icons specified by path and filename
|
||||||
|
@ -203,10 +181,10 @@ void waybar::modules::SNI::Item::updateImage()
|
||||||
// the tray
|
// the tray
|
||||||
pixbuf = pixbuf->scale_simple(icon_size, icon_size,
|
pixbuf = pixbuf->scale_simple(icon_size, icon_size,
|
||||||
Gdk::InterpType::INTERP_BILINEAR);
|
Gdk::InterpType::INTERP_BILINEAR);
|
||||||
image->set(pixbuf);
|
image.set(pixbuf);
|
||||||
}
|
}
|
||||||
} else {
|
} else {
|
||||||
image->set(getIconByName(icon_name, icon_size));
|
image.set(getIconByName(icon_name, icon_size));
|
||||||
}
|
}
|
||||||
} catch (Glib::Error &e) {
|
} catch (Glib::Error &e) {
|
||||||
std::cerr << "Exception: " << e.what() << std::endl;
|
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
|
// An icon extracted may be the wrong size for the tray
|
||||||
icon_pixmap = icon_pixmap->scale_simple(icon_size, icon_size,
|
icon_pixmap = icon_pixmap->scale_simple(icon_size, icon_size,
|
||||||
Gdk::InterpType::INTERP_BILINEAR);
|
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);
|
Gtk::IconLookupFlags::ICON_LOOKUP_FORCE_SIZE);
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::SNI::Item::handleActivate(GObject *src, GAsyncResult *res,
|
void waybar::modules::SNI::Item::onMenuDestroyed(Item *self)
|
||||||
gpointer data) {
|
{
|
||||||
auto item = static_cast<SNI::Item *>(data);
|
self->gtk_menu = nullptr;
|
||||||
sn_item_call_activate_finish(item->proxy_, res, nullptr);
|
self->dbus_menu = nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src,
|
bool waybar::modules::SNI::Item::makeMenu(GdkEventButton *const &ev)
|
||||||
GAsyncResult *res, gpointer data) {
|
{
|
||||||
auto item = static_cast<SNI::Item *>(data);
|
std::cout << bus_name << std::endl;
|
||||||
sn_item_call_secondary_activate_finish(item->proxy_, res, nullptr);
|
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) {
|
bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) {
|
||||||
if (ev->type == GDK_BUTTON_PRESS) {
|
if ((ev->button == 1 && item_is_menu) || ev->button == 3) {
|
||||||
if (!showMenu(ev)) {
|
if (!makeMenu(ev)) {
|
||||||
sn_item_call_activate(
|
return sn_item_call_context_menu_sync(proxy_, ev->x, ev->y, nullptr, nullptr);
|
||||||
proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this);
|
}
|
||||||
|
} 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);
|
||||||
}
|
}
|
||||||
} else if (ev->type == GDK_2BUTTON_PRESS) {
|
|
||||||
sn_item_call_secondary_activate(
|
|
||||||
proxy_, ev->x, ev->y, nullptr, &Item::handleSecondaryActivate, this);
|
|
||||||
} else {
|
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
return true;
|
|
||||||
}
|
|
|
@ -3,7 +3,9 @@
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
waybar::modules::SNI::Tray::Tray(const Json::Value &config)
|
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;
|
std::cout << "Tray is in beta, so there may be bugs or even be unusable." << std::endl;
|
||||||
if (config_["spacing"].isUInt()) {
|
if (config_["spacing"].isUInt()) {
|
||||||
|
@ -11,12 +13,19 @@ waybar::modules::SNI::Tray::Tray(const Json::Value &config)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
auto waybar::modules::SNI::Tray::update() -> void {
|
void waybar::modules::SNI::Tray::onAdd(std::unique_ptr<Item>& item)
|
||||||
auto childrens = box_.get_children();
|
{
|
||||||
// childrens.erase(childrens.begin(), childrens.end());
|
box_.pack_start(item->event_box);
|
||||||
for (auto &item : host_.items) {
|
dp.emit();
|
||||||
box_.pack_start(*item.event_box);
|
|
||||||
}
|
}
|
||||||
|
|
||||||
|
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 {
|
||||||
if (box_.get_children().size() > 0) {
|
if (box_.get_children().size() > 0) {
|
||||||
box_.set_name("tray");
|
box_.set_name("tray");
|
||||||
box_.show_all();
|
box_.show_all();
|
||||||
|
|
|
@ -1,4 +1,4 @@
|
||||||
#include "modules/sni/snw.hpp"
|
#include "modules/sni/watcher.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
Loading…
Reference in New Issue