mirror of
				https://github.com/rad4day/Waybar.git
				synced 2025-10-31 07:52:42 +01:00 
			
		
		
		
	| @@ -2,14 +2,10 @@ | ||||
|  | ||||
| #include <unistd.h> | ||||
| #include <wordexp.h> | ||||
|  | ||||
| #include <fmt/format.h> | ||||
|  | ||||
| #include <gdk/gdk.h> | ||||
| #include <wayland-client.h> | ||||
|  | ||||
| #include <gdk/gdkwayland.h> | ||||
|  | ||||
| #include "bar.hpp" | ||||
|  | ||||
| namespace waybar { | ||||
| @@ -30,14 +26,14 @@ class Client { | ||||
|     struct wl_seat *seat = nullptr; | ||||
|     std::vector<std::unique_ptr<Bar>> bars; | ||||
|  | ||||
| private: | ||||
|   void bindInterfaces(); | ||||
|   auto setupCss(); | ||||
|   private: | ||||
|     void bindInterfaces(); | ||||
|     auto setupCss(); | ||||
|  | ||||
|   static void handleGlobal(void *data, struct wl_registry *registry, | ||||
|     uint32_t name, const char *interface, uint32_t version); | ||||
|   static void handleGlobalRemove(void *data, | ||||
|     struct wl_registry *registry, uint32_t name); | ||||
|     static void handleGlobal(void *data, struct wl_registry *registry, | ||||
|       uint32_t name, const char *interface, uint32_t version); | ||||
|     static void handleGlobalRemove(void *data, | ||||
|       struct wl_registry *registry, uint32_t name); | ||||
| }; | ||||
|  | ||||
| } | ||||
|   | ||||
| @@ -9,6 +9,7 @@ | ||||
| #include "modules/battery.hpp" | ||||
| #include "modules/memory.hpp" | ||||
| #include "modules/cpu.hpp" | ||||
| #include "modules/sni/tray.hpp" | ||||
| #ifdef HAVE_LIBNL | ||||
| #include "modules/network.hpp" | ||||
| #endif | ||||
|   | ||||
							
								
								
									
										39
									
								
								include/modules/sni/snh.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										39
									
								
								include/modules/sni/snh.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,39 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <gtkmm.h> | ||||
|  | ||||
| #include <tuple> | ||||
| #include <dbus-status-notifier-watcher.h> | ||||
| #include "modules/sni/sni.hpp" | ||||
|  | ||||
| namespace waybar::modules::SNI { | ||||
|  | ||||
| class Host { | ||||
|   public: | ||||
|     Host(Glib::Dispatcher*); | ||||
|     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(SnOrgKdeStatusNotifierWatcher*, const gchar*, | ||||
|       gpointer); | ||||
|     static void itemUnregistered(SnOrgKdeStatusNotifierWatcher*, 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; | ||||
|     SnOrgKdeStatusNotifierWatcher* watcher_ = nullptr; | ||||
| }; | ||||
|  | ||||
| } | ||||
							
								
								
									
										51
									
								
								include/modules/sni/sni.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								include/modules/sni/sni.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,51 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <dbus-status-notifier-item.h> | ||||
| #include <gtkmm.h> | ||||
|  | ||||
| namespace waybar::modules::SNI { | ||||
|  | ||||
| class Item { | ||||
| public: | ||||
|   Item(std::string, std::string, Glib::Dispatcher *); | ||||
|  | ||||
|   std::string bus_name; | ||||
|   std::string object_path; | ||||
|   Gtk::EventBox event_box; | ||||
|  | ||||
|   int icon_size; | ||||
|   int effective_icon_size; | ||||
|   Gtk::Image *image; | ||||
|   Gtk::Menu *gtk_menu = nullptr; | ||||
|   std::string category; | ||||
|   std::string id; | ||||
|   std::string status; | ||||
|  | ||||
|   std::string title; | ||||
|   int32_t window_id; | ||||
|   std::string icon_name; | ||||
|   Glib::RefPtr<Gdk::Pixbuf> icon_pixmap; | ||||
|   std::string overlay_icon_name; | ||||
|   std::string attention_icon_name; | ||||
|   std::string attention_movie_name; | ||||
|   std::string icon_theme_path; | ||||
|   std::string menu; | ||||
|   bool item_is_menu; | ||||
|  | ||||
| private: | ||||
|   static void proxyReady(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(); | ||||
|   Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant); | ||||
|   Glib::RefPtr<Gdk::Pixbuf> getIconByName(std::string name, int size); | ||||
|   bool handleClick(GdkEventButton *const & /*ev*/); | ||||
|  | ||||
|   Glib::Dispatcher *dp_; | ||||
|   GCancellable *cancellable_ = nullptr; | ||||
|   SnOrgKdeStatusNotifierItem *proxy_ = nullptr; | ||||
| }; | ||||
|  | ||||
| } // namespace waybar::modules::SNI | ||||
							
								
								
									
										47
									
								
								include/modules/sni/snw.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										47
									
								
								include/modules/sni/snw.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,47 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <gtkmm.h> | ||||
| #include <dbus-status-notifier-watcher.h> | ||||
|  | ||||
| namespace waybar::modules::SNI { | ||||
|  | ||||
| class Watcher { | ||||
| public: | ||||
|   Watcher(); | ||||
|   ~Watcher(); | ||||
|  | ||||
| private: | ||||
|   typedef enum { GF_WATCH_TYPE_HOST, GF_WATCH_TYPE_ITEM } GfWatchType; | ||||
|  | ||||
|   typedef struct { | ||||
|     GfWatchType type; | ||||
|     Watcher *watcher; | ||||
|     gchar *service; | ||||
|     gchar *bus_name; | ||||
|     gchar *object_path; | ||||
|     guint watch_id; | ||||
|   } GfWatch; | ||||
|  | ||||
|   static void busAcquired(GDBusConnection *, const gchar *, gpointer); | ||||
|   static gboolean handleRegisterHost(Watcher *, GDBusMethodInvocation *, | ||||
|                                      const gchar *); | ||||
|   static gboolean handleRegisterItem(Watcher *, GDBusMethodInvocation *, | ||||
|                                      const gchar *); | ||||
|   static GfWatch *gfWatchFind(GSList *list, const gchar *bus_name, | ||||
|                               const gchar *object_path); | ||||
|   static GfWatch *gfWatchNew(GfWatchType, const gchar *, const gchar *, | ||||
|                              const gchar *, Watcher *); | ||||
|   static void nameVanished(GDBusConnection *connection, const char *name, | ||||
|                            gpointer data); | ||||
|  | ||||
|   void updateRegisteredItems(SnOrgKdeStatusNotifierWatcher *obj); | ||||
|  | ||||
|   uint32_t bus_name_id_; | ||||
|   uint32_t watcher_id_; | ||||
|   GSList *hosts_ = nullptr; | ||||
|   GSList *items_ = nullptr; | ||||
|   SnOrgKdeStatusNotifierWatcher *watcher_ = nullptr; | ||||
| }; | ||||
|  | ||||
| } // namespace waybar::modules::SNI | ||||
|  | ||||
							
								
								
									
										25
									
								
								include/modules/sni/tray.hpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										25
									
								
								include/modules/sni/tray.hpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,25 @@ | ||||
| #pragma once | ||||
|  | ||||
| #include <fmt/format.h> | ||||
| #include <thread> | ||||
| #include "util/json.hpp" | ||||
| #include "IModule.hpp" | ||||
| #include "modules/sni/snw.hpp" | ||||
| #include "modules/sni/snh.hpp" | ||||
|  | ||||
| namespace waybar::modules::SNI { | ||||
|  | ||||
| class Tray : public IModule { | ||||
|   public: | ||||
|     Tray(const Json::Value&); | ||||
|     auto update() -> void; | ||||
|     operator Gtk::Widget &(); | ||||
|   private: | ||||
|     std::thread thread_; | ||||
|     const Json::Value& config_; | ||||
|     Gtk::Box box_; | ||||
|     SNI::Watcher watcher_ ; | ||||
|     SNI::Host host_; | ||||
| }; | ||||
|  | ||||
| } | ||||
| @@ -32,6 +32,7 @@ wayland_cursor = dependency('wayland-cursor') | ||||
| wayland_protos = dependency('wayland-protocols') | ||||
| wlroots = dependency('wlroots', fallback: ['wlroots', 'wlroots']) | ||||
| gtkmm = dependency('gtkmm-3.0') | ||||
| dbusmenu_gtk = dependency('dbusmenu-gtk3-0.4') | ||||
| jsoncpp = dependency('jsoncpp') | ||||
| sigcpp = dependency('sigc++-2.0') | ||||
| libnl = dependency('libnl-3.0', required: get_option('libnl')) | ||||
| @@ -46,6 +47,10 @@ src_files = files( | ||||
|     'src/modules/clock.cpp', | ||||
|     'src/modules/custom.cpp', | ||||
|     'src/modules/cpu.cpp', | ||||
|     'src/modules/sni/tray.cpp', | ||||
|     'src/modules/sni/snw.cpp', | ||||
|     'src/modules/sni/snh.cpp', | ||||
|     'src/modules/sni/sni.cpp', | ||||
|     'src/main.cpp', | ||||
|     'src/bar.cpp', | ||||
|     'src/client.cpp' | ||||
| @@ -86,9 +91,10 @@ executable( | ||||
|         libinput, | ||||
|         wayland_cursor, | ||||
|         gtkmm, | ||||
|         dbusmenu_gtk, | ||||
|         libnl, | ||||
|         libnlgen, | ||||
|         libpulse, | ||||
|         libpulse | ||||
|     ], | ||||
|     include_directories: [include_directories('include')], | ||||
|     install: true, | ||||
|   | ||||
							
								
								
									
										69
									
								
								protocol/dbus-menu.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										69
									
								
								protocol/dbus-menu.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,69 @@ | ||||
| <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" | ||||
| "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> | ||||
| <node> | ||||
| <interface name="com.canonical.dbusmenu"> | ||||
|     <!-- Properties --> | ||||
|     <property name="Version" type="u" access="read" /> | ||||
|     <property name="TextDirection" type="s" access="read" /> | ||||
|     <property name="Status" type="s" access="read" /> | ||||
|     <property name="IconThemePath" type="as" access="read" /> | ||||
|  | ||||
|     <!-- Functions --> | ||||
|     <method name="GetLayout"> | ||||
|         <arg type="i" name="parentId" direction="in" /> | ||||
|         <arg type="i" name="recursionDepth" direction="in" /> | ||||
|         <arg type="as" name="propertyNames" direction="in" /> | ||||
|         <arg type="u" name="revision" direction="out" /> | ||||
|         <arg type="(ia{sv}av)" name="layout" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="GetGroupProperties"> | ||||
|         <arg type="ai" name="ids" direction="in" /> | ||||
|         <arg type="as" name="propertyNames" direction="in" /> | ||||
|         <arg type="a(ia{sv})" name="properties" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="GetProperty"> | ||||
|         <arg type="i" name="id" direction="in" /> | ||||
|         <arg type="s" name="name" direction="in" /> | ||||
|         <arg type="v" name="value" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="Event"> | ||||
|         <arg type="i" name="id" direction="in" /> | ||||
|         <arg type="s" name="eventId" direction="in" /> | ||||
|         <arg type="v" name="data" direction="in" /> | ||||
|         <arg type="u" name="timestamp" direction="in" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="EventGroup"> | ||||
|         <arg type="a(isvu)" name="events" direction="in" /> | ||||
|         <arg type="ai" name="idErrors" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="AboutToShow"> | ||||
|         <arg type="i" name="id" direction="in" /> | ||||
|         <arg type="b" name="needUpdate" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <method name="AboutToShowGroup"> | ||||
|         <arg type="ai" name="ids" direction="in" /> | ||||
|         <arg type="ai" name="updatesNeeded" direction="out" /> | ||||
|         <arg type="ai" name="idErrors" direction="out" /> | ||||
|     </method> | ||||
|  | ||||
|     <!-- Signals --> | ||||
|     <signal name="ItemsPropertiesUpdated"> | ||||
|         <arg type="a(ia{sv})" name="updatedProps" direction="out" /> | ||||
|         <arg type="a(ias)" name="removedProps" direction="out" /> | ||||
|     </signal> | ||||
|     <signal name="LayoutUpdated"> | ||||
|         <arg type="u" name="revision" direction="out" /> | ||||
|         <arg type="i" name="parent" direction="out" /> | ||||
|     </signal> | ||||
|     <signal name="ItemActivationRequested"> | ||||
|         <arg type="i" name="id" direction="out" /> | ||||
|         <arg type="u" name="timestamp" direction="out" /> | ||||
|     </signal> | ||||
| </interface> | ||||
| </node> | ||||
							
								
								
									
										77
									
								
								protocol/dbus-status-notifier-item.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										77
									
								
								protocol/dbus-status-notifier-item.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,77 @@ | ||||
| <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" | ||||
| "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> | ||||
| <node> | ||||
| <interface name="org.kde.StatusNotifierItem"> | ||||
|     <property name="Category" type="s" access="read"/> | ||||
|     <property name="Id" type="s" access="read"/> | ||||
|     <property name="Title" type="s" access="read"/> | ||||
|     <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 name="SecondaryActivate"> | ||||
|         <arg name="x" type="i" direction="in"/> | ||||
|         <arg name="y" type="i" direction="in"/> | ||||
|     </method> | ||||
|     <method name="Scroll"> | ||||
|         <arg name="delta" type="i" direction="in"/> | ||||
|         <arg name="dir"   type="s" direction="in"/> | ||||
|     </method> | ||||
|  | ||||
|     <!-- Signals: the client wants to change something in the status--> | ||||
|     <signal name="NewTitle"></signal> | ||||
|     <signal name="NewIcon"></signal> | ||||
|     <signal name="NewIconThemePath"> | ||||
|         <arg type="s" name="icon_theme_path" direction="out" /> | ||||
|     </signal> | ||||
|     <signal name="NewAttentionIcon"></signal> | ||||
|     <signal name="NewOverlayIcon"></signal> | ||||
|     <signal name="NewToolTip"></signal> | ||||
|     <signal name="NewStatus"> | ||||
|         <arg name="status" type="s" /> | ||||
|     </signal> | ||||
|  | ||||
|     <!-- ayatana labels --> | ||||
|     <!-- These are commented out because GDBusProxy would otherwise require them, | ||||
|          but they are not available for KDE indicators | ||||
|     --> | ||||
|     <!--<signal name="XAyatanaNewLabel"> | ||||
|         <arg type="s" name="label" direction="out" /> | ||||
|         <arg type="s" name="guide" direction="out" /> | ||||
|     </signal> | ||||
|     <property name="XAyatanaLabel" type="s" access="read" /> | ||||
|     <property name="XAyatanaLabelGuide" type="s" access="read" />--> | ||||
|  | ||||
|  | ||||
| </interface> | ||||
| </node> | ||||
							
								
								
									
										42
									
								
								protocol/dbus-status-notifier-watcher.xml
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										42
									
								
								protocol/dbus-status-notifier-watcher.xml
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,42 @@ | ||||
| <!DOCTYPE node PUBLIC "-//freedesktop//DTD D-BUS Object Introspection 1.0//EN" "http://www.freedesktop.org/standards/dbus/1.0/introspect.dtd"> | ||||
| <node> | ||||
|   <interface name="org.kde.StatusNotifierWatcher"> | ||||
|  | ||||
|     <!-- methods --> | ||||
|     <method name="RegisterStatusNotifierItem"> | ||||
|        <arg name="service" type="s" direction="in"/> | ||||
|     </method> | ||||
|  | ||||
|     <method name="RegisterStatusNotifierHost"> | ||||
|        <arg name="service" type="s" direction="in"/> | ||||
|     </method> | ||||
|  | ||||
|  | ||||
|     <!-- properties --> | ||||
|  | ||||
|     <property name="RegisteredStatusNotifierItems" type="as" access="read"> | ||||
|        <annotation name="org.qtproject.QtDBus.QtTypeName.Out0" value="QStringList"/> | ||||
|     </property> | ||||
|  | ||||
|     <property name="IsStatusNotifierHostRegistered" type="b" access="read"/> | ||||
|  | ||||
|     <property name="ProtocolVersion" type="i" access="read"/> | ||||
|  | ||||
|  | ||||
|     <!-- signals --> | ||||
|  | ||||
|     <signal name="StatusNotifierItemRegistered"> | ||||
|         <arg type="s"/> | ||||
|     </signal> | ||||
|  | ||||
|     <signal name="StatusNotifierItemUnregistered"> | ||||
|         <arg type="s"/> | ||||
|     </signal> | ||||
|  | ||||
|     <signal name="StatusNotifierHostRegistered"> | ||||
|     </signal> | ||||
|  | ||||
|     <signal name="StatusNotifierHostUnregistered"> | ||||
|     </signal> | ||||
|   </interface> | ||||
| </node> | ||||
| @@ -36,10 +36,28 @@ foreach p : client_protocols | ||||
| 	client_protos_headers += wayland_scanner_client.process(xml) | ||||
| endforeach | ||||
|  | ||||
| gdbus_code = generator( | ||||
|     find_program('gdbus-codegen'), | ||||
|     output: '@BASENAME@.c', | ||||
|     arguments: ['--c-namespace', 'Sn', '--body', '--output', '@OUTPUT@', '@INPUT@'] | ||||
| ) | ||||
|  | ||||
| gdbus_header = generator( | ||||
|     find_program('gdbus-codegen'), | ||||
|     output: '@BASENAME@.h', | ||||
|     arguments: ['--c-namespace', 'Sn', '--header', '--output', '@OUTPUT@', '@INPUT@'] | ||||
| ) | ||||
|  | ||||
| client_protos_src += gdbus_code.process('./dbus-status-notifier-watcher.xml') | ||||
| client_protos_headers += gdbus_header.process('./dbus-status-notifier-watcher.xml') | ||||
|  | ||||
| client_protos_src += gdbus_code.process('./dbus-status-notifier-item.xml') | ||||
| client_protos_headers += gdbus_header.process('./dbus-status-notifier-item.xml') | ||||
|  | ||||
| lib_client_protos = static_library( | ||||
| 	'client_protos', | ||||
| 	client_protos_src + client_protos_headers, | ||||
| 	dependencies: [wayland_client] | ||||
| 	dependencies: [wayland_client, gtkmm] | ||||
| ) # for the include directory | ||||
|  | ||||
| client_protos = declare_dependency( | ||||
|   | ||||
| @@ -6,7 +6,7 @@ | ||||
|     // Choose the order of the modules | ||||
|     "modules-left": ["sway/workspaces", "custom/spotify"], | ||||
|     "modules-center": ["sway/window"], | ||||
|     "modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock"], | ||||
|     "modules-right": ["pulseaudio", "network", "cpu", "memory", "battery", "clock", "tray"], | ||||
|     // Modules configuration | ||||
|     // "sway/workspaces": { | ||||
|     //     "disable-scroll": true, | ||||
|   | ||||
| @@ -5,7 +5,7 @@ | ||||
|     font-size: 13px; | ||||
| } | ||||
|  | ||||
| window { | ||||
| window#waybar { | ||||
|     background: rgba(43, 48, 59, 0.5); | ||||
|     border-bottom: 3px solid rgba(100, 114, 125, 0.5); | ||||
|     color: white; | ||||
| @@ -23,7 +23,7 @@ window { | ||||
|     border-bottom: 3px solid white; | ||||
| } | ||||
|  | ||||
| #clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify { | ||||
| #clock, #battery, #cpu, #memory, #network, #pulseaudio, #custom-spotify, #tray { | ||||
|     padding: 0 10px; | ||||
|     margin: 0 5px; | ||||
| } | ||||
| @@ -90,3 +90,7 @@ window { | ||||
|     background: #66cc99; | ||||
|     color: #2a5c45; | ||||
| } | ||||
|  | ||||
| #tray { | ||||
|     background-color: #2980b9; | ||||
| } | ||||
|   | ||||
| @@ -21,6 +21,7 @@ waybar::Bar::Bar(const Client& client, | ||||
| 	zxdg_output_v1_add_listener(xdg_output_, &xdgOutputListener, this); | ||||
|   window.set_title("waybar"); | ||||
|   window.set_decorated(false); | ||||
|   window.set_name("waybar"); | ||||
|   window.set_resizable(false); | ||||
|   setupConfig(); | ||||
|   setupCss(); | ||||
| @@ -199,14 +200,14 @@ auto waybar::Bar::setupWidgets() -> void | ||||
|   getModules(factory, "modules-left"); | ||||
|   getModules(factory, "modules-center"); | ||||
|   getModules(factory, "modules-right"); | ||||
|   for (auto& module : modules_left_) { | ||||
|   for (auto const& module : modules_left_) { | ||||
|     left.pack_start(*module, false, true, 0); | ||||
|   } | ||||
|   for (auto& module : modules_center_) { | ||||
|   for (auto const& module : modules_center_) { | ||||
|     center.pack_start(*module, true, true, 0); | ||||
|   } | ||||
|   std::reverse(modules_right_.begin(), modules_right_.end()); | ||||
|   for (auto& module : modules_right_) { | ||||
|   for (auto const& module : modules_right_) { | ||||
|     right.pack_end(*module, false, false, 0); | ||||
|   } | ||||
| } | ||||
|   | ||||
| @@ -27,6 +27,9 @@ waybar::IModule* waybar::Factory::makeModule(const std::string &name) const | ||||
|     if (name == "clock") { | ||||
|       return new waybar::modules::Clock(config_[name]); | ||||
|     } | ||||
|     if (name == "tray") { | ||||
|       return new waybar::modules::SNI::Tray(config_[name]); | ||||
|     } | ||||
|     #ifdef HAVE_LIBNL | ||||
|     if (name == "network") { | ||||
|       return new waybar::modules::Network(config_[name]); | ||||
|   | ||||
| @@ -4,7 +4,7 @@ waybar::modules::Battery::Battery(const Json::Value& config) | ||||
|   : ALabel(config, "{capacity}%") | ||||
| { | ||||
|   try { | ||||
|     for (auto &node : fs::directory_iterator(data_dir_)) { | ||||
|     for (auto const& node : fs::directory_iterator(data_dir_)) { | ||||
|       if (fs::is_directory(node) && fs::exists(node / "capacity") | ||||
|         && fs::exists(node / "status") && fs::exists(node / "uevent")) { | ||||
|         batteries_.push_back(node); | ||||
| @@ -20,7 +20,7 @@ waybar::modules::Battery::Battery(const Json::Value& config) | ||||
|   if (fd_ == -1) { | ||||
|     throw std::runtime_error("Unable to listen batteries."); | ||||
|   } | ||||
|   for (auto &bat : batteries_) { | ||||
|   for (auto const& bat : batteries_) { | ||||
|     inotify_add_watch(fd_, (bat / "uevent").c_str(), IN_ACCESS); | ||||
|   } | ||||
|   label_.set_name("battery"); | ||||
| @@ -51,7 +51,7 @@ auto waybar::modules::Battery::update() -> void | ||||
|   try { | ||||
|     uint16_t total = 0; | ||||
|     std::string status; | ||||
|     for (auto &bat : batteries_) { | ||||
|     for (auto const& bat : batteries_) { | ||||
|       uint16_t capacity; | ||||
|       std::string _status; | ||||
|       std::ifstream(bat / "capacity") >> capacity; | ||||
|   | ||||
| @@ -142,7 +142,7 @@ int waybar::modules::Network::getExternalInterface() | ||||
|   int ifidx = -1; | ||||
|  | ||||
|   /* Prepare request. */ | ||||
|   uint32_t reqlen = NLMSG_SPACE(sizeof(*rt)); | ||||
|   constexpr uint32_t reqlen = NLMSG_SPACE(sizeof(*rt)); | ||||
|   char req[reqlen] = {0}; | ||||
|  | ||||
|   /* Build the RTM_GETROUTE request. */ | ||||
|   | ||||
| @@ -118,7 +118,7 @@ const std::string waybar::modules::Pulseaudio::getPortIcon() const | ||||
|     "hifi", | ||||
|     "phone", | ||||
|   }; | ||||
|   for (auto port : ports) { | ||||
|   for (auto const& port : ports) { | ||||
|     if (port_name_.find(port) != std::string::npos) { | ||||
|       return port; | ||||
|     } | ||||
|   | ||||
							
								
								
									
										155
									
								
								src/modules/sni/snh.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										155
									
								
								src/modules/sni/snh.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,155 @@ | ||||
| #include "modules/sni/snh.hpp" | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| using namespace waybar::modules::SNI; | ||||
|  | ||||
| Host::Host(Glib::Dispatcher* dp) | ||||
| : dp_(dp) | ||||
| { | ||||
|   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) | ||||
| { | ||||
|   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); | ||||
| } | ||||
|  | ||||
| void Host::nameAppeared(GDBusConnection* connection, | ||||
|   const gchar* name, const gchar* name_owner, gpointer data) | ||||
| { | ||||
|   auto host = static_cast<SNI::Host *>(data); | ||||
|   if (host->cancellable_ != nullptr) { | ||||
|     std::cout << "WTF" << std::endl; | ||||
|   } | ||||
|   host->cancellable_ = g_cancellable_new(); | ||||
|   sn_org_kde_status_notifier_watcher_proxy_new( | ||||
|     connection, | ||||
|     G_DBUS_PROXY_FLAGS_NONE, | ||||
|     "org.kde.StatusNotifierWatcher", | ||||
|     "/StatusNotifierWatcher", | ||||
|     host->cancellable_, &Host::proxyReady, data); | ||||
| } | ||||
|  | ||||
| void Host::nameVanished(GDBusConnection* connection, | ||||
|   const gchar* name, gpointer data) | ||||
| { | ||||
|   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(); | ||||
| } | ||||
|  | ||||
| void Host::proxyReady(GObject* src, GAsyncResult* res, | ||||
|   gpointer data) | ||||
| { | ||||
|   GError* error = nullptr; | ||||
|   SnOrgKdeStatusNotifierWatcher* watcher = | ||||
|     sn_org_kde_status_notifier_watcher_proxy_new_finish(res, &error); | ||||
|   if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   auto host = static_cast<SNI::Host *>(data); | ||||
|   host->watcher_ = watcher; | ||||
|   if (error != nullptr) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   sn_org_kde_status_notifier_watcher_call_register_status_notifier_host( | ||||
|     host->watcher_, host->object_path_.c_str(), host->cancellable_, | ||||
|     &Host::registerHost, data); | ||||
| } | ||||
|  | ||||
| void Host::registerHost(GObject* src, GAsyncResult* res, | ||||
|   gpointer data) | ||||
| { | ||||
|   GError* error = nullptr; | ||||
|   sn_org_kde_status_notifier_watcher_call_register_status_notifier_host_finish( | ||||
|     SN_ORG_KDE_STATUS_NOTIFIER_WATCHER(src), res, &error); | ||||
|   if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   auto host = static_cast<SNI::Host *>(data); | ||||
|   if (error != nullptr) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return;  | ||||
|   } | ||||
|   g_signal_connect(host->watcher_, "status-notifier-item-registered", | ||||
|     G_CALLBACK(&Host::itemRegistered), data); | ||||
|   g_signal_connect(host->watcher_, "status-notifier-item-unregistered", | ||||
|     G_CALLBACK(&Host::itemUnregistered), data); | ||||
|   auto items = | ||||
|     sn_org_kde_status_notifier_watcher_dup_registered_status_notifier_items(host->watcher_); | ||||
|   if (items) { | ||||
|     for (uint32_t i = 0; items[i] != nullptr; i += 1) { | ||||
|       host->addRegisteredItem(items[i]); | ||||
|     } | ||||
|   } | ||||
|   g_strfreev(items); | ||||
| } | ||||
|  | ||||
| void Host::itemRegistered( | ||||
|   SnOrgKdeStatusNotifierWatcher* watcher, const gchar* service, gpointer data) | ||||
| { | ||||
|   std::cout << "Item registered" << std::endl; | ||||
|   auto host = static_cast<SNI::Host *>(data); | ||||
|   host->addRegisteredItem(service); | ||||
| } | ||||
|  | ||||
| void Host::itemUnregistered( | ||||
|   SnOrgKdeStatusNotifierWatcher* watcher, const gchar* service, gpointer data) | ||||
| { | ||||
|   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); | ||||
|       std::cout << "Item Unregistered" << std::endl; | ||||
|       break; | ||||
|     } | ||||
|   } | ||||
|   host->dp_->emit(); | ||||
| } | ||||
|  | ||||
| std::tuple<std::string, std::string> Host::getBusNameAndObjectPath( | ||||
|   const gchar* 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"; | ||||
|   } | ||||
|   return { bus_name, object_path }; | ||||
| } | ||||
|  | ||||
| void Host::addRegisteredItem(const gchar* service) | ||||
| { | ||||
|   auto [bus_name, object_path] = getBusNameAndObjectPath(service); | ||||
|   items.emplace_back(bus_name, object_path, dp_); | ||||
| } | ||||
							
								
								
									
										260
									
								
								src/modules/sni/sni.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										260
									
								
								src/modules/sni/sni.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,260 @@ | ||||
| #include "modules/sni/sni.hpp" | ||||
|  | ||||
| #include <iostream> | ||||
| #include <libdbusmenu-gtk/dbusmenu-gtk.h> | ||||
|  | ||||
| waybar::modules::SNI::Item::Item(std::string bn, std::string op, | ||||
|                                  Glib::Dispatcher *dp) | ||||
|     : bus_name(bn), object_path(op), event_box(), icon_size(16), | ||||
|       effective_icon_size(0), image(Gtk::manage(new Gtk::Image())), dp_(dp) { | ||||
|   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_org_kde_status_notifier_item_proxy_new_for_bus( | ||||
|       G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, bus_name.c_str(), | ||||
|       object_path.c_str(), cancellable_, &Item::proxyReady, this); | ||||
| } | ||||
|  | ||||
| void waybar::modules::SNI::Item::proxyReady(GObject *obj, GAsyncResult *res, | ||||
|                                             gpointer data) { | ||||
|   GError *error = nullptr; | ||||
|   SnOrgKdeStatusNotifierItem *proxy = | ||||
|       sn_org_kde_status_notifier_item_proxy_new_for_bus_finish(res, &error); | ||||
|   if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   auto item = static_cast<SNI::Item *>(data); | ||||
|   item->proxy_ = proxy; | ||||
|   if (error) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   auto conn = g_dbus_proxy_get_connection(G_DBUS_PROXY(proxy)); | ||||
|  | ||||
|   g_dbus_connection_call(conn, item->bus_name.c_str(), | ||||
|                          item->object_path.c_str(), | ||||
|                          "org.freedesktop.DBus.Properties", "GetAll", | ||||
|                          g_variant_new("(s)", "org.kde.StatusNotifierItem"), | ||||
|                          G_VARIANT_TYPE("(a{sv})"), G_DBUS_CALL_FLAGS_NONE, -1, | ||||
|                          item->cancellable_, &Item::getAll, data); | ||||
| } | ||||
|  | ||||
| void waybar::modules::SNI::Item::getAll(GObject *obj, GAsyncResult *res, | ||||
|                                         gpointer data) { | ||||
|   GError *error = nullptr; | ||||
|   auto conn = G_DBUS_CONNECTION(obj); | ||||
|   GVariant *properties = g_dbus_connection_call_finish(conn, res, &error); | ||||
|   if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) { | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   auto item = static_cast<SNI::Item *>(data); | ||||
|   if (error) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   GVariantIter *it = nullptr; | ||||
|   g_variant_get(properties, "(a{sv})", &it); | ||||
|   gchar *key; | ||||
|   GVariant *value; | ||||
|   while (g_variant_iter_next(it, "{sv}", &key, &value)) { | ||||
|     if (g_strcmp0(key, "Category") == 0) { | ||||
|       item->category = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "Id") == 0) { | ||||
|       item->id = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "Title") == 0) { | ||||
|       item->title = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "Status") == 0) { | ||||
|       item->status = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "WindowId") == 0) { | ||||
|       item->window_id = g_variant_get_int32(value); | ||||
|     } else if (g_strcmp0(key, "IconName") == 0) { | ||||
|       item->icon_name = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "IconPixmap") == 0) { | ||||
|       item->icon_pixmap = item->extractPixBuf(value); | ||||
|     } else if (g_strcmp0(key, "OverlayIconName") == 0) { | ||||
|       item->overlay_icon_name = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "OverlayIconPixmap") == 0) { | ||||
|       // TODO: overlay_icon_pixmap | ||||
|     } else if (g_strcmp0(key, "AttentionIconName") == 0) { | ||||
|       item->attention_icon_name = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "AttentionIconPixmap") == 0) { | ||||
|       // TODO: attention_icon_pixmap | ||||
|     } else if (g_strcmp0(key, "AttentionMovieName") == 0) { | ||||
|       item->attention_movie_name = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "ToolTip") == 0) { | ||||
|       // TODO: tooltip | ||||
|     } else if (g_strcmp0(key, "IconThemePath") == 0) { | ||||
|       item->icon_theme_path = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "Menu") == 0) { | ||||
|       item->menu = g_variant_dup_string(value, nullptr); | ||||
|     } else if (g_strcmp0(key, "ItemIsMenu") == 0) { | ||||
|       item->item_is_menu = g_variant_get_boolean(value); | ||||
|     } | ||||
|     g_variant_unref(value); | ||||
|     g_free(key); | ||||
|   } | ||||
|   g_variant_iter_free(it); | ||||
|   g_variant_unref(properties); | ||||
|   if (item->id.empty() || item->category.empty() || item->status.empty()) { | ||||
|     std::cerr << "Invalid Status Notifier Item: " + item->bus_name + "," + | ||||
|                      item->object_path | ||||
|               << std::endl; | ||||
|     return; | ||||
|   } | ||||
|   if (!item->icon_theme_path.empty()) { | ||||
|     GtkIconTheme *icon_theme = gtk_icon_theme_get_default(); | ||||
|     gtk_icon_theme_append_search_path(icon_theme, | ||||
|                                       item->icon_theme_path.c_str()); | ||||
|   } | ||||
|   item->updateImage(); | ||||
|   item->dp_->emit(); | ||||
|   // TODO: handle change | ||||
| } | ||||
|  | ||||
| Glib::RefPtr<Gdk::Pixbuf> | ||||
| waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) { | ||||
|   GVariantIter *it; | ||||
|   g_variant_get(variant, "a(iiay)", &it); | ||||
|   if (it == nullptr) { | ||||
|     return Glib::RefPtr<Gdk::Pixbuf>{}; | ||||
|   } | ||||
|   GVariant *val; | ||||
|   gint lwidth = 0; | ||||
|   gint lheight = 0; | ||||
|   gint width; | ||||
|   gint height; | ||||
|   guchar *array = nullptr; | ||||
|   while (g_variant_iter_loop(it, "(ii@ay)", &width, &height, &val)) { | ||||
|     if (width > 0 && height > 0 && val != nullptr && | ||||
|         width * height > lwidth * lheight) { | ||||
|       auto size = g_variant_get_size(val); | ||||
|       /* Sanity check */ | ||||
|       if (size == 4U * width * height) { | ||||
|         /* Find the largest image */ | ||||
|         gconstpointer data = g_variant_get_data(val); | ||||
|         if (data != nullptr) { | ||||
|           if (array != nullptr) { | ||||
|             g_free(array); | ||||
|           } | ||||
|           array = static_cast<guchar *>(g_memdup(data, size)); | ||||
|           lwidth = width; | ||||
|           lheight = height; | ||||
|         } | ||||
|       } | ||||
|     } | ||||
|   } | ||||
|   g_variant_iter_free(it); | ||||
|   if (array != nullptr) { | ||||
|     /* argb to rgba */ | ||||
|     for (uint32_t i = 0; i < 4U * lwidth * lheight; i += 4) { | ||||
|       guchar alpha = array[i]; | ||||
|       array[i] = array[i + 1]; | ||||
|       array[i + 1] = array[i + 2]; | ||||
|       array[i + 2] = array[i + 3]; | ||||
|       array[i + 3] = alpha; | ||||
|     } | ||||
|     return Gdk::Pixbuf::create_from_data(array, Gdk::Colorspace::COLORSPACE_RGB, | ||||
|                                          true, 8, lwidth, lheight, 4 * lwidth); | ||||
|   } | ||||
|   return Glib::RefPtr<Gdk::Pixbuf>{}; | ||||
| } | ||||
|  | ||||
| void waybar::modules::SNI::Item::updateImage() | ||||
| { | ||||
|   if (!icon_name.empty()) { | ||||
|     auto pixbuf = getIconByName(icon_name, icon_size); | ||||
|     if (pixbuf->gobj() == nullptr) { | ||||
|       // Try to find icons specified by path and filename | ||||
|       try { | ||||
|         pixbuf = Gdk::Pixbuf::create_from_file(icon_name); | ||||
|         if (pixbuf->gobj() != nullptr) { | ||||
|           // An icon specified by path and filename may be the wrong size for | ||||
|           // the tray | ||||
|           pixbuf->scale_simple(icon_size - 2, icon_size - 2, | ||||
|                                Gdk::InterpType::INTERP_BILINEAR); | ||||
|         } | ||||
|       } catch (Glib::Error &e) { | ||||
|         std::cerr << "Exception: " << e.what() << std::endl; | ||||
|         pixbuf = getIconByName("image-missing", icon_size); | ||||
|       } | ||||
|     } | ||||
|     if (pixbuf->gobj() == nullptr) { | ||||
|       pixbuf = getIconByName("image-missing", icon_size); | ||||
|     } | ||||
|     image->set(pixbuf); | ||||
|   } else if (icon_pixmap) { | ||||
|     image->set(icon_pixmap); | ||||
|   } else { | ||||
|     image->set_from_icon_name("image-missing", Gtk::ICON_SIZE_MENU); | ||||
|     image->set_pixel_size(icon_size); | ||||
|   } | ||||
|   if (!menu.empty()) { | ||||
|     auto *dbmenu = dbusmenu_gtkmenu_new(bus_name.data(), menu.data()); | ||||
|     if (dbmenu) | ||||
|       gtk_menu = Glib::wrap(GTK_MENU(dbmenu), false); | ||||
|   } | ||||
| } | ||||
|  | ||||
| Glib::RefPtr<Gdk::Pixbuf> | ||||
| waybar::modules::SNI::Item::getIconByName(std::string name, int request_size) { | ||||
|   int icon_size = 0; | ||||
|   Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default(); | ||||
|   icon_theme->rescan_if_needed(); | ||||
|   auto sizes = icon_theme->get_icon_sizes(name.c_str()); | ||||
|  | ||||
|   for (auto const &size : sizes) { | ||||
|     // -1 == scalable | ||||
|     if (size == request_size || size == -1) { | ||||
|       icon_size = request_size; | ||||
|       break; | ||||
|     } else if (size < request_size || size > icon_size) { | ||||
|       icon_size = size; | ||||
|     } | ||||
|   } | ||||
|   if (icon_size == 0) { | ||||
|     icon_size = request_size; | ||||
|   } | ||||
|   return icon_theme->load_icon(name.c_str(), icon_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_org_kde_status_notifier_item_call_activate_finish(item->proxy_, res, | ||||
|                                                        nullptr); | ||||
| } | ||||
|  | ||||
| void waybar::modules::SNI::Item::handleSecondaryActivate(GObject *src, | ||||
|                                                          GAsyncResult *res, | ||||
|                                                          gpointer data) { | ||||
|   auto item = static_cast<SNI::Item *>(data); | ||||
|   sn_org_kde_status_notifier_item_call_secondary_activate_finish(item->proxy_, | ||||
|                                                                  res, nullptr); | ||||
| } | ||||
|  | ||||
| bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) { | ||||
|   if (ev->type == GDK_BUTTON_PRESS) { | ||||
|     if (gtk_menu) { | ||||
|       if (!gtk_menu->get_attach_widget()) { | ||||
|         gtk_menu->attach_to_widget(event_box); | ||||
|       } | ||||
|       gtk_menu->popup(ev->button, ev->time); | ||||
|     } else { | ||||
|       sn_org_kde_status_notifier_item_call_activate( | ||||
|           proxy_, ev->x, ev->y, nullptr, &Item::handleActivate, this); | ||||
|     } | ||||
|   } else if (ev->type == GDK_2BUTTON_PRESS) { | ||||
|     sn_org_kde_status_notifier_item_call_secondary_activate( | ||||
|         proxy_, ev->x, ev->y, nullptr, &Item::handleSecondaryActivate, this); | ||||
|   } else { | ||||
|     return false; | ||||
|   } | ||||
|   return true; | ||||
| } | ||||
							
								
								
									
										183
									
								
								src/modules/sni/snw.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										183
									
								
								src/modules/sni/snw.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,183 @@ | ||||
