Skip to content

Instantly share code, notes, and snippets.

@diegok
Created September 4, 2018 10:42
Show Gist options
  • Save diegok/e0dd90455d74bc375033e53b9b731f8e to your computer and use it in GitHub Desktop.
Save diegok/e0dd90455d74bc375033e53b9b731f8e to your computer and use it in GitHub Desktop.
Script to auto-configure external displays
#!/usr/bin/env perl
use FindBin qw($Bin);
use lib "$Bin/local/lib/perl5";
use Mojo::Base -strict, -signatures;
use Mojo::File qw( path );
use Parse::EDID qw/ parse_edid /;
use Mojo::JSON qw/ to_json /;
my $cards = cards_info();
my $cmd = auto_cmd($cards);
path('/tmp/autorandr.last')->spurt(to_json({
cmd => $cmd,
debug => $cards
}));
system($cmd);
sub auto_cmd($cards) {
if ( $cards->[1]{connected} ) {
my ( $main, $ext ) = $cards->@*;
$cards->[0]{opt} = "--output $main->{name} --mode $main->{mode}{string} --pos 0x@{[ abs( $ext->{mode}{vertical} - $main->{mode}{vertical} ) ]}";
$cards->[1]{opt} = "--output $ext->{name} --mode $ext->{mode}{string} --pos $main->{mode}{horizontal}x0";
}
else {
$cards->[0]{opt} = "--output $cards->[0]{name} --mode $cards->[0]{mode}{string} --pos 0x0";
$cards->[1]{opt} = "--output $cards->[1]{name} --off";
}
join(' ', 'xrandr', map { $_->{opt} } $cards->@* );
}
sub cards_info() {
my $cards = [
{ name => 'eDP1', path => path('/sys/class/drm/card0-eDP-1') },
{ name => 'DP1', path => path('/sys/class/drm/card0-DP-1') },
];
for my $card ( $cards->@* ) {
$card->{enabled} = (read_card($card, 'enabled') eq 'enabled') || 0;
$card->{connected} = (read_card($card, 'status') eq 'connected') || 0;
# Get screen info when it's connected
next unless $card->{connected};
my $edid_bin = $card->{path}->child('edid')->slurp || do {
# When screen is mounted it takes some time to be ready
# so we need to retry until we can read EDID.
# Calling xrandr makes this work faster :-/
my ($try, $data) = (0, undef);
while ( !$data && ++$try < 20 ) {
$_ = `xrandr`;
sleep 1;
$data = $card->{path}->child('edid')->slurp
}
$card->{waited} = $try;
$data;
};
next unless $edid_bin;
my $edid = parse_edid($edid_bin);
#$card->{edid} = $edid;
$card->{screen_id} = $edid->{EISA_ID};
$card->{screen_name} = $edid->{monitor_name} || 'Embed';
$card->{ratio} = $edid->{ratio_name};
$card->{modes} = [map {{
preferred => $_->{preferred} || 0,
horizontal => $_->{horizontal_active},
vertical => $_->{vertical_active},
string => "$_->{horizontal_active}x$_->{vertical_active}" . ($_->{ModeLine} =~ /Interlace/ ? 'i' : ''),
line => $_->{ModeLine},
comment => $_->{ModeLine_comment},
}} $edid->{detailed_timings}->@*];
($card->{mode}) = grep { $_->{preferred} } $card->{modes}->@*;
}
$cards;
}
sub read_card($card, $file) {
chomp( my $value = $card->{path}->child($file)->slurp );
$value;
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment