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 { struct randr_output {
xcb_randr_output_t randr_output;
string name; string name;
int w = 0; int w = 0;
int h = 0; int h = 0;
int x = 0; int x = 0;
int y = 0; int y = 0;
xcb_randr_output_t output;
backlight_values backlight; 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>; using monitor_t = shared_ptr<randr_output>;
namespace randr_util { namespace randr_util {
monitor_t make_monitor(xcb_randr_output_t randr, string name, int w, int h, int x, int y); 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_range(connection& conn, const monitor_t& mon, backlight_values& dst);
void get_backlight_value(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() { // {{{ void bar::create_monitor() { // {{{
m_log.trace("bar: Create monitor from matching X RandR output"); 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()) { if (monitors.empty()) {
throw application_error("No monitors found"); throw application_error("No monitors found");
} }
auto name = m_conf.get<string>(m_conf.bar_section(), "monitor", ""); auto name = m_conf.get<string>(m_conf.bar_section(), "monitor", "");
if (name.empty()) { if (name.empty()) {
name = monitors[0]->name; name = monitors[0]->name;
m_log.warn("No monitor specified, using \"%s\"", name); m_log.warn("No monitor specified, using \"%s\"", name);
} }
for (auto&& monitor : monitors) { for (auto&& monitor : monitors) {
if (name == monitor->name) { if (monitor->match(name, strict)) {
m_opts.monitor = move(monitor); m_opts.monitor = move(monitor);
break; break;
} }
@ -841,18 +844,14 @@ void bar::handle(const evt::expose& evt) { // {{{
/** /**
* Event handler for XCB_PROPERTY_NOTIFY events * Event handler for XCB_PROPERTY_NOTIFY events
* *
* Used to emit events whenever the bar window's * - Emit events whenever the bar window's
* visibility gets changes. This allows us to toggle the * visibility gets changed. This allows us to toggle the
* state of the tray container even though the tray * 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. * - Track the root pixmap atom to update the
* * pseudo-transparent background when it changes
* 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
*/ */
void bar::handle(const evt::property_notify& evt) { // {{{ void bar::handle(const evt::property_notify& evt) { // {{{
#ifdef DEBUG #ifdef DEBUG

View File

@ -10,10 +10,11 @@ namespace modules {
*/ */
void xbacklight_module::setup() { void xbacklight_module::setup() {
auto output = m_conf.get<string>(name(), "output", m_bar.monitor->name); 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 // 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())) { for (auto&& mon : randr_util::get_monitors(m_connection, m_connection.root(), strict)) {
if (mon->name == output) { if (mon->match(output, strict)) {
m_output.swap(mon); m_output.swap(mon);
break; break;
} }
@ -70,7 +71,7 @@ namespace modules {
return; return;
else if (evt->u.op.window != m_proxy) else if (evt->u.op.window != m_proxy)
return; return;
else if (evt->u.op.output != m_output->randr_output) else if (evt->u.op.output != m_output->output)
return; return;
else if (evt->u.op.atom != m_output->backlight.atom) else if (evt->u.op.atom != m_output->backlight.atom)
return; return;
@ -164,7 +165,7 @@ namespace modules {
const int values[1]{new_value}; const int values[1]{new_value};
m_connection.change_output_property_checked( 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) { } catch (const exception& err) {
m_log.err("%s: %s", name(), err.what()); 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 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{}}; monitor_t mon{new monitor_t::element_type{}};
mon->randr_output = randr; mon->output = randr;
mon->name = name; mon->name = name;
mon->x = x; mon->x = x;
mon->y = y; mon->y = y;
@ -20,14 +20,14 @@ namespace randr_util {
/** /**
* Create a list of all available randr outputs * 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; vector<monitor_t> monitors;
auto outputs = conn.get_screen_resources(root).outputs(); auto outputs = conn.get_screen_resources(root).outputs();
for (auto it = outputs.begin(); it != outputs.end(); it++) { for (auto it = outputs.begin(); it != outputs.end(); it++) {
try { try {
auto info = conn.get_output_info(*it); auto info = conn.get_output_info(*it);
if (info->connection != XCB_RANDR_CONNECTION_CONNECTED) if (connected_only && info->connection != XCB_RANDR_CONNECTION_CONNECTED)
continue; continue;
auto crtc = conn.get_crtc_info(info->crtc); auto crtc = conn.get_crtc_info(info->crtc);
string name{info.name().begin(), info.name().end()}; 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) { void get_backlight_range(connection& conn, const monitor_t& mon, backlight_values& dst) {
auto atom = Backlight; 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.min = 0;
dst.max = 0; dst.max = 0;
if (!reply->range || reply->length != 2) { if (!reply->range || reply->length != 2) {
atom = BACKLIGHT; 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) { if (!reply->range || reply->length != 2) {
@ -84,7 +84,7 @@ namespace randr_util {
return; 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) 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())); dst.val = *reinterpret_cast<uint32_t*>(xcb_randr_get_output_property_data(reply.get().get()));