| #include "modules/sni/snw.hpp" | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| using namespace waybar::modules::SNI; | ||||
|  | ||||
| Watcher::Watcher() | ||||
| { | ||||
|   GBusNameOwnerFlags flags = static_cast<GBusNameOwnerFlags>( | ||||
|     G_BUS_NAME_OWNER_FLAGS_ALLOW_REPLACEMENT | ||||
|     | G_BUS_NAME_OWNER_FLAGS_REPLACE); | ||||
|   bus_name_id_ = g_bus_own_name(G_BUS_TYPE_SESSION, | ||||
|     "org.kde.StatusNotifierWatcher", flags, | ||||
|     &Watcher::busAcquired, nullptr, nullptr, this, nullptr); | ||||
|   watcher_ = sn_org_kde_status_notifier_watcher_skeleton_new(); | ||||
| } | ||||
|  | ||||
| Watcher::~Watcher() | ||||
| { | ||||
| } | ||||
|  | ||||
| void Watcher::busAcquired(GDBusConnection* connection, const gchar* name, | ||||
|   gpointer data) | ||||
| { | ||||
|   GError* error = nullptr; | ||||
|   auto host = static_cast<SNI::Watcher*>(data); | ||||
|   g_dbus_interface_skeleton_export(G_DBUS_INTERFACE_SKELETON(host->watcher_), | ||||
|     connection, "/StatusNotifierWatcher", &error); | ||||
|   if (error != nullptr) { | ||||
|     std::cerr << error->message << std::endl; | ||||
|     g_error_free(error); | ||||
|     return; | ||||
|   } | ||||
|   g_signal_connect_swapped(host->watcher_, | ||||
|     "handle-register-status-notifier-item", | ||||
|     G_CALLBACK(&Watcher::handleRegisterItem), data); | ||||
|   g_signal_connect_swapped(host->watcher_, | ||||
|     "handle-register-status-notifier-host", | ||||
|     G_CALLBACK(&Watcher::handleRegisterHost), data); | ||||
|   sn_org_kde_status_notifier_watcher_set_protocol_version(host->watcher_, 0); | ||||
|   sn_org_kde_status_notifier_watcher_set_is_status_notifier_host_registered( | ||||
|     host->watcher_, TRUE); | ||||
|   std::cout << "Bus aquired" << std::endl; | ||||
| } | ||||
|  | ||||
| gboolean Watcher::handleRegisterHost(Watcher* obj, | ||||
|   GDBusMethodInvocation* invocation, const gchar* service) | ||||
| { | ||||
|   const gchar* bus_name = service; | ||||
|   const gchar* object_path = "/StatusNotifierHost"; | ||||
|  | ||||
|   if (*service == '/') { | ||||
|     bus_name = g_dbus_method_invocation_get_sender(invocation); | ||||
|     object_path = service; | ||||
|   } | ||||
|   if (g_dbus_is_name(bus_name) == FALSE) { | ||||
|     g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, | ||||
|       G_DBUS_ERROR_INVALID_ARGS, "D-Bus bus name '%s' is not valid", bus_name); | ||||
|     return TRUE; | ||||
|   } | ||||
|   auto watch = gfWatchFind(obj->hosts_, bus_name, object_path); | ||||
|   if (watch != nullptr) { | ||||
|     g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, | ||||
|       G_DBUS_ERROR_INVALID_ARGS, "Status Notifier Host with bus name '%s' and object path '%s' is already registered", | ||||
|       bus_name, object_path); | ||||
|     return TRUE; | ||||
|   } | ||||
|   watch = gfWatchNew(GF_WATCH_TYPE_HOST, service, bus_name, object_path, obj); | ||||
|   obj->hosts_ = g_slist_prepend(obj->hosts_, watch); | ||||
|   sn_org_kde_status_notifier_watcher_set_is_status_notifier_host_registered( | ||||
|     obj->watcher_, TRUE); | ||||
|   if (g_slist_length(obj->hosts_)) { | ||||
|     sn_org_kde_status_notifier_watcher_emit_status_notifier_host_registered( | ||||
|       obj->watcher_); | ||||
|   } | ||||
|   sn_org_kde_status_notifier_watcher_complete_register_status_notifier_host( | ||||
|     obj->watcher_, invocation); | ||||
|   std::cout << "Host registered: " << bus_name << std::endl; | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| gboolean Watcher::handleRegisterItem(Watcher* obj, | ||||
|   GDBusMethodInvocation* invocation, const gchar* service) | ||||
| { | ||||
|   const gchar* bus_name = service; | ||||
|   const gchar* object_path = "/StatusNotifierItem"; | ||||
|  | ||||
|   if (*service == '/') { | ||||
|     bus_name = g_dbus_method_invocation_get_sender(invocation); | ||||
|     object_path = service; | ||||
|   } | ||||
|   if (g_dbus_is_name(bus_name) == FALSE) { | ||||
|     g_dbus_method_invocation_return_error(invocation, G_DBUS_ERROR, | ||||
|       G_DBUS_ERROR_INVALID_ARGS, "D-Bus bus name '%s' is not valid", bus_name); | ||||
|     return TRUE; | ||||
|   } | ||||
|   auto watch = gfWatchFind(obj->items_, bus_name, object_path); | ||||
|   if (watch != nullptr) { | ||||
|     g_warning("Status Notifier Item with bus name '%s' and object path '%s' is already registered", | ||||
|       bus_name, object_path); | ||||
|     sn_org_kde_status_notifier_watcher_complete_register_status_notifier_item( | ||||
|       obj->watcher_, invocation); | ||||
|     return TRUE; | ||||
|   } | ||||
|   watch = gfWatchNew(GF_WATCH_TYPE_ITEM, service, bus_name, object_path, obj); | ||||
|   obj->items_ = g_slist_prepend(obj->items_, watch); | ||||
|   obj->updateRegisteredItems(obj->watcher_); | ||||
|   gchar* tmp = g_strdup_printf("%s%s", bus_name, object_path); | ||||
|   sn_org_kde_status_notifier_watcher_emit_status_notifier_item_registered( | ||||
|     obj->watcher_, tmp); | ||||
|   g_free(tmp); | ||||
|   sn_org_kde_status_notifier_watcher_complete_register_status_notifier_item( | ||||
|     obj->watcher_, invocation); | ||||
|   return TRUE; | ||||
| } | ||||
|  | ||||
| Watcher::GfWatch* Watcher::gfWatchFind(GSList* list, const gchar* bus_name, | ||||
|   const gchar* object_path) | ||||
| { | ||||
|   for (GSList* l = list; l != nullptr; l = g_slist_next (l)) { | ||||
|     GfWatch* watch = static_cast<GfWatch*>(l->data); | ||||
|     if (g_strcmp0 (watch->bus_name, bus_name) == 0 | ||||
|       && g_strcmp0 (watch->object_path, object_path) == 0) { | ||||
|       return watch; | ||||
|     } | ||||
|   } | ||||
|   return nullptr; | ||||
| } | ||||
|  | ||||
| Watcher::GfWatch* Watcher::gfWatchNew(GfWatchType type, const gchar* service, | ||||
|   const gchar* bus_name, const gchar* object_path, Watcher* watcher) | ||||
| { | ||||
|   GfWatch* watch = g_new0(GfWatch, 1); | ||||
|   watch->type = type; | ||||
|   watch->watcher = watcher; | ||||
|   watch->service = g_strdup(service); | ||||
|   watch->bus_name = g_strdup(bus_name); | ||||
|   watch->object_path = g_strdup(object_path); | ||||
|   watch->watch_id = g_bus_watch_name(G_BUS_TYPE_SESSION, bus_name, | ||||
|     G_BUS_NAME_WATCHER_FLAGS_NONE, nullptr, &Watcher::nameVanished, watch, | ||||
|     nullptr); | ||||
|   return watch; | ||||
| } | ||||
|  | ||||
| void Watcher::nameVanished(GDBusConnection* connection, const char* name, | ||||
|   gpointer data) | ||||
| { | ||||
|   auto watch = static_cast<GfWatch *>(data); | ||||
|   if (watch->type == GF_WATCH_TYPE_HOST) { | ||||
|     watch->watcher->hosts_ = g_slist_remove(watch->watcher->hosts_, watch); | ||||
|     if (watch->watcher->hosts_ == nullptr)  { | ||||
|       sn_org_kde_status_notifier_watcher_set_is_status_notifier_host_registered( | ||||
|         watch->watcher->watcher_, FALSE); | ||||
|       sn_org_kde_status_notifier_watcher_emit_status_notifier_host_registered( | ||||
|         watch->watcher->watcher_); | ||||
|     } | ||||
|   } else if (watch->type == GF_WATCH_TYPE_ITEM) { | ||||
|     watch->watcher->items_ = g_slist_remove(watch->watcher->items_, watch); | ||||
|     watch->watcher->updateRegisteredItems(watch->watcher->watcher_); | ||||
|     gchar* tmp = g_strdup_printf("%s%s", watch->bus_name, watch->object_path); | ||||
|     sn_org_kde_status_notifier_watcher_emit_status_notifier_item_unregistered( | ||||
|       watch->watcher->watcher_, tmp); | ||||
|     g_free(tmp); | ||||
|   } | ||||
| } | ||||
|  | ||||
| void Watcher::updateRegisteredItems(SnOrgKdeStatusNotifierWatcher* obj) | ||||
| { | ||||
|   GVariantBuilder builder; | ||||
|   g_variant_builder_init(&builder, G_VARIANT_TYPE("as"));  | ||||
|   for (GSList* l = items_; l != nullptr; l = g_slist_next(l)) { | ||||
|     GfWatch* watch = static_cast<GfWatch*>(l->data); | ||||
|     gchar* item = g_strdup_printf("%s%s", watch->bus_name, watch->object_path); | ||||
|     g_variant_builder_add(&builder, "s", item); | ||||
|     g_free(item); | ||||
|   } | ||||
|   GVariant* variant = g_variant_builder_end(&builder); | ||||
|   const gchar** items = g_variant_get_strv(variant, nullptr); | ||||
|   sn_org_kde_status_notifier_watcher_set_registered_status_notifier_items( | ||||
|     obj, items); | ||||
|   g_variant_unref(variant); | ||||
|   g_free(items); | ||||
| } | ||||
							
								
								
									
										21
									
								
								src/modules/sni/tray.cpp
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										21
									
								
								src/modules/sni/tray.cpp
									
									
									
									
									
										Normal file
									
								
							| @@ -0,0 +1,21 @@ | ||||
