Skip to content

Commit 1dcf674

Browse files
committed
Add general 'fullscreen' switch to CPlay
Adds a full screen parameter to the title's underlying executable automatically if available and known. Only Ruffle is currently supported.
1 parent e529222 commit 1dcf674

File tree

6 files changed

+119
-66
lines changed

6 files changed

+119
-66
lines changed

README.md

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -208,6 +208,7 @@ Notes:
208208
Options:
209209

210210
- [Title Command](#title-commands) options
211+
- **-f | --fullscreen:** Forces the title to run in full screen if the underlying executable supports it.
211212
- **--ruffle:** Forces the use of Ruffle for applicable Flash games. Takes precedence over **--flash**.
212213
- **--flash:** Forces the use of the standard app (usually Flash Player) for applicable Flash games.
213214

lib/backend/src/command/c-play.cpp

Lines changed: 89 additions & 58 deletions
Original file line numberDiff line numberDiff line change
@@ -3,6 +3,7 @@
33

44
// Qx Includes
55
#include <qx/core/qx-regularexpression.h>
6+
#include <qx/utility/qx-helpers.h>
67

78
// Project Includes
89
#include "kernel/core.h"
@@ -71,22 +72,48 @@ Fp::AddApp CPlay::buildAdditionalApp(const Fp::Db::QueryBuffer& addAppResult)
7172

7273
//-Instance Functions-------------------------------------------------------------
7374
//Private:
74-
void CPlay::addPassthroughParameters(QString& param)
75+
void CPlay::addExtraExecParameters(TExec* execTask, Task::Stage taskStage)
7576
{
76-
// Consider all positional arguments (can be explicitly added with "-- <args>") to be passthrough
77-
QStringList ptp = mParser.positionalArguments();
78-
if(!ptp.isEmpty())
77+
// Currently only affects primary execs
78+
if(taskStage != Task::Stage::Primary)
79+
return;
80+
81+
QStringList extraParams;
82+
83+
// Check for fullscreen
84+
if(mParser.isSet(CL_OPTION_FULLSCREEN))
7985
{
80-
param.append(u' ');
81-
param.append(TExec::joinArguments(ptp));
86+
logEvent(LOG_EVENT_FORCING_FULLSCREEN);
87+
auto lookupName = QFileInfo(execTask->executable()).baseName().toLower();
88+
auto fsItr = FULLSCREEN_PARAMS.constFind(lookupName);
89+
if(fsItr != FULLSCREEN_PARAMS.cend())
90+
{
91+
logEvent(LOG_EVENT_FULLSCREEN_SUPPORTED);
92+
extraParams.append(*fsItr);
93+
}
94+
else
95+
logEvent(LOG_EVENT_FULLSCREEN_UNSUPPORTED);
8296
}
83-
}
8497

85-
void CPlay::addPassthroughParameters(QStringList& param)
86-
{
87-
// See above method
88-
QStringList ptp = mParser.positionalArguments();
89-
param.append(ptp);
98+
// Get passthrough args
99+
if(auto ptp = mParser.positionalArguments(); !ptp.isEmpty())
100+
extraParams.append(ptp);
101+
102+
/* Add extra params, which may be
103+
* - Passthrough args (i.e. <rest_of_command> -- <passthrough_args>)
104+
* - Fullscreen params
105+
*/
106+
auto params = execTask->parameters();
107+
std::visit(qxFuncAggregate{
108+
[&](QString& ps){
109+
ps.append(u' ');
110+
ps.append(TExec::joinArguments(extraParams));
111+
},
112+
[&](QStringList& ps){
113+
ps.append(extraParams);
114+
}
115+
}, params);
116+
execTask->setParameters(params);
90117
}
91118

92119
QString CPlay::getServerOverride(const Fp::GameData& gd)
@@ -282,29 +309,16 @@ Qx::Error CPlay::enqueueAdditionalApp(const Fp::AddApp& addApp, const Fp::Game&
282309

283310
mCore.enqueueSingleTask(extraTask);
284311
}
285-
else if(useRuffle(parent, taskStage))
286-
enqueueRuffleTask(addApp.name(), addApp.launchCommand());
287312
else
288313
{
289-
QString addAppPath = mCore.resolveFullAppPath(addApp.appPath(), parent.platformName());
290-
QFileInfo addAppPathInfo(addAppPath);
291-
QString param = addApp.launchCommand();
292-
addPassthroughParameters(param);
293-
294-
TExec* addAppTask = new TExec(mCore);
295-
addAppTask->setIdentifier(addApp.name());
296-
addAppTask->setStage(taskStage);
297-
addAppTask->setExecutable(QDir::cleanPath(addAppPathInfo.absoluteFilePath())); // Like canonical but doesn't care if path DNE
298-
addAppTask->setDirectory(addAppPathInfo.absoluteDir());
299-
addAppTask->setParameters(param);
300-
addAppTask->setEnvironment(mCore.childTitleProcessEnvironment());
301-
addAppTask->setProcessType(addApp.isWaitExit() || taskStage == Task::Stage::Primary ? TExec::ProcessType::Blocking : TExec::ProcessType::Deferred);
302-
303-
mCore.enqueueSingleTask(addAppTask);
314+
TExec* execTask = useRuffle(parent, taskStage) ? createRuffleTask(addApp.name(), addApp.launchCommand()) :
315+
createStdAddAppExecTask(addApp, parent, taskStage);
316+
addExtraExecParameters(execTask, taskStage);
317+
mCore.enqueueSingleTask(execTask);
304318

305319
#ifdef _WIN32
306320
// Add wait task if required
307-
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(addAppPathInfo); ee.isValid())
321+
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(execTask); ee.isValid())
308322
return ee;
309323
#endif
310324
}
@@ -315,19 +329,28 @@ Qx::Error CPlay::enqueueAdditionalApp(const Fp::AddApp& addApp, const Fp::Game&
315329

316330
Qx::Error CPlay::enqueueGame(const Fp::Game& game, const Fp::GameData& gameData, Task::Stage taskStage)
317331
{
318-
QString param = !gameData.isNull() ? gameData.launchCommand() : game.launchCommand();
332+
TExec* execTask = useRuffle(game, taskStage) ? createRuffleTask(game.title(), !gameData.isNull() ? gameData.launchCommand() : game.launchCommand()) :
333+
createStdGameExecTask(game, gameData, taskStage);
319334

320-
if(useRuffle(game, taskStage))
321-
{
322-
enqueueRuffleTask(game.title(), param);
323-
return Qx::Error();
324-
}
335+
addExtraExecParameters(execTask, taskStage);
336+
mCore.enqueueSingleTask(execTask);
337+
338+
#ifdef _WIN32
339+
// Add wait task if required
340+
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(execTask); ee.isValid())
341+
return ee;
342+
#endif
343+
344+
// Return success
345+
return Qx::Error();
346+
}
325347

