これは伺か・伺的 Advent Calendar 2025の5日目の記事です。
昨日はあーるでぃーさんのランダムトークを形にするでした。
以下本文。
これは伺かのベースウェア(ninix-kagari)を作っていて色々あったことをまとめ、
デスクトップマスコット1をLinuxで作りたい、とか
WindowsやMacで動いているデスクトップマスコットをLinuxに移植したい、とか
そういった方へ、「技術面で難しい部分があるから頑張ってね(はぁと」と
エールを送るものである。
ぼやいているだけとも言う。
-
Waylandのサポートが面倒
-
マルチディスプレイ対応も面倒
-
クロスプラットフォーム対応も面倒
-
SDL3ならライブラリの範疇でなんとかなりそう
LinuxのGUI環境の変化による影響で、当然出来ると思われていたことが 出来なくなっているのが主な要素。
今まではX11と呼ばれるライブラリが使われていたけれど、 セキュリティがザルだからそれをどうにかしたいよね、ということで Waylandなるものが作られた。
そのWaylandが、デスクトップマスコット作りには逆風な機能がけっこうある。
-
プログラム側でウィンドウの移動操作ができない
-
プログラム側でウィンドウのリサイズ操作が出来ない
-
初期表示位置は基本的に(マウスカーソルがいる)ディスプレイの真ん中が中心になるように配置される
-
フルスクリーンのウィンドウにフォーカスがあると他のウィンドウの描画をしない
-
マウスはウィンドウの左上を原点とした座標で、ウィンドウ内にいるときしか取得できない
-
一部unstableな仕様を使わないといけなかったりする上に、それの実装状況が様々
などなど…。
- ウィンドウの大きさは表示したいキャラクターの画像(or 3Dモデル)のサイズ
わざわざフルスクリーンにする必要はなかろう。 そう思ってuDesktopMascotのデモを見たら普通に全画面表示だった。 影の部分を考慮したウィンドウサイズの計算が面倒だったりするんだろうか…。
でもそういう前提で話を作っていたと思ってほしい。
- 出来ればマルチディスプレイに対応したい
今のご時世ディスプレイが複数あるのが当たり前らしい[要出典]ので、それには対応しておきたい。
こんな問題が発生する。というかした。
- 複数のキャラクターを切り替えられるようにしたい
リサイズ出来ないのでキャラクターA(小さい)からキャラクターB(大きい)に変更した時に見切れる。
- キャラクターをドラッグして移動したい
キャラクターのサイズ=ウィンドウのサイズだとウィンドウの移動操作が出来ないので当然できない。2
- ウィンドウサイズをキャラクターの大きさではなくディスプレイ全体にする
青はディスプレイで、緑がウィンドウを表している。
キャラクターの描画されたウィンドウがディスプレイを動き回る…のではなく、 キャラクターがディスプレイと同じサイズのウィンドウ内を動き回ることで 問題を回避した。
一見するとこれで解決に思えるが、そうはならないのがLinux。 新たに2つの問題が現れる。
いくらでもやりようがありそうだけれど、そうでもない。 4つの方法がある。
- 最大化
2個目の問題を考えなければ良い選択。 ninix-kagariではこの方法も採っている。3
ただし、swayやHyprlandのようなタイル型では、アプリ側からの最大化/最小化が出来ない。
- フルスクリーン
2個目の問題を考えるなら良い選択。 ninix-kagariではこの方法も採っている。
フルスクリーンなので、メニュー/ステータスバーは無視される。
フルスクリーンのアプリがアクティブだと他のウィンドウ/背景が 描画されない関係上、複数キャラを表示することはおろか、 他アプリの操作も出来ない。
一応、他のウィンドウ/背景も描画される実装はあるものの、割合は少ない。
- ディスプレイサイズの大きさの、最大化/フルスクリーンでないウィンドウ
2個目の問題を考えなければ、かつ、 ウィンドウはカーソルのあるディスプレイに表示されるので、 カーソルのあるディスプレイのサイズを知ることが出来れば良い選択。
ただし、ディスプレイのサイズは分かっても、そのディスプレイに カーソルが存在するか判別するのが難しい。
- 環境変数でディスプレイサイズを教えてもらう
最終手段。3が出来るならいらない。 ninix-kagariではこの方法も採っている。
…と、これらの方法のいずれかを取れば一応は解決する。一応は。
まず考えるのが、
- 1ディスプレイにしか存在し得ないキャラクターをどうやって他のディスプレイに持っていくか
で、これは 「各ディスプレイにそれぞれのサイズに合わせたウィンドウを用意して、その中を移動させる」 という筋肉的方法で解決できる。
先ほど同様、青はディスプレイで緑がウィンドウを表している。
問題は、どうやって各ディスプレイにウィンドウを表示するか。
これは、調べた限りでは
- 「指定したディスプレイにフルスクリーンで表示する」なるAPIを使う
しかない。
それ以外の方法も考えてみたが、 ウィンドウはカーソルのあるディスプレイに表示される関係上、 少なくとも起動時に全てのディスプレイにウィンドウを用意することが出来ない。
で、フルスクリーンだと、ほとんどの実装で他のウィンドウ/背景が描画されない4ので、これも頓挫している。
この考え方だとマルチディスプレイ対応は難しいかもしれない。
WindowsやMacでも動くようにしたい!となるとさらに問題が発生する。
そのままだとWindowsではウィンドウの透明部分の
マウスイベントの透過が行われない。
v3からv4になって、SetWindowRgnを使わずにWM_NCHITTESTを
使うようになったことで発生しているようだ。5
ウィンドウはディスプレイと同じサイズにしているので、 このままではキャラクターを横に置きながら作業…のようなことが出来ない。
これを軽減するため、従来通り「ウィンドウサイズ=キャラクターの大きさ」にしようとすると これはこれで問題がある。
GTK4はWaylandを中心に開発が行われている関係で、 ウィンドウを移動したりリサイズするAPIが存在しない。 そのため、WindowsやMac等で移動したい場合は ウィンドウハンドルを取得してネイティブのAPIを呼ぶ必要があり、 開発に使用する言語次第では詰む。というか詰んだ。
何も知らない。 今のところ大丈夫そうだけれど、Waylandに注力するらしいので ウィンドウ操作系のAPIが消えてもおかしくない。
WindowsやMac向けに作って、LinuxはProton(Wine)で動作させれば良くね? …と思われるかもしれないが、Wayland環境下ではそうはいかない。 上で説明した制限があるので、 ウィンドウのど真ん中に移動できないキャラクターが表示されてしまう。 ディスプレイサイズのウィンドウを用意すればとりあえず1ディスプレイでは動きそうだけれど、 環境によっては透過が機能せず透明になるはずの部分が真っ黒になってしまうため、うまくいかない。
何も知らない。 軽く調べた感じだとUnityのWaylandサポートはまだ実験段階っぽい?
OpenGL(or Vulkan)の勉強が必要。 しかもMacだとOpenGLは非推奨なのでMetalの勉強が必要。
何も知らない。いつの間にかSDL2じゃなくなってた。
調べて使ってみたところ、むしろ一番選択肢としては有力。そうでもなかった。後述。
Ruby3.3 + GTK4で作っている。 RubyでGTK4を扱う関係上、ネイティブのウィンドウハンドルは取得できない。6
なので、X11でもウィンドウは全画面表示でなんやかんやする。
-
スタック型WM(openboxとかxfceとか): 最大化でもいいがマルチディスプレイ対応を考えてフルスクリーン
-
タイル型WM(i3とか): 最大化が機能しないのでフルスクリーン
-
LabwcとKDE Plasma: フルスクリーンが使える。
-
他のスタック型WM(mutterとか): フルスクリーンがうまくいかないので最大化。
-
タイル型WM(swayとかHyprlandとか): 最大化もフルスクリーンもうまくいかないので環境変数でサイズを指定。
Ruby + GTKではどうにもならなそうなので、GUI周りの一部をGLFWで書き直している。
ってな感じで、マルチディスプレイ対応は難しいよ、という締めくくりのつもりで これを書いていたんだねえ。
今しがたGLFWで書いていた部分をSDL3で書き直している訳だけれど、 Wayland環境でも任意のディスプレイにウィンドウを出せることが判明。 もちろん任意のディスプレイのサイズを知ることも出来る。 ということは、全ディスプレイに、ディスプレイと同じサイズのウィンドウを用意することが出来る。 最大化もしないし、フルスクリーンもしないので(おそらく)どのWayland環境でもうまく動作しそう。7~~
つまるところ、問題提起したディスプレイのサイズのウィンドウを用意するのとマルチディスプレイの両方をクリアしたことになる。 そう、なってしまうのだ…。
SDL3で出来るということは、理論上はどのライブラリ使おうがマルチディスプレイ対応まで可能ということだ。 SDL3以外のGUIライブラリを使うなら、Waylandプロトコルをしっかり読んで実装しないといけないかもしれない…。
もしデスクトップマスコットをWayland対応にするならその辺を頑張ってね☆ミ
と思ってウキウキしていたら、XWayland上で動作していたことが分かった。 SDL3はデフォルトでWaylandで動作するんじゃなかったの…?
とにかく、Waylandで動かすとやっぱりダメだったのでマルチディスプレイ問題は解決しなさそう…。
おのれWayland。
マルチディスプレイ対応まで見るならSDL3がおすすめマルチディスプレイはどうにもならんよ
シングルディスプレイで良いなら好きなライブラリが使えるんじゃないかな。
クロスプラットフォーム対応ならやっぱりSDL3がおすすめクロスプラットフォーム対応なら少なくともGTKはおすすめしない
大体のライブラリはWin32API/Cocoa/X11/Waylandと戦う覚悟がいるぞ。 私は戦った。
- テストに使うWayland環境は色々用意して試してみるべし
Aの環境では動くけど、Bの環境では動かない、なんてことがWindowsのそれをはるかに上回るぞ。 ディストリだけじゃなく、Waylandの実装を変えるのを忘れずに。
- クロスプラットフォーム対応するなら、何かあったときのためにネイティブのAPIを(簡単に)呼び出せる言語で開発する
詰み防止に。いっそ詰んだ方がマシかもしれないが。
~~アドカレの公開日が近くなってから着地点が90度くらい変わった。~~検証の結果着地点が戻った。 話の流れが分かりにくくなってたらすまねえ。
明日はどっとステーション駅長さんの伺的デスクトップマスコットアプリを要件定義するです。お楽しみに。


