アプリをフルスクリーンで表示する

setFullscreen と core:window:allow-set-fullscreen で全画面を切り替える。F11・Esc での解除、onResized での状態同期、外部モニター表示、macOS の Space の扱いも。

ウィンドウ 対象: Tauri 2.x 更新日: 読了目安: 約11分 win-004
目次
  1. 前提条件
  2. 1. フロントエンドから実装する (TypeScript)
  3. F11 で切り替え、Esc で抜ける
  4. 状態の変化に UI を追従させる
  5. 外部モニターに全画面のウィンドウを出す
  6. HTML の Fullscreen API との関係
  7. 2. バックエンドから実装する (Rust)
  8. 動作確認
  9. よくあるエラーと対処法
  10. OS ごとの違いと注意点
  11. 関連レシピ

動画プレーヤー、スライドショー、ゲーム、キオスク端末などでは、タイトルバーやタスクバーを消して画面全体を使います。起動時から全画面にするなら tauri.conf.json の fullscreen: true、実行中に切り替えるなら @tauri-apps/api/window の setFullscreen()(Rust は set_fullscreen())です。Tauri の全画面は解像度を変えない「ボーダーレス全画面」で、ウィンドウがいるモニターいっぱいに広がります。抜け方を自分で用意する必要があることと、macOS では別の Space に移ることが迷いやすい点です。

前提条件

プラグインは不要です。状態の取得は core:default だけで動き、切り替えには個別の権限が要ります。

使う API権限core:window:default
isFullscreen()core:window:allow-is-fullscreen含まれる
setFullscreen()core:window:allow-set-fullscreen含まれない
setSimpleFullscreen()core:window:allow-set-simple-fullscreen含まれない
全画面用のウィンドウを新しく作るcore:webview:allow-create-webview-window含まれない(core:webview:default にもない)

権限は capability の windows に書いたウィンドウにしか効きません。後述のプレゼン用ウィンドウ(ラベル presenter)の中から全画面を操作するなら、そのラベルも入れます。

{
  "$schema": "../gen/schemas/desktop-schema.json",
  "identifier": "default",
  "description": "Capability for the main window",
  "windows": ["main", "presenter"],
  "permissions": [
    "core:default",
    "core:window:allow-set-fullscreen",
    "core:window:allow-set-simple-fullscreen",
    "core:webview:allow-create-webview-window"
  ]
}

起動時から全画面にする設定です。これだけなら権限は不要です。width / height は解除したときの大きさとして書いておきます。

{
  "app": {
    "windows": [
      { "label": "main", "title": "Kiosk", "width": 1280, "height": 720, "fullscreen": true }
    ]
  }
}

fullscreen は作成時の状態を決めるだけで、ユーザーが途中で解除した状態は次回に引き継がれません。前回の状態を再現したいなら、全画面かどうかも保存できる Window State プラグイン(plugin-005)を使います。

1. フロントエンドから実装する (TypeScript)

F11 で切り替え、Esc で抜ける

トグル用の関数はないので、isFullscreen() を見て反対の値を setFullscreen() に渡します。Tauri には Esc で全画面を抜ける処理がなく、Windows の全画面にはタイトルバーもないため、キー操作を用意しないとユーザーが元に戻れません。

import { getCurrentWindow } from '@tauri-apps/api/window';

const win = getCurrentWindow();

// 全画面を切り替え、切り替え後の状態を返す
export async function toggleFullscreen(): Promise<boolean> {
  const next = !(await win.isFullscreen());
  await win.setFullscreen(next);
  return next;
}

window.addEventListener('keydown', async (e) => {
  if (e.key === 'F11') {
    e.preventDefault();
    console.log('fullscreen:', await toggleFullscreen());
  } else if (e.key === 'Escape' && (await win.isFullscreen())) {
    await win.setFullscreen(false);
    console.log('fullscreen:', false);
  }
});

keydown は Webview にフォーカスがあるときだけ届きます。解除すると、全画面にする前の位置と大きさに戻ります。

状態の変化に UI を追従させる

全画面の出入りを知らせる専用イベントはないので、大きさが変わったときに届く onResized の中で isFullscreen() を問い合わせます。macOS の緑ボタンや既定メニュー、Windows の動画の全画面ボタンのように、アプリのコードを通らない切り替えにも追従できます。

