アクティブなウインドウを四隅に移動させる

いろいろと作業をしていると別のウインドウを見つつしたいから, ちょっと
隅まで移動させたいということがあります. マウスで移動させてもいいのですが,
キーボード操作で移動できた方がいいかな, ということで書いてみました.

利用したコマンド

  • wmctrl
  • xprop
  • xwininfo
  • zenity

これらのコマンドです. zenityはエラー表示だけです.
xprop, xwininfoは X Window System使ってればたぶん入っているもの
だと思うので, wmctrlをインストールすれば使えると思います.

コード

シェルスクリプトで書くような内容だと思うのですが, シェルスクリプト
超絶に苦手なので Perlで書きました.

追記 2011-09-14 コード修正

#!/home/syohei/perl5/perlbrew/perls/perl-5.14.1/bin/perl
use strict;
use warnings;
use File::Which qw/which/;

use utf8;
use Encode qw(encode_utf8);

local $SIG{__DIE__} = sub {
    exec qw/zenity --error --text/, encode_utf8(shift);
};

check_environment();

my $direction = shift or die "Usage: $0 [top|right|bottom|left]";

my ($desktop_width, $desktop_height);
my $id = get_display_info();
my $window_info = get_window_info($id);

move_window($window_info);

sub get_display_info {
    my @cmd = qw/xprop -root/;

    open my $fh, '-|', @cmd or die "Can't exec '@cmd'";

    my $window_id;
    my ($is_set_window_size, $does_get_id) = (0, 0);
    while ( my $line = <$fh> ) {
        chomp $line;

        if ($line =~ m{^_NET_DESKTOP_GEOMETRY [^=]+ = \s+ (\d+), \s+ (\d+)}x) {
            ($desktop_width, $desktop_height) = ($1, $2);
            $is_set_window_size = 1;
        }

        if ($line =~ m{^_NET_ACTIVE_WINDOW}) {
            if ($line =~ m{window \s+ id \s+ \# \s+ ( [^\s,]+ )}x) {
                $window_id = $1;
                $does_get_id = 1;
            }
        }

        last if $is_set_window_size && $does_get_id;
    }

    close $fh;

    unless ($is_set_window_size && $does_get_id) {
        die "Can't get window info";
    }

    return $window_id;
}

sub move_window {
    my $window_info = shift;

    my $panel_height = 0;
    if ($ENV{DESKTOP_SESSION} ne 'gnome') {
        $panel_height = get_panel_height();
    }

    my @cmd = ('wmctrl', '-i', '-r', $window_info->{id}, '-e');

    my $move_parameter;
    if ($direction eq 'top') {
        my $y_pos = $panel_height;
        $move_parameter = "0,-1,$panel_height,-1,-1";
    } elsif ($direction eq 'right') {
        my $x_pos = $desktop_width - $window_info->{width};
        $move_parameter =  "0,$x_pos,-1,-1,-1";
    } elsif ($direction eq 'bottom') {
        my $y_pos = $desktop_height - $window_info->{height} - $panel_height;
        $move_parameter =  "0,-1,$y_pos,-1,-1";
    } elsif ($direction eq 'left') {
        $move_parameter = '0,0,-1,-1,-1';
    } else {
        die "Unknown direction '$direction'";
    }

    push @cmd, $move_parameter;
    system(@cmd) == 0 or die "Can't exec '@cmd'";
}

sub get_panel_height {
    my @cmd = qw/wmctrl -l -G/;

    open my $fh, "-|", @cmd or die "Can't exec '@cmd'";

    my $panel_height = 0;
    while ( my $line = <$fh> ) {
        chomp $line;

        if ( $line =~ m{xfce4-panel} ) {
            my ($id, $workspace, $x_pos, $y_pos, $width, $height, @rest)
                = split /\s+/, $line;

            $panel_height = $height;
            last;
        }

    }
    close $fh;

    return $panel_height;
}

sub get_window_info {
    my $id = shift;
    my @cmd = (qw/xwininfo -id/, $id);

    open my $fh, '-|', @cmd or die "Can't exec '@cmd'";

    my $window_info = { id => $id };
    while ( my $line = <$fh> ) {
        chomp $line;

        if ($line =~ m{Width:\s+(\d+)}) {
            $window_info->{width} = $1;
        } elsif ($line =~ m{Height:\s+(\d+)}) {
            $window_info->{height} = $1;
        }
    }
    close $fh;

    return $window_info;
}

sub check_environment {
    for my $cmd (qw/wmctrl xprop xwininfo zenity/) {
        die "Please install '$cmd'" unless defined which($cmd);
    }
}

GNOMEの場合, パネルを考慮して動いてしまうのですが, xfce4の場合
パネルにめり込んでしまう場合があったので, それを考慮しています.
私がインストール後にいろいろいじったせいかもしれないですのです,
環境に合わせてその辺は修正すればよいかと思います.


このスクリプトに実行権限を与えて, /usr/local/binや $HOME/binに置きます.


使用する Perlが /usr/binや /usr/local/binでない場合(perlbrewを使用)は
shebangはフルパスで指定してください. キーボードショートカットに割り当てる
とき, どこかでパスを明示的に指定してやれば問題ないと思いますが, .bashrc
や .zshrc等で設定することが多いと思うので, フルパスが無難です.

利用方法

  % window_move.pl [top|right|bottom|left]

端末エミュレータで入力してしまうとその端末エミュレータのみと
なってしまうので, ウインドウマネージャのショートカットキーに
割り当てます.


xfce4であれば
「設定マネージャ」=>「キーボード」=>「アプリケーションショートカット」
から設定できます.


私は以下のように設定しました.


これで Superキー + 上下左右でウインドウが隅から隅へと動きます.

まとめ

コマンドでウインドウを移動させる方法を示しました.
タイル型ウインドウマネージャを使えばデフォルトでこんな
機能が備わっていると思うんだけど, 慣れ親しんだものから
変えるっていうのはなかなかできないので, 今の環境で
なんとかできないかと検討し, コードを書きました.