Hello community, here is the log from the commit of package waybar for openSUSE:Factory checked in at 2019-04-05 12:04:50 ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Comparing /work/SRC/openSUSE:Factory/waybar (Old) and /work/SRC/openSUSE:Factory/.waybar.new.3908 (New) ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++
Package is "waybar" Fri Apr 5 12:04:50 2019 rev:3 rq:691469 version:0.5.1 Changes: -------- --- /work/SRC/openSUSE:Factory/waybar/waybar.changes 2019-03-26 15:44:16.368160332 +0100 +++ /work/SRC/openSUSE:Factory/.waybar.new.3908/waybar.changes 2019-04-05 12:06:21.506566034 +0200 @@ -1,0 +2,16 @@ +Thu Apr 4 10:31:19 UTC 2019 - [email protected] + +- Update to 0.5.1: + Added: + * Tray: Handle icons updates #252 + * Allow waybar to be positioned on left/right 47142a6 + * Custom: Allow icon selection based on json alt attribute #245 + Changed: + * Network: Escape ESSID #241 + * Workspace: Reversed scrolling direction to reflect swaybar + behavior 5144426 + * Script: mediaplayer script is now generic and return json + data with player name for icon matching #249 + * Network: Fixed multiple networking module regression 1f6f443 + +------------------------------------------------------------------- Old: ---- 0.5.0.tar.gz New: ---- 0.5.1.tar.gz ++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++++ Other differences: ------------------ ++++++ waybar.spec ++++++ --- /var/tmp/diff_new_pack.0O2J5e/_old 2019-04-05 12:06:23.806565279 +0200 +++ /var/tmp/diff_new_pack.0O2J5e/_new 2019-04-05 12:06:23.810565281 +0200 @@ -17,7 +17,7 @@ Name: waybar -Version: 0.5.0 +Version: 0.5.1 Release: 0 Summary: Customizable Wayland bar for Sway and Wlroots based compositors License: MIT ++++++ 0.5.0.tar.gz -> 0.5.1.tar.gz ++++++ diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/README.md new/Waybar-0.5.1/README.md --- old/Waybar-0.5.0/README.md 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/README.md 2019-04-04 12:01:00.000000000 +0200 @@ -2,7 +2,8 @@ **Proof of concept** > Highly customizable Wayland bar for Sway and Wlroots based compositors.<br> -> Available on [AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar) +> Available in Arch [community](https://www.archlinux.org/packages/community/x86_64/waybar/) or +[AUR](https://aur.archlinux.org/packages/waybar-git/) and [openSUSE](https://build.opensuse.org/package/show/X11:Wayland/waybar) **Current features** - Sway (Workspaces, Binding mode, Focused window name) diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/include/bar.hpp new/Waybar-0.5.1/include/bar.hpp --- old/Waybar-0.5.0/include/bar.hpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/include/bar.hpp 2019-04-04 12:01:00.000000000 +0200 @@ -32,6 +32,7 @@ std::string output_name; uint32_t wl_name; bool visible = true; + bool vertical = false; private: static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t, int32_t); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/include/modules/network.hpp new/Waybar-0.5.1/include/modules/network.hpp --- old/Waybar-0.5.0/include/modules/network.hpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/include/modules/network.hpp 2019-04-04 12:01:00.000000000 +0200 @@ -23,6 +23,7 @@ static const uint8_t MAX_RETRY = 5; static const uint8_t EPOLL_MAX = 255; + static int handleEvents(struct nl_msg*, void*); static int handleScan(struct nl_msg*, void*); void worker(); @@ -31,7 +32,6 @@ void createEventSocket(); int getExternalInterface(); void getInterfaceAddress(); - void handleEvents(); int netlinkRequest(void*, uint32_t, uint32_t groups = 0); int netlinkResponse(void*, uint32_t, uint32_t groups = 0); void parseEssid(struct nlattr**); @@ -45,7 +45,7 @@ sa_family_t family_; struct sockaddr_nl nladdr_ = {0}; struct nl_sock* sk_ = nullptr; - int info_sock_; + struct nl_sock* info_sock_ = nullptr; int efd_; int ev_fd_; int nl80211_id_; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/include/modules/sni/item.hpp new/Waybar-0.5.1/include/modules/sni/item.hpp --- old/Waybar-0.5.0/include/modules/sni/item.hpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/include/modules/sni/item.hpp 2019-04-04 12:01:00.000000000 +0200 @@ -2,12 +2,14 @@ #include <dbus-status-notifier-item.h> #include <glibmm/refptr.h> +#include <giomm/dbusproxy.h> #include <gtkmm/eventbox.h> #include <gtkmm/image.h> #include <gtkmm/icontheme.h> #include <gtkmm/menu.h> #include <json/json.h> #include <libdbusmenu-gtk/dbusmenu-gtk.h> +#include <sigc++/trackable.h> #ifdef FILESYSTEM_EXPERIMENTAL #include <experimental/filesystem> #else @@ -16,7 +18,7 @@ namespace waybar::modules::SNI { -class Item { +class Item : public sigc::trackable { public: Item(std::string, std::string, const Json::Value&); ~Item() = default; @@ -46,8 +48,12 @@ bool item_is_menu; private: - static void proxyReady(GObject *obj, GAsyncResult *res, gpointer data); - static void getAll(GObject *obj, GAsyncResult *res, gpointer data); + void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result); + void setProperty(const Glib::ustring& name, Glib::VariantBase& value); + void getUpdatedProperties(); + void processUpdatedProperties(Glib::RefPtr<Gio::AsyncResult>& result); + void onSignal(const Glib::ustring& sender_name, const Glib::ustring& signal_name, + const Glib::VariantContainerBase& arguments); void updateImage(); Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant); @@ -56,8 +62,9 @@ bool makeMenu(GdkEventButton *const &ev); bool handleClick(GdkEventButton *const & /*ev*/); - GCancellable *cancellable_ = nullptr; - SnItem *proxy_ = nullptr; + Glib::RefPtr<Gio::Cancellable> cancellable_; + Glib::RefPtr<Gio::DBus::Proxy> proxy_; + bool update_pending_; }; } // namespace waybar::modules::SNI diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/include/modules/sni/tray.hpp new/Waybar-0.5.1/include/modules/sni/tray.hpp --- old/Waybar-0.5.0/include/modules/sni/tray.hpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/include/modules/sni/tray.hpp 2019-04-04 12:01:00.000000000 +0200 @@ -11,7 +11,7 @@ class Tray : public IModule { public: - Tray(const std::string&, const Json::Value&); + Tray(const std::string&, const Bar&, const Json::Value&); ~Tray() = default; auto update() -> void; operator Gtk::Widget &(); diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/meson.build new/Waybar-0.5.1/meson.build --- old/Waybar-0.5.0/meson.build 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/meson.build 2019-04-04 12:01:00.000000000 +0200 @@ -1,6 +1,6 @@ project( 'waybar', 'cpp', 'c', - version: '0.5.0', + version: '0.5.1', license: 'MIT', default_options : [ 'cpp_std=c++17', @@ -72,7 +72,7 @@ 'src/client.cpp' ) -if find_program('sway', required : false).found() +if true # find_program('sway', required : false).found() add_project_arguments('-DHAVE_SWAY', language: 'cpp') src_files += [ 'src/modules/sway/ipc/client.cpp', diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/resources/config new/Waybar-0.5.1/resources/config --- old/Waybar-0.5.0/resources/config 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/resources/config 2019-04-04 12:01:00.000000000 +0200 @@ -1,10 +1,10 @@ { "layer": "top", // Waybar at top layer - // "position": "bottom", // Waybar at the bottom of your screen + // "position": "bottom", // Waybar position (top|bottom|left|right) // "height": 30, // Waybar height // "width": 1280, // Waybar width // Choose the order of the modules - "modules-left": ["sway/workspaces", "sway/mode", "custom/spotify"], + "modules-left": ["sway/workspaces", "sway/mode", "custom/media"], "modules-center": ["sway/window"], "modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"], // Modules configuration @@ -95,9 +95,15 @@ }, "on-click": "pavucontrol" }, - "custom/spotify": { - "format": " {}", + "custom/media": { + "format": "{icon} {}", + "return-type": "json", "max-length": 40, + "format-icons": { + "spotify": "", + "default": "🎜" + }, + "escape": true, "exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/resources/custom_modules/mediaplayer.py new/Waybar-0.5.1/resources/custom_modules/mediaplayer.py --- old/Waybar-0.5.0/resources/custom_modules/mediaplayer.py 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/resources/custom_modules/mediaplayer.py 2019-04-04 12:01:00.000000000 +0200 @@ -1,19 +1,34 @@ #!/usr/bin/env python3 +import argparse +import logging import sys import signal import gi +import json gi.require_version('Playerctl', '2.0') from gi.repository import Playerctl, GLib -manager = Playerctl.PlayerManager() -loop = GLib.MainLoop() +logger = logging.getLogger(__name__) + + +def write_output(text, player): + logger.info('Writing output') + + output = {'text': text, + 'class': 'custom-' + player.props.player_name, + 'alt': player.props.player_name} + + sys.stdout.write(json.dumps(output) + '\n') + sys.stdout.flush() def on_play(player, status, manager): + logger.info('Received new playback status') on_metadata(player, player.props.metadata, manager) def on_metadata(player, metadata, manager): + logger.info('Received new metadata') track_info = '' if player.props.player_name == 'spotify' and \ @@ -23,28 +38,27 @@ elif player.get_artist() != '' and player.get_title() != '': track_info = '{artist} - {title}'.format(artist=player.get_artist(), title=player.get_title()) - else: - sys.stdout.write('\n') - sys.stdout.flush() - return - if player.props.status == 'Playing': - sys.stdout.write(track_info + '\n') - else: - sys.stdout.write(' ' + track_info + '\n') - sys.stdout.flush() + if player.props.status != 'Playing': + track_info = ' ' + track_info + write_output(track_info, player) -def on_name_appeared(manager, name): - init_player(name) +def on_player_appeared(manager, player, selected_player=None): + if player is not None and player.name == selected_player: + init_player(manager, player) + else: + logger.debug("New player appeared, but it's not the selected player, skipping") def on_player_vanished(manager, player): - sys.stdout.write("\n") + logger.info('Player has vanished') + sys.stdout.write('\n') sys.stdout.flush() -def init_player(name): +def init_player(manager, name): + logger.debug('Initialize player: {player}'.format(player=name.name)) player = Playerctl.Player.new_from_name(name) player.connect('playback-status', on_play, manager) player.connect('metadata', on_metadata, manager) @@ -53,19 +67,60 @@ def signal_handler(sig, frame): - sys.stdout.write("\n") + logger.debug('Received signal to stop, exiting') + sys.stdout.write('\n') sys.stdout.flush() - loop.quit() + # loop.quit() sys.exit(0) -manager.connect('name-appeared', on_name_appeared) -manager.connect('player-vanished', on_player_vanished) +def parse_arguments(): + parser = argparse.ArgumentParser() + + # Increase verbosity with every occurance of -v + parser.add_argument('-v', '--verbose', action='count', default=0) + + # Define for which player we're listening + parser.add_argument('--player') + + return parser.parse_args() + + +def main(): + arguments = parse_arguments() + + # Initialize logging + logging.basicConfig(stream=sys.stderr, level=logging.DEBUG, + format='%(name)s %(levelname)s %(message)s') + + # Logging is set by default to WARN and higher. + # With every occurrence of -v it's lowered by one + logger.setLevel(max((3 - arguments.verbose) * 10, 0)) + + # Log the sent command line arguments + logger.debug('Arguments received {}'.format(vars(arguments))) + + manager = Playerctl.PlayerManager() + loop = GLib.MainLoop() + + manager.connect('name-appeared', lambda *args: on_player_appeared(*args, arguments.player)) + manager.connect('player-vanished', on_player_vanished) + + signal.signal(signal.SIGINT, signal_handler) + signal.signal(signal.SIGTERM, signal_handler) + + for player in manager.props.player_names: + if arguments.player is not None and arguments.player != player.name: + logger.debug('{player} is not the filtered player, skipping it' + .format(player=player.name) + ) + continue + + init_player(manager, player) + + loop.run() -signal.signal(signal.SIGINT, signal_handler) -signal.signal(signal.SIGTERM, signal_handler) -for player in manager.props.player_names: - init_player(player) +if __name__ == '__main__': + main() -loop.run() diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/resources/style.css new/Waybar-0.5.1/resources/style.css --- old/Waybar-0.5.0/resources/style.css 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/resources/style.css 2019-04-04 12:01:00.000000000 +0200 @@ -25,12 +25,16 @@ border-bottom: 3px solid #ffffff; } +#workspaces button.urgent { + background-color: #eb4d4b; +} + #mode { background: #64727D; border-bottom: 3px solid #ffffff; } -#clock, #battery, #cpu, #memory, #temperature, #backlight, #network, #pulseaudio, #custom-spotify, #tray, #mode, #idle_inhibitor { +#clock, #battery, #cpu, #memory, #temperature, #backlight, #network, #pulseaudio, #custom-media, #tray, #mode, #idle_inhibitor { padding: 0 10px; margin: 0 5px; } @@ -97,11 +101,19 @@ color: #2a5c45; } -#custom-spotify { +#custom-media { background: #66cc99; color: #2a5c45; } +.custom-spotify { + background: #66cc99; +} + +.custom-vlc { + background: #ffa000; +} + #temperature { background: #f0932b; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/bar.cpp new/Waybar-0.5.1/src/bar.cpp --- old/Waybar-0.5.0/src/bar.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/bar.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -84,10 +84,10 @@ setupAltFormatKeyForModuleList("modules-left"); setupAltFormatKeyForModuleList("modules-right"); setupAltFormatKeyForModuleList("modules-center"); - std::size_t layer_top = config_["layer"] == "top" + std::size_t layer = config_["layer"] == "top" ? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM; layer_surface = zwlr_layer_shell_v1_get_layer_surface( - client.layer_shell, surface, *output, layer_top, "waybar"); + client.layer_shell, surface, *output, layer, "waybar"); static const struct zwlr_layer_surface_v1_listener layer_surface_listener = { .configure = layerSurfaceHandleConfigure, @@ -95,18 +95,35 @@ }; zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this); - std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT - | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; - if (config_["position"] == "bottom") { - anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; - } else { - anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + if (config_["position"] == "right" || config_["position"] == "left") { + height_ = 0; + width_ = 30; } auto height = config_["height"].isUInt() ? config_["height"].asUInt() : height_; auto width = config_["width"].isUInt() ? config_["width"].asUInt() : width_; + + std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP; + if (config_["position"] == "bottom") { + anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + } else if (config_["position"] == "left") { + anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT; + } else if (config_["position"] == "right") { + anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + } + if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP) { + anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT | ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT; + } else if (anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT || anchor == ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT) { + anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP | ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM; + left_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); + center_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); + right_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); + box_ = Gtk::Box(Gtk::ORIENTATION_VERTICAL, 0); + vertical = true; + } + zwlr_layer_surface_v1_set_anchor(layer_surface, anchor); - zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, height); + zwlr_layer_surface_v1_set_exclusive_zone(layer_surface, vertical ? width : height); zwlr_layer_surface_v1_set_size(layer_surface, width, height); wl_surface_commit(surface); @@ -213,13 +230,18 @@ o->window.set_size_request(o->width_, o->height_); o->window.resize(o->width_, o->height_); - int dummy_width, min_height; - o->window.get_size(dummy_width, min_height); + int min_width, min_height; + o->window.get_size(min_width, min_height); if (o->height_ < static_cast<uint32_t>(min_height)) { std::cout << fmt::format("Requested height: {} exceeds the minimum \ height: {} required by the modules", o->height_, min_height) << std::endl; o->height_ = min_height; } + if (o->width_ < static_cast<uint32_t>(min_width)) { + std::cout << fmt::format("Requested width: {} exceeds the minimum \ +width: {} required by the modules", o->height_, min_width) << std::endl; + o->width_ = min_width; + } std::cout << fmt::format( "Bar configured (width: {}, height: {}) for output: {}", o->width_, o->height_, o->output_name) << std::endl; diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/factory.cpp new/Waybar-0.5.1/src/factory.cpp --- old/Waybar-0.5.0/src/factory.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/factory.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -38,7 +38,7 @@ } #ifdef HAVE_DBUSMENU if (ref == "tray") { - return new waybar::modules::SNI::Tray(id, config_[name]); + return new waybar::modules::SNI::Tray(id, bar_, config_[name]); } #endif #ifdef HAVE_LIBNL diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/modules/custom.cpp new/Waybar-0.5.1/src/modules/custom.cpp --- old/Waybar-0.5.0/src/modules/custom.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/modules/custom.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -98,7 +98,7 @@ auto str = fmt::format(format_, text_, fmt::arg("alt", alt_), - fmt::arg("icon", getIcon(percentage_)), + fmt::arg("icon", getIcon(percentage_, alt_)), fmt::arg("percentage", percentage_)); label_.set_markup(str); if (tooltipEnabled()) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/modules/network.cpp new/Waybar-0.5.1/src/modules/network.cpp --- old/Waybar-0.5.0/src/modules/network.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/modules/network.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -2,8 +2,8 @@ #include "modules/network.hpp" waybar::modules::Network::Network(const std::string& id, const Json::Value& config) - : ALabel(config, "{ifname}", 60), family_(AF_INET), info_sock_(-1), efd_(-1), - ev_fd_(-1), cidr_(-1), signal_strength_dbm_(0), signal_strength_(0) + : ALabel(config, "{ifname}", 60), family_(AF_INET), efd_(-1), ev_fd_(-1), + cidr_(-1), signal_strength_dbm_(0), signal_strength_(0) { label_.set_name("network"); if (!id.empty()) { @@ -39,8 +39,11 @@ if (efd_ > -1) { close(efd_); } - if (info_sock_ != -1) { - close(info_sock_); + if (info_sock_ != nullptr) { + nl_socket_drop_membership(info_sock_, RTMGRP_LINK); + nl_socket_drop_membership(info_sock_, RTMGRP_IPV4_IFADDR); + nl_close(info_sock_); + nl_socket_free(info_sock_); } if (sk_ != nullptr) { nl_close(sk_); @@ -50,18 +53,19 @@ void waybar::modules::Network::createInfoSocket() { - struct sockaddr_nl sa; - info_sock_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE); - if (info_sock_ < 0) { + info_sock_ = nl_socket_alloc(); + if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) { throw std::runtime_error("Can't connect network socket"); } - sa.nl_family = AF_NETLINK; - sa.nl_groups = RTMGRP_LINK | RTMGRP_IPV4_IFADDR | RTMGRP_IPV4_ROUTE - | RTMGRP_IPV6_IFADDR | RTMGRP_IPV6_ROUTE; - auto ret = bind(info_sock_, (struct sockaddr *)&sa, sizeof(sa)); - if (ret < 0) { + if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) { + throw std::runtime_error("Can't add membership"); + } + if (nl_socket_add_membership(info_sock_, RTMGRP_IPV4_IFADDR) != 0) { throw std::runtime_error("Can't add membership"); } + nl_socket_disable_seq_check(info_sock_); + nl_socket_set_nonblocking(info_sock_); + nl_socket_modify_cb(info_sock_, NL_CB_VALID, NL_CB_CUSTOM, handleEvents, this); efd_ = epoll_create1(0); if (efd_ < 0) { throw std::runtime_error("Can't create epoll"); @@ -76,10 +80,11 @@ } } { + auto fd = nl_socket_get_fd(info_sock_); struct epoll_event event; - event.events = EPOLLIN | EPOLLET; - event.data.fd = info_sock_; - if (epoll_ctl(efd_, EPOLL_CTL_ADD, info_sock_, &event) == -1) { + event.events = EPOLLIN | EPOLLET | EPOLLRDHUP; + event.data.fd = fd; + if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) { throw std::runtime_error("Can't add epoll event"); } } @@ -109,15 +114,16 @@ } thread_timer_.sleep_for(interval_); }; - struct epoll_event events[EPOLL_MAX] = {0}; + struct epoll_event events[EPOLL_MAX]; thread_ = [this, &events] { int ec = epoll_wait(efd_, events, EPOLL_MAX, -1); if (ec > 0) { for (auto i = 0; i < ec; i++) { - if (events[i].data.fd == ev_fd_) { + if (events[i].data.fd == nl_socket_get_fd(info_sock_)) { + nl_recvmsgs_default(info_sock_); + } else { thread_.stop(); - } else if (events[i].events & EPOLLIN) { - handleEvents(); + break; } } } else if (ec == -1) { @@ -371,7 +377,7 @@ sa.nl_groups = groups; struct iovec iov = { req, reqlen }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; - return sendmsg(info_sock_, &msg, 0); + return sendmsg(nl_socket_get_fd(info_sock_), &msg, 0); } int waybar::modules::Network::netlinkResponse(void *resp, @@ -382,64 +388,58 @@ sa.nl_groups = groups; struct iovec iov = { resp, resplen }; struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 }; - auto ret = recvmsg(info_sock_, &msg, 0); + auto ret = recvmsg(nl_socket_get_fd(info_sock_), &msg, 0); if (msg.msg_flags & MSG_TRUNC) { return -1; } return ret; } -void waybar::modules::Network::handleEvents() { - struct sockaddr_nl addr; - char buff[2048] = {0}; - socklen_t len = 0; - - while (true) { - len = sizeof(addr); - auto ret = recvfrom(info_sock_, (void *)buff, sizeof(buff), 0, - (struct sockaddr *)&addr, &len); - auto nh = (struct nlmsghdr *)buff; - for(; NLMSG_OK(nh, ret); nh = NLMSG_NEXT(nh, ret)) { - bool need_update = false; - if (nh->nlmsg_type == RTM_NEWADDR) { +int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) { + int ret = 0; + auto net = static_cast<waybar::modules::Network *>(data); + bool need_update = false; + for (nlmsghdr *nh = nlmsg_hdr(msg); NLMSG_OK(nh, ret); + nh = NLMSG_NEXT(nh, ret)) { + if (nh->nlmsg_type == RTM_NEWADDR) { + need_update = true; + } + if (nh->nlmsg_type < RTM_NEWADDR) { + auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh)); + if (rtif->ifi_index == static_cast<int>(net->ifid_)) { need_update = true; - } - if (nh->nlmsg_type < RTM_NEWADDR) { - auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh)); - if (rtif->ifi_index == static_cast<int>(ifid_)) { - need_update = true; - if (!(rtif->ifi_flags & IFF_RUNNING)) { - disconnected(); - dp.emit(); - return; - } + if (!(rtif->ifi_flags & IFF_RUNNING)) { + net->disconnected(); + net->dp.emit(); + return NL_SKIP; } } - if (ifid_ <= 0 && !config_["interface"].isString()) { - for (uint8_t i = 0; i < MAX_RETRY; i += 1) { - ifid_ = getExternalInterface(); - if (ifid_ > 0) { - break; - } - // Need to wait before get external interface - thread_.sleep_for(std::chrono::seconds(1)); - } - if (ifid_ > 0) { - char ifname[IF_NAMESIZE]; - if_indextoname(ifid_, ifname); - ifname_ = ifname; - need_update = true; - } - } - if (need_update) { - if (ifid_ > 0) { - getInfo(); - } - dp.emit(); + } + if (need_update) break; + } + if (net->ifid_ <= 0 && !net->config_["interface"].isString()) { + for (uint8_t i = 0; i < MAX_RETRY; i += 1) { + net->ifid_ = net->getExternalInterface(); + if (net->ifid_ > 0) { + break; } - break; + // Need to wait before get external interface + net->thread_.sleep_for(std::chrono::seconds(1)); + } + if (net->ifid_ > 0) { + char ifname[IF_NAMESIZE]; + if_indextoname(net->ifid_, ifname); + net->ifname_ = ifname; + need_update = true; } } + if (need_update) { + if (net->ifid_ > 0) { + net->getInfo(); + } + net->dp.emit(); + } + return NL_SKIP; } int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) { @@ -491,7 +491,9 @@ if (ies_len > hdr_len && ies_len > ies[1] + hdr_len) { auto essid_begin = ies + hdr_len; auto essid_end = essid_begin + ies[1]; - std::copy(essid_begin, essid_end, std::back_inserter(essid_)); + std::string essid_raw; + std::copy(essid_begin, essid_end, std::back_inserter(essid_raw)); + essid_ = Glib::Markup::escape_text(essid_raw); } } } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/modules/sni/item.cpp new/Waybar-0.5.1/src/modules/sni/item.cpp --- old/Waybar-0.5.0/src/modules/sni/item.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/modules/sni/item.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -1,10 +1,16 @@ #include "modules/sni/item.hpp" #include <iostream> +#include <glibmm/main.h> + +using namespace Glib; + +static const ustring SNI_INTERFACE_NAME = sn_item_interface_info()->name; +static const unsigned UPDATE_DEBOUNCE_TIME = 10; 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) -{ + : bus_name(bn), object_path(op), icon_size(16), effective_icon_size(0), + update_pending_(false) { if (config["icon-size"].isUInt()) { icon_size = config["icon-size"].asUInt(); } @@ -12,107 +18,148 @@ 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( - 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; - SnItem *proxy = sn_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); + + cancellable_ = Gio::Cancellable::create(); + + auto interface = Glib::wrap(sn_item_interface_info(), true); + Gio::DBus::Proxy::create_for_bus(Gio::DBus::BusType::BUS_TYPE_SESSION, bus_name, + object_path, SNI_INTERFACE_NAME, sigc::mem_fun(*this, &Item::proxyReady), + cancellable_, interface); +} + +void waybar::modules::SNI::Item::proxyReady(Glib::RefPtr<Gio::AsyncResult>& result) { + try { + this->proxy_ = Gio::DBus::Proxy::create_for_bus_finish(result); + /* Properties are already cached during object creation */ + auto cached_properties = this->proxy_->get_cached_property_names(); + for (const auto& name: cached_properties) { + Glib::VariantBase value; + this->proxy_->get_cached_property(value, name); + setProperty(name, value); + } + + this->proxy_->signal_signal().connect(sigc::mem_fun(*this, &Item::onSignal)); + + if (this->id.empty() || this->category.empty() || this->status.empty()) { + std::cerr << "Invalid Status Notifier Item: " + this->bus_name + "," + + this->object_path << std::endl; + return; } - g_variant_unref(value); - g_free(key); + if (!this->icon_theme_path.empty()) { + Glib::RefPtr<Gtk::IconTheme> icon_theme = Gtk::IconTheme::get_default(); + icon_theme->append_search_path(this->icon_theme_path); + } + this->updateImage(); + // this->event_box.set_tooltip_text(this->title); + + } catch (const Glib::Error& err) { + g_error("Failed to create DBus Proxy for %s %s: %s", bus_name.c_str(), + object_path.c_str(), err.what().c_str()); + } catch (const std::exception& err) { + g_error("Failed to create DBus Proxy for %s %s: %s", bus_name.c_str(), + object_path.c_str(), err.what()); + } +} + +template<typename T> +T get_variant(VariantBase& value) { + return VariantBase::cast_dynamic<Variant<T>>(value).get(); +} + +void +waybar::modules::SNI::Item::setProperty(const ustring& name, + VariantBase& value) { + if (name == "Category") { + category = get_variant<std::string>(value); + } else if (name == "Id") { + id = get_variant<std::string>(value); + } else if (name == "Title") { + title = get_variant<std::string>(value); + } else if (name == "Status") { + status = get_variant<std::string>(value); + } else if (name == "WindowId") { + window_id = get_variant<int32_t>(value); + } else if (name == "IconName") { + icon_name = get_variant<std::string>(value); + } else if (name == "IconPixmap") { + icon_pixmap = this->extractPixBuf(value.gobj()); + } else if (name == "OverlayIconName") { + overlay_icon_name = get_variant<std::string>(value); + } else if (name == "OverlayIconPixmap") { + // TODO: overlay_icon_pixmap + } else if (name == "AttentionIconName") { + attention_icon_name = get_variant<std::string>(value); + } else if (name == "AttentionIconPixmap") { + // TODO: attention_icon_pixmap + } else if (name == "AttentionMovieName") { + attention_movie_name = get_variant<std::string>(value); + } else if (name == "ToolTip") { + // TODO: tooltip + } else if (name == "IconThemePath") { + icon_theme_path = get_variant<std::string>(value); + } else if (name == "Menu") { + menu = get_variant<std::string>(value); + } else if (name == "ItemIsMenu") { + item_is_menu = get_variant<bool>(value); + } +} + +void +waybar::modules::SNI::Item::getUpdatedProperties() { + update_pending_ = false; + + auto params = VariantContainerBase::create_tuple({ + Variant<ustring>::create(SNI_INTERFACE_NAME) + }); + proxy_->call("org.freedesktop.DBus.Properties.GetAll", + sigc::mem_fun(*this, &Item::processUpdatedProperties), params); +}; + +void +waybar::modules::SNI::Item::processUpdatedProperties( + Glib::RefPtr<Gio::AsyncResult>& _result) { + try { + auto result = proxy_->call_finish(_result); + // extract "a{sv}" from VariantContainerBase + Variant<std::map<ustring, VariantBase>> properties_variant; + result.get_child(properties_variant); + auto properties = properties_variant.get(); + + for (const auto& [name, value]: properties) { + VariantBase old_value; + proxy_->get_cached_property(old_value, name); + if (!value.equal(old_value)) { + proxy_->set_cached_property(name, value); + setProperty(name, const_cast<VariantBase&>(value)); + } + } + + this->updateImage(); + // this->event_box.set_tooltip_text(this->title); + } catch (const Glib::Error& err) { + g_warning("Failed to update properties: %s", err.what().c_str()); + } catch (const std::exception& err) { + g_warning("Failed to update properties: %s", err.what()); } - 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->event_box.set_tooltip_text(item->title); - // TODO: handle change +} + +void +waybar::modules::SNI::Item::onSignal(const ustring& sender_name, + const ustring& signal_name, const VariantContainerBase& arguments) { + if (!update_pending_ && signal_name.compare(0, 3, "New") == 0) { + /* Debounce signals and schedule update of all properties. + * Based on behavior of Plasma dataengine for StatusNotifierItem. + */ + update_pending_ = true; + Glib::signal_timeout().connect_once( + sigc::mem_fun(*this, &Item::getUpdatedProperties), UPDATE_DEBOUNCE_TIME); + } +} + + +static void +pixbuf_data_deleter(const guint8* data) { + g_free((void*) data); } Glib::RefPtr<Gdk::Pixbuf> @@ -158,7 +205,8 @@ array[i + 3] = alpha; } return Gdk::Pixbuf::create_from_data(array, Gdk::Colorspace::COLORSPACE_RGB, - true, 8, lwidth, lheight, 4 * lwidth); + true, 8, lwidth, lheight, 4 * lwidth, + &pixbuf_data_deleter); } return Glib::RefPtr<Gdk::Pixbuf>{}; } @@ -251,15 +299,21 @@ } bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) { + auto parameters = VariantContainerBase::create_tuple({ + Variant<int>::create(ev->x), + Variant<int>::create(ev->y) + }); 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); + proxy_->call("ContextMenu", parameters); + return true; } } else if (ev->button == 1) { - return sn_item_call_activate_sync(proxy_, ev->x, ev->y, nullptr, nullptr); + proxy_->call("Activate", parameters); + return true; } else if (ev->button == 2) { - return sn_item_call_secondary_activate_sync(proxy_, ev->x, ev->y, - nullptr, nullptr); + proxy_->call("SecondaryActivate", parameters); + return true; } return false; } diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/modules/sni/tray.cpp new/Waybar-0.5.1/src/modules/sni/tray.cpp --- old/Waybar-0.5.0/src/modules/sni/tray.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/modules/sni/tray.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -2,8 +2,11 @@ #include <iostream> -waybar::modules::SNI::Tray::Tray(const std::string& id, const Json::Value &config) - : config_(config), watcher_(), host_(nb_hosts_, config, +waybar::modules::SNI::Tray::Tray(const std::string& id, const Bar& bar, + const Json::Value &config) + : config_(config), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), + watcher_(), host_(nb_hosts_, config, std::bind(&Tray::onAdd, this, std::placeholders::_1), std::bind(&Tray::onRemove, this, std::placeholders::_1)) { diff -urN '--exclude=CVS' '--exclude=.cvsignore' '--exclude=.svn' '--exclude=.svnignore' old/Waybar-0.5.0/src/modules/sway/workspaces.cpp new/Waybar-0.5.1/src/modules/sway/workspaces.cpp --- old/Waybar-0.5.0/src/modules/sway/workspaces.cpp 2019-03-20 10:51:40.000000000 +0100 +++ new/Waybar-0.5.1/src/modules/sway/workspaces.cpp 2019-04-04 12:01:00.000000000 +0200 @@ -2,7 +2,9 @@ waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& bar, const Json::Value& config) - : bar_(bar), config_(config), scrolling_(false) + : bar_(bar), config_(config), + box_(bar.vertical ? Gtk::ORIENTATION_VERTICAL : Gtk::ORIENTATION_HORIZONTAL, 0), + scrolling_(false) { box_.set_name("workspaces"); if (!id.empty()) { @@ -171,19 +173,19 @@ } std::string name; if (e->direction == GDK_SCROLL_UP) { - name = getCycleWorkspace(idx, false); + name = getCycleWorkspace(idx, true); } if (e->direction == GDK_SCROLL_DOWN) { - name = getCycleWorkspace(idx, true); + name = getCycleWorkspace(idx, false); } if (e->direction == GDK_SCROLL_SMOOTH) { gdouble delta_x, delta_y; gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e), &delta_x, &delta_y); if (delta_y < 0) { - name = getCycleWorkspace(idx, false); - } else if (delta_y > 0) { name = getCycleWorkspace(idx, true); + } else if (delta_y > 0) { + name = getCycleWorkspace(idx, false); } } if (name.empty() || name == workspaces_[idx]["name"].asString()) {