348+
TExec* CPlay::createStdGameExecTask(const Fp::Game& game, const Fp::GameData& gameData, Task::Stage taskStage)
349+
{
326350
QString gamePath = mCore.resolveFullAppPath(!gameData.isNull() ? gameData.appPath() : game.appPath(),
327351
game.platformName());
328352
QFileInfo gamePathInfo(gamePath);
329-
330-
addPassthroughParameters(param);
353+
QString param = !gameData.isNull() ? gameData.launchCommand() : game.launchCommand();
331354

332355
TExec* gameTask = new TExec(mCore);
333356
gameTask->setIdentifier(game.title());
@@ -338,19 +361,28 @@ Qx::Error CPlay::enqueueGame(const Fp::Game& game, const Fp::GameData& gameData,
338361
gameTask->setEnvironment(mCore.childTitleProcessEnvironment());
339362
gameTask->setProcessType(TExec::ProcessType::Blocking);
340363

341-
mCore.enqueueSingleTask(gameTask);
342-
343-
#ifdef _WIN32
344-
// Add wait task if required
345-
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(gamePathInfo); ee.isValid())
346-
return ee;
347-
#endif
364+
return gameTask;
365+
}
348366

349-
// Return success
350-
return Qx::Error();
367+
TExec* CPlay::createStdAddAppExecTask(const Fp::AddApp& addApp, const Fp::Game& parent, Task::Stage taskStage)
368+
{
369+
QString addAppPath = mCore.resolveFullAppPath(addApp.appPath(), parent.platformName());
370+
QFileInfo addAppPathInfo(addAppPath);
371+
QString param = addApp.launchCommand();
372+
373+
TExec* addAppTask = new TExec(mCore);
374+
addAppTask->setIdentifier(addApp.name());
375+
addAppTask->setStage(taskStage);
376+
addAppTask->setExecutable(QDir::cleanPath(addAppPathInfo.absoluteFilePath())); // Like canonical but doesn't care if path DNE
377+
addAppTask->setDirectory(addAppPathInfo.absoluteDir());
378+
addAppTask->setParameters(param);
379+
addAppTask->setEnvironment(mCore.childTitleProcessEnvironment());
380+
addAppTask->setProcessType(addApp.isWaitExit() || taskStage == Task::Stage::Primary ? TExec::ProcessType::Blocking : TExec::ProcessType::Deferred);
381+
382+
return addAppTask;
351383
}
352384

