1
0
mirror of git://projects.qi-hardware.com/gmenu2x.git synced 2024-07-02 18:54:31 +03:00

Launch application after destructing menu

This allows all destructors to do their job before we pass control to
a new process.
This commit is contained in:
Maarten ter Huurne 2014-08-10 02:09:34 +02:00
parent 303ecf298a
commit 7c4fa5d77a
4 changed files with 107 additions and 67 deletions

View File

@ -125,8 +125,9 @@ static const char *colorToString(enum color c)
} }
static void quit_all(int err) { static void quit_all(int err) {
delete app; delete app;
exit(err); SDL_Quit();
exit(err);
} }
const string GMenu2X::getHome(void) const string GMenu2X::getHome(void)
@ -163,11 +164,31 @@ int main(int /*argc*/, char * /*argv*/[]) {
DEBUG("Home path: %s.\n", gmenu2x_home.c_str()); DEBUG("Home path: %s.\n", gmenu2x_home.c_str());
app = new GMenu2X(); GMenu2X::run();
DEBUG("Starting main()\n");
app->main();
return 0; return EXIT_FAILURE;
}
void GMenu2X::run() {
auto menu = new GMenu2X();
app = menu;
DEBUG("Starting main()\n");
menu->mainLoop();
app = nullptr;
Launcher *toLaunch = menu->toLaunch.release();
delete menu;
SDL_Quit();
unsetenv("SDL_FBCON_DONT_CLEAR");
if (toLaunch) {
toLaunch->exec();
// If control gets here, execution failed. Since we already destructed
// everything, the easiest solution is to exit and let the system
// respawn the menu.
delete toLaunch;
}
} }
#ifdef ENABLE_CPUFREQ #ifdef ENABLE_CPUFREQ
@ -194,7 +215,6 @@ void GMenu2X::initCPULimits() {
#endif #endif
GMenu2X::GMenu2X() GMenu2X::GMenu2X()
: appToLaunch(nullptr)
{ {
usbnet = samba = inet = web = false; usbnet = samba = inet = web = false;
useSelectionPng = false; useSelectionPng = false;
@ -219,7 +239,9 @@ GMenu2X::GMenu2X()
if( SDL_Init(SDL_INIT_TIMER) < 0) { if( SDL_Init(SDL_INIT_TIMER) < 0) {
ERROR("Could not initialize SDL: %s\n", SDL_GetError()); ERROR("Could not initialize SDL: %s\n", SDL_GetError());
quit(); // TODO: We don't use exceptions, so don't put things that can fail
// in a constructor.
exit(EXIT_FAILURE);
} }
bg = NULL; bg = NULL;
@ -232,7 +254,9 @@ GMenu2X::GMenu2X()
* a black screen for a couple of seconds. */ * a black screen for a couple of seconds. */
if( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { if( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) {
ERROR("Could not initialize SDL: %s\n", SDL_GetError()); ERROR("Could not initialize SDL: %s\n", SDL_GetError());
quit(); // TODO: We don't use exceptions, so don't put things that can fail
// in a constructor.
exit(EXIT_FAILURE);
} }
s = Surface::openOutputSurface(resX, resY, confInt["videoBpp"]); s = Surface::openOutputSurface(resX, resY, confInt["videoBpp"]);
@ -275,22 +299,17 @@ GMenu2X::GMenu2X()
} }
GMenu2X::~GMenu2X() { GMenu2X::~GMenu2X() {
if (PowerSaver::isRunning()) if (PowerSaver::isRunning()) {
delete PowerSaver::getInstance(); delete PowerSaver::getInstance();
quit(); }
#ifdef ENABLE_INOTIFY
delete monitor;
#endif
}
void GMenu2X::quit() {
fflush(NULL); fflush(NULL);
sc.clear(); sc.clear();
delete s; delete s;
SDL_Quit(); #ifdef ENABLE_INOTIFY
unsetenv("SDL_FBCON_DONT_CLEAR"); delete monitor;
#endif
} }
void GMenu2X::initBG() { void GMenu2X::initBG() {
@ -567,12 +586,10 @@ void GMenu2X::writeTmp(int selelem, const string &selectordir) {
} }
} }
void GMenu2X::main() { void GMenu2X::mainLoop() {
if (!fileExists(CARD_ROOT)) if (!fileExists(CARD_ROOT))
CARD_ROOT = ""; CARD_ROOT = "";
appToLaunch = nullptr;
// Recover last session // Recover last session
readTmp(); readTmp();
if (lastSelectorElement > -1 && menu->selLinkApp() && if (lastSelectorElement > -1 && menu->selLinkApp() &&
@ -600,10 +617,12 @@ void GMenu2X::main() {
for (auto layer : layers) { for (auto layer : layers) {
layer->paint(*s); layer->paint(*s);
} }
if (appToLaunch) { s->flip();
// Exit main loop once we have something to launch.
if (toLaunch) {
break; break;
} }
s->flip();
// Handle touchscreen events. // Handle touchscreen events.
if (ts.available()) { if (ts.available()) {
@ -630,11 +649,6 @@ void GMenu2X::main() {
} }
} }
} }
if (appToLaunch) {
appToLaunch->drawRun();
appToLaunch->launch(fileToLaunch);
}
} }
void GMenu2X::explorer() { void GMenu2X::explorer() {
@ -645,24 +659,20 @@ void GMenu2X::explorer() {
string command = cmdclean(fd.getPath()+"/"+fd.getFile()); string command = cmdclean(fd.getPath()+"/"+fd.getFile());
chdir(fd.getPath().c_str()); chdir(fd.getPath().c_str());
quit();
#ifdef ENABLE_CPUFREQ #ifdef ENABLE_CPUFREQ
setClock(cpuFreqAppDefault); setClock(cpuFreqAppDefault);
#endif #endif
Launcher launcher(vector<string> { "/bin/sh", "-c", command }); toLaunch.reset(new Launcher(
launcher.exec(); vector<string> { "/bin/sh", "-c", command }));
//if execution continues then something went wrong and as we already called SDL_Quit we cannot continue
//try relaunching gmenu2x
ERROR("Error executing selected application, re-launching gmenu2x\n");
main();
} }
} }
void GMenu2X::queueLaunch(LinkApp *app, const std::string &file) { void GMenu2X::queueLaunch(
appToLaunch = app; unique_ptr<Launcher>&& launcher, shared_ptr<Layer> launchLayer
fileToLaunch = file; ) {
toLaunch = move(launcher);
layers.push_back(launchLayer);
} }
void GMenu2X::showHelpPopup() { void GMenu2X::showHelpPopup() {

View File

@ -38,8 +38,8 @@ class Button;
class Font; class Font;
class HelpPopup; class HelpPopup;
class IconButton; class IconButton;
class Launcher;
class Layer; class Layer;
class LinkApp;
class MediaMonitor; class MediaMonitor;
class Menu; class Menu;
class Surface; class Surface;
@ -76,8 +76,7 @@ private:
MediaMonitor *monitor; MediaMonitor *monitor;
#endif #endif
LinkApp *appToLaunch; std::unique_ptr<Launcher> toLaunch;
std::string fileToLaunch;
std::vector<std::shared_ptr<Layer>> layers; std::vector<std::shared_ptr<Layer>> layers;
@ -120,9 +119,10 @@ private:
void initBG(); void initBG();
public: public:
static void run();
GMenu2X(); GMenu2X();
~GMenu2X(); ~GMenu2X();
void quit();
/* Returns the home directory of gmenu2x, usually /* Returns the home directory of gmenu2x, usually
* ~/.gmenu2x */ * ~/.gmenu2x */
@ -162,7 +162,7 @@ public:
std::unique_ptr<Font> font; std::unique_ptr<Font> font;
//Status functions //Status functions
void main(); void mainLoop();
void showContextMenu(); void showContextMenu();
void showHelpPopup(); void showHelpPopup();
void showManual(); void showManual();
@ -184,7 +184,9 @@ public:
* The launch won't happen immediately; it will happen after control * The launch won't happen immediately; it will happen after control
* returns to the main loop. * returns to the main loop.
*/ */
void queueLaunch(LinkApp *app, const std::string &file); void queueLaunch(std::unique_ptr<Launcher>&& launcher,
std::shared_ptr<Layer> launchLayer);
void saveSelection(); void saveSelection();
void writeConfig(); void writeConfig();
void writeSkinConfig(); void writeSkinConfig();

View File

@ -24,6 +24,7 @@
#include "delegate.h" #include "delegate.h"
#include "gmenu2x.h" #include "gmenu2x.h"
#include "launcher.h" #include "launcher.h"
#include "layer.h"
#include "menu.h" #include "menu.h"
#include "selector.h" #include "selector.h"
#include "surface.h" #include "surface.h"
@ -55,6 +56,31 @@ using namespace std;
static array<const char *, 4> tokens = { "%f", "%F", "%u", "%U", }; static array<const char *, 4> tokens = { "%f", "%F", "%u", "%U", };
/**
* Displays the launch message (loading screen).
*/
class LaunchLayer: public Layer {
public:
LaunchLayer(LinkApp& app) : app(app) {}
void paint(Surface &s) override {
app.drawLaunch(s);
}
bool handleButtonPress(InputManager::Button) override {
return true;
}
bool handleTouchscreen(Touchscreen&) override {
return true;
}
private:
LinkApp& app;
};
#ifdef HAVE_LIBOPK #ifdef HAVE_LIBOPK
LinkApp::LinkApp(GMenu2X *gmenu2x_, const char* linkfile, LinkApp::LinkApp(GMenu2X *gmenu2x_, const char* linkfile,
struct OPK *opk, const char *metadata_) struct OPK *opk, const char *metadata_)
@ -323,9 +349,9 @@ bool LinkApp::save() {
return false; return false;
} }
void LinkApp::drawRun() { void LinkApp::drawLaunch(Surface& s) {
//Darkened background //Darkened background
gmenu2x->s->box(0, 0, gmenu2x->resX, gmenu2x->resY, 0,0,0,150); s.box(0, 0, gmenu2x->resX, gmenu2x->resY, 0,0,0,150);
string text = getLaunchMsg().empty() string text = getLaunchMsg().empty()
? gmenu2x->tr.translate("Launching $1", getTitle().c_str(), nullptr) ? gmenu2x->tr.translate("Launching $1", getTitle().c_str(), nullptr)
@ -336,25 +362,25 @@ void LinkApp::drawRun() {
int halfBoxW = boxW/2; int halfBoxW = boxW/2;
//outer box //outer box
gmenu2x->s->box(gmenu2x->halfX-2-halfBoxW, gmenu2x->halfY-23, halfBoxW*2+5, 47, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BG]); s.box(gmenu2x->halfX-2-halfBoxW, gmenu2x->halfY-23, halfBoxW*2+5, 47, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BG]);
//inner rectangle //inner rectangle
gmenu2x->s->rectangle(gmenu2x->halfX-halfBoxW, gmenu2x->halfY-21, boxW, 42, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BORDER]); s.rectangle(gmenu2x->halfX-halfBoxW, gmenu2x->halfY-21, boxW, 42, gmenu2x->skinConfColors[COLOR_MESSAGE_BOX_BORDER]);
int x = gmenu2x->halfX+10-halfBoxW; int x = gmenu2x->halfX+10-halfBoxW;
/*if (!getIcon().empty()) /*if (!getIcon().empty())
gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104); gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104);
else else
gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/ gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/
iconSurface->blit(gmenu2x->s,x,gmenu2x->halfY-16); iconSurface->blit(&s, x, gmenu2x->halfY - 16);
gmenu2x->font->write(gmenu2x->s, text, x+42, gmenu2x->halfY+1, Font::HAlignLeft, Font::VAlignMiddle ); gmenu2x->font->write(&s, text, x + 42, gmenu2x->halfY + 1, Font::HAlignLeft, Font::VAlignMiddle);
gmenu2x->s->flip();
} }
void LinkApp::start() { void LinkApp::start() {
if (!selectordir.empty()) if (selectordir.empty()) {
gmenu2x->queueLaunch(prepareLaunch(""), make_shared<LaunchLayer>(*this));
} else {
selector(); selector();
else }
gmenu2x->queueLaunch(this, "");
} }
void LinkApp::showManual() { void LinkApp::showManual() {
@ -510,11 +536,13 @@ void LinkApp::selector(int startSelection, const string &selectorDir) {
selectordir = selectedDir; selectordir = selectedDir;
} }
gmenu2x->writeTmp(selection, selectedDir); gmenu2x->writeTmp(selection, selectedDir);
gmenu2x->queueLaunch(this, selectedDir + sel.getFile()); gmenu2x->queueLaunch(
prepareLaunch(selectedDir + sel.getFile()),
make_shared<LaunchLayer>(*this));
} }
} }
void LinkApp::launch(const string &selectedFile) { unique_ptr<Launcher> LinkApp::prepareLaunch(const string &selectedFile) {
save(); save();
if (!isOpk()) { if (!isOpk()) {
@ -568,7 +596,6 @@ void LinkApp::launch(const string &selectedFile) {
gmenu2x->setClock(clock()); gmenu2x->setClock(clock());
} }
#endif #endif
gmenu2x->quit();
vector<string> commandLine; vector<string> commandLine;
if (isOpk()) { if (isOpk()) {
@ -582,12 +609,8 @@ void LinkApp::launch(const string &selectedFile) {
commandLine = { "/bin/sh", "-c", exec + " " + params }; commandLine = { "/bin/sh", "-c", exec + " " + params };
} }
Launcher launcher(move(commandLine), consoleApp); return std::unique_ptr<Launcher>(new Launcher(
launcher.exec(); move(commandLine), consoleApp));
//if execution continues then something went wrong and as we already called SDL_Quit we cannot continue
//try relaunching gmenu2x
gmenu2x->main();
} }
const string &LinkApp::getExec() { const string &LinkApp::getExec() {

View File

@ -23,9 +23,11 @@
#include "link.h" #include "link.h"
#include <memory>
#include <string> #include <string>
class GMenu2X; class GMenu2X;
class Launcher;
/** /**
Parses links files. Parses links files.
@ -95,8 +97,11 @@ public:
const std::string &getFile() { return file; } const std::string &getFile() { return file; }
void renameFile(const std::string &name); void renameFile(const std::string &name);
void drawRun(); private:
void launch(const std::string &selectedFile); void drawLaunch(Surface& s);
std::unique_ptr<Launcher> prepareLaunch(const std::string &selectedFile);
friend class LaunchLayer;
}; };
#endif #endif