X11: NetWM (3) - デスクトップ

デスクトップ
通常、X のデスクトップはルートウィンドウであり、それは固定サイズとなりますが、NetWM では、スクリーンサイズよりも大きなデスクトップを実装したり、複数の仮想デスクトップを実装することができます。
大きなデスクトップ
ルートウィンドウは、スクリーンサイズ (モニタのサイズ) で固定されているので、それより大きな領域を扱うことはできません。

大きなデスクトップは、仮想的に大きなスクリーンを想定して、その一部をモニタに表示させることで、実現させることができます。

現在モニタに表示されている範囲は「ビューポート」となります。
ビューポートの位置は、スクリーンのサイズ単位で増減させたり (ページング)、任意の位置に変更することができます (スクロール)。
実装方法
ウィンドウマネージャは、以下の2通りで、大きなデスクトップを実装できます。

  • クライアントのウィンドウ (またはフレームウィンドウ) は、通常通りルートウィンドウの子として設定する。
    ビューポートを移動する場合は、すべてのウィンドウの位置を、ビューポートの移動分、増減させる。
    ルートウィンドウの範囲外の位置にあるウィンドウは表示されない。
  • 大きなデスクトップの指定サイズのウィンドウ (仮想ルートと呼ぶ) を別途作成し、クライアントのウィンドウは、その子として設定する。
    ビューポートを移動する場合は、仮想ルートウィンドウの位置を移動させる。

2番目の場合、本来のルートウィンドウが、仮想ルートで覆われることになります。
そのため、ルートウィンドウに対して背景を設定するようなアプリを使用する場合、その背景が反映されないといった問題が起こります。
仮想デスクトップ
スクリーンには1つのルートウィンドウしか存在しないので、1つのルートウィンドウで、複数のデスクトップを扱うようなことはできません。

そのため、NetWM では、仮想的に複数のデスクトップを作り、その中の一つを、実際のデスクトップとして表示する方法が定義されています。

仮想デスクトップは、各ウィンドウマネージャ (またはデスクトップ環境) の設定画面によって、数などを変更できます。
仮想デスクトップの設定を行うのは、基本的にユーザーです。
実装方法
仮想デスクトップは、以下の2通りで実装できます。

  • クライアントのウィンドウを、通常通りルートウィンドウの子として扱う。
    デスクトップを切り替えた場合、現在のデスクトップで表示されないウィンドウは非表示にする。
    また、ウィンドウが画面上に表示されていないことを示すため、_NET_WM_STATE プロパティに _NET_WM_STATE_HIDDEN の状態を追加する。
  • デスクトップごとに仮想ルートウィンドウを作成し、クライアントのウィンドウは、その子として扱う。
    仮想ルートウィンドウの重ね順を変更することで、デスクトップを切り替える。
プロパティ
デスクトップ関連は、ルートウィンドウのプロパティを読み込むことで情報を取得できます。
また、ルートウィンドウのプロパティ値を変更したり、XSendEvent 関数でルートウィンドウに ClientMessage イベントを送信することで、設定を変更できます。

※xprop コマンドを使って、「$ xprop -root」でルートウィンドウの各プロパティを表示できるので、ここではテストプログラムは作りません。
_NET_NUMBER_OF_DESKTOPS
type = "CARDIAL", format = 32, 1個

現在の仮想デスクトップの数がセットされています。
_NET_DESKTOP_GEOMETRY
type = "CARDINAL", format = 32, 2個

(width, height) で、すべてのデスクトップの共通サイズがセットされています。
デスクトップの仮想サイズか、スクリーンのサイズになります。
_NET_DESKTOP_VIEWPORT
type = "CARDINAL", format = 32, 2個 x デスクトップ数

各仮想デスクトップの、現在のビューポートの位置 (x, y)。
_NET_CURRENT_DESKTOP
type = "CARDIAL", format = 32, 1個

現在の仮想デスクトップのインデックス番号がセットされています。
(0 〜 _NET_NUMBER_OF_DESKTOPS - 1)
_NET_DESKTOP_NAMES
type = "UTF8_STRING", format = 8

各仮想デスクトップの名前。
ヌル文字で終わる UTF-8 文字列が、複数個並びます。

文字列の数は、_NET_NUMBER_OF_DESKTOPS の数と異なっていても構いません。

デスクトップの名前は必須ではなく、ユーザーによって設定されます。
_NET_VIRTUAL_ROOTS
type = "WINDOW", format = 32, 可変数

仮想ルートウィンドウを作成してデスクトップを実装する場合、各仮想ルートウィンドウの ID がセットされています。

ルートウィンドウに背景を設定したいアプリケーションは、代わりにこのウィンドウに背景を設定すると、それを適用させることができます。
_NET_WORKAREA
type = "CARDIAL", format = 32, 4個 x デスクトップ数

各仮想デスクトップの作業領域が、(x, y, width, height) でセットされています。
各デスクトップのビューポート位置を基準として、現在のビューポート内に完全に含まれている領域となります。

スクリーンの領域から、ドックやパネルなどの、常に前面に表示されるウィンドウのサイズを引いた範囲になります。
_NET_SHOWING_DESKTOP
type = "CARDIAL", format = 32, 1個 (0 or 1)

一部のウィンドウマネージャーには、「デスクトップを表示」のような、すべてのウィンドウを非表示にして、デスクトップ全体が表示できる状態にするモードがあります。

デスクトップを表示している状態では 1、通常の状態では 0 にセットされています。
_NET_ACTIVE_WINDOW
type = "WINDOW", format = 32, 1個, 読み込み専用

現在のアクティブな (入力フォーカスがある) ウィンドウの ID がセットされています。
アクティブなウィンドウがない場合、None になります。

アクティブなウィンドウを変更
アクティブなウィンドウを変更したい場合、XSendEvent() で、ルートウィンドウに ClientMessage イベントを送信します。
※XSendEvent に渡す引数については、NetWM (1) で説明しています。

[ClientMessage]
window = アクティブにしたいウィンドウ
message_type = (Atom) _NET_ACTIVE_WINDOW
format = 32
data.l[0] = 1 でアプリから、2 でページャから
data.l[1] = タイムスタンプ
data.l[2] = 現在アクティブなウィンドウ。0 でなし