A variety of simple automation scripts and enhancements to Sway and i3.
Vous ne pouvez pas sélectionner plus de 25 sujets Les noms de sujets doivent commencer par une lettre ou un nombre, peuvent contenir des tirets ('-') et peuvent comporter jusqu'à 35 caractères.

356 lignes
11KB

  1. #!/usr/bin/perl
  2. ########################################################################
  3. # Usage
  4. ########################################################################
  5. #
  6. # $ displays.pl [layout] [-w]
  7. #
  8. # layout Name of desired layout, as configured starting at line 100
  9. # If missing, last known layout is used (logged to file $last)
  10. # -w (Re)load waybar only. Skip display configuration. Only kill
  11. # existing waybars and start new ones for desired layout
  12. ########################################################################
  13. # Dependencies
  14. ########################################################################
  15. #
  16. # Depends on JSON::XS and Proc::ProcessTable
  17. #
  18. # Debian:
  19. # apt install libjson-xs-perl libproc-processtable-perl
  20. ########################################################################
  21. # Directories and Files
  22. ########################################################################
  23. # Template is a normal config with the following in place of values:
  24. # "output": __OUTPUT__
  25. # "position": __POSITION__
  26. # "width": __WIDTH__ (optional)
  27. my $waybar_template = "$ENV{'HOME'}/.config/waybar/config.template";
  28. # Temporary directory to save generated waybar config(s)
  29. my $waybar_temporary = '/tmp';
  30. # File to log and recover last used layout name
  31. my $last = "$ENV{'HOME'}/.config/last_display";
  32. ########################################################################
  33. # Display Serials and Names
  34. ########################################################################
  35. # Hash to match display Serial with a friendly name.
  36. # You can get the serial from (quoted with *):
  37. # $ swaymsg -t get_outputs
  38. # Output eDP-1 'Unknown 0x057D *0x00000000*'
  39. my %outputs = (
  40. '0x00000101' => 'Sam',
  41. '3CQ4342S6W' => 'HP-1',
  42. '3CQ3310Q1Q' => 'HP-2',
  43. '0x00000000' => 'LVDS'
  44. );
  45. ########################################################################
  46. # Display Configurations
  47. ########################################################################
  48. # First-level key of hash is the name of each configuration
  49. # Second-level keys are the display friendly-names, above
  50. # Third-level are the actual settings for that display
  51. my %configs = (
  52. 'detached' => {
  53. 'HP-1' => {
  54. 'on' => 0
  55. },
  56. 'HP-2' => {
  57. 'on' => 0
  58. },
  59. 'Sam' => {
  60. 'on' => 0
  61. },
  62. 'LVDS' => {
  63. 'on' => 1,
  64. 'width' => 1920,
  65. 'height' => 1080,
  66. 'x' => 0,
  67. 'y' => 0,
  68. 'rotate' => 0,
  69. 'waybar' => 'bottom'
  70. }
  71. },
  72. 'stacked' => {
  73. 'Sam' => {
  74. 'on' => 1,
  75. 'width' => 1920,
  76. 'height' => 1080,
  77. 'x' => 960,
  78. 'y' => 0,
  79. 'rotate' => 0,
  80. 'waybar' => 'bottom'
  81. },
  82. 'HP-1' => {
  83. 'on' => 1,
  84. 'width' => 1920,
  85. 'height' => 1080,
  86. 'x' => 0,
  87. 'y' => 1200,
  88. 'rotate' => 0,
  89. 'waybar' => 'top'
  90. },
  91. 'HP-2' => {
  92. 'on' => 1,
  93. 'width' => 1920,
  94. 'height' => 1080,
  95. 'x' => 1920,
  96. 'y' => 1200,
  97. 'rotate' => 0,
  98. 'waybar' => 'top'
  99. },
  100. 'LVDS' => {
  101. 'on' => 0
  102. }
  103. },
  104. 'sidebyside' => {
  105. 'HP-1' => {
  106. 'on' => 1,
  107. 'width' => 1080,
  108. 'height' => 1920,
  109. 'x' => 0,
  110. 'y' => 225,
  111. 'rotate' => 270,
  112. 'waybar' => 'top'
  113. },
  114. 'Sam' => {
  115. 'on' => 1,
  116. 'width' => 1200,
  117. 'height' => 1920,
  118. 'x' => 1080,
  119. 'y' => 0,
  120. 'rotate' => 90,
  121. 'waybar' => 'top'
  122. },
  123. 'HP-2' => {
  124. 'on' => 1,
  125. 'width' => 1080,
  126. 'height' => 1920,
  127. 'x' => 2280,
  128. 'y' => 225,
  129. 'rotate' => 90,
  130. 'waybar' => 'top'
  131. },
  132. 'LVDS' => {
  133. 'on' => 0,
  134. }
  135. }
  136. );
  137. ########################################################################
  138. # Program (do not edit below)
  139. ########################################################################
  140. use strict;
  141. use warnings;
  142. my $waybar_only = 0;
  143. my $config;
  144. if (scalar(@ARGV)) {
  145. while (@ARGV) {
  146. my $arg = shift;
  147. if ($arg eq "-w") {
  148. $waybar_only = 1;
  149. } else {
  150. if (defined $config) {
  151. die "Too many arguments.\n";
  152. }
  153. $config = $arg;
  154. }
  155. }
  156. }
  157. # Get previous config if one is not provided
  158. unless (defined $config) {
  159. open(my $fh, '<', $last) ||
  160. die "Config name not provided and failed to open $last\n";
  161. $config = <$fh>;
  162. close($fh);
  163. chomp $config;
  164. }
  165. # Bail if requested config doesn't exist
  166. unless (defined $configs{$config}) {
  167. die "$config is not a defined configuration: "
  168. . join(', ', keys %configs) . "\n";
  169. }
  170. # Write config that is to be used so that it can be recovered as default
  171. open(my $fh, '>', $last) ||
  172. print STDERR "Config name cannot be written to $last\n";
  173. print $fh $config;
  174. close($fh);
  175. # Fetch connected displays
  176. use JSON::XS;
  177. my $json = JSON::XS->new();
  178. my $displays_raw = `swaymsg -t get_outputs --raw`;
  179. my $displays = $json->decode($displays_raw);
  180. # For each connected display, collect the desired settings for enabled
  181. # displays and a list of displays to disable
  182. my $on;
  183. my @off;
  184. for (my $i = 0; $i < scalar(@$displays); $i++) {
  185. # If a display is found without any settings print error and turn it off
  186. unless (defined $configs{$config}{$outputs{$displays->[$i]->{serial}}}){
  187. print STDERR "Output $displays->[$i]->{name} ("
  188. . $displays->[$i]->{serial}
  189. . ") found without defined function. Disabling.\n";
  190. push @off, $displays->[$i]->{name};
  191. next;
  192. }
  193. # If display is enabled, copy all of the desired settings
  194. if ($configs{$config}{$outputs{$displays->[$i]->{serial}}}{on}) {
  195. $on->{$outputs{$displays->[$i]->{serial}}} =
  196. $configs{$config}{$outputs{$displays->[$i]->{serial}}};
  197. $on->{$outputs{$displays->[$i]->{serial}}}{output} =
  198. $displays->[$i]->{name};
  199. # Otherwise simply list it for disabling
  200. } else {
  201. push @off, $displays->[$i]->{name};
  202. }
  203. }
  204. # Skip enabling/disabling displays if only running waybar (re)start
  205. unless ($waybar_only) {
  206. # Number of simultaneous outputs is limited by gpu, so disabled displays
  207. # first
  208. foreach (@off) {
  209. # Sway returns status as JSON
  210. my $res_raw = `sway output $_ disable`;
  211. my $res = $json->decode($res_raw)->[0];
  212. # If failed, print to STDERR
  213. unless ($res->{success}) {
  214. print STDERR "Error ($res->{error}) in command 'sway"
  215. . "output $_ disable'\n";
  216. }
  217. }
  218. }
  219. # Kill existing Waybars
  220. require Proc::ProcessTable;
  221. my $t = new Proc::ProcessTable;
  222. foreach my $p ( @{ $t->table } ) {
  223. my $cmndline = $p->{'cmndline'};
  224. $cmndline =~ s/\s*$//g;
  225. if ($cmndline =~ /^waybar.*/) {
  226. # Never kill this process
  227. if ($p->{'pid'} == $$) {
  228. next;
  229. } else {
  230. $p->kill(9);
  231. }
  232. }
  233. }
  234. # Load in config template
  235. my $template;
  236. if (open (my $fh, '<', $waybar_template)) {
  237. while (<$fh>) {
  238. $template .= $_;
  239. }
  240. close $fh;
  241. chomp $template;
  242. } else {
  243. print STDERR "Failed to load template $waybar_template\n";
  244. }
  245. # If template is already set up as an array, remove the square brackets so that
  246. # we can concatenate multiple displays
  247. $template =~ s/^[^\[\{]*\[(.*)\]$/$1/s;
  248. # Setup waybar config file
  249. my $waybar = '';
  250. # Configure each enabled display
  251. foreach my $out (keys %$on) {
  252. unless ($waybar_only) {
  253. # Build command, starting by enabling and powering on
  254. my $cmd = "sway output $on->{$out}->{output} enable dpms on";
  255. # If additional options are provided, add them to command
  256. if (defined $on->{$out}->{rotate}) {
  257. $cmd .= " transform $on->{$out}->{rotate}";
  258. }
  259. if (defined $on->{$out}->{x} && defined $on->{$out}->{y}) {
  260. $cmd .= " position $on->{$out}->{x} $on->{$out}->{y}";
  261. }
  262. if (defined $on->{$out}->{width} &&
  263. defined $on->{$out}->{height} )
  264. {
  265. $cmd .= " mode $on->{$out}->{width}x$on->{$out}->{height}";
  266. }
  267. # Sway returns status as JSON
  268. my $res_raw = `$cmd`;
  269. my $res = $json->decode($res_raw)->[0];
  270. # If failed, print to STDERR
  271. unless ($res->{success}) {
  272. print STDERR "Error ($res->{error}) in command '$cmd'\n";
  273. }
  274. }
  275. # Skip waybar setup if template failed to be loaded
  276. if ( (defined $template) &&
  277. (defined $on->{$out}->{waybar}) &&
  278. ($on->{$out}->{waybar} =~ m/(top|bottom|left|right)/) )
  279. {
  280. # If there's already a display set up, add a comma
  281. unless ($waybar eq '') {
  282. $waybar .= ',';
  283. }
  284. $waybar .= $template;
  285. # Replace basic preferences
  286. $waybar =~ s/__OUTPUT__/"$on->{$out}->{output}"/;
  287. $waybar =~ s/__POSITION__/"$on->{$out}->{waybar}"/;
  288. if (defined $on->{$out}->{width}) {
  289. $waybar =~ s/__WIDTH__/$on->{$out}->{width}/;
  290. # If width is not set, comment that line out to use default
  291. } else {
  292. $waybar =~ s/([^\s]*\s*)__WIDTH__/\/\/ $1__WIDTH__/gg;
  293. }
  294. }
  295. }
  296. # Restore array formatting
  297. $waybar = '[' . $waybar . ']';
  298. # Start Waybar as fork
  299. my $pid = fork;
  300. unless ($pid) {
  301. open STDIN, '/dev/null';
  302. open STDOUT, '>>/dev/null';
  303. open STDERR, '>>/dev/null';
  304. # Write config to a temporary file
  305. my $tmp = $waybar_temporary . "/waybar-" . time() .".config";
  306. open ($fh, '>', $tmp);
  307. print $fh $waybar;
  308. close $fh;
  309. `nohup waybar --config=$tmp`;
  310. # Remove config
  311. unlink $tmp;
  312. }