import { getCurrentWindow } from '@tauri-apps/api/window';

const win = getCurrentWindow();

async function syncFullscreenUi() {
  const fs = await win.isFullscreen();
  document.body.classList.toggle('fullscreen', fs);             // 全画面中の余白調整などの CSS 用
  document.getElementById('toolbar')?.toggleAttribute('hidden', fs);
}

await syncFullscreenUi();
await win.onResized(syncFullscreenUi);

setFullscreen() の Promise は大きさの変化を待たずに解決します。Canvas の解像度合わせのように新しい大きさが要る処理は、setFullscreen() の直後ではなく onResized の中で行います。

外部モニターに全画面のウィンドウを出す

setFullscreen(true) はウィンドウが今いるモニターで全画面になります。2 台目のモニターに出したいときは、その座標に fullscreen: true のウィンドウを作ると、作成時の位置で対象のモニターが決まります。x / y は論理ピクセルなので、物理ピクセルの Monitor.position を scaleFactor で変換して渡します(モニター情報は win-022)。

import { availableMonitors } from '@tauri-apps/api/window';
import { WebviewWindow } from '@tauri-apps/api/webviewWindow';

// index 番目のモニターに全画面のプレゼン用ウィンドウを開く
export async function openPresenter(index: number) {
  const monitor = (await availableMonitors())[index];
  if (!monitor) throw new Error(`monitor #${index} not found`);
  const pos = monitor.position.toLogical(monitor.scaleFactor);
  const presenter = new WebviewWindow('presenter', {
    url: '/presenter.html', title: 'Presenter', x: pos.x, y: pos.y, width: 800, height: 600, fullscreen: true,
  });
  presenter.once('tauri://error', (e) => console.error('create failed', e));
}

既存のウィンドウを別のモニターで全画面にするなら、全画面を解除してから setPosition()(win-005、core:window:allow-set-position が必要)で移し、setFullscreen(true) を呼びます。

HTML の Fullscreen API との関係

element.requestFullscreen() や <video> の全画面ボタンは Web 標準の仕組みで、Tauri のウィンドウ全画面とは別物です。

  • Windows: WebView2 で要素が全画面になると Tauri がウィンドウも全画面にし、要素の全画面が終わるとウィンドウの全画面も解除します。
  • macOS: WKWebView の要素全画面は既定で無効で、tauri.conf.json の app.macOSPrivateApi: true で有効になります。プライベート API を使うため、App Store で配布するアプリでは使えません。

逆に setFullscreen() で全画面にしても document.fullscreenElement は null のままなので、全画面かどうかの判定には isFullscreen() を使います。

2. バックエンドから実装する (Rust)

Window / WebviewWindow の set_fullscreen() / is_fullscreen() / set_simple_fullscreen() を使い、新しいウィンドウは WebviewWindowBuilder の .fullscreen(true) で全画面にできます。「リリースビルドだけ全画面で起動する」のような条件付きの起動は設定ファイルでは書けないので、setup で行います。

use tauri::{Manager, WebviewWindow};

#[tauri::command]
fn toggle_fullscreen(window: WebviewWindow) -> Result<bool, String> {
    let next = !window.is_fullscreen().map_err(|e| e.to_string())?;
    window.set_fullscreen(next).map_err(|e| e.to_string())?;
    Ok(next)
}

// macOS では新しい Space を作らない全画面。ほかの OS では set_fullscreen と同じ動作
#[tauri::command]
fn set_presentation_mode(window: WebviewWindow, enable: bool) -> Result<(), String> {
    window.set_simple_fullscreen(enable).map_err(|e| e.to_string())
}

#[cfg_attr(mobile, tauri::mobile_entry_point)]
pub fn run() {
    tauri::Builder::default()
        .setup(|app| {
            // 開発中は通常のウィンドウ、リリースビルド(キオスク端末)だけ全画面で起動する
            if !cfg!(debug_assertions) {
                if let Some(main) = app.get_webview_window("main") {
                    main.set_fullscreen(true)?;
                }
            }
            Ok(())
        })
        .invoke_handler(tauri::generate_handler![toggle_fullscreen, set_presentation_mode])
        .run(tauri::generate_context!())
        .expect("error while running tauri application");
}
import { invoke } from '@tauri-apps/api/core';

