【1日1アプリ Day2】NixOS (Wayland) の壁を越える!PyQt6で実用的な付箋アプリを作ってみた

1日1アプリ開発チャレンジの2日目は、デスクトップの定番「付箋アプリ」を作成しました。一見シンプルなツールですが、NixOS(Wayland環境)特有のセキュリティモデルに直面し、入力ブロックなどの壁にぶつかることに。PyQt6への移行と startSystemMove を用いて制限を突破した試行錯誤のプロセスを紹介します。NixOSですぐ試せるコードも公開中です!

こんにちは!1日1アプリ開発チャレンジ、2日目の記事です。

昨日(Day1)はシステムユーティリティの「USBフォーマッター」を作成しましたが、今日はデスクトップの定番ツール「付箋(Sticky Note)アプリ」を作ってみました。

「ただの付箋アプリでしょ?」と思うかもしれませんが、実は最新のLinuxデスクトップ環境(Wayland)でこれを完璧に動かすには、思わぬ技術的な壁がありました。今回はその試行錯誤の過程と、NixOSならではのスマートな開発環境の作り方を紹介します。

ソースコードはGitHubに公開しているので、NixOSユーザーの方はぜひ手元で動かしてみてください! 👉 GitHub: forestnote/sticky-note

今回作った付箋アプリの機能

まずは完成品から。シンプルながら、普段使いできる実用性を詰め込みました。

sticky-note
sticky-note
  • 完全な枠なしデザイン: タイトルバーを排除し、デスクトップに馴染むデザインに。
  • スムーズなドラッグ移動: 上部のヘッダー(グレーのバー)を掴んで自由に移動可能。
  • ダブルクリックでカラーチェンジ: ヘッダーをダブルクリックするたびに、4色のパステルカラー(黄・ピンク・水色・緑)に切り替わります。
  • 「常に最前面」のピン留めON/OFF: 右上の「📌」アイコンで、他のウィンドウの下に隠すか、常に手前に置くかをワンタッチで切り替え。
  • 右クリックで終了 & 自動保存: アプリを閉じると、テキスト・現在の色・ピン留めの状態を JSON に自動保存。次回起動時に完全に元の状態を復元します。

立ちはだかる「Wayland」の厳しい壁

最初はPythonの標準ライブラリである Tkinter を使ってサクッと作る予定でした。しかし、私の環境(NixOS + KDE Plasma / Wayland)で動かそうとしたところ、Waylandの強固なセキュリティモデルに阻まれることになります。

  1. 枠なしにすると文字が打てない overrideredirect(True) でウィンドウの枠を消すと、Wayland側が「システムに管理されていない怪しいウィンドウだ」と判断し、キーボードの入力フォーカスを完全にブロックしてしまいました。
  2. 自力でウィンドウを動かせない マウスの座標を計算してウィンドウを動かす処理(move())を書いたところ、今度は「アプリが勝手に画面内の座標を操作してはいけない」という制限に引っかかりました。

PyQt6 と startSystemMove() による解決策

このWaylandの壁を突破するため、KDEネイティブなフレームワークであるQt(PyQt6)へ移行することにしました。

最大のポイントは、ドラッグ移動の実装です。アプリが自力で座標を計算して動かすのではなく、「OS(コンポジタ)に直接ウィンドウの移動を依頼する」というアプローチを取ります。

Python

def mousePressEvent(self, event):
    if event.button() == Qt.MouseButton.LeftButton:
        # アプリが自力で動くのではなく、システム(Wayland)に移動処理を丸投げする
        window = self.window().windowHandle()
        if window:
            window.startSystemMove()

この startSystemMove() を使うことで、セキュリティ制限に引っかかることなく、OSネイティブの非常に滑らかなウィンドウ移動を実現できました。入力ブロックの問題もPyQt6に移行したことで見事に解決しました。

NixOSを汚さないスマートな環境構築(shell.nix

NixOSで開発をする際、システム全体(configuration.nix)にPythonやPyQt6をインストールしてしまうと、今後のアプリ開発で依存関係がごちゃごちゃになってしまいます。

そこで、今回のプロジェクトディレクトリ専用の shell.nix を用意しました。

Nix

{ pkgs ? import <nixpkgs> {} }:

pkgs.mkShell {
  buildInputs = [
    (pkgs.python312.withPackages (ps: [
      ps.pyqt6
    ]))
  ];

  # Wayland環境下でQtアプリをネイティブ動作させる設定
  shellHook = ''
    export QT_QPA_PLATFORM=wayland
  '';
}

このファイルをリポジトリに置いておくことで、手元で試したい人は nix-shell コマンドを打つだけで、自分の環境を一切汚さずにこのアプリを起動できます。この「いつでも再現・破棄できる」手軽さこそ、NixOS最大の魅力ですね!

おわりに

Day2にして、Waylandの仕様に悩まされたり、初めてGitHubのCLI(gh)認証でハマったりと、非常に学びの多い1日になりました。

しかし、最終的に「書ける・動かせる・保存できる」実用的な付箋アプリを完成させられて大満足です。明日も引き続き、新しいアイデアでデスクトップアプリを作っていきたいと思います!

最後まで読んでいただきありがとうございました。

返信を残す

メールアドレスが公開されることはありません。 が付いている欄は必須項目です