泥沼SEの備忘録

やってみたいこと、やってみたことを記録しています

GPD Pocket Linux Ubuntu

Ubuntu 26.04のGPD PocketでiPadを無線サブモニターにしてみた【Wayland使用・HDMIダミープラグ不要】

投稿日:2026年8月11日 更新日:

はじめに

Ubuntu 26.04をインストールした初代GPD Pocketをいろいろ触っています。GPD Pocketは7インチという小さな画面が特徴ですが、実際に使っていると、「もう少し画面が広ければ使いやすいのにな」と思うことがあります。
そこで、手元にあるiPadをGPD Pocketの外部モニターとして使えないか試してみることにしました。有線であればHDMIキャプチャなどを使う方法もありますが、せっかくの小型PCなのでケーブルは増やしたくありません。今回の目標は次のようにしました。

  • GPD PocketとiPadを無線接続する
  • iPadをミラーリングではなく第2モニターとして使う
  • HDMIダミープラグなどは使用しない
  • UbuntuのWayland環境をそのまま使用する

最終的には、Mutterで仮想モニターを作成 → DeskreenでiPadへ配信という方法で実現できました。

今回の環境

GPD Pocket側の環境は以下です。

$ echo $XDG_SESSION_TYPE
wayland

$ gnome-shell --version
GNOME Shell 50.1

$ echo $XDG_CURRENT_DESKTOP
ubuntu:GNOME

GPD PocketのCPUアーキテクチャはx86_64です。今回はUbuntu 26.04のWayland環境で試しています。

まずDeskreenを試してみる

iPadへ画面を無線転送するソフトとして、今回はDeskreen Community Editionを使用しました。Deskreen Community Edition(Deskreen CE)は公式配布ページからAppImage版を入手しました。
https://deskreen.com/ja/downloads-ce/
DeskreenをGPD Pocketで起動し、iPadから接続すると、GPD Pocketの画面をiPadへ表示すること自体は比較的簡単にできました。しかし、この状態では基本的に画面のミラーリングです。


今回作成したい構成は以下のイメージです。

GPD Pocket
┌──────────┐
│ 画面1         │
└──────────┘
┌──────────┐
│ iPad          │
│ 画面2         │
└──────────┘

そこで、Ubuntuに仮想的な第2モニターを作ることにしました。

Wayland上で仮想モニターを作れるか調べる

Ubuntu 26.04ではWaylandを使用していることは確認済みです。当初はX11へ切り替えて仮想ディスプレイを作る方法も考えましたが、できればWaylandのまま実現したいところです。調べていくと、GNOMEのウィンドウマネージャーであるMutterにはScreenCast用のD-Busインターフェースがあります。
さっそく、確認してみます。

gdbus introspect \
  --session \
  --dest org.gnome.Mutter.ScreenCast \
  --object-path /org/gnome/Mutter/ScreenCast

この環境では、CreateSessionが利用できました。さらにScreenCast Sessionを作成して調べてみると、

RecordMonitor
RecordWindow
RecordArea
RecordVirtual

といったメソッドが存在しました。この中の RecordVirtual を利用します。

PythonからMutterの仮想モニターを作る

PythonのPyGObjectからD-Bus経由でMutterへアクセスします。PyGObjectが利用できることを確認しました。

python3 -c 'from gi.repository import Gio, GLib; print("PyGObject OK")'

結果、「PyGObject OK」となれば準備OKです。
今回はホームディレクトリに、以下のスクリプトを作成しました。

~/mutter-virtual-monitor-test.py

スクリプトの内容は以下です。

#!/usr/bin/env python3

from gi.repository import Gio, GLib

BUS_NAME = "org.gnome.Mutter.ScreenCast"
ROOT_PATH = "/org/gnome/Mutter/ScreenCast"

ROOT_IFACE = "org.gnome.Mutter.ScreenCast"
SESSION_IFACE = "org.gnome.Mutter.ScreenCast.Session"
STREAM_IFACE = "org.gnome.Mutter.ScreenCast.Stream"

WIDTH = 1280
HEIGHT = 960
REFRESH_RATE = 60.0


def on_stream_signal(proxy, sender_name, signal_name, parameters):
    if signal_name == "PipeWireStreamAdded":
        node_id = parameters.unpack()[0]

        print()
        print("================================")
        print(f"PipeWire node ID: {node_id}")
        print("================================")
        print()


