diff --git a/src/gmenu2x.cpp b/src/gmenu2x.cpp index 9916f2d..8c8bd05 100644 --- a/src/gmenu2x.cpp +++ b/src/gmenu2x.cpp @@ -125,8 +125,9 @@ static const char *colorToString(enum color c) } static void quit_all(int err) { - delete app; - exit(err); + delete app; + SDL_Quit(); + exit(err); } const string GMenu2X::getHome(void) @@ -163,11 +164,31 @@ int main(int /*argc*/, char * /*argv*/[]) { DEBUG("Home path: %s.\n", gmenu2x_home.c_str()); - app = new GMenu2X(); - DEBUG("Starting main()\n"); - app->main(); + GMenu2X::run(); - 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 @@ -194,7 +215,6 @@ void GMenu2X::initCPULimits() { #endif GMenu2X::GMenu2X() - : appToLaunch(nullptr) { usbnet = samba = inet = web = false; useSelectionPng = false; @@ -219,7 +239,9 @@ GMenu2X::GMenu2X() if( SDL_Init(SDL_INIT_TIMER) < 0) { 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; @@ -232,7 +254,9 @@ GMenu2X::GMenu2X() * a black screen for a couple of seconds. */ if( SDL_InitSubSystem(SDL_INIT_VIDEO) < 0) { 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"]); @@ -275,22 +299,17 @@ GMenu2X::GMenu2X() } GMenu2X::~GMenu2X() { - if (PowerSaver::isRunning()) + if (PowerSaver::isRunning()) { delete PowerSaver::getInstance(); - quit(); + } -#ifdef ENABLE_INOTIFY - delete monitor; -#endif -} - -void GMenu2X::quit() { fflush(NULL); sc.clear(); delete s; - SDL_Quit(); - unsetenv("SDL_FBCON_DONT_CLEAR"); +#ifdef ENABLE_INOTIFY + delete monitor; +#endif } 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)) CARD_ROOT = ""; - appToLaunch = nullptr; - // Recover last session readTmp(); if (lastSelectorElement > -1 && menu->selLinkApp() && @@ -600,10 +617,12 @@ void GMenu2X::main() { for (auto layer : layers) { layer->paint(*s); } - if (appToLaunch) { + s->flip(); + + // Exit main loop once we have something to launch. + if (toLaunch) { break; } - s->flip(); // Handle touchscreen events. if (ts.available()) { @@ -630,11 +649,6 @@ void GMenu2X::main() { } } } - - if (appToLaunch) { - appToLaunch->drawRun(); - appToLaunch->launch(fileToLaunch); - } } void GMenu2X::explorer() { @@ -645,24 +659,20 @@ void GMenu2X::explorer() { string command = cmdclean(fd.getPath()+"/"+fd.getFile()); chdir(fd.getPath().c_str()); - quit(); #ifdef ENABLE_CPUFREQ setClock(cpuFreqAppDefault); #endif - Launcher launcher(vector { "/bin/sh", "-c", command }); - launcher.exec(); - - //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(); + toLaunch.reset(new Launcher( + vector { "/bin/sh", "-c", command })); } } -void GMenu2X::queueLaunch(LinkApp *app, const std::string &file) { - appToLaunch = app; - fileToLaunch = file; +void GMenu2X::queueLaunch( + unique_ptr&& launcher, shared_ptr launchLayer +) { + toLaunch = move(launcher); + layers.push_back(launchLayer); } void GMenu2X::showHelpPopup() { diff --git a/src/gmenu2x.h b/src/gmenu2x.h index ca00e80..41fc87d 100644 --- a/src/gmenu2x.h +++ b/src/gmenu2x.h @@ -38,8 +38,8 @@ class Button; class Font; class HelpPopup; class IconButton; +class Launcher; class Layer; -class LinkApp; class MediaMonitor; class Menu; class Surface; @@ -76,8 +76,7 @@ private: MediaMonitor *monitor; #endif - LinkApp *appToLaunch; - std::string fileToLaunch; + std::unique_ptr toLaunch; std::vector> layers; @@ -120,9 +119,10 @@ private: void initBG(); public: + static void run(); + GMenu2X(); ~GMenu2X(); - void quit(); /* Returns the home directory of gmenu2x, usually * ~/.gmenu2x */ @@ -162,7 +162,7 @@ public: std::unique_ptr font; //Status functions - void main(); + void mainLoop(); void showContextMenu(); void showHelpPopup(); void showManual(); @@ -184,7 +184,9 @@ public: * The launch won't happen immediately; it will happen after control * returns to the main loop. */ - void queueLaunch(LinkApp *app, const std::string &file); + void queueLaunch(std::unique_ptr&& launcher, + std::shared_ptr launchLayer); + void saveSelection(); void writeConfig(); void writeSkinConfig(); diff --git a/src/linkapp.cpp b/src/linkapp.cpp index d19c5ed..57426d8 100644 --- a/src/linkapp.cpp +++ b/src/linkapp.cpp @@ -24,6 +24,7 @@ #include "delegate.h" #include "gmenu2x.h" #include "launcher.h" +#include "layer.h" #include "menu.h" #include "selector.h" #include "surface.h" @@ -55,6 +56,31 @@ using namespace std; static array 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 LinkApp::LinkApp(GMenu2X *gmenu2x_, const char* linkfile, struct OPK *opk, const char *metadata_) @@ -323,9 +349,9 @@ bool LinkApp::save() { return false; } -void LinkApp::drawRun() { +void LinkApp::drawLaunch(Surface& s) { //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() ? gmenu2x->tr.translate("Launching $1", getTitle().c_str(), nullptr) @@ -336,25 +362,25 @@ void LinkApp::drawRun() { int halfBoxW = boxW/2; //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 - 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; /*if (!getIcon().empty()) gmenu2x->sc[getIcon()]->blit(gmenu2x->s,x,104); else gmenu2x->sc["icons/generic.png"]->blit(gmenu2x->s,x,104);*/ - iconSurface->blit(gmenu2x->s,x,gmenu2x->halfY-16); - gmenu2x->font->write(gmenu2x->s, text, x+42, gmenu2x->halfY+1, Font::HAlignLeft, Font::VAlignMiddle ); - gmenu2x->s->flip(); + iconSurface->blit(&s, x, gmenu2x->halfY - 16); + gmenu2x->font->write(&s, text, x + 42, gmenu2x->halfY + 1, Font::HAlignLeft, Font::VAlignMiddle); } void LinkApp::start() { - if (!selectordir.empty()) + if (selectordir.empty()) { + gmenu2x->queueLaunch(prepareLaunch(""), make_shared(*this)); + } else { selector(); - else - gmenu2x->queueLaunch(this, ""); + } } void LinkApp::showManual() { @@ -510,11 +536,13 @@ void LinkApp::selector(int startSelection, const string &selectorDir) { selectordir = selectedDir; } gmenu2x->writeTmp(selection, selectedDir); - gmenu2x->queueLaunch(this, selectedDir + sel.getFile()); + gmenu2x->queueLaunch( + prepareLaunch(selectedDir + sel.getFile()), + make_shared(*this)); } } -void LinkApp::launch(const string &selectedFile) { +unique_ptr LinkApp::prepareLaunch(const string &selectedFile) { save(); if (!isOpk()) { @@ -568,7 +596,6 @@ void LinkApp::launch(const string &selectedFile) { gmenu2x->setClock(clock()); } #endif - gmenu2x->quit(); vector commandLine; if (isOpk()) { @@ -582,12 +609,8 @@ void LinkApp::launch(const string &selectedFile) { commandLine = { "/bin/sh", "-c", exec + " " + params }; } - Launcher launcher(move(commandLine), consoleApp); - launcher.exec(); - - //if execution continues then something went wrong and as we already called SDL_Quit we cannot continue - //try relaunching gmenu2x - gmenu2x->main(); + return std::unique_ptr(new Launcher( + move(commandLine), consoleApp)); } const string &LinkApp::getExec() { diff --git a/src/linkapp.h b/src/linkapp.h index 25ef346..5ce8d2a 100644 --- a/src/linkapp.h +++ b/src/linkapp.h @@ -23,9 +23,11 @@ #include "link.h" +#include #include class GMenu2X; +class Launcher; /** Parses links files. @@ -95,8 +97,11 @@ public: const std::string &getFile() { return file; } void renameFile(const std::string &name); - void drawRun(); - void launch(const std::string &selectedFile); +private: + void drawLaunch(Surface& s); + std::unique_ptr prepareLaunch(const std::string &selectedFile); + + friend class LaunchLayer; }; #endif