2018-07-09 05:06:52 +00:00
import QtQuick 2.0
import QtQuick . Controls 2.2
2018-09-05 22:15:53 +00:00
import QtQuick . Window 2.2
2018-07-09 05:06:52 +00:00
2018-10-29 00:59:07 +00:00
import SdlGamepadKeyNavigation 1.0
2018-07-09 05:06:52 +00:00
import Session 1.0
Item {
property Session session
2018-08-02 05:32:21 +00:00
property string appName
2021-01-01 03:33:41 +00:00
property string stageText : isResume ? qsTr ( "Resuming %1..." ) . arg ( appName ) :
qsTr ( "Starting %1..." ) . arg ( appName )
property bool isResume : false
2018-09-29 21:06:55 +00:00
property bool quitAfter : false
2018-07-09 05:06:52 +00:00
function stageStarting ( stage )
{
// Update the spinner text
2020-11-21 19:15:54 +00:00
stageText = qsTr ( "Starting %1..." ) . arg ( stage )
2018-07-09 05:06:52 +00:00
}
2020-12-23 19:56:15 +00:00
function stageFailed ( stage , errorCode , failingPorts )
2018-07-09 05:06:52 +00:00
{
2019-03-30 06:20:43 +00:00
// Display the error dialog after Session::exec() returns
2020-11-21 19:15:54 +00:00
streamSegueErrorDialog . text = qsTr ( "Starting %1 failed: Error %2" ) . arg ( stage ) . arg ( errorCode )
2020-12-23 19:56:15 +00:00
if ( failingPorts ) {
streamSegueErrorDialog . text += "\n\n" + qsTr ( "Check your firewall and port forwarding rules for port(s): %1" ) . arg ( failingPorts )
}
2018-07-09 05:06:52 +00:00
}
function connectionStarted ( )
{
// Hide the UI contents so the user doesn't
// see them briefly when we pop off the StackView
stageSpinner . visible = false
stageLabel . visible = false
2019-03-02 22:13:32 +00:00
hintText . visible = false
2018-07-09 05:06:52 +00:00
// Hide the window now that streaming has begun
window . visible = false
}
function displayLaunchError ( text )
{
2018-10-01 01:38:54 +00:00
// Display the error dialog after Session::exec() returns
2019-04-24 02:40:21 +00:00
streamSegueErrorDialog . text = text
2018-07-09 05:06:52 +00:00
}
function displayLaunchWarning ( text )
{
2018-08-04 23:05:37 +00:00
// This toast appears for 3 seconds, just shorter than how long
// Session will wait for it to be displayed. This gives it time
// to transition to invisible before continuing.
2019-03-23 04:30:06 +00:00
var toast = Qt . createQmlObject ( 'import QtQuick.Controls 2.2; ToolTip {}' , parent , '' )
2018-08-04 23:05:37 +00:00
toast . text = text
toast . timeout = 3000
toast . visible = true
2018-07-09 05:06:52 +00:00
}
2018-12-06 03:49:06 +00:00
function quitStarting ( )
{
// Avoid the push transition animation
var component = Qt . createComponent ( "QuitSegue.qml" )
stackView . replace ( stackView . currentItem , component . createObject ( stackView , { "appName" : appName } ) , StackView . Immediate )
// Show the Qt window again to show quit segue
window . visible = true
}
2020-08-09 00:59:26 +00:00
function sessionFinished ( portTestResult )
2018-12-06 03:49:06 +00:00
{
2020-08-11 05:21:54 +00:00
if ( portTestResult !== 0 && portTestResult !== - 1 && streamSegueErrorDialog . text ) {
2020-11-21 19:15:54 +00:00
streamSegueErrorDialog . text += "\n\n" + qsTr ( "This PC's Internet connection is blocking Moonlight. Streaming over the Internet may not work while connected to this network." )
2020-08-09 00:59:26 +00:00
}
2019-03-30 06:20:43 +00:00
// Enable GUI gamepad usage now
SdlGamepadKeyNavigation . enable ( )
2018-12-06 02:45:28 +00:00
if ( quitAfter ) {
2019-04-24 02:40:21 +00:00
if ( streamSegueErrorDialog . text ) {
2018-12-06 06:22:30 +00:00
// Quit when the error dialog is acknowledged
2019-04-24 02:40:21 +00:00
streamSegueErrorDialog . quitAfter = quitAfter
streamSegueErrorDialog . open ( )
2018-12-06 06:22:30 +00:00
}
else {
// Quit immediately
Qt . quit ( )
}
2018-12-06 02:45:28 +00:00
} else {
// Exit this view
stackView . pop ( )
2018-12-06 03:49:06 +00:00
// Show the Qt window again after streaming
window . visible = true
2018-12-06 02:45:28 +00:00
// Display any launch errors. We do this after
// the Qt UI is visible again to prevent losing
// focus on the dialog which would impact gamepad
// users.
2019-04-24 02:40:21 +00:00
if ( streamSegueErrorDialog . text ) {
streamSegueErrorDialog . quitAfter = quitAfter
streamSegueErrorDialog . open ( )
2018-12-06 02:45:28 +00:00
}
}
2022-03-06 19:11:36 +00:00
}
2020-12-19 01:54:11 +00:00
2022-03-06 19:11:36 +00:00
function sessionReadyForDeletion ( )
{
2020-12-19 01:54:11 +00:00
// Garbage collect the Session object since it's pretty heavyweight
// and keeps other libraries (like SDL_TTF) around until it is deleted.
session = null
gc ( )
2018-12-06 02:45:28 +00:00
}
2019-02-23 06:14:06 +00:00
StackView.onDeactivating: {
2019-03-02 22:11:30 +00:00
// Show the toolbar again when popped off the stack
2019-02-23 06:14:06 +00:00
toolBar . visible = true
2019-03-23 21:15:55 +00:00
// Enable GUI gamepad usage now
SdlGamepadKeyNavigation . enable ( )
2018-07-09 05:06:52 +00:00
}
2019-03-03 04:55:50 +00:00
StackView.onActivated: {
// Hide the toolbar before we start loading
toolBar . visible = false
// Hook up our signals
session . stageStarting . connect ( stageStarting )
session . stageFailed . connect ( stageFailed )
session . connectionStarted . connect ( connectionStarted )
session . displayLaunchError . connect ( displayLaunchError )
session . displayLaunchWarning . connect ( displayLaunchWarning )
session . quitStarting . connect ( quitStarting )
session . sessionFinished . connect ( sessionFinished )
2022-03-06 19:11:36 +00:00
session . readyForDeletion . connect ( sessionReadyForDeletion )
2019-03-03 04:55:50 +00:00
// Kick off the stream
2020-03-28 06:32:46 +00:00
spinnerTimer . start ( )
2019-03-03 04:55:50 +00:00
streamLoader . active = true
}
2020-03-28 06:32:46 +00:00
Timer {
id: spinnerTimer
// Display the spinner appearance a bit to allow us to reach
// the code in Session.exec() that pumps the event loop.
// If we display it immediately, it will briefly hang in the
// middle of the animation on Windows, which looks very
// obviously broken.
interval: 100
onTriggered: stageSpinner . running = true
}
2019-03-03 04:55:50 +00:00
Loader {
id: streamLoader
active: false
asynchronous: true
2019-03-02 22:11:30 +00:00
2019-03-03 04:55:50 +00:00
onLoaded: {
2019-03-02 22:11:30 +00:00
// Set the hint text. We do this here rather than
// in the hintText control itself to synchronize
// with Session.exec() which requires no concurrent
// gamepad usage.
2020-11-21 19:15:54 +00:00
hintText . text = qsTr ( "Tip:" ) + " " + qsTr ( "Press %1 to disconnect your session" ) . arg ( SdlGamepadKeyNavigation . getConnectedGamepads ( ) > 0 ?
qsTr ( "Start+Select+L1+R1" ) : qsTr ( "Ctrl+Alt+Shift+Q" ) )
2019-03-02 22:11:30 +00:00
2019-03-23 21:15:55 +00:00
// Stop GUI gamepad usage now
SdlGamepadKeyNavigation . disable ( )
2020-12-19 01:54:11 +00:00
// Garbage collect QML stuff before we start streaming,
// since we'll probably be streaming for a while and we
// won't be able to GC during the stream.
gc ( )
2019-03-02 22:11:30 +00:00
// Run the streaming session to completion
session . exec ( Screen . virtualX , Screen . virtualY )
}
2019-03-03 04:55:50 +00:00
sourceComponent: Item { }
2019-03-02 22:11:30 +00:00
}
2018-07-09 05:06:52 +00:00
Row {
anchors.centerIn: parent
spacing: 5
BusyIndicator {
id: stageSpinner
2020-03-28 06:32:46 +00:00
running: false
2018-07-09 05:06:52 +00:00
}
Label {
id: stageLabel
height: stageSpinner . height
text: stageText
font.pointSize: 20
verticalAlignment: Text . AlignVCenter
wrapMode: Text . Wrap
}
}
2018-09-15 02:11:06 +00:00
Label {
2018-10-29 00:59:07 +00:00
id: hintText
2018-09-15 02:11:06 +00:00
anchors.bottom: parent . bottom
anchors.bottomMargin: 50
anchors.horizontalCenter: parent . horizontalCenter
font.pointSize: 18
verticalAlignment: Text . AlignVCenter
wrapMode: Text . Wrap
}
2018-07-09 05:06:52 +00:00
}