mirror of
https://github.com/rad4day/Waybar.git
synced 2023-12-21 10:22:59 +01:00
Compare commits
33 Commits
Author | SHA1 | Date | |
---|---|---|---|
24684ca71b | |||
8351dea292 | |||
a68011bce6 | |||
1f6f443c48 | |||
7fac483530 | |||
0ad9a03d3d | |||
0f689b733d | |||
618fe80670 | |||
3a8cd91cc0 | |||
30725824d0 | |||
6522a7acb4 | |||
fd3e4ab2d4 | |||
949a4ecf2e | |||
860a6a1b81 | |||
5a2b5624dc | |||
82fcee33b3 | |||
842e8501f9 | |||
7bd5454e43 | |||
8340e88795 | |||
095294389b | |||
3bcf3befec | |||
db69b449ba | |||
ed358ef024 | |||
faa79ea216 | |||
b17984f75e | |||
4521db66ce | |||
7912b7f119 | |||
55a6e4907b | |||
dda0cc793e | |||
5144426f0e | |||
98c028226d | |||
3eb901f800 | |||
47142a61ae |
@ -2,7 +2,8 @@
|
|||||||
**Proof of concept**
|
**Proof of concept**
|
||||||
|
|
||||||
> Highly customizable Wayland bar for Sway and Wlroots based compositors.<br>
|
> 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**
|
**Current features**
|
||||||
- Sway (Workspaces, Binding mode, Focused window name)
|
- Sway (Workspaces, Binding mode, Focused window name)
|
||||||
|
@ -32,6 +32,7 @@ class Bar {
|
|||||||
std::string output_name;
|
std::string output_name;
|
||||||
uint32_t wl_name;
|
uint32_t wl_name;
|
||||||
bool visible = true;
|
bool visible = true;
|
||||||
|
bool vertical = false;
|
||||||
private:
|
private:
|
||||||
static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t,
|
static void handleLogicalPosition(void *, struct zxdg_output_v1 *, int32_t,
|
||||||
int32_t);
|
int32_t);
|
||||||
|
@ -23,6 +23,7 @@ class Network : public ALabel {
|
|||||||
static const uint8_t MAX_RETRY = 5;
|
static const uint8_t MAX_RETRY = 5;
|
||||||
static const uint8_t EPOLL_MAX = 255;
|
static const uint8_t EPOLL_MAX = 255;
|
||||||
|
|
||||||
|
static int handleEvents(struct nl_msg*, void*);
|
||||||
static int handleScan(struct nl_msg*, void*);
|
static int handleScan(struct nl_msg*, void*);
|
||||||
|
|
||||||
void worker();
|
void worker();
|
||||||
@ -31,7 +32,6 @@ class Network : public ALabel {
|
|||||||
void createEventSocket();
|
void createEventSocket();
|
||||||
int getExternalInterface();
|
int getExternalInterface();
|
||||||
void getInterfaceAddress();
|
void getInterfaceAddress();
|
||||||
void handleEvents();
|
|
||||||
int netlinkRequest(void*, uint32_t, uint32_t groups = 0);
|
int netlinkRequest(void*, uint32_t, uint32_t groups = 0);
|
||||||
int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
|
int netlinkResponse(void*, uint32_t, uint32_t groups = 0);
|
||||||
void parseEssid(struct nlattr**);
|
void parseEssid(struct nlattr**);
|
||||||
@ -45,7 +45,7 @@ class Network : public ALabel {
|
|||||||
sa_family_t family_;
|
sa_family_t family_;
|
||||||
struct sockaddr_nl nladdr_ = {0};
|
struct sockaddr_nl nladdr_ = {0};
|
||||||
struct nl_sock* sk_ = nullptr;
|
struct nl_sock* sk_ = nullptr;
|
||||||
int info_sock_;
|
struct nl_sock* info_sock_ = nullptr;
|
||||||
int efd_;
|
int efd_;
|
||||||
int ev_fd_;
|
int ev_fd_;
|
||||||
int nl80211_id_;
|
int nl80211_id_;
|
||||||
|
@ -2,12 +2,14 @@
|
|||||||
|
|
||||||
#include <dbus-status-notifier-item.h>
|
#include <dbus-status-notifier-item.h>
|
||||||
#include <glibmm/refptr.h>
|
#include <glibmm/refptr.h>
|
||||||
|
#include <giomm/dbusproxy.h>
|
||||||
#include <gtkmm/eventbox.h>
|
#include <gtkmm/eventbox.h>
|
||||||
#include <gtkmm/image.h>
|
#include <gtkmm/image.h>
|
||||||
#include <gtkmm/icontheme.h>
|
#include <gtkmm/icontheme.h>
|
||||||
#include <gtkmm/menu.h>
|
#include <gtkmm/menu.h>
|
||||||
#include <json/json.h>
|
#include <json/json.h>
|
||||||
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
|
#include <libdbusmenu-gtk/dbusmenu-gtk.h>
|
||||||
|
#include <sigc++/trackable.h>
|
||||||
#ifdef FILESYSTEM_EXPERIMENTAL
|
#ifdef FILESYSTEM_EXPERIMENTAL
|
||||||
#include <experimental/filesystem>
|
#include <experimental/filesystem>
|
||||||
#else
|
#else
|
||||||
@ -16,7 +18,7 @@
|
|||||||
|
|
||||||
namespace waybar::modules::SNI {
|
namespace waybar::modules::SNI {
|
||||||
|
|
||||||
class Item {
|
class Item : public sigc::trackable {
|
||||||
public:
|
public:
|
||||||
Item(std::string, std::string, const Json::Value&);
|
Item(std::string, std::string, const Json::Value&);
|
||||||
~Item() = default;
|
~Item() = default;
|
||||||
@ -46,8 +48,12 @@ public:
|
|||||||
bool item_is_menu;
|
bool item_is_menu;
|
||||||
|
|
||||||
private:
|
private:
|
||||||
static void proxyReady(GObject *obj, GAsyncResult *res, gpointer data);
|
void proxyReady(Glib::RefPtr<Gio::AsyncResult>& result);
|
||||||
static void getAll(GObject *obj, GAsyncResult *res, gpointer data);
|
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();
|
void updateImage();
|
||||||
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
|
Glib::RefPtr<Gdk::Pixbuf> extractPixBuf(GVariant *variant);
|
||||||
@ -56,8 +62,9 @@ private:
|
|||||||
bool makeMenu(GdkEventButton *const &ev);
|
bool makeMenu(GdkEventButton *const &ev);
|
||||||
bool handleClick(GdkEventButton *const & /*ev*/);
|
bool handleClick(GdkEventButton *const & /*ev*/);
|
||||||
|
|
||||||
GCancellable *cancellable_ = nullptr;
|
Glib::RefPtr<Gio::Cancellable> cancellable_;
|
||||||
SnItem *proxy_ = nullptr;
|
Glib::RefPtr<Gio::DBus::Proxy> proxy_;
|
||||||
|
bool update_pending_;
|
||||||
};
|
};
|
||||||
|
|
||||||
} // namespace waybar::modules::SNI
|
} // namespace waybar::modules::SNI
|
||||||
|
@ -11,7 +11,7 @@ namespace waybar::modules::SNI {
|
|||||||
|
|
||||||
class Tray : public IModule {
|
class Tray : public IModule {
|
||||||
public:
|
public:
|
||||||
Tray(const std::string&, const Json::Value&);
|
Tray(const std::string&, const Bar&, const Json::Value&);
|
||||||
~Tray() = default;
|
~Tray() = default;
|
||||||
auto update() -> void;
|
auto update() -> void;
|
||||||
operator Gtk::Widget &();
|
operator Gtk::Widget &();
|
||||||
|
@ -1,6 +1,6 @@
|
|||||||
project(
|
project(
|
||||||
'waybar', 'cpp', 'c',
|
'waybar', 'cpp', 'c',
|
||||||
version: '0.5.0',
|
version: '0.5.1',
|
||||||
license: 'MIT',
|
license: 'MIT',
|
||||||
default_options : [
|
default_options : [
|
||||||
'cpp_std=c++17',
|
'cpp_std=c++17',
|
||||||
@ -72,7 +72,7 @@ src_files = files(
|
|||||||
'src/client.cpp'
|
'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')
|
add_project_arguments('-DHAVE_SWAY', language: 'cpp')
|
||||||
src_files += [
|
src_files += [
|
||||||
'src/modules/sway/ipc/client.cpp',
|
'src/modules/sway/ipc/client.cpp',
|
||||||
|
@ -1,10 +1,10 @@
|
|||||||
{
|
{
|
||||||
"layer": "top", // Waybar at top layer
|
"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
|
// "height": 30, // Waybar height
|
||||||
// "width": 1280, // Waybar width
|
// "width": 1280, // Waybar width
|
||||||
// Choose the order of the modules
|
// 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-center": ["sway/window"],
|
||||||
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
|
"modules-right": ["idle_inhibitor", "pulseaudio", "network", "cpu", "memory", "temperature", "backlight", "battery", "battery#bat2", "clock", "tray"],
|
||||||
// Modules configuration
|
// Modules configuration
|
||||||
@ -95,9 +95,15 @@
|
|||||||
},
|
},
|
||||||
"on-click": "pavucontrol"
|
"on-click": "pavucontrol"
|
||||||
},
|
},
|
||||||
"custom/spotify": {
|
"custom/media": {
|
||||||
"format": " {}",
|
"format": "{icon} {}",
|
||||||
|
"return-type": "json",
|
||||||
"max-length": 40,
|
"max-length": 40,
|
||||||
|
"format-icons": {
|
||||||
|
"spotify": "",
|
||||||
|
"default": "🎜"
|
||||||
|
},
|
||||||
|
"escape": true,
|
||||||
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
|
"exec": "$HOME/.config/waybar/mediaplayer.py 2> /dev/null" // Script in resources folder
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,19 +1,34 @@
|
|||||||
#!/usr/bin/env python3
|
#!/usr/bin/env python3
|
||||||
|
import argparse
|
||||||
|
import logging
|
||||||
import sys
|
import sys
|
||||||
import signal
|
import signal
|
||||||
import gi
|
import gi
|
||||||
|
import json
|
||||||
gi.require_version('Playerctl', '2.0')
|
gi.require_version('Playerctl', '2.0')
|
||||||
from gi.repository import Playerctl, GLib
|
from gi.repository import Playerctl, GLib
|
||||||
|
|
||||||
manager = Playerctl.PlayerManager()
|
logger = logging.getLogger(__name__)
|
||||||
loop = GLib.MainLoop()
|
|
||||||
|
|
||||||
|
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):
|
def on_play(player, status, manager):
|
||||||
|
logger.info('Received new playback status')
|
||||||
on_metadata(player, player.props.metadata, manager)
|
on_metadata(player, player.props.metadata, manager)
|
||||||
|
|
||||||
|
|
||||||
def on_metadata(player, metadata, manager):
|
def on_metadata(player, metadata, manager):
|
||||||
|
logger.info('Received new metadata')
|
||||||
track_info = ''
|
track_info = ''
|
||||||
|
|
||||||
if player.props.player_name == 'spotify' and \
|
if player.props.player_name == 'spotify' and \
|
||||||
@ -23,28 +38,27 @@ def on_metadata(player, metadata, manager):
|
|||||||
elif player.get_artist() != '' and player.get_title() != '':
|
elif player.get_artist() != '' and player.get_title() != '':
|
||||||
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
|
track_info = '{artist} - {title}'.format(artist=player.get_artist(),
|
||||||
title=player.get_title())
|
title=player.get_title())
|
||||||
|
|
||||||
|
if player.props.status != 'Playing':
|
||||||
|
track_info = ' ' + track_info
|
||||||
|
write_output(track_info, player)
|
||||||
|
|
||||||
|
|
||||||
|
def on_player_appeared(manager, player, selected_player=None):
|
||||||
|
if player is not None and player.name == selected_player:
|
||||||
|
init_player(manager, player)
|
||||||
else:
|
else:
|
||||||
sys.stdout.write('\n')
|
logger.debug("New player appeared, but it's not the selected player, skipping")
|
||||||
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()
|
|
||||||
|
|
||||||
|
|
||||||
def on_name_appeared(manager, name):
|
|
||||||
init_player(name)
|
|
||||||
|
|
||||||
|
|
||||||
def on_player_vanished(manager, player):
|
def on_player_vanished(manager, player):
|
||||||
sys.stdout.write("\n")
|
logger.info('Player has vanished')
|
||||||
|
sys.stdout.write('\n')
|
||||||
sys.stdout.flush()
|
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 = Playerctl.Player.new_from_name(name)
|
||||||
player.connect('playback-status', on_play, manager)
|
player.connect('playback-status', on_play, manager)
|
||||||
player.connect('metadata', on_metadata, manager)
|
player.connect('metadata', on_metadata, manager)
|
||||||
@ -53,19 +67,60 @@ def init_player(name):
|
|||||||
|
|
||||||
|
|
||||||
def signal_handler(sig, frame):
|
def signal_handler(sig, frame):
|
||||||
sys.stdout.write("\n")
|
logger.debug('Received signal to stop, exiting')
|
||||||
|
sys.stdout.write('\n')
|
||||||
sys.stdout.flush()
|
sys.stdout.flush()
|
||||||
loop.quit()
|
# loop.quit()
|
||||||
sys.exit(0)
|
sys.exit(0)
|
||||||
|
|
||||||
|
|
||||||
manager.connect('name-appeared', on_name_appeared)
|
def parse_arguments():
|
||||||
manager.connect('player-vanished', on_player_vanished)
|
parser = argparse.ArgumentParser()
|
||||||
|
|
||||||
signal.signal(signal.SIGINT, signal_handler)
|
# Increase verbosity with every occurance of -v
|
||||||
signal.signal(signal.SIGTERM, signal_handler)
|
parser.add_argument('-v', '--verbose', action='count', default=0)
|
||||||
|
|
||||||
for player in manager.props.player_names:
|
# Define for which player we're listening
|
||||||
init_player(player)
|
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()
|
||||||
|
|
||||||
|
|
||||||
|
if __name__ == '__main__':
|
||||||
|
main()
|
||||||
|
|
||||||
loop.run()
|
|
||||||
|
@ -25,12 +25,16 @@ window#waybar {
|
|||||||
border-bottom: 3px solid #ffffff;
|
border-bottom: 3px solid #ffffff;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
#workspaces button.urgent {
|
||||||
|
background-color: #eb4d4b;
|
||||||
|
}
|
||||||
|
|
||||||
#mode {
|
#mode {
|
||||||
background: #64727D;
|
background: #64727D;
|
||||||
border-bottom: 3px solid #ffffff;
|
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;
|
padding: 0 10px;
|
||||||
margin: 0 5px;
|
margin: 0 5px;
|
||||||
}
|
}
|
||||||
@ -97,11 +101,19 @@ window#waybar {
|
|||||||
color: #2a5c45;
|
color: #2a5c45;
|
||||||
}
|
}
|
||||||
|
|
||||||
#custom-spotify {
|
#custom-media {
|
||||||
background: #66cc99;
|
background: #66cc99;
|
||||||
color: #2a5c45;
|
color: #2a5c45;
|
||||||
}
|
}
|
||||||
|
|
||||||
|
.custom-spotify {
|
||||||
|
background: #66cc99;
|
||||||
|
}
|
||||||
|
|
||||||
|
.custom-vlc {
|
||||||
|
background: #ffa000;
|
||||||
|
}
|
||||||
|
|
||||||
#temperature {
|
#temperature {
|
||||||
background: #f0932b;
|
background: #f0932b;
|
||||||
}
|
}
|
||||||
|
44
src/bar.cpp
44
src/bar.cpp
@ -84,10 +84,10 @@ void waybar::Bar::initBar()
|
|||||||
setupAltFormatKeyForModuleList("modules-left");
|
setupAltFormatKeyForModuleList("modules-left");
|
||||||
setupAltFormatKeyForModuleList("modules-right");
|
setupAltFormatKeyForModuleList("modules-right");
|
||||||
setupAltFormatKeyForModuleList("modules-center");
|
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;
|
? ZWLR_LAYER_SHELL_V1_LAYER_TOP : ZWLR_LAYER_SHELL_V1_LAYER_BOTTOM;
|
||||||
layer_surface = zwlr_layer_shell_v1_get_layer_surface(
|
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 = {
|
static const struct zwlr_layer_surface_v1_listener layer_surface_listener = {
|
||||||
.configure = layerSurfaceHandleConfigure,
|
.configure = layerSurfaceHandleConfigure,
|
||||||
@ -95,18 +95,35 @@ void waybar::Bar::initBar()
|
|||||||
};
|
};
|
||||||
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
|
zwlr_layer_surface_v1_add_listener(layer_surface, &layer_surface_listener, this);
|
||||||
|
|
||||||
std::size_t anchor = ZWLR_LAYER_SURFACE_V1_ANCHOR_LEFT
|
if (config_["position"] == "right" || config_["position"] == "left") {
|
||||||
| ZWLR_LAYER_SURFACE_V1_ANCHOR_RIGHT;
|
height_ = 0;
|
||||||
if (config_["position"] == "bottom") {
|
width_ = 30;
|
||||||
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_BOTTOM;
|
|
||||||
} else {
|
|
||||||
anchor |= ZWLR_LAYER_SURFACE_V1_ANCHOR_TOP;
|
|
||||||
}
|
}
|
||||||
|
|
||||||
auto height = config_["height"].isUInt() ? config_["height"].asUInt() : height_;
|
auto height = config_["height"].isUInt() ? config_["height"].asUInt() : height_;
|
||||||
auto width = config_["width"].isUInt() ? config_["width"].asUInt() : width_;
|
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_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);
|
zwlr_layer_surface_v1_set_size(layer_surface, width, height);
|
||||||
|
|
||||||
wl_surface_commit(surface);
|
wl_surface_commit(surface);
|
||||||
@ -213,13 +230,18 @@ void waybar::Bar::layerSurfaceHandleConfigure(void* data,
|
|||||||
o->window.set_size_request(o->width_, o->height_);
|
o->window.set_size_request(o->width_, o->height_);
|
||||||
o->window.resize(o->width_, o->height_);
|
o->window.resize(o->width_, o->height_);
|
||||||
|
|
||||||
int dummy_width, min_height;
|
int min_width, min_height;
|
||||||
o->window.get_size(dummy_width, min_height);
|
o->window.get_size(min_width, min_height);
|
||||||
if (o->height_ < static_cast<uint32_t>(min_height)) {
|
if (o->height_ < static_cast<uint32_t>(min_height)) {
|
||||||
std::cout << fmt::format("Requested height: {} exceeds the minimum \
|
std::cout << fmt::format("Requested height: {} exceeds the minimum \
|
||||||
height: {} required by the modules", o->height_, min_height) << std::endl;
|
height: {} required by the modules", o->height_, min_height) << std::endl;
|
||||||
o->height_ = min_height;
|
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(
|
std::cout << fmt::format(
|
||||||
"Bar configured (width: {}, height: {}) for output: {}",
|
"Bar configured (width: {}, height: {}) for output: {}",
|
||||||
o->width_, o->height_, o->output_name) << std::endl;
|
o->width_, o->height_, o->output_name) << std::endl;
|
||||||
|
@ -38,7 +38,7 @@ waybar::IModule* waybar::Factory::makeModule(const std::string &name) const
|
|||||||
}
|
}
|
||||||
#ifdef HAVE_DBUSMENU
|
#ifdef HAVE_DBUSMENU
|
||||||
if (ref == "tray") {
|
if (ref == "tray") {
|
||||||
return new waybar::modules::SNI::Tray(id, config_[name]);
|
return new waybar::modules::SNI::Tray(id, bar_, config_[name]);
|
||||||
}
|
}
|
||||||
#endif
|
#endif
|
||||||
#ifdef HAVE_LIBNL
|
#ifdef HAVE_LIBNL
|
||||||
|
@ -98,7 +98,7 @@ auto waybar::modules::Custom::update() -> void
|
|||||||
|
|
||||||
auto str = fmt::format(format_, text_,
|
auto str = fmt::format(format_, text_,
|
||||||
fmt::arg("alt", alt_),
|
fmt::arg("alt", alt_),
|
||||||
fmt::arg("icon", getIcon(percentage_)),
|
fmt::arg("icon", getIcon(percentage_, alt_)),
|
||||||
fmt::arg("percentage", percentage_));
|
fmt::arg("percentage", percentage_));
|
||||||
label_.set_markup(str);
|
label_.set_markup(str);
|
||||||
if (tooltipEnabled()) {
|
if (tooltipEnabled()) {
|
||||||
|
@ -2,8 +2,8 @@
|
|||||||
#include "modules/network.hpp"
|
#include "modules/network.hpp"
|
||||||
|
|
||||||
waybar::modules::Network::Network(const std::string& id, const Json::Value& config)
|
waybar::modules::Network::Network(const std::string& id, const Json::Value& config)
|
||||||
: ALabel(config, "{ifname}", 60), family_(AF_INET), info_sock_(-1), efd_(-1),
|
: ALabel(config, "{ifname}", 60), family_(AF_INET), efd_(-1), ev_fd_(-1),
|
||||||
ev_fd_(-1), cidr_(-1), signal_strength_dbm_(0), signal_strength_(0)
|
cidr_(-1), signal_strength_dbm_(0), signal_strength_(0)
|
||||||
{
|
{
|
||||||
label_.set_name("network");
|
label_.set_name("network");
|
||||||
if (!id.empty()) {
|
if (!id.empty()) {
|
||||||
@ -39,8 +39,11 @@ waybar::modules::Network::~Network()
|
|||||||
if (efd_ > -1) {
|
if (efd_ > -1) {
|
||||||
close(efd_);
|
close(efd_);
|
||||||
}
|
}
|
||||||
if (info_sock_ != -1) {
|
if (info_sock_ != nullptr) {
|
||||||
close(info_sock_);
|
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) {
|
if (sk_ != nullptr) {
|
||||||
nl_close(sk_);
|
nl_close(sk_);
|
||||||
@ -50,18 +53,19 @@ waybar::modules::Network::~Network()
|
|||||||
|
|
||||||
void waybar::modules::Network::createInfoSocket()
|
void waybar::modules::Network::createInfoSocket()
|
||||||
{
|
{
|
||||||
struct sockaddr_nl sa;
|
info_sock_ = nl_socket_alloc();
|
||||||
info_sock_ = socket(AF_NETLINK, SOCK_RAW, NETLINK_ROUTE);
|
if (nl_connect(info_sock_, NETLINK_ROUTE) != 0) {
|
||||||
if (info_sock_ < 0) {
|
|
||||||
throw std::runtime_error("Can't connect network socket");
|
throw std::runtime_error("Can't connect network socket");
|
||||||
}
|
}
|
||||||
sa.nl_family = AF_NETLINK;
|
if (nl_socket_add_membership(info_sock_, RTMGRP_LINK) != 0) {
|
||||||
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) {
|
|
||||||
throw std::runtime_error("Can't add membership");
|
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);
|
efd_ = epoll_create1(0);
|
||||||
if (efd_ < 0) {
|
if (efd_ < 0) {
|
||||||
throw std::runtime_error("Can't create epoll");
|
throw std::runtime_error("Can't create epoll");
|
||||||
@ -76,10 +80,11 @@ void waybar::modules::Network::createInfoSocket()
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
{
|
{
|
||||||
|
auto fd = nl_socket_get_fd(info_sock_);
|
||||||
struct epoll_event event;
|
struct epoll_event event;
|
||||||
event.events = EPOLLIN | EPOLLET;
|
event.events = EPOLLIN | EPOLLET | EPOLLRDHUP;
|
||||||
event.data.fd = info_sock_;
|
event.data.fd = fd;
|
||||||
if (epoll_ctl(efd_, EPOLL_CTL_ADD, info_sock_, &event) == -1) {
|
if (epoll_ctl(efd_, EPOLL_CTL_ADD, fd, &event) == -1) {
|
||||||
throw std::runtime_error("Can't add epoll event");
|
throw std::runtime_error("Can't add epoll event");
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
@ -109,15 +114,16 @@ void waybar::modules::Network::worker()
|
|||||||
}
|
}
|
||||||
thread_timer_.sleep_for(interval_);
|
thread_timer_.sleep_for(interval_);
|
||||||
};
|
};
|
||||||
struct epoll_event events[EPOLL_MAX] = {0};
|
struct epoll_event events[EPOLL_MAX];
|
||||||
thread_ = [this, &events] {
|
thread_ = [this, &events] {
|
||||||
int ec = epoll_wait(efd_, events, EPOLL_MAX, -1);
|
int ec = epoll_wait(efd_, events, EPOLL_MAX, -1);
|
||||||
if (ec > 0) {
|
if (ec > 0) {
|
||||||
for (auto i = 0; i < ec; i++) {
|
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();
|
thread_.stop();
|
||||||
} else if (events[i].events & EPOLLIN) {
|
break;
|
||||||
handleEvents();
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
} else if (ec == -1) {
|
} else if (ec == -1) {
|
||||||
@ -371,7 +377,7 @@ int waybar::modules::Network::netlinkRequest(void *req,
|
|||||||
sa.nl_groups = groups;
|
sa.nl_groups = groups;
|
||||||
struct iovec iov = { req, reqlen };
|
struct iovec iov = { req, reqlen };
|
||||||
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 };
|
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,
|
int waybar::modules::Network::netlinkResponse(void *resp,
|
||||||
@ -382,64 +388,58 @@ int waybar::modules::Network::netlinkResponse(void *resp,
|
|||||||
sa.nl_groups = groups;
|
sa.nl_groups = groups;
|
||||||
struct iovec iov = { resp, resplen };
|
struct iovec iov = { resp, resplen };
|
||||||
struct msghdr msg = { &sa, sizeof(sa), &iov, 1, nullptr, 0, 0 };
|
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) {
|
if (msg.msg_flags & MSG_TRUNC) {
|
||||||
return -1;
|
return -1;
|
||||||
}
|
}
|
||||||
return ret;
|
return ret;
|
||||||
}
|
}
|
||||||
|
|
||||||
void waybar::modules::Network::handleEvents() {
|
int waybar::modules::Network::handleEvents(struct nl_msg *msg, void *data) {
|
||||||
struct sockaddr_nl addr;
|
int ret = 0;
|
||||||
char buff[2048] = {0};
|
auto net = static_cast<waybar::modules::Network *>(data);
|
||||||
socklen_t len = 0;
|
bool need_update = false;
|
||||||
|
for (nlmsghdr *nh = nlmsg_hdr(msg); NLMSG_OK(nh, ret);
|
||||||
while (true) {
|
nh = NLMSG_NEXT(nh, ret)) {
|
||||||
len = sizeof(addr);
|
if (nh->nlmsg_type == RTM_NEWADDR) {
|
||||||
auto ret = recvfrom(info_sock_, (void *)buff, sizeof(buff), 0,
|
need_update = true;
|
||||||
(struct sockaddr *)&addr, &len);
|
}
|
||||||
auto nh = (struct nlmsghdr *)buff;
|
if (nh->nlmsg_type < RTM_NEWADDR) {
|
||||||
for(; NLMSG_OK(nh, ret); nh = NLMSG_NEXT(nh, ret)) {
|
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
|
||||||
bool need_update = false;
|
if (rtif->ifi_index == static_cast<int>(net->ifid_)) {
|
||||||
if (nh->nlmsg_type == RTM_NEWADDR) {
|
|
||||||
need_update = true;
|
need_update = true;
|
||||||
}
|
if (!(rtif->ifi_flags & IFF_RUNNING)) {
|
||||||
if (nh->nlmsg_type < RTM_NEWADDR) {
|
net->disconnected();
|
||||||
auto rtif = static_cast<struct ifinfomsg *>(NLMSG_DATA(nh));
|
net->dp.emit();
|
||||||
if (rtif->ifi_index == static_cast<int>(ifid_)) {
|
return NL_SKIP;
|
||||||
need_update = true;
|
|
||||||
if (!(rtif->ifi_flags & IFF_RUNNING)) {
|
|
||||||
disconnected();
|
|
||||||
dp.emit();
|
|
||||||
return;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (ifid_ <= 0 && !config_["interface"].isString()) {
|
}
|
||||||
for (uint8_t i = 0; i < MAX_RETRY; i += 1) {
|
if (need_update) break;
|
||||||
ifid_ = getExternalInterface();
|
}
|
||||||
if (ifid_ > 0) {
|
if (net->ifid_ <= 0 && !net->config_["interface"].isString()) {
|
||||||
break;
|
for (uint8_t i = 0; i < MAX_RETRY; i += 1) {
|
||||||
}
|
net->ifid_ = net->getExternalInterface();
|
||||||
// Need to wait before get external interface
|
if (net->ifid_ > 0) {
|
||||||
thread_.sleep_for(std::chrono::seconds(1));
|
break;
|
||||||
}
|
|
||||||
if (ifid_ > 0) {
|
|
||||||
char ifname[IF_NAMESIZE];
|
|
||||||
if_indextoname(ifid_, ifname);
|
|
||||||
ifname_ = ifname;
|
|
||||||
need_update = true;
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
if (need_update) {
|
// Need to wait before get external interface
|
||||||
if (ifid_ > 0) {
|
net->thread_.sleep_for(std::chrono::seconds(1));
|
||||||
getInfo();
|
}
|
||||||
}
|
if (net->ifid_ > 0) {
|
||||||
dp.emit();
|
char ifname[IF_NAMESIZE];
|
||||||
}
|
if_indextoname(net->ifid_, ifname);
|
||||||
break;
|
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) {
|
int waybar::modules::Network::handleScan(struct nl_msg *msg, void *data) {
|
||||||
@ -491,7 +491,9 @@ void waybar::modules::Network::parseEssid(struct nlattr **bss)
|
|||||||
if (ies_len > hdr_len && ies_len > ies[1] + hdr_len) {
|
if (ies_len > hdr_len && ies_len > ies[1] + hdr_len) {
|
||||||
auto essid_begin = ies + hdr_len;
|
auto essid_begin = ies + hdr_len;
|
||||||
auto essid_end = essid_begin + ies[1];
|
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);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -1,10 +1,16 @@
|
|||||||
#include "modules/sni/item.hpp"
|
#include "modules/sni/item.hpp"
|
||||||
|
|
||||||
#include <iostream>
|
#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)
|
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()) {
|
if (config["icon-size"].isUInt()) {
|
||||||
icon_size = config["icon-size"].asUInt();
|
icon_size = config["icon-size"].asUInt();
|
||||||
}
|
}
|
||||||
@ -12,107 +18,148 @@ waybar::modules::SNI::Item::Item(std::string bn, std::string op, const Json::Val
|
|||||||
event_box.add_events(Gdk::BUTTON_PRESS_MASK);
|
event_box.add_events(Gdk::BUTTON_PRESS_MASK);
|
||||||
event_box.signal_button_press_event().connect(
|
event_box.signal_button_press_event().connect(
|
||||||
sigc::mem_fun(*this, &Item::handleClick));
|
sigc::mem_fun(*this, &Item::handleClick));
|
||||||
cancellable_ = g_cancellable_new();
|
|
||||||
sn_item_proxy_new_for_bus(
|
cancellable_ = Gio::Cancellable::create();
|
||||||
G_BUS_TYPE_SESSION, G_DBUS_PROXY_FLAGS_NONE, bus_name.c_str(),
|
|
||||||
object_path.c_str(), cancellable_, &Item::proxyReady, this);
|
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(GObject *obj, GAsyncResult *res,
|
void waybar::modules::SNI::Item::proxyReady(Glib::RefPtr<Gio::AsyncResult>& result) {
|
||||||
gpointer data) {
|
try {
|
||||||
GError *error = nullptr;
|
this->proxy_ = Gio::DBus::Proxy::create_for_bus_finish(result);
|
||||||
SnItem *proxy = sn_item_proxy_new_for_bus_finish(res, &error);
|
/* Properties are already cached during object creation */
|
||||||
if (g_error_matches(error, G_IO_ERROR, G_IO_ERROR_CANCELLED)) {
|
auto cached_properties = this->proxy_->get_cached_property_names();
|
||||||
g_error_free(error);
|
for (const auto& name: cached_properties) {
|
||||||
return;
|
Glib::VariantBase value;
|
||||||
}
|
this->proxy_->get_cached_property(value, name);
|
||||||
auto item = static_cast<SNI::Item *>(data);
|
setProperty(name, value);
|
||||||
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);
|
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;
|
||||||
|
}
|
||||||
|
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());
|
||||||
}
|
}
|
||||||
g_variant_iter_free(it);
|
}
|
||||||
g_variant_unref(properties);
|
|
||||||
if (item->id.empty() || item->category.empty() || item->status.empty()) {
|
template<typename T>
|
||||||
std::cerr << "Invalid Status Notifier Item: " + item->bus_name + "," +
|
T get_variant(VariantBase& value) {
|
||||||
item->object_path << std::endl;
|
return VariantBase::cast_dynamic<Variant<T>>(value).get();
|
||||||
return;
|
}
|
||||||
|
|
||||||
|
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);
|
||||||
}
|
}
|
||||||
if (!item->icon_theme_path.empty()) {
|
}
|
||||||
GtkIconTheme *icon_theme = gtk_icon_theme_get_default();
|
|
||||||
gtk_icon_theme_append_search_path(icon_theme,
|
void
|
||||||
item->icon_theme_path.c_str());
|
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());
|
||||||
}
|
}
|
||||||
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>
|
Glib::RefPtr<Gdk::Pixbuf>
|
||||||
@ -158,7 +205,8 @@ waybar::modules::SNI::Item::extractPixBuf(GVariant *variant) {
|
|||||||
array[i + 3] = alpha;
|
array[i + 3] = alpha;
|
||||||
}
|
}
|
||||||
return Gdk::Pixbuf::create_from_data(array, Gdk::Colorspace::COLORSPACE_RGB,
|
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>{};
|
return Glib::RefPtr<Gdk::Pixbuf>{};
|
||||||
}
|
}
|
||||||
@ -251,15 +299,21 @@ bool waybar::modules::SNI::Item::makeMenu(GdkEventButton *const &ev)
|
|||||||
}
|
}
|
||||||
|
|
||||||
bool waybar::modules::SNI::Item::handleClick(GdkEventButton *const &ev) {
|
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 ((ev->button == 1 && item_is_menu) || ev->button == 3) {
|
||||||
if (!makeMenu(ev)) {
|
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) {
|
} 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) {
|
} else if (ev->button == 2) {
|
||||||
return sn_item_call_secondary_activate_sync(proxy_, ev->x, ev->y,
|
proxy_->call("SecondaryActivate", parameters);
|
||||||
nullptr, nullptr);
|
return true;
|
||||||
}
|
}
|
||||||
return false;
|
return false;
|
||||||
}
|
}
|
||||||
|
@ -2,8 +2,11 @@
|
|||||||
|
|
||||||
#include <iostream>
|
#include <iostream>
|
||||||
|
|
||||||
waybar::modules::SNI::Tray::Tray(const std::string& id, const Json::Value &config)
|
waybar::modules::SNI::Tray::Tray(const std::string& id, const Bar& bar,
|
||||||
: config_(config), watcher_(), host_(nb_hosts_, config,
|
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::onAdd, this, std::placeholders::_1),
|
||||||
std::bind(&Tray::onRemove, this, std::placeholders::_1))
|
std::bind(&Tray::onRemove, this, std::placeholders::_1))
|
||||||
{
|
{
|
||||||
|
@ -2,7 +2,9 @@
|
|||||||
|
|
||||||
waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& bar,
|
waybar::modules::sway::Workspaces::Workspaces(const std::string& id, const Bar& bar,
|
||||||
const Json::Value& config)
|
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");
|
box_.set_name("workspaces");
|
||||||
if (!id.empty()) {
|
if (!id.empty()) {
|
||||||
@ -171,19 +173,19 @@ bool waybar::modules::sway::Workspaces::handleScroll(GdkEventScroll *e)
|
|||||||
}
|
}
|
||||||
std::string name;
|
std::string name;
|
||||||
if (e->direction == GDK_SCROLL_UP) {
|
if (e->direction == GDK_SCROLL_UP) {
|
||||||
name = getCycleWorkspace(idx, false);
|
name = getCycleWorkspace(idx, true);
|
||||||
}
|
}
|
||||||
if (e->direction == GDK_SCROLL_DOWN) {
|
if (e->direction == GDK_SCROLL_DOWN) {
|
||||||
name = getCycleWorkspace(idx, true);
|
name = getCycleWorkspace(idx, false);
|
||||||
}
|
}
|
||||||
if (e->direction == GDK_SCROLL_SMOOTH) {
|
if (e->direction == GDK_SCROLL_SMOOTH) {
|
||||||
gdouble delta_x, delta_y;
|
gdouble delta_x, delta_y;
|
||||||
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e),
|
gdk_event_get_scroll_deltas(reinterpret_cast<const GdkEvent *>(e),
|
||||||
&delta_x, &delta_y);
|
&delta_x, &delta_y);
|
||||||
if (delta_y < 0) {
|
if (delta_y < 0) {
|
||||||
name = getCycleWorkspace(idx, false);
|
|
||||||
} else if (delta_y > 0) {
|
|
||||||
name = getCycleWorkspace(idx, true);
|
name = getCycleWorkspace(idx, true);
|
||||||
|
} else if (delta_y > 0) {
|
||||||
|
name = getCycleWorkspace(idx, false);
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if (name.empty() || name == workspaces_[idx]["name"].asString()) {
|
if (name.empty() || name == workspaces_[idx]["name"].asString()) {
|
||||||
|
Reference in New Issue
Block a user