xenocara/app/fvwm/extras/FvwmCommand/push-away.pl

189 lines
4.0 KiB
Perl

#!/usr/bin/perl
# FvwmCommand script
# Written by Toshi Isogai
#
# push-away
# push other windows back when they overlap
# usage: push-away <direction> <window name>
# direction - direction (down,up,left,right) to push away
# window name - windows to be protected, name can be regular expression
# icons are ignored
$Dir = shift;
$Wn = shift;
if( $Dir =~ /down/i ) {
$Dir = 1;
}elsif( $Dir =~ /up/i ) {
$Dir = 2;
}elsif( $Dir =~ /left/i ) {
$Dir = 3;
}elsif( $Dir =~ /right/i ) {
$Dir = 4;
}
if( $Dir == 0 || $Wn eq '' ) {
print STDERR "push other windows back when they overlap\n";
print STDERR "usage: push-away <direction> <window name>\n";
print STDERR " direction - direction (down,up,left,right) to push away\n";
print STDERR " window name - windows to be protected\n";
print STDERR " name can be regular expression\n";
exit(1);
}
# start a dedicated server
$fifo = "$ENV{'HOME'}/.FCMpb";
system( "FvwmCommand 'FvwmCommandS $fifo'");
# larger number for slow machine
select(undef,undef,undef,0.5);
# we need this to run this script in background job
$SIG{'TTIN'} = "IGNORE";
# start monitoring (-m option ) all fvwm transaction (-i3 option )
open( FCM, "FvwmCommand -f $fifo -m -i3 |" ) || die "FCM $fifo";
# send command through the new fifo which is "$fifo" + "C"
open( FCC, ">${fifo}C" ) || die "FCC $fifo" ;
# non blocking outputs
select( FCC ); $| = 1;
select( STDOUT ); $| = 1;
# some delay for slow one
select(undef,undef,undef,0.1);
print FCC "send_windowlist\n";
# yet some more delay for slow one
select(undef,undef,undef,0.1);
$endlist = 0;
while( <FCM> ) {
if( /^(0x\S+) frame\s+x (-?\d+), y (-?\d+), width (\d+), height (\d+)/ ) {
$id = $1;
$Config{$id}{'x'} = $2;
$Config{$id}{'y'} = $3;
$Config{$id}{'w'} = $4;
$Config{$id}{'h'} = $5;
next if ! $endlist ;
# move other windows if necessary
if( $Config{$id}{'protect'} ) {
foreach $w (keys %Config) {
if( $id ne $w ) {
move_if_overlap( $w, $id );
}
}
}else{
foreach $w (keys %Config) {
if( $Config{$w}{'protect'} ) {
move_if_overlap( $id, $w );
}
}
}
}elsif( /^(0x\S+) desktop +(-?\d+)/ ) {
$Config{$1}{'desk'} = $2;
}elsif( /^(0x\S+) Iconified +(yes|no)/ ) {
$Config{$1}{'Iconified'} = $2;
}elsif( /^(0x\S+) window +(.*)/ ) {
$id = $1;
$window = $2;
if( $window =~ /$Wn/ ) {
$Config{$id}{'protect'} = 1;
}
}elsif( /end windowlist/ ) {
$endlist = 1;
foreach $id (keys %Config) {
if( $Config{$id}{'protect'} ) {
foreach $w (keys %Config) {
if( $id ne $w ) {
move_if_overlap( $w, $id );
}
}
}
}
}elsif( /^(0x\S+) destroy/ ) {
delete $Config{$1};
}
}
sub move_if_overlap {
my($id1, $id2) = @_;
my($ov);
my($c1xl,$c1xh,$c1yl,$c1yh);
my($c2xl,$c2xh,$c2yl,$c2yh);
if( $Config{$id1}{'desk'} != $Config{$id2}{'desk'}
|| $Config{$id1}{'Iconified'} eq 'yes'
|| $Config{$id2}{'Iconified'} eq 'yes' ) {
return;
}
$ov = 0;
$c1xl = $Config{$id1}{'x'};
$c1yl = $Config{$id1}{'y'};
$c1xh = $Config{$id1}{'x'}+$Config{$id1}{'w'};
$c1yh = $Config{$id1}{'y'}+$Config{$id1}{'h'};
$c2xl = $Config{$id2}{'x'};
$c2yl = $Config{$id2}{'y'};
$c2xh = $Config{$id2}{'x'}+$Config{$id2}{'w'};
$c2yh = $Config{$id2}{'y'}+$Config{$id2}{'h'};
if( $c2xl >= $c1xl && $c2xl <= $c1xh
|| $c2xh >= $c1xl && $c2xh <= $c1xh ) {
if($c2yl >= $c1yl && $c2yl <= $c1yh
|| $c2yh >= $c1yl && $c2yh <= $c1yh ) {
$ov = 1;
}
}elsif( $c1xl >= $c2xl && $c1xl <= $c2xh
|| $c1xh >= $c2xl && $c1xh <= $c2xh ) {
if($c1yl >= $c2yl && $c1yl <= $c2yh
|| $c1yh >= $c2yl && $c1yh <= $c2yh ) {
$ov = 1;
}
}
if( $ov ) {
$x = $c1xl;
$y = $c1yl;
if( $Dir==1 ) {
$y = $c2yh+1;
}elsif( $Dir==2 ) {
$y = $c2yl-($c1yh-$c1yl)-1;
}elsif( $Dir==3 ) {
$x = $c2xl-($c1xh-$c1xl)-1;
}elsif( $Dir==4 ) {
$x = $c2xh+1;
}
print FCC "windowid $id1 move ${x}p ${y}p\n";
# ignore - pixel info is the last info for move
while(<FCM>) {
last if /^0x\S+ pixel/;
}
select(undef,undef,undef,0.1);
}
}