353-
void CPlay::enqueueRuffleTask(const QString& name, const QString& originalParams)
385+
TExec* CPlay::createRuffleTask(const QString& name, const QString& originalParams)
354386
{
355387
/* Replicating:
356388
*
@@ -384,19 +416,18 @@ void CPlay::enqueueRuffleTask(const QString& name, const QString& originalParams
384416
u"--proxy"_s,
385417
fp.preferences().browserModeProxy
386418
};
387-
addPassthroughParameters(newParams);
388419
newParams.append(QProcess::splitCommand(originalParams));
389420

390-
TExec* gameTask = new TExec(mCore);
391-
gameTask->setIdentifier(name);
392-
gameTask->setStage(Task::Stage::Primary);
393-
gameTask->setExecutable(ruffle.absoluteFilePath());
394-
gameTask->setDirectory(ruffle.absoluteDir());
395-
gameTask->setParameters(newParams);
396-
gameTask->setEnvironment(mCore.childTitleProcessEnvironment());
397-
gameTask->setProcessType(TExec::ProcessType::Blocking);
421+
TExec* ruffleTask = new TExec(mCore);
422+
ruffleTask->setIdentifier(name);
423+
ruffleTask->setStage(Task::Stage::Primary);
424+
ruffleTask->setExecutable(ruffle.absoluteFilePath());
425+
ruffleTask->setDirectory(ruffle.absoluteDir());
426+
ruffleTask->setParameters(newParams);
427+
ruffleTask->setEnvironment(mCore.childTitleProcessEnvironment());
428+
ruffleTask->setProcessType(TExec::ProcessType::Blocking);
398429

399-
mCore.enqueueSingleTask(gameTask);
430+
return ruffleTask;
400431
}
401432

402433
//Protected:

lib/backend/src/command/c-play.h

Lines changed: 22 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -8,6 +8,8 @@
88
#include "command/title-command.h"
99
#include "task/task.h"
1010

11+
class TExec;
12+
1113
class QX_ERROR_TYPE(CPlayError, "CPlayError", 1212)
1214
{
1315
friend class CPlay;
@@ -59,8 +61,19 @@ class CPlay : public TitleCommand
5961
static inline const QRegularExpression URL_REGEX = QRegularExpression(
6062
u"flashpoint:\\/\\/(?<id>[0-9a-fA-F]{8}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{4}\\b-[0-9a-fA-F]{12})\\/?$"_s
6163
);
64+
static inline const QHash<QString, QString> FULLSCREEN_PARAMS{
65+
/* Might want to do this in a more flexible way to account for exe name differences,
66+
* but for now it's just a map of the lowercase basename of the executeable to the parameter(s)
67+
* to use for fullscreen
68+
*/
69+
{u"ruffle"_s, u"--fullscreen"_s}
70+
};
6271

