From bea485bddc4c70f600a432ba78be72ebf683d583 Mon Sep 17 00:00:00 2001
From: Dan Long <139961+dansl@users.noreply.github.com>
Date: Wed, 31 Dec 2025 00:23:39 -0600
Subject: [PATCH] Add Picture-in-Picture support for Android video playback
Implemented native Picture-in-Picture (PiP) mode for Android by updating the AndroidManifest, MainActivity, and introducing PipService and VideoPIPManager. Updated video player screen and controls to support toggling PiP mode, and added localized strings for the PiP button in multiple languages.
Relating to Issue #44: At this time PiP in Plezy only supports Android devices... iOS+MacOS will require significant changes to the video player for it to work properly...
---
android/app/src/main/AndroidManifest.xml | 5 ++++
.../flutter_application_1/MainActivity.kt | 29 ++++++++++++++++++
lib/i18n/strings.g.dart | 14 +++++++++
lib/screens/video_player_screen.dart | 16 +++++++++-
lib/services/pip_service.dart | 20 +++++++++++++
lib/services/video_pip_manager.dart | 28 +++++++++++++++++
.../desktop_video_controls.dart | 3 ++
.../video_controls/video_controls.dart | 30 +++++++++++++++++++
.../widgets/track_chapter_controls.dart | 21 +++++++++++++
9 files changed, 165 insertions(+), 1 deletion(-)
create mode 100644 lib/services/pip_service.dart
create mode 100644 lib/services/video_pip_manager.dart
diff --git a/android/app/src/main/AndroidManifest.xml b/android/app/src/main/AndroidManifest.xml
index 3c0021f1..3a93af8d 100644
--- a/android/app/src/main/AndroidManifest.xml
+++ b/android/app/src/main/AndroidManifest.xml
@@ -3,6 +3,10 @@
+
+
+
+
@@ -28,6 +32,7 @@
android:launchMode="singleTop"
android:taskAffinity=""
android:theme="@style/LaunchTheme"
+ android:supportsPictureInPicture="true"
android:configChanges="orientation|keyboardHidden|keyboard|screenSize|smallestScreenSize|locale|layoutDirection|fontScale|screenLayout|density|uiMode"
android:hardwareAccelerated="true"
android:windowSoftInputMode="adjustResize">
diff --git a/android/app/src/main/kotlin/com/example/flutter_application_1/MainActivity.kt b/android/app/src/main/kotlin/com/example/flutter_application_1/MainActivity.kt
index 857a5482..81c64d54 100644
--- a/android/app/src/main/kotlin/com/example/flutter_application_1/MainActivity.kt
+++ b/android/app/src/main/kotlin/com/example/flutter_application_1/MainActivity.kt
@@ -2,11 +2,18 @@ package com.edde746.plezy
import android.os.Build
import android.os.Bundle
+import android.app.PictureInPictureParams
+import android.content.res.Configuration
+import android.util.Rational
import io.flutter.embedding.android.FlutterActivity
import io.flutter.embedding.engine.FlutterEngine
+import io.flutter.plugin.common.MethodChannel
import com.edde746.plezy.mpv.MpvPlayerPlugin
class MainActivity : FlutterActivity() {
+
+ private val PIP_CHANNEL = "app.plezy/pip"
+
override fun onCreate(savedInstanceState: Bundle?) {
super.onCreate(savedInstanceState)
@@ -20,5 +27,27 @@ class MainActivity : FlutterActivity() {
override fun configureFlutterEngine(flutterEngine: FlutterEngine) {
super.configureFlutterEngine(flutterEngine)
flutterEngine.plugins.add(MpvPlayerPlugin())
+
+ MethodChannel( flutterEngine.dartExecutor.binaryMessenger, PIP_CHANNEL ).setMethodCallHandler { call, result ->
+ when (call.method) {
+ "isSupported" -> {
+ result.success(Build.VERSION.SDK_INT >= Build.VERSION_CODES.O)
+ }
+ "enter" -> {
+ if (Build.VERSION.SDK_INT >= Build.VERSION_CODES.O) {
+ val width = call.argument("width") ?: 16
+ val height = call.argument("height") ?: 9
+ val params = PictureInPictureParams.Builder().setAspectRatio(Rational(width, height)).build()
+ enterPictureInPictureMode(params)
+ }
+ result.success(null)
+ } else -> result.notImplemented()
+ }
+ }
+ }
+
+ override fun onPictureInPictureModeChanged(isInPictureInPictureMode: Boolean,newConfig: Configuration) {
+ super.onPictureInPictureModeChanged(isInPictureInPictureMode, newConfig)
+ MethodChannel( flutterEngine!!.dartExecutor.binaryMessenger, PIP_CHANNEL ).invokeMethod( "onPipChanged" , isInPictureInPictureMode)
}
}
diff --git a/lib/i18n/strings.g.dart b/lib/i18n/strings.g.dart
index a94c5044..f4d9e9e0 100644
--- a/lib/i18n/strings.g.dart
+++ b/lib/i18n/strings.g.dart
@@ -532,6 +532,7 @@ class _StringsVideoControlsEn {
String get subtitlesButton => 'Subtitles';
String get chaptersButton => 'Chapters';
String get versionsButton => 'Video versions';
+ String get pipButton => 'Picture-in-Picture mode';
String get aspectRatioButton => 'Aspect ratio';
String get fullscreenButton => 'Enter fullscreen';
String get exitFullscreenButton => 'Exit fullscreen';
@@ -1404,6 +1405,7 @@ class _StringsVideoControlsDe implements _StringsVideoControlsEn {
@override String get subtitlesButton => 'Untertitel';
@override String get chaptersButton => 'Kapitel';
@override String get versionsButton => 'Videoversionen';
+ @override String get pipButton => 'Bild-in-Bild Modus';
@override String get aspectRatioButton => 'Seitenverhältnis';
@override String get fullscreenButton => 'Vollbild aktivieren';
@override String get exitFullscreenButton => 'Vollbild verlassen';
@@ -2277,6 +2279,7 @@ class _StringsVideoControlsIt implements _StringsVideoControlsEn {
@override String get subtitlesButton => 'Sottotitoli';
@override String get chaptersButton => 'Capitoli';
@override String get versionsButton => 'Versioni video';
+ @override String get pipButton => 'Modalità Picture-in-Picture';
@override String get aspectRatioButton => 'Proporzioni';
@override String get fullscreenButton => 'Attiva schermo intero';
@override String get exitFullscreenButton => 'Esci da schermo intero';
@@ -3150,6 +3153,7 @@ class _StringsVideoControlsKo implements _StringsVideoControlsEn {
@override String get subtitlesButton => '자막';
@override String get chaptersButton => '챕터';
@override String get versionsButton => '동영상 버전';
+ @override String get pipButton => '픽처 인 픽처 모드';
@override String get aspectRatioButton => '화면비율';
@override String get fullscreenButton => '전체화면';
@override String get exitFullscreenButton => '전체화면 종료';
@@ -4023,6 +4027,7 @@ class _StringsVideoControlsNl implements _StringsVideoControlsEn {
@override String get subtitlesButton => 'Ondertitels';
@override String get chaptersButton => 'Hoofdstukken';
@override String get versionsButton => 'Videoversies';
+ @override String get pipButton => 'Beeld-in-beeld modus';
@override String get aspectRatioButton => 'Beeldverhouding';
@override String get fullscreenButton => 'Volledig scherm activeren';
@override String get exitFullscreenButton => 'Volledig scherm verlaten';
@@ -4896,6 +4901,7 @@ class _StringsVideoControlsSv implements _StringsVideoControlsEn {
@override String get subtitlesButton => 'Undertexter';
@override String get chaptersButton => 'Kapitel';
@override String get versionsButton => 'Videoversioner';
+ @override String get pipButton => 'Bild-i-bild läge';
@override String get aspectRatioButton => 'Bildförhållande';
@override String get fullscreenButton => 'Aktivera helskärm';
@override String get exitFullscreenButton => 'Avsluta helskärm';
@@ -5769,6 +5775,7 @@ class _StringsVideoControlsZh implements _StringsVideoControlsEn {
@override String get subtitlesButton => '字幕';
@override String get chaptersButton => '章节';
@override String get versionsButton => '视频版本';
+ @override String get pipButton => '画中画模式';
@override String get aspectRatioButton => '宽高比';
@override String get fullscreenButton => '进入全屏';
@override String get exitFullscreenButton => '退出全屏';
@@ -6465,6 +6472,7 @@ extension on Translations {
case 'videoControls.subtitlesButton': return 'Subtitles';
case 'videoControls.chaptersButton': return 'Chapters';
case 'videoControls.versionsButton': return 'Video versions';
+ case 'videoControls.pipButton': return 'Picture-in-Picture mode';
case 'videoControls.aspectRatioButton': return 'Aspect ratio';
case 'videoControls.fullscreenButton': return 'Enter fullscreen';
case 'videoControls.exitFullscreenButton': return 'Exit fullscreen';
@@ -6979,6 +6987,7 @@ extension on _StringsDe {
case 'videoControls.subtitlesButton': return 'Untertitel';
case 'videoControls.chaptersButton': return 'Kapitel';
case 'videoControls.versionsButton': return 'Videoversionen';
+ case 'videoControls.pipButton': return 'Bild-in-Bild Modus';
case 'videoControls.aspectRatioButton': return 'Seitenverhältnis';
case 'videoControls.fullscreenButton': return 'Vollbild aktivieren';
case 'videoControls.exitFullscreenButton': return 'Vollbild verlassen';
@@ -7494,6 +7503,7 @@ extension on _StringsIt {
case 'videoControls.subtitlesButton': return 'Sottotitoli';
case 'videoControls.chaptersButton': return 'Capitoli';
case 'videoControls.versionsButton': return 'Versioni video';
+ case 'videoControls.pipButton': return 'Modalità Picture-in-Picture';
case 'videoControls.aspectRatioButton': return 'Proporzioni';
case 'videoControls.fullscreenButton': return 'Attiva schermo intero';
case 'videoControls.exitFullscreenButton': return 'Esci da schermo intero';
@@ -8009,6 +8019,7 @@ extension on _StringsKo {
case 'videoControls.subtitlesButton': return '자막';
case 'videoControls.chaptersButton': return '챕터';
case 'videoControls.versionsButton': return '동영상 버전';
+ case 'videoControls.pipButton': return '픽처 인 픽처 모드';
case 'videoControls.aspectRatioButton': return '화면비율';
case 'videoControls.fullscreenButton': return '전체화면';
case 'videoControls.exitFullscreenButton': return '전체화면 종료';
@@ -8524,6 +8535,7 @@ extension on _StringsNl {
case 'videoControls.subtitlesButton': return 'Ondertitels';
case 'videoControls.chaptersButton': return 'Hoofdstukken';
case 'videoControls.versionsButton': return 'Videoversies';
+ case 'videoControls.pipButton': return 'Beeld-in-beeld modus';
case 'videoControls.aspectRatioButton': return 'Beeldverhouding';
case 'videoControls.fullscreenButton': return 'Volledig scherm activeren';
case 'videoControls.exitFullscreenButton': return 'Volledig scherm verlaten';
@@ -9039,6 +9051,7 @@ extension on _StringsSv {
case 'videoControls.subtitlesButton': return 'Undertexter';
case 'videoControls.chaptersButton': return 'Kapitel';
case 'videoControls.versionsButton': return 'Videoversioner';
+ case 'videoControls.pipButton': return 'Bild-i-bild läge';
case 'videoControls.aspectRatioButton': return 'Bildförhållande';
case 'videoControls.fullscreenButton': return 'Aktivera helskärm';
case 'videoControls.exitFullscreenButton': return 'Avsluta helskärm';
@@ -9554,6 +9567,7 @@ extension on _StringsZh {
case 'videoControls.subtitlesButton': return '字幕';
case 'videoControls.chaptersButton': return '章节';
case 'videoControls.versionsButton': return '视频版本';
+ case 'videoControls.pipButton': return '画中画模式';
case 'videoControls.aspectRatioButton': return '宽高比';
case 'videoControls.fullscreenButton': return '进入全屏';
case 'videoControls.exitFullscreenButton': return '退出全屏';
diff --git a/lib/screens/video_player_screen.dart b/lib/screens/video_player_screen.dart
index f8e4b75a..3a21d0e0 100644
--- a/lib/screens/video_player_screen.dart
+++ b/lib/screens/video_player_screen.dart
@@ -29,6 +29,7 @@ import '../services/offline_watch_sync_service.dart';
import '../services/settings_service.dart';
import '../services/track_selection_service.dart';
import '../services/video_filter_manager.dart';
+import '../services/video_pip_manager.dart';
import '../providers/user_profile_provider.dart';
import '../utils/app_logger.dart';
import '../utils/orientation_helper.dart';
@@ -104,6 +105,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin
MediaControlsManager? _mediaControlsManager;
PlaybackProgressTracker? _progressTracker;
VideoFilterManager? _videoFilterManager;
+ VideoPIPManager? _videoPIPManager;
final EpisodeNavigationService _episodeNavigation = EpisodeNavigationService();
// Watch Together provider reference (stored early to use in dispose)
@@ -714,7 +716,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin
_currentMediaInfo = result.mediaInfo;
});
- // Initialize video filter manager with player and available versions
+ // Initialize video PIP and filter manager with player and available versions
if (player != null) {
_videoFilterManager = VideoFilterManager(
player: player!,
@@ -723,6 +725,11 @@ class VideoPlayerScreenState extends State with WidgetsBindin
);
// Update video filter once dimensions are available
_videoFilterManager!.updateVideoFilter();
+
+ // PIP Manager
+ _videoPIPManager = VideoPIPManager(
+ player: player!
+ );
}
// Add external subtitles to the player
@@ -782,6 +789,12 @@ class VideoPlayerScreenState extends State with WidgetsBindin
);
}
+ void _togglePIPMode() {
+ setState(() {
+ _videoPIPManager?.togglePIP();
+ });
+ }
+
/// Cycle through BoxFit modes: contain → cover → fill → contain (for button)
void _cycleBoxFitMode() {
setState(() {
@@ -1519,6 +1532,7 @@ class VideoPlayerScreenState extends State with WidgetsBindin
onPrevious: (_previousEpisode != null && _canNavigateEpisodes()) ? _playPrevious : null,
availableVersions: _availableVersions,
selectedMediaIndex: widget.selectedMediaIndex,
+ onTogglePIPMode: _togglePIPMode,
boxFitMode: _videoFilterManager?.boxFitMode ?? 0,
onCycleBoxFitMode: _cycleBoxFitMode,
onAudioTrackChanged: _onAudioTrackChanged,
diff --git a/lib/services/pip_service.dart b/lib/services/pip_service.dart
new file mode 100644
index 00000000..88b16328
--- /dev/null
+++ b/lib/services/pip_service.dart
@@ -0,0 +1,20 @@
+import 'package:flutter/services.dart';
+
+class PipService {
+ static const MethodChannel _channel =
+ MethodChannel('app.plezy/pip');
+
+ static Future isSupported() async {
+ return await _channel.invokeMethod('isSupported') ?? false;
+ }
+
+ static Future enter({
+ int? width,
+ int? height,
+ }) async {
+ await _channel.invokeMethod('enter', {
+ 'width': width,
+ 'height': height,
+ });
+ }
+}
\ No newline at end of file
diff --git a/lib/services/video_pip_manager.dart b/lib/services/video_pip_manager.dart
new file mode 100644
index 00000000..6bcb7a27
--- /dev/null
+++ b/lib/services/video_pip_manager.dart
@@ -0,0 +1,28 @@
+import 'package:flutter/material.dart';
+import '../mpv/mpv.dart';
+import '../services/pip_service.dart';
+
+/// Manages video Picture-in-Picture mode
+
+class VideoPIPManager {
+ final Player player;
+
+ bool isPIPactive = false;
+
+ VideoPIPManager({required this.player});
+
+ Size? _playerSize;
+ Size? get playerSize => _playerSize;
+
+ /// Toggle native PiP
+ Future togglePIP() async {
+ final supported = await PipService.isSupported();
+ if (!supported) return;
+
+ await PipService.enter(
+ width: _playerSize?.width.toInt(),
+ height: _playerSize?.height.toInt(),
+ );
+
+ }
+}
\ No newline at end of file
diff --git a/lib/widgets/video_controls/desktop_video_controls.dart b/lib/widgets/video_controls/desktop_video_controls.dart
index 1d4afbb2..73f3574b 100644
--- a/lib/widgets/video_controls/desktop_video_controls.dart
+++ b/lib/widgets/video_controls/desktop_video_controls.dart
@@ -52,6 +52,7 @@ class DesktopVideoControls extends StatefulWidget {
final int subtitleSyncOffset;
final bool isFullscreen;
final bool isAlwaysOnTop;
+ final VoidCallback? onTogglePIPMode;
final VoidCallback? onCycleBoxFitMode;
final VoidCallback? onToggleFullscreen;
final VoidCallback? onToggleAlwaysOnTop;
@@ -95,6 +96,7 @@ class DesktopVideoControls extends StatefulWidget {
this.subtitleSyncOffset = 0,
this.isFullscreen = false,
this.isAlwaysOnTop = false,
+ this.onTogglePIPMode,
this.onCycleBoxFitMode,
this.onToggleFullscreen,
this.onToggleAlwaysOnTop,
@@ -524,6 +526,7 @@ class DesktopVideoControlsState extends State {
isFullscreen: widget.isFullscreen,
isAlwaysOnTop: widget.isAlwaysOnTop,
serverId: widget.serverId,
+ onTogglePIPMode: null, // PIP not supported on desktop
onCycleBoxFitMode: widget.onCycleBoxFitMode,
onToggleFullscreen: widget.onToggleFullscreen,
onToggleAlwaysOnTop: widget.onToggleAlwaysOnTop,
diff --git a/lib/widgets/video_controls/video_controls.dart b/lib/widgets/video_controls/video_controls.dart
index 03d82376..81dc7d0e 100644
--- a/lib/widgets/video_controls/video_controls.dart
+++ b/lib/widgets/video_controls/video_controls.dart
@@ -15,6 +15,7 @@ import 'package:flutter/services.dart'
KeyDownEvent,
HardwareKeyboard;
import '../../services/macos_window_service.dart';
+import '../../services/pip_service.dart';
import 'package:window_manager/window_manager.dart';
import '../../mpv/mpv.dart';
@@ -51,6 +52,7 @@ Widget plexVideoControlsBuilder(
VoidCallback? onPrevious,
List? availableVersions,
int? selectedMediaIndex,
+ VoidCallback? onTogglePIPMode,
int boxFitMode = 0,
VoidCallback? onCycleBoxFitMode,
Function(AudioTrack)? onAudioTrackChanged,
@@ -68,6 +70,7 @@ Widget plexVideoControlsBuilder(
availableVersions: availableVersions ?? [],
selectedMediaIndex: selectedMediaIndex ?? 0,
boxFitMode: boxFitMode,
+ onTogglePIPMode: onTogglePIPMode,
onCycleBoxFitMode: onCycleBoxFitMode,
onAudioTrackChanged: onAudioTrackChanged,
onSubtitleTrackChanged: onSubtitleTrackChanged,
@@ -86,6 +89,7 @@ class PlexVideoControls extends StatefulWidget {
final List availableVersions;
final int selectedMediaIndex;
final int boxFitMode;
+ final VoidCallback? onTogglePIPMode;
final VoidCallback? onCycleBoxFitMode;
final Function(AudioTrack)? onAudioTrackChanged;
final Function(SubtitleTrack)? onSubtitleTrackChanged;
@@ -111,6 +115,7 @@ class PlexVideoControls extends StatefulWidget {
this.availableVersions = const [],
this.selectedMediaIndex = 0,
this.boxFitMode = 0,
+ this.onTogglePIPMode,
this.onCycleBoxFitMode,
this.onAudioTrackChanged,
this.onSubtitleTrackChanged,
@@ -186,6 +191,9 @@ class _PlexVideoControlsState extends State with WindowListen
double? _rateBeforeLongPress;
bool _showSpeedIndicator = false;
+ // PiP support
+ bool _isPipSupported = false;
+
@override
void initState() {
super.initState();
@@ -203,6 +211,7 @@ class _PlexVideoControlsState extends State with WindowListen
_listenToPosition();
_listenToPlayingState();
_listenToCompleted();
+ _checkPipSupport();
// Add lifecycle observer to reload settings when app resumes
WidgetsBinding.instance.addObserver(this);
// Add window listener for tracking fullscreen state (for button icon)
@@ -210,6 +219,7 @@ class _PlexVideoControlsState extends State with WindowListen
windowManager.addListener(this);
_initAlwaysOnTopState();
}
+
// Focus play/pause button on first frame if in keyboard mode
WidgetsBinding.instance.addPostFrameCallback((_) {
_focusPlayPauseIfKeyboardMode();
@@ -636,6 +646,24 @@ class _PlexVideoControlsState extends State with WindowListen
await MacOSWindowService.setTrafficLightsVisible(_showControls);
}
+ /// Check whether PiP is supported on this device
+ Future _checkPipSupport() async {
+ if (!Platform.isAndroid) {
+ return;
+ }
+
+ try {
+ final supported = await PipService.isSupported();
+ if (mounted) {
+ setState(() {
+ _isPipSupported = supported;
+ });
+ }
+ } catch (e) {
+ return;
+ }
+ }
+
Future _loadPlaybackExtras() async {
try {
appLogger.d('_loadPlaybackExtras: starting for ${widget.metadata.ratingKey}');
@@ -731,6 +759,7 @@ class _PlexVideoControlsState extends State with WindowListen
subtitleSyncOffset: _subtitleSyncOffset,
isRotationLocked: _isRotationLocked,
isFullscreen: _isFullscreen,
+ onTogglePIPMode: (_isPipSupported && Platform.isAndroid) ? widget.onTogglePIPMode : null,
onCycleBoxFitMode: widget.onCycleBoxFitMode,
onToggleRotationLock: _toggleRotationLock,
onToggleFullscreen: _toggleFullscreen,
@@ -1498,6 +1527,7 @@ class _PlexVideoControlsState extends State with WindowListen
subtitleSyncOffset: _subtitleSyncOffset,
isFullscreen: _isFullscreen,
isAlwaysOnTop: _isAlwaysOnTop,
+ onTogglePIPMode: (_isPipSupported && Platform.isAndroid) ? widget.onTogglePIPMode : null,
onCycleBoxFitMode: widget.onCycleBoxFitMode,
onToggleFullscreen: _toggleFullscreen,
onToggleAlwaysOnTop: _toggleAlwaysOnTop,
diff --git a/lib/widgets/video_controls/widgets/track_chapter_controls.dart b/lib/widgets/video_controls/widgets/track_chapter_controls.dart
index 0d6cbc16..ebab0ee7 100644
--- a/lib/widgets/video_controls/widgets/track_chapter_controls.dart
+++ b/lib/widgets/video_controls/widgets/track_chapter_controls.dart
@@ -32,6 +32,7 @@ class TrackChapterControls extends StatelessWidget {
final bool isRotationLocked;
final bool isFullscreen;
final bool isAlwaysOnTop;
+ final VoidCallback? onTogglePIPMode;
final VoidCallback? onCycleBoxFitMode;
final VoidCallback? onToggleRotationLock;
final VoidCallback? onToggleFullscreen;
@@ -70,6 +71,7 @@ class TrackChapterControls extends StatelessWidget {
required this.isFullscreen,
required this.serverId,
this.isAlwaysOnTop = false,
+ this.onTogglePIPMode,
this.onCycleBoxFitMode,
this.onToggleRotationLock,
this.onToggleFullscreen,
@@ -288,6 +290,24 @@ class TrackChapterControls extends StatelessWidget {
buttonIndex++;
}
+ // Picture-in-Picture mode
+ if (onTogglePIPMode != null) {
+ final currentIndex = buttonIndex;
+ buttons.add(
+ _buildTrackButton(
+ buttonIndex: currentIndex,
+ icon: Symbols.picture_in_picture_alt,
+ tooltip: t.videoControls.pipButton,
+ semanticLabel: t.videoControls.pipButton,
+ tracks: tracks,
+ isMobile: isMobile,
+ isDesktop: isDesktop,
+ onPressed: onTogglePIPMode,
+ ),
+ );
+ buttonIndex++;
+ }
+
// BoxFit mode button
if (onCycleBoxFitMode != null) {
final currentIndex = buttonIndex;
@@ -372,6 +392,7 @@ class TrackChapterControls extends StatelessWidget {
if (_hasSubtitles(tracks)) count++;
if (chapters.isNotEmpty) count++;
if (availableVersions.length > 1 && onSwitchVersion != null) count++;
+ if (onTogglePIPMode != null) count++;
if (onCycleBoxFitMode != null) count++;
if (isMobile && !PlatformDetector.isTV()) count++; // Rotation lock (not on TV)
if (isDesktop) count++; // Fullscreen