最近 Kubuntu を使い始めて割といい感じなんだけど、アクティブウィンドウの上にあるウィンドウだけを半透明化することができなかった。
設定でアクティブウィンドウ以外を半透明化することはできるんだけどなー。
というか、Compiz 以外でそういう機能を持ってるのは見たことないんで、あんまり需要はないのかもしれない。そもそもアクティブウィンドウを最前面にしない設定で使ってる人自体少数派な気がするし仕方ない。便利なんだけどな。
ChatGPT に聞いてみたらウィンドウマネージャーの外からでも制御できそうなので作ってみた。
必要そうな技術要素
ウィンドウを透明度を指定
次のコマンドを実行するとマウスカーソルが ┼ になるのでウィンドウをクリックすると、そのウィンドウが透明度50%になる。
% xprop -f _NET_WM_WINDOW_OPACITY 32c -set _NET_WM_WINDOW_OPACITY 0x80000000
C だとこんな感じ。
unsigned long opacity = 0x80000000; XChangeProperty(display, window, XInternAtom(display, "_NET_WM_WINDOW_OPACITY", False), XA_CARDINAL, 32, PropModeReplace, &opacity, 1);
ウィンドウの深さ順を得る
% xwininfo -root -tree
で浅い順に表示される。
C では XQueryTree()
を使うと深い順のウィンドウリストが返される。
ウィンドウが重なっているかどうかを調べる
xwininfo の geometry でウィンドウの位置と幅と高さがわかるので、計算すれば重なってるかどうかわかる。 ただし、xwininfo の ┼ で選択したときのウィンドウではダメで、root 直下のウィンドウじゃないとディスプレイ上の位置がちゃんと取れないっぽい。
xwininfo -tree
の Parent window id
が root window
になるまで親を辿る感じで。
% xwininfo -tree -id 0x63ae7b | grep 'Parent window' Parent window id: 0x137b273 (has no name) % xwininfo -tree -id 0x137b273 | grep 'Parent window' Parent window id: 0x137b272 (has no name) % xwininfo -tree -id 0x137b272 | grep 'Parent window' Parent window id: 0x5e3 (the root window) (has no name)
この場合は 0x137b272 の geometry を取ればいいっぽい。
% xwininfo -id 0x137b272 | grep geometry -geometry 582x438+2799+1344
C では XGetGeometry()
で取得できる。
Window root; int x, y; unsigned int width, height, border_width, depth; XGetGeometry(display, window, &root, &x, &y, &width, &height, &border_width, &depth);
アクティブウィンドウを得る
% xprop -root _NET_ACTIVE_WINDOW _NET_ACTIVE_WINDOW(WINDOW): window id # 0x63ae7b
C だとこんな感じ。
unsigned long type; int format; unsigned long nitems; unsigned long bytes; unsigned long *win; XGetWindowProperty(display, window, XInternAtom(@display, '_NET_ACTIVE_WINDOW', False), 0, ~0, 0, AnyPropertyType, &type, &format, &nitems, &bytes, &win); // win がウィンドウID
アクティブウィンドウが変わったことを知る
_NET_ACTIVE_WINDOW
イベントを監視すればいいらしい。
xprop -spy
を実行するとアクティブウィンドウが切り替わるごとに通知される。
% xprop -spy -root _NET_ACTIVE_WINDOW _NET_ACTIVE_WINDOW(WINDOW): window id # 0x4a000b0 _NET_ACTIVE_WINDOW(WINDOW): window id # 0x4a000b0 _NET_ACTIVE_WINDOW(WINDOW): window id # 0x4c0002c _NET_ACTIVE_WINDOW(WINDOW): window id # 0x4c0002c _NET_ACTIVE_WINDOW(WINDOW): window id # 0x6000e0 _NET_ACTIVE_WINDOW(WINDOW): window id # 0x6000e0 _NET_ACTIVE_WINDOW(WINDOW): window id # 0x63ae7b _NET_ACTIVE_WINDOW(WINDOW): window id # 0x63ae7b ^C
何故か2行ずつ出るけど理由は知らない。
C だと XSelectInput()
で PropertyChangeMask
を指定して、XNextEvnet()
を呼ぶと PropertyNotify
イベントが発生すると復帰する。
Ruby で作った
C で作るのもアレだし、コマンドがあるのでシェルでも作れそうなんだけど、Ruby 好きなので Ruby で作ってみた。
Ruby から X を使うためのライブラリを探してみたけど良さそうなのが見つからなかったので、まずは Fiddle を使って必要な関数のラッパーを作って、それを使う感じで作った。
https://gitlab.com/tmtms/wmadd/
それなりに動くようになったので Gem にした。gem install wmadd
でインストールできる。wmadd
で起動できる。