6372
// Command line option strings
73+
static inline const QString CL_OPT_FULLSCREEN_S_NAME = u"f"_s;
74+
static inline const QString CL_OPT_FULLSCREEN_L_NAME = u"fullscreen"_s;
75+
static inline const QString CL_OPT_FULLSCREEN_DESC = u"Runs the title in fullscreen mode, if supported."_s;
76+
6477
static inline const QString CL_OPT_URL_S_NAME = u"u"_s;
6578
static inline const QString CL_OPT_URL_L_NAME = u"url"_s;
6679
static inline const QString CL_OPT_URL_DESC = u""_s;
@@ -73,9 +86,10 @@ class CPlay : public TitleCommand
7386

7487
// Command line options
7588
static inline const QCommandLineOption CL_OPTION_URL{{CL_OPT_URL_S_NAME, CL_OPT_URL_L_NAME}, CL_OPT_URL_DESC, u"url"_s}; // Takes value
89+
static inline const QCommandLineOption CL_OPTION_FULLSCREEN{{CL_OPT_FULLSCREEN_S_NAME, CL_OPT_FULLSCREEN_L_NAME}, CL_OPT_FULLSCREEN_DESC}; // Boolean
7690
static inline const QCommandLineOption CL_OPTION_RUFFLE{{CL_OPT_RUFFLE_L_NAME}, CL_OPT_URL_DESC}; // Boolean
7791
static inline const QCommandLineOption CL_OPTION_FLASH{{CL_OPT_FLASH_L_NAME}, CL_OPT_FLASH_DESC}; // Boolean
78-
static inline const QList<const QCommandLineOption*> CL_OPTIONS_SPECIFIC{&CL_OPTION_URL, &CL_OPTION_RUFFLE, &CL_OPTION_FLASH};
92+
static inline const QList<const QCommandLineOption*> CL_OPTIONS_SPECIFIC{&CL_OPTION_URL, &CL_OPTION_FULLSCREEN, &CL_OPTION_RUFFLE, &CL_OPTION_FLASH};
7993

8094
// Logging - Messages
8195
static inline const QString LOG_EVENT_HANDLING_AUTO = u"Handling automatic tasks..."_s;
@@ -85,6 +99,9 @@ class CPlay : public TitleCommand
8599
static inline const QString LOG_EVENT_FOUND_AUTORUN = u"Found autorun-before additional app: %1"_s;
86100
static inline const QString LOG_EVENT_DATA_PACK_TITLE = u"Selected title uses a data pack"_s;
87101
static inline const QString LOG_EVENT_SERVER_OVERRIDE = u"Selected title overrides the server to: %1"_s;
102+
static inline const QString LOG_EVENT_FORCING_FULLSCREEN = u"Fullscreen requested..."_s;
103+
static inline const QString LOG_EVENT_FULLSCREEN_UNSUPPORTED = u"No fullscreen parameter is known for this application."_s;
104+
static inline const QString LOG_EVENT_FULLSCREEN_SUPPORTED = u"Fullscreen parameter: %1"_s;
88105
static inline const QString LOG_EVENT_USING_RUFFLE_SUPPORTED = u"Using Ruffle for this title (supported)"_s;
89106
static inline const QString LOG_EVENT_USING_RUFFLE_UNSUPPORTED = u"Using Ruffle for this title (unsupported)"_s;
90107
static inline const QString LOG_EVENT_FORCING_RUFFLE = u"Forcing the use of Ruffle for this title"_s;
@@ -106,15 +123,16 @@ class CPlay : public TitleCommand
106123