const nowFullscreen = await invoke<boolean>('toggle_fullscreen');
console.log('fullscreen:', nowFullscreen);

Rust 側で全画面の出入りを検知するなら、win-003 と同じく on_window_event で WindowEvent::Resized を受けて is_fullscreen() を確かめます。

動作確認

npm run tauri dev で起動して F11 を押すと、ウィンドウがモニター全体に広がり(Windows ではタスクバーも隠れます)、コンソールに fullscreen: true と出ます。Esc かもう一度 F11 を押すと元の位置と大きさに戻り、fullscreen: false と出ます。macOS では全画面用の Space へアニメーションしながら移ります。openPresenter(1) を呼ぶと、2 台目のモニターにだけプレゼン用ウィンドウが全画面で出ます。

fullscreen: true
fullscreen: false

よくあるエラーと対処法

  • window.set_fullscreen not allowed. Permissions associated with this command: core:window:allow-set-fullscreen: 権限の追加漏れです(開発ビルドの文言。リリースビルドでは Command plugin:window|set_fullscreen not allowed by ACL)。isFullscreen() は動くのに切り替えだけ失敗するのはこのパターンです。
  • プレゼン用ウィンドウの中で window.set_fullscreen not allowed on window "presenter" で始まるエラー: capability の windows にそのラベルがありません。"windows": ["main", "presenter"] のように追加します。
  • macOS で setSimpleFullscreen(true) が効かない、isFullscreen() が false のまま: simple fullscreen は通常の全画面中には使えず、逆に simple fullscreen 中は setFullscreen() が無視されます。isFullscreen() は simple fullscreen を全画面として数えないので、状態はアプリ側で持ち、2 つの方式を混ぜないようにします。
  • Windows で動画の全画面を閉じたら、アプリの全画面まで解除された: 要素の全画面の終了にウィンドウが連動する実装のためです。onResized で検知し、必要なら setFullscreen(true) をかけ直します。
  • macOSPrivateApi を有効にしたら、Cargo.toml の feature が tauri.conf.json と一致しないという趣旨のエラーでビルドが止まる: Cargo の macos-private-api feature が設定と食い違っています。tauri dev / tauri build 経由で実行するか、Cargo.toml の tauri にこの feature を加えます。

OS ごとの違いと注意点

  • Windows: モニター全体(タスクバーの領域も含む)を覆い、タスクバーにも全画面であることを知らせます。全画面中はスクリーンセーバーが無効になります。
  • macOS: setFullscreen(true) は全画面用の Space を作ってそこへ移り、その間は Dock とメニューバーが使えません。出入りのアニメーション中に呼んだ setFullscreen() は、遷移が終わってから反映されます。ユーザーは緑のボタンや既定メニューの「Toggle Full Screen」(Ctrl + Cmd + F)でも全画面にできるので、UI は onResized で追従させます。緑ボタンからの全画面化を止めるなら maximizable: false にします(ズームも無効になります)。独自のメニューを設定すると既定メニューは使われないため、この項目が必要なら PredefinedMenuItem の fullscreen を自分で入れます(macOS のみ対応。menu-001)。
  • macOS の simple fullscreen: setSimpleFullscreen(true) は Space を作らず、同じ Space のままタイトルバーを消して画面いっぱいに広げ、Dock とメニューバーを自動で隠します。その間はリサイズ・最小化・移動ができません。
  • Linux: ウィンドウがいるモニターで全画面になります。setSimpleFullscreen() は setFullscreen() と同じ動作です。
  • 解像度を切り替える「排他的全画面」は Tauri の API にはありません。

関連レシピ

参考リンク(公式ドキュメント)

Web Ninja

この記事を書いた人

Web Ninja ウェブエンジニア (Web Engineer)

会社員ネットワークエンジニアから独立してかれこれ 25 年以上 Web エンジニアとして活動中。普段は JavaScript と Node.js を自在に操り、時には C++ や Perl といった古流の技も嗜みます。近年は Tauri × Rust という新たな武器を手に、デスクトップアプリ開発の最前線を駆け抜けています。「作りたい」を「作れる」に変えるための、実践的な「技」をお届けします。

お問い合わせ: tauri.ninja@gmail.com

内容の誤り・動かないコードを報告する