Skip to content

Instantly share code, notes, and snippets.

@Tatakinov
Last active December 31, 2025 14:59
Show Gist options
  • Select an option

  • Save Tatakinov/1434986b65fa68bb2b3ae974db43a50b to your computer and use it in GitHub Desktop.

Select an option

Save Tatakinov/1434986b65fa68bb2b3ae974db43a50b to your computer and use it in GitHub Desktop.
「Linuxでデスクトップマスコット」は茨の道かもしれない、という話

「Linuxでデスクトップマスコット」は茨の道かもしれない、という話

これは伺か・伺的 Advent Calendar 2025の5日目の記事です。

昨日はあーるでぃーさんのランダムトークを形にするでした。

以下本文。

これは伺かのベースウェア(ninix-kagari)を作っていて色々あったことをまとめ、 デスクトップマスコット1をLinuxで作りたい、とか WindowsやMacで動いているデスクトップマスコットをLinuxに移植したい、とか そういった方へ、「技術面で難しい部分があるから頑張ってね(はぁと」と エールを送るものである。 ぼやいているだけとも言う。

TL;DR

  • Waylandのサポートが面倒

  • マルチディスプレイ対応も面倒

  • クロスプラットフォーム対応も面倒

  • SDL3ならライブラリの範疇でなんとかなりそう

何が茨の道なのか

LinuxのGUI環境の変化による影響で、当然出来ると思われていたことが 出来なくなっているのが主な要素。

今まではX11と呼ばれるライブラリが使われていたけれど、 セキュリティがザルだからそれをどうにかしたいよね、ということで Waylandなるものが作られた。

そのWaylandが、デスクトップマスコット作りには逆風な機能がけっこうある。

  • プログラム側でウィンドウの移動操作ができない

  • プログラム側でウィンドウのリサイズ操作が出来ない

  • 初期表示位置は基本的に(マウスカーソルがいる)ディスプレイの真ん中が中心になるように配置される

  • フルスクリーンのウィンドウにフォーカスがあると他のウィンドウの描画をしない

  • マウスはウィンドウの左上を原点とした座標で、ウィンドウ内にいるときしか取得できない

  • 一部unstableな仕様を使わないといけなかったりする上に、それの実装状況が様々

などなど…。

前提

  • ウィンドウの大きさは表示したいキャラクターの画像(or 3Dモデル)のサイズ

わざわざフルスクリーンにする必要はなかろう。 そう思ってuDesktopMascotのデモを見たら普通に全画面表示だった。 影の部分を考慮したウィンドウサイズの計算が面倒だったりするんだろうか…。

でもそういう前提で話を作っていたと思ってほしい。

  • 出来ればマルチディスプレイに対応したい

今のご時世ディスプレイが複数あるのが当たり前らしい[要出典]ので、それには対応しておきたい。

問題

こんな問題が発生する。というかした。

  • 複数のキャラクターを切り替えられるようにしたい

リサイズ出来ないのでキャラクターA(小さい)からキャラクターB(大きい)に変更した時に見切れる。

  • キャラクターをドラッグして移動したい

キャラクターのサイズ=ウィンドウのサイズだとウィンドウの移動操作が出来ないので当然できない。2

対策

  • ウィンドウサイズをキャラクターの大きさではなくディスプレイ全体にする

つまり、これ before をこう after する。

青はディスプレイで、緑がウィンドウを表している。

キャラクターの描画されたウィンドウがディスプレイを動き回る…のではなく、 キャラクターがディスプレイと同じサイズのウィンドウ内を動き回ることで 問題を回避した。

新たな2つの問題

一見するとこれで解決に思えるが、そうはならないのがLinux。 新たに2つの問題が現れる。

どうやってディスプレイサイズのウィンドウを用意するか

いくらでもやりようがありそうだけれど、そうでもない。 4つの方法がある。

  1. 最大化

2個目の問題を考えなければ良い選択。 ninix-kagariではこの方法も採っている。3

ただし、swayHyprlandのようなタイル型では、アプリ側からの最大化/最小化が出来ない。

  1. フルスクリーン

2個目の問題を考えるなら良い選択。 ninix-kagariではこの方法も採っている。

フルスクリーンなので、メニュー/ステータスバーは無視される。

フルスクリーンのアプリがアクティブだと他のウィンドウ/背景が 描画されない関係上、複数キャラを表示することはおろか、 他アプリの操作も出来ない。

一応、他のウィンドウ/背景も描画される実装はあるものの、割合は少ない。

  1. ディスプレイサイズの大きさの、最大化/フルスクリーンでないウィンドウ

2個目の問題を考えなければ、かつ、 ウィンドウはカーソルのあるディスプレイに表示されるので、 カーソルのあるディスプレイのサイズを知ることが出来れば良い選択。

ただし、ディスプレイのサイズは分かっても、そのディスプレイに カーソルが存在するか判別するのが難しい。

  1. 環境変数でディスプレイサイズを教えてもらう

最終手段。3が出来るならいらない。 ninix-kagariではこの方法も採っている。

…と、これらの方法のいずれかを取れば一応は解決する。一応は。

マルチディスプレイの対応

まず考えるのが、

  • 1ディスプレイにしか存在し得ないキャラクターをどうやって他のディスプレイに持っていくか

で、これは 「各ディスプレイにそれぞれのサイズに合わせたウィンドウを用意して、その中を移動させる」 という筋肉的方法で解決できる。

つまりこう multi する。

先ほど同様、青はディスプレイで緑がウィンドウを表している。

問題は、どうやって各ディスプレイにウィンドウを表示するか。

これは、調べた限りでは

  • 「指定したディスプレイにフルスクリーンで表示する」なるAPIを使う

しかない。

それ以外の方法も考えてみたが、 ウィンドウはカーソルのあるディスプレイに表示される関係上、 少なくとも起動時に全てのディスプレイにウィンドウを用意することが出来ない。

で、フルスクリーンだと、ほとんどの実装で他のウィンドウ/背景が描画されない4ので、これも頓挫している。

この考え方だとマルチディスプレイ対応は難しいかもしれない。

クロスプラットフォームの問題

WindowsやMacでも動くようにしたい!となるとさらに問題が発生する。

GTK

そのままだとWindowsではウィンドウの透明部分の マウスイベントの透過が行われない。 v3からv4になって、SetWindowRgnを使わずにWM_NCHITTESTを 使うようになったことで発生しているようだ。5

ウィンドウはディスプレイと同じサイズにしているので、 このままではキャラクターを横に置きながら作業…のようなことが出来ない。

これを軽減するため、従来通り「ウィンドウサイズ=キャラクターの大きさ」にしようとすると これはこれで問題がある。

GTK4はWaylandを中心に開発が行われている関係で、 ウィンドウを移動したりリサイズするAPIが存在しない。 そのため、WindowsやMac等で移動したい場合は ウィンドウハンドルを取得してネイティブのAPIを呼ぶ必要があり、 開発に使用する言語次第では詰む。というか詰んだ。

Qt

何も知らない。 今のところ大丈夫そうだけれど、Waylandに注力するらしいので ウィンドウ操作系のAPIが消えてもおかしくない。

Proton(Wine)

WindowsやMac向けに作って、LinuxはProton(Wine)で動作させれば良くね? …と思われるかもしれないが、Wayland環境下ではそうはいかない。 上で説明した制限があるので、 ウィンドウのど真ん中に移動できないキャラクターが表示されてしまう。 ディスプレイサイズのウィンドウを用意すればとりあえず1ディスプレイでは動きそうだけれど、 環境によっては透過が機能せず透明になるはずの部分が真っ黒になってしまうため、うまくいかない。

Unity

何も知らない。 軽く調べた感じだとUnityのWaylandサポートはまだ実験段階っぽい?

GLFW

OpenGL(or Vulkan)の勉強が必要。 しかもMacだとOpenGLは非推奨なのでMetalの勉強が必要。

SDL3

何も知らない。いつの間にかSDL2じゃなくなってた。 調べて使ってみたところ、むしろ一番選択肢としては有力。そうでもなかった。後述。

ninix-kagariではこうしてます

前提

Ruby3.3 + GTK4で作っている。 RubyでGTK4を扱う関係上、ネイティブのウィンドウハンドルは取得できない。6

なので、X11でもウィンドウは全画面表示でなんやかんやする。

各環境への対応

X11(要コンポジタ)

  • スタック型WM(openboxとかxfceとか): 最大化でもいいがマルチディスプレイ対応を考えてフルスクリーン

  • タイル型WM(i3とか): 最大化が機能しないのでフルスクリーン

Wayland

  • LabwcとKDE Plasma: フルスクリーンが使える。

  • 他のスタック型WM(mutterとか): フルスクリーンがうまくいかないので最大化。

  • タイル型WM(swayとかHyprlandとか): 最大化もフルスクリーンもうまくいかないので環境変数でサイズを指定。

Windows

Ruby + GTKではどうにもならなそうなので、GUI周りの一部をGLFWで書き直している。

どんでん返し

ってな感じで、マルチディスプレイ対応は難しいよ、という締めくくりのつもりで これを書いていたんだねえ。

今しがたGLFWで書いていた部分をSDL3で書き直している訳だけれど、 Wayland環境でも任意のディスプレイにウィンドウを出せることが判明。 もちろん任意のディスプレイのサイズを知ることも出来る。 ということは、全ディスプレイに、ディスプレイと同じサイズのウィンドウを用意することが出来る。 最大化もしないし、フルスクリーンもしないので(おそらく)どのWayland環境でもうまく動作しそう。7~~

つまるところ、問題提起したディスプレイのサイズのウィンドウを用意するのとマルチディスプレイの両方をクリアしたことになる。 そう、なってしまうのだ…。

SDL3で出来るということは、理論上はどのライブラリ使おうがマルチディスプレイ対応まで可能ということだ。 SDL3以外のGUIライブラリを使うなら、Waylandプロトコルをしっかり読んで実装しないといけないかもしれない…。

もしデスクトップマスコットをWayland対応にするならその辺を頑張ってね☆ミ

どんでん返しのどんでん返し(12/31追記)

と思ってウキウキしていたら、XWayland上で動作していたことが分かった。 SDL3はデフォルトでWaylandで動作するんじゃなかったの…?

とにかく、Waylandで動かすとやっぱりダメだったのでマルチディスプレイ問題は解決しなさそう…。

おのれWayland。

結局どうすりゃ良いの?

  • マルチディスプレイ対応まで見るならSDL3がおすすめマルチディスプレイはどうにもならんよ

シングルディスプレイで良いなら好きなライブラリが使えるんじゃないかな。

  • クロスプラットフォーム対応ならやっぱりSDL3がおすすめクロスプラットフォーム対応なら少なくともGTKはおすすめしない

大体のライブラリはWin32API/Cocoa/X11/Waylandと戦う覚悟がいるぞ。 私は戦った。

  • テストに使うWayland環境は色々用意して試してみるべし

Aの環境では動くけど、Bの環境では動かない、なんてことがWindowsのそれをはるかに上回るぞ。 ディストリだけじゃなく、Waylandの実装を変えるのを忘れずに。

  • クロスプラットフォーム対応するなら、何かあったときのためにネイティブのAPIを(簡単に)呼び出せる言語で開発する

詰み防止に。いっそ詰んだ方がマシかもしれないが。

最後に

~~アドカレの公開日が近くなってから着地点が90度くらい変わった。~~検証の結果着地点が戻った。 話の流れが分かりにくくなってたらすまねえ。

明日はどっとステーション駅長さんの伺的デスクトップマスコットアプリを要件定義するです。お楽しみに。

Footnotes

  1. ここでは伺かのSSPのような不定形ウィンドウのものを指す。

  2. AltキーやCommandキーを押しながらなら出来ることもあるが面倒。

  3. 奇遇にも前身のninix-ayaではこの方法を採っていた。

  4. 描画されない方がセキュリティ的に良いらしいのでいずれ全実装で出来なくなるかも。

  5. HTTRANSPARENTじゃなくてHTNOWHEREを返さないといけない可能性。知らんけど。

  6. 多分。出来たとてせっかくのRubyなのにWaylandとかX11のAPIを直接呼ぶのは考えたくない。

  7. SDL3は最近リリースされたので、自前ビルドが必要なLinux環境があることが懸念点。

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment