Merge branch 'master' into master

pull/1002/head
nullobsi 2021-02-10 09:39:03 -08:00 committed by GitHub
commit b12b500bfc
No known key found for this signature in database
GPG Key ID: 4AEE18F83AFDEB23
29 changed files with 282 additions and 26 deletions

View File

@ -20,7 +20,7 @@ class Workspaces : public AModule, public sigc::trackable {
auto update() -> void; auto update() -> void;
private: private:
static inline const std::string workspace_switch_cmd_ = "workspace --no-auto-back-and-forth \"{}\""; static inline const std::string workspace_switch_cmd_ = "workspace {} \"{}\"";
static int convertWorkspaceNameToNum(std::string name); static int convertWorkspaceNameToNum(std::string name);

View File

@ -0,0 +1,5 @@
#pragma once
#include <glibmm/ustring.h>
// calculate column width of ustring
int ustring_clen(const Glib::ustring &str);

View File

@ -24,6 +24,14 @@ The *backlight* module displays the current backlight level.
typeof: integer ++ typeof: integer ++
The maximum length in characters the module should display. The maximum length in characters the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.

View File

@ -55,6 +55,14 @@ The *battery* module displays the current capacity and state (eg. charging) of y
typeof: integer++ typeof: integer++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer++ typeof: integer++
Positive value to rotate the text label. Positive value to rotate the text label.

View File

@ -35,6 +35,14 @@ Addressed by *bluetooth*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -45,6 +45,14 @@ The *clock* module displays the current date and time.
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.

View File

@ -24,6 +24,14 @@ The *cpu* module displays the current cpu utilization.
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*rotate*: ++ *rotate*: ++
typeof: integer ++ typeof: integer ++
Positive value to rotate the text label. Positive value to rotate the text label.

View File

@ -67,6 +67,14 @@ Addressed by *custom/<name>*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -39,6 +39,14 @@ Addressed by *disk*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -27,6 +27,14 @@ screensaving, also known as "presentation mode".
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. A click also toggles the state Command to execute when clicked on the module. A click also toggles the state

View File

@ -34,6 +34,14 @@ Addressed by *memory*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -97,6 +97,14 @@ Addressed by *mpd*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -64,6 +64,14 @@ Addressed by *network*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -50,6 +50,14 @@ Additionally you can control the volume by scrolling *up* or *down* while the cu
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*scroll-step*: ++ *scroll-step*: ++
typeof: float ++ typeof: float ++
default: 1.0 ++ default: 1.0 ++

View File

@ -26,6 +26,14 @@ cursor is over the module, and clicking on the module toggles mute.
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*scroll-step*: ++ *scroll-step*: ++
typeof: int ++ typeof: int ++
default: 5 ++ default: 5 ++

View File

@ -25,6 +25,14 @@ Addressed by *sway/language*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -25,6 +25,14 @@ Addressed by *sway/mode*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -25,6 +25,14 @@ Addressed by *sway/window*
typeof: integer ++ typeof: integer ++
The maximum length in character the module should display. The maximum length in character the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when clicked on the module. Command to execute when clicked on the module.

View File

@ -66,12 +66,16 @@ Addressed by *sway/workspaces*
Lists workspaces that should always be shown, even when non existent Lists workspaces that should always be shown, even when non existent
*on-update*: ++ *on-update*: ++
typeof: string ++ typeof: string ++
Command to execute when the module is updated. Command to execute when the module is updated.
*numeric-first*: ++ *numeric-first*: ++
typeof: bool ++ typeof: bool ++
Whether to put workspaces starting with numbers before workspaces that do not start with a number. Whether to put workspaces starting with numbers before workspaces that do not start with a number.
*disable-auto-back-and-forth*: ++
typeof: bool ++
Whether to disable *workspace_auto_back_and_forth* when clicking on workspaces. If this is set to *true*, clicking on a workspace you are already on won't do anything, even if *workspace_auto_back_and_forth* is enabled in the Sway configuration.
# FORMAT REPLACEMENTS # FORMAT REPLACEMENTS

View File

@ -63,6 +63,14 @@ Addressed by *temperature*
typeof: integer ++ typeof: integer ++
The maximum length in characters the module should display. The maximum length in characters the module should display.
*min-length*: ++
typeof: integer ++
The minimum length in characters the module should take up.
*align*: ++
typeof: float ++
The alignment of the text, where 0 is left-aligned and 1 is right-aligned. If the module is rotated, it will follow the flow of the text.
*on-click*: ++ *on-click*: ++
typeof: string ++ typeof: string ++
Command to execute when you clicked on the module. Command to execute when you clicked on the module.

View File

@ -147,6 +147,7 @@ src_files = files(
'src/main.cpp', 'src/main.cpp',
'src/bar.cpp', 'src/bar.cpp',
'src/client.cpp', 'src/client.cpp',
'src/util/ustring_clen.cpp'
) )
if is_linux if is_linux

