fix(xrandr): Less strict monitor matching

Be less strict when matching randr outputs
against specified name. This is a workaround
to fix the output naming issue when switching
between graphic drivers.

On my system the output names include a dash
when using the nvidia drivers but the intel
driver does not.

   nvidia:
      HDMI-1
      eDP-1
   xf86-video-intel:
      HDMI1
      eDP1

When strict mode is disabled the matching
won't care about the connection state.

The user can re-enable exact matching and
connection state testing by setting the
config parameter `monitor-strict = true`
This commit is contained in:
Michael Carlberg 2016-11-12 20:31:39 +01:00
parent 2314b57bce
commit 4d7f6c14e6
4 changed files with 35 additions and 24 deletions

View File

@ -20,20 +20,31 @@ struct backlight_values {
};
struct randr_output {
xcb_randr_output_t randr_output;
string name;
int w = 0;
int h = 0;
int x = 0;
int y = 0;
xcb_randr_output_t output;
backlight_values backlight;
/**
* Workaround for the inconsistent naming
* of outputs between my intel and nvidia
* drivers (xf86-video-intel drops the dash)
*/
bool match(const string& o, bool strict = false) const {
if (strict && name != o)
return false;
return name == o || name == string_util::replace(o, "-", "");
}
};
using monitor_t = shared_ptr<randr_output>;
namespace randr_util {
monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y);
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root);
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root, bool connected_only = 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

@ -532,19 +532,22 @@ void bar::configure_geom() { // {{{
void bar::create_monitor() { // {{{
m_log.trace("bar: Create monitor from matching X RandR output");
auto monitors = randr_util::get_monitors(m_connection, m_screen->root);
auto strict = m_conf.get<bool>(m_conf.bar_section(), "monitor-strict", false);
auto monitors = randr_util::get_monitors(m_connection, m_screen->root, strict);
if (monitors.empty()) {
throw application_error("No monitors found");
}
auto name = m_conf.get<string>(m_conf.bar_section(), "monitor", "");
if (name.empty()) {
name = monitors[0]->name;
m_log.warn("No monitor specified, using \"%s\"", name);
}
for (auto&& monitor : monitors) {
if (name == monitor->name) {
if (monitor->match(name, strict)) {
m_opts.monitor = move(monitor);
break;
}
@ -841,18 +844,14 @@ void bar::handle(const evt::expose& evt) { // {{{
/**
* Event handler for XCB_PROPERTY_NOTIFY events
*
* Used to emit events whenever the bar window's
* visibility gets changes. This allows us to toggle the
* - Emit events whenever the bar window's
* visibility gets changed. This allows us to toggle the
* state of the tray container even though the tray
* window restacking failed.
* window restacking failed. Used as a fallback for
* tedious WM's, like i3.
*
* This is used as a fallback for tedious WM's, like i3.
*
* Some might call it a dirty hack, others a crappy
* solution... I choose to call it a masterpiece! Plus
* it's not really any overhead worth talking about.
*
* Also tracks the root pixmap
* - Track the root pixmap atom to update the
* pseudo-transparent background when it changes
*/
void bar::handle(const evt::property_notify& evt) { // {{{
#ifdef DEBUG

View File

@ -10,10 +10,11 @@ namespace modules {
*/
void xbacklight_module::setup() {
auto output = m_conf.get<string>(name(), "output", m_bar.monitor->name);
auto strict = m_conf.get<bool>(name(), "monitor-strict", false);
// Grab a list of all outputs and try to find the one defined in the config
for (auto&& mon : randr_util::get_monitors(m_connection, m_connection.root())) {
if (mon->name == output) {
for (auto&& mon : randr_util::get_monitors(m_connection, m_connection.root(), strict)) {
if (mon->match(output, strict)) {
m_output.swap(mon);
break;
}
@ -70,7 +71,7 @@ namespace modules {
return;
else if (evt->u.op.window != m_proxy)
return;
else if (evt->u.op.output != m_output->randr_output)
else if (evt->u.op.output != m_output->output)
return;
else if (evt->u.op.atom != m_output->backlight.atom)
return;
@ -164,7 +165,7 @@ namespace modules {
const int values[1]{new_value};
m_connection.change_output_property_checked(
m_output->randr_output, m_output->backlight.atom, XCB_ATOM_INTEGER, 32, XCB_PROP_MODE_REPLACE, 1, values);
m_output->output, m_output->backlight.atom, XCB_ATOM_INTEGER, 32, XCB_PROP_MODE_REPLACE, 1, values);
} catch (const exception& err) {
m_log.err("%s: %s", name(), err.what());
}

View File

@ -8,7 +8,7 @@ namespace randr_util {
*/
monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y) {
monitor_t mon{new monitor_t::element_type{}};
mon->randr_output = randr;
mon->output = randr;
mon->name = name;
mon->x = x;
mon->y = y;
@ -20,14 +20,14 @@ namespace randr_util {
/**
* Create a list of all available randr outputs
*/
vector<monitor_t> get_monitors(connection& conn, xcb_window_t root) {
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();
for (auto it = outputs.begin(); it != outputs.end(); it++) {
try {
auto info = conn.get_output_info(*it);
if (info->connection != XCB_RANDR_CONNECTION_CONNECTED)
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()};
@ -54,14 +54,14 @@ namespace randr_util {
*/
void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst) {
auto atom = Backlight;
auto reply = conn.query_output_property(mon->randr_output, atom);
auto reply = conn.query_output_property(mon->output, atom);
dst.min = 0;
dst.max = 0;
if (!reply->range || reply->length != 2) {
atom = BACKLIGHT;
reply = conn.query_output_property(mon->randr_output, atom);
reply = conn.query_output_property(mon->output, atom);
}
if (!reply->range || reply->length != 2) {
@ -84,7 +84,7 @@ namespace randr_util {
return;
}
auto reply = conn.get_output_property(mon->randr_output, dst.atom, XCB_ATOM_NONE, 0, 4, 0, 0);
auto reply = conn.get_output_property(mon->output, dst.atom, XCB_ATOM_NONE, 0, 4, 0, 0);
if (reply->num_items == 1 && reply->format == 32 && reply->type == XCB_ATOM_INTEGER)
dst.val = *reinterpret_cast<uint32_t*>(xcb_randr_get_output_property_data(reply.get().get()));