def main():

    bus = Gio.bus_get_sync(
        Gio.BusType.SESSION,
        None
    )

    root = Gio.DBusProxy.new_sync(
        bus,
        Gio.DBusProxyFlags.NONE,
        None,
        BUS_NAME,
        ROOT_PATH,
        ROOT_IFACE,
        None,
    )

    result = root.call_sync(
        "CreateSession",
        GLib.Variant("(a{sv})", ({},)),
        Gio.DBusCallFlags.NONE,
        -1,
        None,
    )

    session_path = result.unpack()[0]
    print(f"Session: {session_path}")

    session = Gio.DBusProxy.new_sync(
        bus,
        Gio.DBusProxyFlags.NONE,
        None,
        BUS_NAME,
        session_path,
        SESSION_IFACE,
        None,
    )

    mode = {
        "size": GLib.Variant(
            "(uu)",
            (WIDTH, HEIGHT)
        ),
        "refresh-rate": GLib.Variant(
            "d",
            REFRESH_RATE
        ),
        "is-preferred": GLib.Variant(
            "b",
            True
        ),
    }

    modes = GLib.Variant(
        "aa{sv}",
        [mode]
    )

    properties = {
        "is-platform": GLib.Variant(
            "b",
            True
        ),
        "modes": modes,
    }

    result = session.call_sync(
        "RecordVirtual",
        GLib.Variant(
            "(a{sv})",
            (properties,)
        ),
        Gio.DBusCallFlags.NONE,
        -1,
        None,
    )

    stream_path = result.unpack()[0]
    print(f"Stream: {stream_path}")

    stream = Gio.DBusProxy.new_sync(
        bus,
        Gio.DBusProxyFlags.NONE,
        None,
        BUS_NAME,
        stream_path,
        STREAM_IFACE,
        None,
    )

    stream.connect(
        "g-signal",
        on_stream_signal
    )

    session.call_sync(
        "Start",
        None,
        Gio.DBusCallFlags.NONE,
        -1,
        None,
    )

    print()
    print("Virtual monitor started.")
    print("Ctrl+C で終了します。")
    print()

    loop = GLib.MainLoop()

    try:
        loop.run()

    except KeyboardInterrupt:

        print()
        print("Stopping virtual monitor...")

        try:
            session.call_sync(
                "Stop",
                None,
                Gio.DBusCallFlags.NONE,
                -1,
                None,
            )

        except Exception as e:
            print(f"Stop failed: {e}")

        print("Done.")


if __name__ == "__main__":
    main()

今回はiPad側の仮想モニターを、1280 × 960の解像度で設定しています。解像度を変更したい場合は、スクリプト冒頭の WIDTH と HEIGHT を変更します。

仮想モニターを起動する

作成したスクリプトを実行します。

python3 ~/mutter-virtual-monitor-test.py

正常に動作すると、以下が表示されます。「PipeWire node ID」の番号は毎回変わります。

Session: /org/gnome/Mutter/ScreenCast/Session/...
Stream: /org/gnome/Mutter/ScreenCast/Stream/...

Virtual monitor started.
Ctrl+C で終了します。

================================
PipeWire node ID: ...
================================

このターミナルは閉じず、そのままにしておきます。現在の起動方法では、ターミナルを閉じるとスクリプトも終了し、仮想モニターが削除されます。ここは今後要改善ですね。

本当に第2モニターができた

「設定」→「ディスプレイ」を開いて確認すると、内蔵ディスプレイとMetaVendorの2台のディスプレイが認識されているじゃないですか。

今回作成した仮想モニターは、Ubuntuからは以下のように認識されています。

コマンドでも確認できます。

gdbus call \
  --session \
  --dest org.gnome.Mutter.DisplayConfig \
  --object-path /org/gnome/Mutter/DisplayConfig \
  --method org.gnome.Mutter.DisplayConfig.GetCurrentState

以下が返ってくるはずです。

Meta-0
MetaVendor
1280x960@60.000

ここまで来れば、Ubuntuには物理モニターと同じように扱える仮想第2画面が存在しています。

DeskreenからMetaVendorを共有する

ここまで来たら仮想第2画面をiPadに表示することは目前です。
まずは、Deskreen CEを起動します。iPadからDeskreenへ接続し、画面共有を開始すると、Waylandの画面共有ダイアログに、以下の2つのモニターが表示されます。