View File

@ -20,7 +20,7 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
} }
event_box_.add(label_); event_box_.add(label_);
if (config_["max-length"].isUInt()) { if (config_["max-length"].isUInt()) {
label_.set_max_width_chars(config_["max-length"].asUInt()); label_.set_max_width_chars(config_["max-length"].asInt());
label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END); label_.set_ellipsize(Pango::EllipsizeMode::ELLIPSIZE_END);
label_.set_single_line_mode(true); label_.set_single_line_mode(true);
} else if (ellipsize && label_.get_max_width_chars() == -1) { } else if (ellipsize && label_.get_max_width_chars() == -1) {
@ -28,9 +28,28 @@ ALabel::ALabel(const Json::Value& config, const std::string& name, const std::st
label_.set_single_line_mode(true); label_.set_single_line_mode(true);
} }
if (config_["rotate"].isUInt()) { if (config_["min-length"].isUInt()) {
label_.set_angle(config["rotate"].asUInt()); label_.set_width_chars(config_["min-length"].asUInt());
} }
uint rotate = 0;
if (config_["rotate"].isUInt()) {
rotate = config["rotate"].asUInt();
label_.set_angle(rotate);
}
if (config_["align"].isDouble()) {
auto align = config_["align"].asFloat();
if (rotate == 90 || rotate == 270) {
label_.set_yalign(align);
} else {
label_.set_xalign(align);
}
}
} }
auto ALabel::update() -> void { auto ALabel::update() -> void {

View File

@ -120,17 +120,26 @@ void waybar::Client::handleOutputDone(void *data, struct zxdg_output_v1 * /*xdg_
auto client = waybar::Client::inst(); auto client = waybar::Client::inst();
try { try {
auto &output = client->getOutput(data); auto &output = client->getOutput(data);
spdlog::debug("Output detection done: {} ({})", output.name, output.identifier); /**
* Multiple .done events may arrive in batch. In this case libwayland would queue
* xdg_output.destroy and dispatch all pending events, triggering this callback several times
* for the same output. .done events can also arrive after that for a scale or position changes.
* We wouldn't want to draw a duplicate bar for each such event either.
*
* All the properties we care about are immutable so it's safe to delete the xdg_output object
* on the first event and use the ptr value to check that the callback was already invoked.
*/
if (output.xdg_output) {
output.xdg_output.reset();
spdlog::debug("Output detection done: {} ({})", output.name, output.identifier);
auto configs = client->getOutputConfigs(output); auto configs = client->getOutputConfigs(output);
if (!configs.empty()) { if (!configs.empty()) {
wl_display_roundtrip(client->wl_display); for (const auto &config : configs) {
for (const auto &config : configs) { client->bars.emplace_back(std::make_unique<Bar>(&output, config));
client->bars.emplace_back(std::make_unique<Bar>(&output, config)); }
} }
} }
// unsubscribe
output.xdg_output.reset();
} catch (const std::exception &e) { } catch (const std::exception &e) {
std::cerr << e.what() << std::endl; std::cerr << e.what() << std::endl;
} }

View File

@ -5,6 +5,7 @@
#include <sstream> #include <sstream>
#include <type_traits> #include <type_traits>
#include "util/ustring_clen.hpp"
#ifdef HAVE_LANGINFO_1STDAY #ifdef HAVE_LANGINFO_1STDAY
#include <langinfo.h> #include <langinfo.h>
#include <locale.h> #include <locale.h>
@ -154,12 +155,14 @@ auto waybar::modules::Clock::weekdays_header(const date::weekday& first_dow, std
do { do {
if (wd != first_dow) os << ' '; if (wd != first_dow) os << ' ';
Glib::ustring wd_ustring(date::format(locale_, "%a", wd)); Glib::ustring wd_ustring(date::format(locale_, "%a", wd));
auto wd_len = wd_ustring.length(); auto clen = ustring_clen(wd_ustring);
if (wd_len > 2) { auto wd_len = wd_ustring.length();
wd_ustring = wd_ustring.substr(0, 2); while (clen > 2) {
wd_len = 2; wd_ustring = wd_ustring.substr(0, wd_len-1);
wd_len--;
clen = ustring_clen(wd_ustring);
} }
const std::string pad(2 - wd_len, ' '); const std::string pad(2 - clen, ' ');
os << pad << wd_ustring; os << pad << wd_ustring;
} while (++wd != first_dow); } while (++wd != first_dow);
os << "\n"; os << "\n";

View File

@ -12,6 +12,10 @@ waybar::modules::IdleInhibitor::IdleInhibitor(const std::string& id, const Bar&
bar_(bar), bar_(bar),
idle_inhibitor_(nullptr), idle_inhibitor_(nullptr),
pid_(-1) { pid_(-1) {
if (waybar::Client::inst()->idle_inhibit_manager == nullptr) {
throw std::runtime_error("idle-inhibit not available");
}
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, &IdleInhibitor::handleToggle)); sigc::mem_fun(*this, &IdleInhibitor::handleToggle));

View File

@ -56,7 +56,8 @@ auto Window::update() -> void {
bar_.window.get_style_context()->remove_class("solo"); bar_.window.get_style_context()->remove_class("solo");
bar_.window.get_style_context()->remove_class("empty"); bar_.window.get_style_context()->remove_class("empty");
} }
label_.set_markup(fmt::format(format_, window_)); label_.set_markup(fmt::format(format_, fmt::arg("title", window_),
fmt::arg("app_id", app_id_)));
if (tooltipEnabled()) { if (tooltipEnabled()) {
label_.set_tooltip_text(window_); label_.set_tooltip_text(window_);
} }

View File

@ -257,11 +257,19 @@ Gtk::Button &Workspaces::addButton(const Json::Value &node) {
ipc_.sendCmd( ipc_.sendCmd(
IPC_COMMAND, IPC_COMMAND,
fmt::format(workspace_switch_cmd_ + "; move workspace to output \"{}\"; " + workspace_switch_cmd_, fmt::format(workspace_switch_cmd_ + "; move workspace to output \"{}\"; " + workspace_switch_cmd_,
"--no-auto-back-and-forth",
node["name"].asString(), node["name"].asString(),
node["target_output"].asString(), node["target_output"].asString(),
"--no-auto-back-and-forth",
node["name"].asString())); node["name"].asString()));
} else { } else {
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_cmd_, node["name"].asString())); ipc_.sendCmd(
IPC_COMMAND,
fmt::format("workspace {} \"{}\"",
config_["disable-auto-back-and-forth"].asBool()
? "--no-auto-back-and-forth"
: "",
node["name"].asString()));
} }
} catch (const std::exception &e) { } catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what()); spdlog::error("Workspaces: {}", e.what());
@ -322,7 +330,9 @@ bool Workspaces::handleScroll(GdkEventScroll *e) {
} }
} }
try { try {
ipc_.sendCmd(IPC_COMMAND, fmt::format(workspace_switch_cmd_, name)); ipc_.sendCmd(
IPC_COMMAND,
fmt::format(workspace_switch_cmd_, "--no-auto-back-and-forth", name));
} catch (const std::exception &e) { } catch (const std::exception &e) {
spdlog::error("Workspaces: {}", e.what()); spdlog::error("Workspaces: {}", e.what());
} }