107124
//-Instance Functions------------------------------------------------------------------------------------------------------
108125
private:
109-
void addPassthroughParameters(QString& param);
110-
void addPassthroughParameters(QStringList& param);
126+
void addExtraExecParameters(TExec* execTask, Task::Stage taskStage);
111127
QString getServerOverride(const Fp::GameData& gd);
112128
bool useRuffle(const Fp::Game& game, Task::Stage stage);
113129
Qx::Error handleEntry(const Fp::Game& game);
114130
Qx::Error handleEntry(const Fp::AddApp& addApp);
115131
Qx::Error enqueueAdditionalApp(const Fp::AddApp& addApp, const Fp::Game& parent, Task::Stage taskStage);
116132
Qx::Error enqueueGame(const Fp::Game& game, const Fp::GameData& gameData, Task::Stage taskStage);
117-
void enqueueRuffleTask(const QString& name, const QString& originalParams);
133+
TExec* createStdGameExecTask(const Fp::Game& game, const Fp::GameData& gameData, Task::Stage taskStage);
134+
TExec* createStdAddAppExecTask(const Fp::AddApp& addApp, const Fp::Game& parent, Task::Stage taskStage);
135+
TExec* createRuffleTask(const QString& name, const QString& originalParams);
118136

119137
protected:
120138
QList<const QCommandLineOption*> options() const override;

lib/backend/src/command/c-run.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -65,7 +65,7 @@ Qx::Error CRun::perform()
6565

6666
#ifdef _WIN32
6767
// Add wait task if required
68-
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(inputInfo); ee.isValid())
68+
if(Qx::Error ee = mCore.conditionallyEnqueueBideTask(runTask); ee.isValid())
6969
return ee;
7070
#endif
7171

lib/backend/src/kernel/core.cpp

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -631,13 +631,14 @@ void Core::enqueueShutdownTasks()
631631
}
632632

633633
#ifdef _WIN32
634-
Qx::Error Core::conditionallyEnqueueBideTask(QFileInfo precedingAppInfo)
634+
Qx::Error Core::conditionallyEnqueueBideTask(const TExec* precedingTask)
635635
{
636636
const Fp::Toolkit* tk = mFlashpointInstall->toolkit();
637637

638638
// Add wait for apps that involve secure player
639+
QFileInfo preeedingInfo(precedingTask->executable());
639640
bool involvesSecurePlayer;
640-
Qx::Error securePlayerCheckError = tk->appInvolvesSecurePlayer(involvesSecurePlayer, precedingAppInfo);
641+
Qx::Error securePlayerCheckError = tk->appInvolvesSecurePlayer(involvesSecurePlayer, preeedingInfo);
641642
if(securePlayerCheckError.isValid())
642643
{
643644
postDirective<DError>(securePlayerCheckError);

lib/backend/src/kernel/core.h

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -79,6 +79,8 @@ class QX_ERROR_TYPE(CoreError, "CoreError", 1200)
7979
QString deriveSecondary() const override;
8080
};
8181

82+
class TExec;
83+
8284
class Core : public QObject, public Directorate
8385
{
8486
Q_OBJECT;
@@ -252,7 +254,7 @@ class Core : public QObject, public Directorate
252254
CoreError enqueueStartupTasks(const QString& serverOverride = {});
253255
void enqueueShutdownTasks();
254256
#ifdef _WIN32
255-
Qx::Error conditionallyEnqueueBideTask(QFileInfo precedingAppInfo);
257+
Qx::Error conditionallyEnqueueBideTask(const TExec* precedingTask);
256258
#endif
257259
Qx::Error enqueueDataPackTasks(const Fp::GameData& gameData);
258260
void enqueueSingleTask(Task* task);

0 commit comments

Comments
 (0)