feat(xrandr): Support for monitors

Refs #280
This commit is contained in:
Michael Carlberg 2017-01-13 03:52:56 +01:00
parent 462e53d6c8
commit 385572ec64
16 changed files with 122 additions and 41 deletions

View File

@ -68,6 +68,10 @@ option(WITH_XSYNC "XSYNC support" OFF)
option(WITH_XCOMPOSITE "XCOMPOSITE support" OFF)
option(WITH_XKB "XKB support" ON)
if(NOT DEFINED ENABLE_XRANDR_MONITORS)
set(ENABLE_XRANDR_MONITORS OFF CACHE STRING "Enable XRandR monitor feature (requires version 1.5+)")
endif()
# }}}
# Set cache vars {{{

View File

@ -67,6 +67,7 @@ colored_option(STATUS " Enable mpd ${ENABLE_MPD}" ENABLE_MPD "32;1" "3
colored_option(STATUS " Enable network ${ENABLE_NETWORK}" ENABLE_NETWORK "32;1" "37;2")
message(STATUS "--------------------------")
colored_option(STATUS " XRANDR support ${WITH_XRANDR}" WITH_XRANDR "32;1" "37;2")
colored_option(STATUS " + XRandR monitors ${ENABLE_XRANDR_MONITORS}" ENABLE_XRANDR_MONITORS "32;1" "37;2")
colored_option(STATUS " XRENDER support ${WITH_XRENDER}" WITH_XRENDER "32;1" "37;2")
colored_option(STATUS " XDAMAGE support ${WITH_XDAMAGE}" WITH_XDAMAGE "32;1" "37;2")
colored_option(STATUS " XSYNC support ${WITH_XSYNC}" WITH_XSYNC "32;1" "37;2")

View File

@ -6,7 +6,7 @@ add_subdirectory(zsh)
set(MODULES_LEFT "bspwm i3 xwindow")
set(MODULES_CENTER "")
set(MODULES_RIGHT "backlight volume xkeyboard memory cpu wlan eth battery temperature date powermenu")
set(MODULES_RIGHT "xbacklight volume xkeyboard memory cpu wlan eth battery temperature date powermenu")
# Strip disabled modules {{{
@ -20,7 +20,7 @@ if(NOT ENABLE_NETWORK)
string(REPLACE " wlan eth" "" MODULES_RIGHT ${MODULES_RIGHT})
endif()
if(NOT WITH_XRANDR)
string(REPLACE "backlight " "" MODULES_RIGHT ${MODULES_RIGHT})
string(REPLACE "xbacklight " "backlight-acpi " MODULES_RIGHT ${MODULES_RIGHT})
endif()
if(NOT WITH_XKB)
string(REPLACE "xkeyboard " "" MODULES_RIGHT ${MODULES_RIGHT})

View File

@ -164,7 +164,7 @@ icon-repeat = 
toggle-on-foreground = ${colors.primary}
toggle-off-foreground = #66
[module/backlight]
[module/xbacklight]
type = internal/xbacklight
format = <label> <bar>
@ -181,6 +181,11 @@ bar-empty = ─
bar-empty-font = 2
bar-empty-foreground = ${colors.foreground-alt}
[module/backlight-acpi]
inherit = module/xbacklight
type = internal/backlight
card = intel_backlight
[module/cpu]
type = internal/cpu
interval = 2

View File

@ -6,11 +6,12 @@
_polybar() {
_arguments -n : \
'(-h --help)'{-h,--help}'[Display help text and exit]' \
'(-v --version)'{-v,--version}'[Display version information and exit]' \
'(-v --version)'{-v,--version}'[Display build details and exit]' \
'(-l --log)'{-l,--log=}'[Set the logging verbosity (default: warning)]:verbosity level:(error warning info trace)' \
'(-l --log -q --quiet)'{-q,--quiet}'[Be quiet (will override -l)]' \
'(-c --config)'{-c,--config=}'[Path to the configuration file]:configuration file:_files' \
'(-r --reload)'{-r,--reload}'[Reload when the configuration has been modified]' \
'(-m --list-monitors)'{-m,--list-monitors}'[Print list of available monitors and exit]' \
'1:bar name:_polybar_list_names'
}

View File

@ -37,10 +37,10 @@
#if ENABLE_CURL
#include "modules/github.hpp"
#endif
#if WITH_XKB
#if ENABLE_XKEYBOARD
#include "modules/xkeyboard.hpp"
#endif
#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && WITH_XKB)
#if not(ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && ENABLE_XKEYBOARD)
#include "modules/unsupported.hpp"
#endif

View File

@ -1,5 +1,5 @@
#pragma once
#if ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && WITH_XKB
#if ENABLE_I3 && ENABLE_MPD && ENABLE_NETWORK && ENABLE_ALSA && ENABLE_CURL && ENABLE_XKEYBOARD
#error "Support has been enabled for all optional modules"
#endif
@ -46,7 +46,7 @@ namespace modules {
#if not ENABLE_CURL
DEFINE_UNSUPPORTED_MODULE(github_module, "internal/github");
#endif
#if not WITH_XKB
#if not ENABLE_XKEYBOARD
DEFINE_UNSUPPORTED_MODULE(xkeyboard_module, "internal/xkeyboard");
#endif
}

View File

@ -25,6 +25,19 @@
#cmakedefine01 WITH_XSYNC
#cmakedefine01 WITH_XCOMPOSITE
#cmakedefine01 WITH_XKB
#if WITH_XRANDR
#cmakedefine01 ENABLE_XRANDR_MONITORS
#else
#define ENABLE_XRANDR_MONITORS 0
#endif
#if WITH_XKB
#define ENABLE_XKEYBOARD 1
#else
#define ENABLE_XKEYBOARD 0
#endif
#cmakedefine XPP_EXTENSION_LIST @XPP_EXTENSION_LIST@
#cmakedefine DEBUG_LOGGER
@ -83,6 +96,15 @@ const auto print_build_info = [](bool extended = false) {
(ENABLE_NETWORK ? '+' : '-'));
if (extended) {
printf("\n");
printf("X extensions: %cxrandr (%cmonitors) %cxrender %cxdamage %cxsync %cxcomposite %cxkb\n",
(WITH_XRANDR ? '+' : '-'),
(ENABLE_XRANDR_MONITORS ? '+' : '-'),
(WITH_XRENDER ? '+' : '-'),
(WITH_XDAMAGE ? '+' : '-'),
(WITH_XSYNC ? '+' : '-'),
(WITH_XCOMPOSITE ? '+' : '-'),
(WITH_XKB ? '+' : '-'));
printf("\n");
printf("Build type: @CMAKE_BUILD_TYPE@\n");
printf("Compiler: @CMAKE_CXX_COMPILER@\n");
printf("Compiler flags: @CMAKE_CXX_FLAGS@\n");

View File

@ -46,8 +46,10 @@ using monitor_t = shared_ptr<randr_output>;
namespace randr_util {
void query_extension(connection& conn);
bool check_monitor_support();
monitor_t make_monitor(xcb_randr_output_t randr, string name, uint16_t w, uint16_t h, int16_t x, int16_t y);
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only = false);
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only = false, bool realloc = false);
void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst);
void get_backlight_value(connection& conn, const monitor_t& mon, backlight_values& dst);