View File

@ -1,5 +1,7 @@
#include "modules/wlr/taskbar.hpp" #include "modules/wlr/taskbar.hpp"
#include "glibmm/error.h"
#include "glibmm/fileutils.h"
#include "glibmm/refptr.h" #include "glibmm/refptr.h"
#include "util/format.hpp" #include "util/format.hpp"
@ -15,6 +17,7 @@
#include <gtkmm/icontheme.h> #include <gtkmm/icontheme.h>
#include <giomm/desktopappinfo.h> #include <giomm/desktopappinfo.h>
#include <gio/gdesktopappinfo.h>
#include <spdlog/spdlog.h> #include <spdlog/spdlog.h>
@ -64,12 +67,25 @@ static std::vector<std::string> search_prefix()
} while(end != std::string::npos); } while(end != std::string::npos);
} }
std::string home_dir = std::getenv("HOME");
prefixes.push_back(home_dir + "/.local/share/");
for (auto& p : prefixes) for (auto& p : prefixes)
spdlog::debug("Using 'desktop' search path prefix: {}", p); spdlog::debug("Using 'desktop' search path prefix: {}", p);
return prefixes; return prefixes;
} }
static Glib::RefPtr<Gdk::Pixbuf> load_icon_from_file(std::string icon_path, int size)
{
try {
auto pb = Gdk::Pixbuf::create_from_file(icon_path, size, size);
return pb;
} catch(...) {
return {};
}
}
/* Method 1 - get the correct icon name from the desktop file */ /* Method 1 - get the correct icon name from the desktop file */
static std::string get_from_desktop_app_info(const std::string &app_id) static std::string get_from_desktop_app_info(const std::string &app_id)
{ {
@ -111,6 +127,33 @@ static std::string get_from_icon_theme(const Glib::RefPtr<Gtk::IconTheme>& icon_
return ""; return "";
} }
/* Method 3 - as last resort perform a search for most appropriate desktop info file */
static std::string get_from_desktop_app_info_search(const std::string &app_id)
{
std::string desktop_file = "";
gchar*** desktop_list = g_desktop_app_info_search(app_id.c_str());
if (desktop_list != nullptr && desktop_list[0] != nullptr) {
for (size_t i=0; desktop_list[0][i]; i++) {
if (desktop_file == "") {
desktop_file = desktop_list[0][i];
} else {
auto tmp_info = Gio::DesktopAppInfo::create(desktop_list[0][i]);
auto startup_class = tmp_info->get_startup_wm_class();
if (startup_class == app_id) {
desktop_file = desktop_list[0][i];
break;
}
}
}
g_strfreev(desktop_list[0]);
}
g_free(desktop_list);
return get_from_desktop_app_info(desktop_file);
}
static bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme>& icon_theme, static bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme>& icon_theme,
const std::string &app_id_list, int size) const std::string &app_id_list, int size)
{ {
@ -142,11 +185,23 @@ static bool image_load_icon(Gtk::Image& image, const Glib::RefPtr<Gtk::IconTheme
icon_name = get_from_desktop_app_info(lower_app_id); icon_name = get_from_desktop_app_info(lower_app_id);
if (icon_name.empty()) if (icon_name.empty())
icon_name = get_from_desktop_app_info(app_name); icon_name = get_from_desktop_app_info(app_name);
if (icon_name.empty())
icon_name = get_from_desktop_app_info_search(app_id);
if (icon_name.empty()) if (icon_name.empty())
continue; icon_name = "unknown";
Glib::RefPtr<Gdk::Pixbuf> pixbuf;
try {
pixbuf = icon_theme->load_icon(icon_name, size, Gtk::ICON_LOOKUP_FORCE_SIZE);
} catch(...) {
if (Glib::file_test(icon_name, Glib::FILE_TEST_EXISTS))
pixbuf = load_icon_from_file(icon_name, size);
else
pixbuf = {};
}
auto pixbuf = icon_theme->load_icon(icon_name, size, Gtk::ICON_LOOKUP_FORCE_SIZE);
if (pixbuf) { if (pixbuf) {
image.set(pixbuf); image.set(pixbuf);
found = true; found = true;

View File

@ -0,0 +1,9 @@
#include "util/ustring_clen.hpp"
int ustring_clen(const Glib::ustring &str){
int total = 0;
for (auto i = str.begin(); i != str.end(); ++i) {
total += g_unichar_iswide(*i) + 1;
}
return total;
}