今回は拡張した仮想第2モニターである、MetaVendorを選択します。すると、iPadにはGPD Pocketの内蔵画面ではなく、仮想第2モニターの内容が表示されました。あとはGPD Pocket上でウィンドウを画面右側へドラッグしていくと、そのままiPad側へ移動できます。これで、iPadをGPD Pocketの無線第2モニターとして使用できました。

仕組み

今回の構成を簡単にまとめると以下のようになります。

GPD Pocket
Ubuntu 26.04 / Wayland
        │
        ├── DSI-1
        │    └── 内蔵ディスプレイ
        │
        └── Mutter RecordVirtual()
               │
               └── Meta-0
                    1280×960
                       │
                    PipeWire
                       │
                    Deskreen
                       │
                     WebRTC
                       │
                     Wi-Fi
                       │
                       ▼
                     iPad

ポイントは、Deskreenが仮想モニターを作っているわけではないことです。Mutterで先に Meta-0 という仮想モニターを作り、その映像をDeskreenでiPadへ送っています。そのため、HDMIダミープラグなども必要ありません。

今回構成はVPN接続中でも使えるのか

GPD PocketではVPN接続も利用していますが、VPN接続中でもiPadの無線サブモニターは問題なく使用できました。iPadとの通信は同一LAN内で行われており、今回のVPN設定ではローカルLAN宛の通信までVPNへ送っていないため、そのまま併用できています。

まとめ

今回、Ubuntu 26.04をインストールしたGPD Pocketで、iPadを無線の第2モニターとして利用できました。
最終的には、以下の要素の組み合わせになりました。特に嬉しいのは、HDMIダミープラグを使用せず、Waylandのまま実現できたことですね。

  • Ubuntu 26.04
  • Wayland
  • Mutterの仮想モニター
  • PipeWire
  • Deskreen CE
  • iPad

GPD PocketとiPadだけ持って無線LANがある環境にいけば、iPadを用いてデュアルモニター構成が作れます。とても嬉しいですね。

ただし現状では、Ubuntuを起動するたびに以下のコマンドを実行し、仮想モニターを起動する必要があります。毎回コマンドを実行するのは少し面倒なので、次回はこの仮想モニターをsystemdで自動起動できるようにしてみたいと思います。

python3 ~/mutter-virtual-monitor-test.py

その他

初代GPD Pocket + Ubuntu 26.04 関連の記事はこちら!!
「 初代GPD Pocket + Ubuntu 26.04 関連の記事」 一覧

-GPD Pocket, Linux, Ubuntu
-,

執筆者:


comment

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

関連記事

iPad × Ubuntuで快適リモートデスクトップ!XRDPでつなぐ手順と注意点

はじめに Linuxのデスクトップ環境を使いたい。。。昨年から急にそう思うようになりました。Linuxのデスクトップ環境、デスクトップLinuxを使いたくなることってありますよね。その昔、学生の頃にD …

初代GPD PocketにUbuntu 26.04 LTSをインストールし、日本語入力設定でハマった話。IBus + MozcからFcitx5 + Mozcへ。やったことを振り返ってみる

はじめに GPD Pocketをご存知でしょうか?中国のGPD社が2017年に発売した7インチ液晶搭載の超小型ノートPC(UMPC)です。約480gの軽量アルミボディにWindows 10とフルキーボ …

Ubuntu 26.04からYAMAHAルーター(RTX1200)へL2TP/IPsec VPN接続してみた【strongSwan + xl2tpd】

はじめに Ubuntu 26.04をインストールしたGPD Pocketから、自宅のYAMAHAルーター(RTX1200)へVPN接続できるようにしてみました。今回使用するのは、YAMAHAルーターで …

自宅サーバのすすめ。自宅ラック立ち上げてみた

はじめに 20014年ごろから自宅サーバを構築していました。 このご時世にオンプレミス(物理環境)かよ。と思われるかもしれませんが、 身近なところにあると、すぐにサーバが立てれて便利なのです。 以下に …

Ubuntuでターミナル操作を自動的にログ保存する

はじめに LinuxDesktopを使っていて少し気になったことがあります。それはターミナルのログが保存できていないことです。今までWindowsからTeraTermでsshをしていたため、TeraT …

関東のSIerでSEをやっています。

Linuxやネットワーク、サーバー、ガジェットなど、気になったことを実際に試しています。

過去に調べたことや、やってみたもののうまくいかなかったことも含めて、試行錯誤の記録を残しています。

同じところで困っている方にとって、少しでも解決の手がかりになれば幸いです。