| #include "modules/sni/tray.hpp" | ||||
|  | ||||
| #include <iostream> | ||||
|  | ||||
| waybar::modules::SNI::Tray::Tray(const Json::Value &config) | ||||
|     : config_(config), watcher_(), host_(&dp) {} | ||||
|  | ||||
| auto waybar::modules::SNI::Tray::update() -> void { | ||||
|   for (auto &item : host_.items) { | ||||
|     item.event_box.set_tooltip_text(item.title); | ||||
|     box_.pack_start(item.event_box); | ||||
|   } | ||||
|   if (box_.get_children().size() > 0) { | ||||
|     box_.set_name("tray"); | ||||
|     box_.show_all(); | ||||
|   } else { | ||||
|     box_.set_name(""); | ||||
|   } | ||||
| } | ||||
|  | ||||
| waybar::modules::SNI::Tray::operator Gtk::Widget &() { return box_; } | ||||
| @@ -44,7 +44,7 @@ auto waybar::modules::sway::Window::update() -> void | ||||
| std::tuple<int, std::string> waybar::modules::sway::Window::getFocusedNode( | ||||
|   Json::Value nodes) | ||||
| { | ||||
|   for (auto &node : nodes) { | ||||
|   for (auto const& node : nodes) { | ||||
|     if (node["focused"].asBool() && node["type"] == "con") { | ||||
|       return { node["id"].asInt(), node["name"].asString() }; | ||||
|     } | ||||
|   | ||||
| @@ -49,7 +49,7 @@ auto waybar::modules::sway::Workspaces::update() -> void | ||||
|       ++it; | ||||
|     } | ||||
|   } | ||||
|   for (auto node : workspaces_) { | ||||
|   for (auto const& node : workspaces_) { | ||||
|     if (!config_["all-outputs"].asBool() | ||||
|       && bar_.output_name != node["output"].asString()) { | ||||
|       continue; | ||||
|   | ||||
		Reference in New Issue
	
	Block a user
	 Alex
					Alex