Merge pull request #1554 from ErikReider/gamemode-module
Gamemode Module
This commit is contained in:
commit
03bbc9df64
|
@ -42,6 +42,9 @@
|
|||
#ifdef HAVE_LIBEVDEV
|
||||
#include "modules/keyboard_state.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_GAMEMODE
|
||||
#include "modules/gamemode.hpp"
|
||||
#endif
|
||||
#ifdef HAVE_UPOWER
|
||||
#include "modules/upower/upower.hpp"
|
||||
#endif
|
||||
|
|
|
@ -0,0 +1,77 @@
|
|||
#pragma once
|
||||
|
||||
#include <iostream>
|
||||
#include <map>
|
||||
#include <string>
|
||||
|
||||
#include "ALabel.hpp"
|
||||
#include "giomm/dbusconnection.h"
|
||||
#include "giomm/dbusproxy.h"
|
||||
#include "glibconfig.h"
|
||||
#include "gtkmm/box.h"
|
||||
#include "gtkmm/image.h"
|
||||
#include "gtkmm/label.h"
|
||||
#include "gtkmm/overlay.h"
|
||||
|
||||
namespace waybar::modules {
|
||||
|
||||
class Gamemode : public AModule {
|
||||
public:
|
||||
Gamemode(const std::string &, const Json::Value &);
|
||||
~Gamemode();
|
||||
auto update() -> void;
|
||||
|
||||
private:
|
||||
const std::string DEFAULT_ICON_NAME = "input-gaming-symbolic";
|
||||
const std::string DEFAULT_FORMAT = "{glyph}";
|
||||
const std::string DEFAULT_FORMAT_ALT = "{glyph} {count}";
|
||||
const std::string DEFAULT_TOOLTIP_FORMAT = "Games running: {count}";
|
||||
const std::string DEFAULT_GLYPH = "";
|
||||
|
||||
void appear(const Glib::RefPtr<Gio::DBus::Connection> &connection, const Glib::ustring &name,
|
||||
const Glib::ustring &name_owner);
|
||||
void disappear(const Glib::RefPtr<Gio::DBus::Connection> &connection, const Glib::ustring &name);
|
||||
void prepareForSleep_cb(const Glib::RefPtr<Gio::DBus::Connection> &connection,
|
||||
const Glib::ustring &sender_name, const Glib::ustring &object_path,
|
||||
const Glib::ustring &interface_name, const Glib::ustring &signal_name,
|
||||
const Glib::VariantContainerBase ¶meters);
|
||||
void notify_cb(const Glib::ustring &sender_name, const Glib::ustring &signal_name,
|
||||
const Glib::VariantContainerBase &arguments);
|
||||
|
||||
void getData();
|
||||
bool handleToggle(GdkEventButton *const &);
|
||||
|
||||
// Config
|
||||
std::string format = DEFAULT_FORMAT;
|
||||
std::string format_alt = DEFAULT_FORMAT_ALT;
|
||||
std::string tooltip_format = DEFAULT_TOOLTIP_FORMAT;
|
||||
std::string glyph = DEFAULT_GLYPH;
|
||||
bool tooltip = true;
|
||||
bool hideNotRunning = true;
|
||||
bool useIcon = true;
|
||||
uint iconSize = 20;
|
||||
uint iconSpacing = 4;
|
||||
std::string iconName = DEFAULT_ICON_NAME;
|
||||
|
||||
Gtk::Box box_;
|
||||
Gtk::Image icon_;
|
||||
Gtk::Label label_;
|
||||
|
||||
const std::string dbus_name = "com.feralinteractive.GameMode";
|
||||
const std::string dbus_obj_path = "/com/feralinteractive/GameMode";
|
||||
const std::string dbus_interface = "org.freedesktop.DBus.Properties";
|
||||
const std::string dbus_get_interface = "com.feralinteractive.GameMode";
|
||||
|
||||
uint gameCount = 0;
|
||||
|
||||
std::string lastStatus;
|
||||
bool showAltText = false;
|
||||
|
||||
guint login1_id;
|
||||
Glib::RefPtr<Gio::DBus::Proxy> gamemode_proxy;
|
||||
Glib::RefPtr<Gio::DBus::Connection> system_connection;
|
||||
bool gamemodeRunning;
|
||||
guint gamemodeWatcher_id;
|
||||
};
|
||||
|
||||
} // namespace waybar::modules
|
|
@ -0,0 +1,95 @@
|
|||
waybar-gamemode(5)
|
||||
|
||||
# NAME
|
||||
|
||||
waybar - gamemode module
|
||||
|
||||
# DESCRIPTION
|
||||
|
||||
The *gamemode* module displays if any game or application is running with ++
|
||||
Feral Gamemode optimizations.
|
||||
|
||||
# CONFIGURATION
|
||||
|
||||
*format*: ++
|
||||
typeof: string ++
|
||||
default: {glyph} ++
|
||||
The text format.
|
||||
|
||||
*format-alt*: ++
|
||||
typeof: string ++
|
||||
default: {glyph} {count} ++
|
||||
The text format when toggled.
|
||||
|
||||
*tooltip*: ++
|
||||
typeof: bool ++
|
||||
defualt: true ++
|
||||
Option to disable tooltip on hover.
|
||||
|
||||
*tooltip-format*: ++
|
||||
typeof: string ++
|
||||
default: Games running: {glyph} ++
|
||||
The text format of the tooltip.
|
||||
|
||||
*hide-not-running*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Defines if the module should be hidden if no games are running.
|
||||
|
||||
*use-icon*: ++
|
||||
typeof: bool ++
|
||||
default: true ++
|
||||
Defines if the module should display a GTK icon instead of the specified *glyph*
|
||||
|
||||
*glyph*: ++
|
||||
typeof: string ++
|
||||
default: ++
|
||||
The string icon to display. Only visible if *use-icon* is set to false.
|
||||
|
||||
*icon-name*: ++
|
||||
typeof: string ++
|
||||
default: input-gaming-symbolic ++
|
||||
The GTK icon to display. Only visible if *use-icon* is set to true.
|
||||
|
||||
*icon-size*: ++
|
||||
typeof: unsigned integer ++
|
||||
default: 20 ++
|
||||
Defines the size of the icons.
|
||||
|
||||
*icon-spacing*: ++
|
||||
typeof: unsigned integer ++
|
||||
default: 4 ++
|
||||
Defines the spacing between the icon and the text.
|
||||
|
||||
# FORMAT REPLACEMENTS
|
||||
|
||||
*{glyph}*: The string icon glyph to use instead.
|
||||
|
||||
*{count}*: The amount of games running with gamemode optimizations.
|
||||
|
||||
# TOOLTIP FORMAT REPLACEMENTS
|
||||
|
||||
*{count}*: The amount of games running with gamemode optimizations.
|
||||
|
||||
# EXAMPLES
|
||||
|
||||
```
|
||||
"gamemode": {
|
||||
"format": "{glyph}",
|
||||
"format-alt": "{glyph} {count}",
|
||||
"glyph": "",
|
||||
"hide-not-running": true,
|
||||
"use-icon": true,
|
||||
"icon-name": "input-gaming-symbolic",
|
||||
"icon-spacing": 4,
|
||||
"icon-size": 20,
|
||||
"tooltip": true,
|
||||
"tooltip-format": "Games running: {count}"
|
||||
}
|
||||
|
||||
```
|
||||
|
||||
# STYLE
|
||||
|
||||
- *#gamemode*
|
||||
- *#gamemode.running*
|
|
@ -204,6 +204,11 @@ if libnl.found() and libnlgen.found()
|
|||
src_files += 'src/modules/network.cpp'
|
||||
endif
|
||||
|
||||
if (giounix.found() and not get_option('logind').disabled())
|
||||
add_project_arguments('-DHAVE_GAMEMODE', language: 'cpp')
|
||||
src_files += 'src/modules/gamemode.cpp'
|
||||
endif
|
||||
|
||||
if (upower_glib.found() and giounix.found() and not get_option('logind').disabled())
|
||||
add_project_arguments('-DHAVE_UPOWER', language: 'cpp')
|
||||
src_files += 'src/modules/upower/upower.cpp'
|
||||
|
|
|
@ -12,6 +12,11 @@ waybar::AModule* waybar::Factory::makeModule(const std::string& name) const {
|
|||
return new waybar::modules::Battery(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_GAMEMODE
|
||||
if (ref == "gamemode") {
|
||||
return new waybar::modules::Gamemode(id, config_[name]);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_UPOWER
|
||||
if (ref == "upower") {
|
||||
return new waybar::modules::upower::UPower(id, config_[name]);
|
||||
|
|
|
@ -0,0 +1,237 @@
|
|||
#include "modules/gamemode.hpp"
|
||||
|
||||
#include <fmt/core.h>
|
||||
#include <spdlog/spdlog.h>
|
||||
|
||||
#include <cstdio>
|
||||
#include <cstring>
|
||||
#include <string>
|
||||
|
||||
#include "AModule.hpp"
|
||||
#include "giomm/dbusconnection.h"
|
||||
#include "giomm/dbusinterface.h"
|
||||
#include "giomm/dbusproxy.h"
|
||||
#include "giomm/dbuswatchname.h"
|
||||
#include "glibmm/error.h"
|
||||
#include "glibmm/ustring.h"
|
||||
#include "glibmm/variant.h"
|
||||
#include "glibmm/varianttype.h"
|
||||
#include "gtkmm/icontheme.h"
|
||||
#include "gtkmm/label.h"
|
||||
#include "gtkmm/tooltip.h"
|
||||
|
||||
namespace waybar::modules {
|
||||
Gamemode::Gamemode(const std::string& id, const Json::Value& config)
|
||||
: AModule(config, "gamemode", id), box_(Gtk::ORIENTATION_HORIZONTAL, 0), icon_(), label_() {
|
||||
box_.pack_start(icon_);
|
||||
box_.pack_start(label_);
|
||||
box_.set_name(name_);
|
||||
event_box_.add(box_);
|
||||
|
||||
// Tooltip
|
||||
if (config_["tooltip"].isBool()) {
|
||||
tooltip = config_["tooltip"].asBool();
|
||||
}
|
||||
box_.set_has_tooltip(tooltip);
|
||||
|
||||
// Tooltip Format
|
||||
if (config_["tooltip-format"].isString()) {
|
||||
tooltip_format = config_["tooltip-format"].asString();
|
||||
}
|
||||
|
||||
// Hide when game count is 0
|
||||
if (config_["hide-not-running"].isBool()) {
|
||||
hideNotRunning = config_["hide-not-running"].asBool();
|
||||
}
|
||||
|
||||
// Icon Name
|
||||
if (config_["icon-name"].isString()) {
|
||||
iconName = config_["icon-name"].asString();
|
||||
}
|
||||
|
||||
// Icon Spacing
|
||||
if (config_["icon-spacing"].isUInt()) {
|
||||
iconSpacing = config_["icon-spacing"].asUInt();
|
||||
}
|
||||
box_.set_spacing(iconSpacing);
|
||||
|
||||
// Wether to use icon or not
|
||||
if (config_["use-icon"].isBool()) {
|
||||
useIcon = config_["use-icon"].asBool();
|
||||
}
|
||||
|
||||
// Icon Size
|
||||
if (config_["icon-size"].isUInt()) {
|
||||
iconSize = config_["icon-size"].asUInt();
|
||||
}
|
||||
icon_.set_pixel_size(iconSize);
|
||||
|
||||
// Format
|
||||
if (config_["format"].isString()) {
|
||||
format = config_["format"].asString();
|
||||
}
|
||||
|
||||
// Format Alt
|
||||
if (config_["format-alt"].isString()) {
|
||||
format_alt = config_["format-alt"].asString();
|
||||
}
|
||||
|
||||
// Glyph
|
||||
if (config_["glyph"].isString()) {
|
||||
glyph = config_["glyph"].asString();
|
||||
}
|
||||
|
||||
gamemodeWatcher_id = Gio::DBus::watch_name(
|
||||
Gio::DBus::BUS_TYPE_SESSION, dbus_name, sigc::mem_fun(*this, &Gamemode::appear),
|
||||
sigc::mem_fun(*this, &Gamemode::disappear),
|
||||
Gio::DBus::BusNameWatcherFlags::BUS_NAME_WATCHER_FLAGS_AUTO_START);
|
||||
|
||||
// Connect to gamemode
|
||||
gamemode_proxy = Gio::DBus::Proxy::create_for_bus_sync(Gio::DBus::BusType::BUS_TYPE_SESSION,
|
||||
dbus_name, dbus_obj_path, dbus_interface);
|
||||
if (!gamemode_proxy) {
|
||||
throw std::runtime_error("Unable to connect to gamemode DBus!...");
|
||||
} else {
|
||||
gamemode_proxy->signal_signal().connect(sigc::mem_fun(*this, &Gamemode::notify_cb));
|
||||
}
|
||||
|
||||
// Connect to Login1 PrepareForSleep signal
|
||||
system_connection = Gio::DBus::Connection::get_sync(Gio::DBus::BusType::BUS_TYPE_SYSTEM);
|
||||
if (!system_connection) {
|
||||
throw std::runtime_error("Unable to connect to the SYSTEM Bus!...");
|
||||
} else {
|
||||
login1_id = system_connection->signal_subscribe(
|
||||
sigc::mem_fun(*this, &Gamemode::prepareForSleep_cb), "org.freedesktop.login1",
|
||||
"org.freedesktop.login1.Manager", "PrepareForSleep", "/org/freedesktop/login1");
|
||||
}
|
||||
|
||||
event_box_.signal_button_press_event().connect(sigc::mem_fun(*this, &Gamemode::handleToggle));
|
||||
}
|
||||
|
||||
Gamemode::~Gamemode() {
|
||||
if (gamemode_proxy) gamemode_proxy->unreference();
|
||||
if (gamemodeWatcher_id > 0) {
|
||||
Gio::DBus::unwatch_name(gamemodeWatcher_id);
|
||||
gamemodeWatcher_id = 0;
|
||||
}
|
||||
if (login1_id > 0) {
|
||||
system_connection->signal_unsubscribe(login1_id);
|
||||
login1_id = 0;
|
||||
}
|
||||
}
|
||||
|
||||
// Gets the DBus ClientCount
|
||||
void Gamemode::getData() {
|
||||
if (gamemodeRunning && gamemode_proxy) {
|
||||
try {
|
||||
// Get game count
|
||||
auto parameters = Glib::VariantContainerBase(
|
||||
g_variant_new("(ss)", dbus_get_interface.c_str(), "ClientCount"));
|
||||
Glib::VariantContainerBase data = gamemode_proxy->call_sync("Get", parameters);
|
||||
if (data && data.is_of_type(Glib::VariantType("(v)"))) {
|
||||
Glib::VariantBase variant;
|
||||
g_variant_get(data.gobj_copy(), "(v)", &variant);
|
||||
if (variant && variant.is_of_type(Glib::VARIANT_TYPE_INT32)) {
|
||||
g_variant_get(variant.gobj_copy(), "i", &gameCount);
|
||||
return;
|
||||
}
|
||||
}
|
||||
} catch (Glib::Error& e) {
|
||||
spdlog::error("Gamemode Error {}", e.what().c_str());
|
||||
}
|
||||
}
|
||||
gameCount = 0;
|
||||
}
|
||||
|
||||
// Whenever the DBus ClientCount changes
|
||||
void Gamemode::notify_cb(const Glib::ustring& sender_name, const Glib::ustring& signal_name,
|
||||
const Glib::VariantContainerBase& arguments) {
|
||||
if (signal_name == "PropertiesChanged") {
|
||||
getData();
|
||||
dp.emit();
|
||||
}
|
||||
}
|
||||
|
||||
void Gamemode::prepareForSleep_cb(const Glib::RefPtr<Gio::DBus::Connection>& connection,
|
||||
const Glib::ustring& sender_name,
|
||||
const Glib::ustring& object_path,
|
||||
const Glib::ustring& interface_name,
|
||||
const Glib::ustring& signal_name,
|
||||
const Glib::VariantContainerBase& parameters) {
|
||||
if (parameters.is_of_type(Glib::VariantType("(b)"))) {
|
||||
gboolean sleeping;
|
||||
g_variant_get(parameters.gobj_copy(), "(b)", &sleeping);
|
||||
if (!sleeping) {
|
||||
getData();
|
||||
dp.emit();
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// When the gamemode name appears
|
||||
void Gamemode::appear(const Glib::RefPtr<Gio::DBus::Connection>& connection,
|
||||
const Glib::ustring& name, const Glib::ustring& name_owner) {
|
||||
gamemodeRunning = true;
|
||||
event_box_.set_visible(true);
|
||||
getData();
|
||||
dp.emit();
|
||||
}
|
||||
// When the gamemode name disappears
|
||||
void Gamemode::disappear(const Glib::RefPtr<Gio::DBus::Connection>& connection,
|
||||
const Glib::ustring& name) {
|
||||
gamemodeRunning = false;
|
||||
event_box_.set_visible(false);
|
||||
}
|
||||
|
||||
bool Gamemode::handleToggle(GdkEventButton* const& event) {
|
||||
showAltText = !showAltText;
|
||||
dp.emit();
|
||||
return true;
|
||||
}
|
||||
|
||||
auto Gamemode::update() -> void {
|
||||
// Don't update widget if the Gamemode service isn't running
|
||||
if (!gamemodeRunning || (gameCount <= 0 && hideNotRunning)) {
|
||||
event_box_.set_visible(false);
|
||||
return;
|
||||
}
|
||||
|
||||
// Show the module
|
||||
if (!event_box_.get_visible()) event_box_.set_visible(true);
|
||||
|
||||
// CSS status class
|
||||
const std::string status = gamemodeRunning && gameCount > 0 ? "running" : "";
|
||||
// Remove last status if it exists
|
||||
if (!lastStatus.empty() && box_.get_style_context()->has_class(lastStatus)) {
|
||||
box_.get_style_context()->remove_class(lastStatus);
|
||||
}
|
||||
// Add the new status class to the Box
|
||||
if (!status.empty() && !box_.get_style_context()->has_class(status)) {
|
||||
box_.get_style_context()->add_class(status);
|
||||
}
|
||||
lastStatus = status;
|
||||
|
||||
// Tooltip
|
||||
if (tooltip) {
|
||||
std::string text = fmt::format(tooltip_format, fmt::arg("count", gameCount));
|
||||
box_.set_tooltip_text(text);
|
||||
}
|
||||
|
||||
// Label format
|
||||
std::string str =
|
||||
fmt::format(showAltText ? format_alt : format, fmt::arg("glyph", useIcon ? "" : glyph),
|
||||
fmt::arg("count", gameCount > 0 ? std::to_string(gameCount) : ""));
|
||||
label_.set_markup(str);
|
||||
|
||||
if (useIcon) {
|
||||
if (!Gtk::IconTheme::get_default()->has_icon(iconName)) {
|
||||
iconName = DEFAULT_ICON_NAME;
|
||||
}
|
||||
icon_.set_from_icon_name(iconName, Gtk::ICON_SIZE_INVALID);
|
||||
}
|
||||
|
||||
// Call parent update
|
||||
AModule::update();
|
||||
}
|
||||
|
||||
} // namespace waybar::modules
|
Loading…
Reference in New Issue