View File

@ -3,7 +3,7 @@
\fBpolybar\fR \- A fast and easy-to-use tool status bar.
.SH SYNOPSIS
.P
polybar \fIBAR-NAME\fR [\fB\-c\fR \fICONFIG\fR|\fB\-l\fR \fILOG_LEVEL\fR|\fB\-d\fR \fIPARAM\fR|\fB\f-q\fR|\fB\-r\fR|\fB\f-s\fR|\fB\-w\fR]
polybar \fIBAR-NAME\fR [\fB\-c\fR \fICONFIG\fR|\fB\-l\fR \fILOG_LEVEL\fR|\fB\-d\fR \fIPARAM\fR|\fB\f-q\fR|\fB\-r\fR|\fB\-m\fR|\fB\f-s\fR|\fB\-w\fR]
.P
polybar [\fB\-h\fR | \fB\-\-help\fR]
.SH DESCRIPTION
@ -14,10 +14,10 @@ Please report issues by creating a ticket on GitHub (\fIhttps://github.com/jaagr
Mandatory arguments to long options are mandatory for short options too.
.TP
\fB\-h\fR, \fB\-\-help\fR
Show help and program options.
Display help text and exit.
.TP
\fB\-v\fR, \fB\-\-version\fR
Print version information.
Display build details and exit.
.TP
\fB\-l\fR, \fB\-\-log\fR=\fILEVEL\fR
Set how verbose \fBpolybar\fR's logging is. \fILEVEL\fR must be one of: `error`, `warning` or `info`.
@ -29,13 +29,16 @@ Be quiet (will override -l).
Specify the path to the configuration file. By default, configuration files are read from \fI$XDG_CONFIG_HOME/.config/polybar\fR. When the \fI$XDG_CONFIG_HOME\fR variable is absent, then \fI~/.config/polybar\fR directory is used instead.
.TP
\fB\-r\fR, \fB\-\-reload\fR
Reload the application when the config file has been modified. (NOTE: Its recommended to only use this when setting up the bar).
Reload the application when the config file has been modified.
.TP
\fB\-d\fR, \fB\-\-dump\fR=\fIPARAM\fR
Show the value of the specified parameter \fIPARAM\fR in the section [bar/\fIBAR-NAME\fR] inside the configuration file.
Print the value of the specified parameter \fIPARAM\fR in the section [bar/\fIBAR-NAME\fR] inside the configuration file and exit.
.TP
\fB\-m\fR, \fB\-\-list\-monitors\fR
Print list of available monitors and exit.
.TP
\fB\-w\fR, \fB\-\-print\-wmname\fR
Print the generated \fIWM_NAME\fR.
Print the generated \fIWM_NAME\fR and exit.
.TP
\fB\-s\fR, \fB\-\-stdout\fR
Dump content to stdout instead of rendering an X window.

View File

@ -4,7 +4,6 @@
#include <cstdio>
#include <fstream>
#include <iomanip>
#include <iostream>
#include <sstream>
#include <utility>

View File

@ -240,9 +240,9 @@ bar::bar(connection& conn, signal_emitter& emitter, const config& config, const
}
if (m_opts.size.w <= 0 || m_opts.size.w > m_opts.monitor->w) {
throw application_error("Resulting bar width is out of bounds");
throw application_error("Resulting bar width is out of bounds (" + to_string(m_opts.size.w) + ")");
} else if (m_opts.size.h <= 0 || m_opts.size.h > m_opts.monitor->h) {
throw application_error("Resulting bar height is out of bounds");
throw application_error("Resulting bar height is out of bounds (" + to_string(m_opts.size.h) + ")");
}
m_opts.size.w = math_util::cap<int>(m_opts.size.w, 0, m_opts.monitor->w);

View File

@ -102,8 +102,7 @@ void screen::handle(const evt::randr_screen_change_notify& evt) {
if (screen->width_in_pixels != m_size.w || screen->height_in_pixels != m_size.h) {
changed = true;
} else {
auto monitors = randr_util::get_monitors(m_connection, m_root, true);
auto monitors = randr_util::get_monitors(m_connection, m_root, true, true);
for (size_t n = 0; n < monitors.size(); n++) {
if (n < m_monitors.size() && monitors[n]->output != m_monitors[n]->output) {
changed = true;

View File

@ -1,5 +1,3 @@
#include <X11/Xlib-xcb.h>
#include "common.hpp"
#include "components/bar.hpp"
#include "components/command_line.hpp"
@ -23,14 +21,15 @@ using namespace polybar;
int main(int argc, char** argv) {
// clang-format off
const command_line::options opts{
command_line::option{"-h", "--help", "Show help options"},
command_line::option{"-v", "--version", "Print version information"},
command_line::option{"-h", "--help", "Display this help and exit"},
command_line::option{"-v", "--version", "Display build details and exit"},
command_line::option{"-l", "--log", "Set the logging verbosity (default: WARNING)", "LEVEL", {"error", "warning", "info", "trace"}},
command_line::option{"-q", "--quiet", "Be quiet (will override -l)"},
command_line::option{"-c", "--config", "Path to the configuration file", "FILE"},
command_line::option{"-r", "--reload", "Reload when the configuration has been modified"},
command_line::option{"-d", "--dump", "Show value of PARAM in section [bar_name]", "PARAM"},
command_line::option{"-w", "--print-wmname", "Print the generated WM_NAME"},
command_line::option{"-d", "--dump", "Print value of PARAM in section [bar_name] and exit", "PARAM"},
command_line::option{"-m", "--list-monitors", "Print list of available monitors and exit"},
command_line::option{"-w", "--print-wmname", "Print the generated WM_NAME and exit"},
command_line::option{"-s", "--stdout", "Output data to stdout instead of drawing the X window"},
};
// clang-format on
@ -102,11 +101,21 @@ int main(int argc, char** argv) {
// Dump requested data
//==================================================
if (cli->has("dump")) {
std::cout << conf.get(conf.section(), cli->get("dump")) << std::endl;
printf("%s\n", conf.get(conf.section(), cli->get("dump")).c_str());
return EXIT_SUCCESS;
}
if (cli->has("print-wmname")) {
std::cout << bar::make(true)->settings().wmname << std::endl;
printf("%s\n", bar::make(true)->settings().wmname.c_str());
return EXIT_SUCCESS;
}
if (cli->has("list-monitors")) {
for (auto&& mon : randr_util::get_monitors(conn, conn.root(), true)) {
if (ENABLE_XRANDR_MONITORS && mon->output == XCB_NONE) {
printf("%s: %ix%i+%i+%i\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y);
} else {
printf("%s: %ix%i+%i+%i (XRandR monitor)\n", mon->name.c_str(), mon->w, mon->h, mon->x, mon->y);
}
}
return EXIT_SUCCESS;
}

View File

@ -43,7 +43,8 @@ namespace modules {
randr_util::get_backlight_range(m_connection, m_output, backlight);
randr_util::get_backlight_value(m_connection, m_output, backlight);
} catch (const exception& err) {
throw module_error("No backlight data found for \"" + output + "\", stopping module...");
m_log.err("%s: Could not get data (err: %s)", name(), err.what());
throw module_error("Not supported for \"" + output + "\"");
}
// Create window that will proxy all RandR notify events

View File

@ -3,6 +3,7 @@
#include "components/types.hpp"
#include "errors.hpp"
#include "settings.hpp"
#include "utils/string.hpp"
#include "x11/atoms.hpp"
#include "x11/connection.hpp"
@ -30,17 +31,33 @@ bool randr_output::match(const position& p) const {
}
namespace randr_util {
/**
* XRandR version
*/
static uint32_t g_major_version = 0;
static uint32_t g_minor_version = 0;
/**
* Query for the XRandR extension
*/
void query_extension(connection& conn) {
conn.randr().query_version(XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION);
auto ext = conn.randr().query_version(XCB_RANDR_MAJOR_VERSION, XCB_RANDR_MINOR_VERSION);
g_major_version = ext->major_version;
g_minor_version = ext->minor_version;
if (!conn.extension<xpp::randr::extension>()->present) {
throw application_error("Missing X extension: Randr");
}
}
/**
* Check for XRandR monitor support
*/
bool check_monitor_support() {
return ENABLE_XRANDR_MONITORS && g_major_version >= 1 && g_minor_version >= 5;
}
/**
* Define monitor
*/
@ -58,24 +75,40 @@ namespace randr_util {
/**
* Create a list of all available randr outputs
*/
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only) {
vector<monitor_t> monitors;
auto outputs = conn.get_screen_resources(root).outputs();
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only, bool realloc) {
static vector<monitor_t> monitors;
for (auto it = outputs.begin(); it != outputs.end(); it++) {
if (realloc) {
monitors.clear();
} else if (!monitors.empty()) {
return monitors;
}
if (check_monitor_support()) {
for (auto&& mon : conn.get_monitors(root, true).monitors()) {
try {
auto info = conn.get_output_info(*it);
auto name = conn.get_atom_name(mon.name).name();
monitors.emplace_back(make_monitor(XCB_NONE, move(name), mon.width, mon.height, mon.x, mon.y));
} catch (const exception&) {
// silently ignore output
}
}
}
for (auto&& output : conn.get_screen_resources(root).outputs()) {
try {
auto info = conn.get_output_info(output);
if (info->crtc == XCB_NONE) {
continue;
}
if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED) {
} else if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED) {
continue;
}
auto crtc = conn.get_crtc_info(info->crtc);
string name{info.name().begin(), info.name().end()};
monitors.emplace_back(make_monitor(*it, move(name), crtc->width, crtc->height, crtc->x, crtc->y));
} catch (const xpp::randr::error::bad_crtc&) {
} catch (const xpp::randr::error::bad_output&) {
auto name_iter = info.name();
string name{name_iter.begin(), name_iter.end()};
monitors.emplace_back(make_monitor(output, move(name), crtc->width, crtc->height, crtc->x, crtc->y));
} catch (const exception&) {
// silently ignore output
}
}
@ -95,6 +128,8 @@ namespace randr_util {
for (auto& monitor : monitors) {
if ((*m) == monitor || monitor->w == 0) {
continue;
} else if (check_monitor_support() && (monitor->output == XCB_NONE || (*m)->output == XCB_NONE)) {
continue;
}
// clang-format off