A variety of simple automation scripts and enhancements to Sway and i3.
25'ten fazla konu seçemezsiniz Konular bir harf veya rakamla başlamalı, kısa çizgiler ('-') içerebilir ve en fazla 35 karakter uzunluğunda olabilir.

356 satır
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. }